You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-06-29 02:33:43 +00:00
Compare commits
18 Commits
v4.11.4
...
0441238cc5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0441238cc5 | ||
|
|
639bc9c342 | ||
|
|
b3d42a2478 | ||
|
|
418b257ae2 | ||
|
|
664c7963ea | ||
|
|
7363f7497c | ||
|
|
f961b8dc89 | ||
|
|
18175c040e | ||
|
|
9cd47c32bc | ||
|
|
48b38ec34f | ||
|
|
b740dd662d | ||
|
|
f8ac9869f1 | ||
|
|
a5ee687821 | ||
|
|
859fa20d29 | ||
|
|
d89d394e04 | ||
|
|
031d46a321 | ||
|
|
af0e98239b | ||
|
|
5384f61c56 |
6
.github/CODEOWNERS
vendored
Normal file
6
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# This is a comment.
|
||||||
|
# Each line is a file pattern followed by one or more owners.
|
||||||
|
# https://docs.github.com/ja/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||||
|
|
||||||
|
# Default owners
|
||||||
|
* @mob-sakai
|
||||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: mob-sakai # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: mob_sakai # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: mob-sakai
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Environment (please complete the following information):**
|
||||||
|
- Version [e.g. 1.0.0]
|
||||||
|
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
||||||
|
- Unity version: [e.g. 2018.2.8f1]
|
||||||
|
- Build options: [e.g. IL2CPP, .Net 4.x, LWRP]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: mob-sakai
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
16
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
name: Question
|
||||||
|
about: Ask a question about this project
|
||||||
|
title: ''
|
||||||
|
labels: question
|
||||||
|
assignees: mob-sakai
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
|
||||||
|
|
||||||
|
**Describe what help do you need**
|
||||||
|
A description of the question.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the question here.
|
||||||
37
.github/pull_request_template.md
vendored
Normal file
37
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
# Pull Request Template
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
- Please include a summary of the change and which issue is fixed.
|
||||||
|
- Please also include relevant motivation and context.
|
||||||
|
- List any dependencies that are required for this change.
|
||||||
|
|
||||||
|
Fixes #{issue_number}
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
Please write the commit message in the format corresponding to the change type.
|
||||||
|
Please see [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for more information.
|
||||||
|
|
||||||
|
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||||
|
- [ ] New feature (non-breaking change which adds functionality)
|
||||||
|
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||||
|
- [ ] Update documentations
|
||||||
|
- [ ] Others (refactoring, style changes, etc.)
|
||||||
|
|
||||||
|
## Test environment
|
||||||
|
|
||||||
|
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
||||||
|
- Unity version: [e.g. 2022.2.0f1]
|
||||||
|
- Build options: [e.g. IL2CPP, .Net 4.x, URP/HDRP]
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] This pull request is for merging into the `develop` branch
|
||||||
|
- [ ] My code follows the style guidelines of this project
|
||||||
|
- [ ] I have performed a self-review of my own code
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
- [ ] I have made corresponding changes to the documentation
|
||||||
|
- [ ] My changes generate no new warnings
|
||||||
|
- [ ] I have checked my code and corrected any misspellings
|
||||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -27,10 +27,10 @@ jobs:
|
|||||||
split_to: ${{ steps.summary.outputs.split_to }}
|
split_to: ${{ steps.summary.outputs.split_to }}
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout (${{ github.ref_name }})
|
- name: 🚚 Checkout (${{ github.ref_name }})
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: 🔖 Run semantic release
|
- name: 🔖 Run semantic release
|
||||||
uses: cycjimmy/semantic-release-action@v5
|
uses: cycjimmy/semantic-release-action@v6
|
||||||
id: release
|
id: release
|
||||||
with:
|
with:
|
||||||
working_directory: Packages/src
|
working_directory: Packages/src
|
||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
@semantic-release/changelog
|
@semantic-release/changelog
|
||||||
@semantic-release/git
|
@semantic-release/git
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
- id: summary
|
- id: summary
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
47
.github/workflows/test.yml
vendored
47
.github/workflows/test.yml
vendored
@@ -7,9 +7,9 @@ run-name: 🧪 Test (${{ github.event.pull_request.title || github.ref_name }})
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# MINIMUM_VERSION: The minimum version of Unity.
|
# MINIMUM_VERSION: The minimum version of Unity.
|
||||||
MINIMUM_VERSION: 2019.4
|
MINIMUM_VERSION: 2020.3
|
||||||
# EXCLUDE_FILTER: The excluded versions of Unity.
|
# EXCLUDE_FILTER: The excluded versions of Unity.
|
||||||
EXCLUDE_FILTER: "(2020.2.0|2021.1|2023.3)"
|
EXCLUDE_FILTER: "(2017|2018|2023.3)"
|
||||||
PROJECT_PATH: .
|
PROJECT_PATH: .
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -27,7 +27,7 @@ on:
|
|||||||
- "!*"
|
- "!*"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "**.md"
|
- "**.md"
|
||||||
pull_request_target:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- reopened
|
- reopened
|
||||||
@@ -39,16 +39,29 @@ jobs:
|
|||||||
setup:
|
setup:
|
||||||
name: ⚙️ Setup
|
name: ⚙️ Setup
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions: {} # No permissions needed for setup job
|
||||||
outputs:
|
outputs:
|
||||||
unityVersions: ${{ steps.setup.outputs.unityVersions }}
|
unityVersions: ${{ steps.setup.outputs.unityVersions }}
|
||||||
steps:
|
steps:
|
||||||
|
- name: 🔑 Secrets check
|
||||||
|
run: |
|
||||||
|
if [ -z "$UNITY_EMAIL" ] || [ -z "$UNITY_PASSWORD" ] || [ -z "UNITY_LICENSE" ]; then
|
||||||
|
echo "Error: UNITY_EMAIL, UNITY_PASSWORD, and UNITY_LICENSE secrets must be set." | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||||
|
echo "Error: See https://game.ci/docs/github/test-runner#basic-setup" | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||||
|
echo "Error: Set the secrets at ${{ github.server_url }}/${{ github.repository }}/settings/secrets/actions" | tee -a $GITHUB_STEP_SUMMARY >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
- name: ⚙️ Find target Unity versions
|
- name: ⚙️ Find target Unity versions
|
||||||
id: setup
|
id: setup
|
||||||
run: |
|
run: |
|
||||||
echo "==== Target Unity Versions ===="
|
echo "==== Target Unity Versions ===="
|
||||||
LATEST_VERSIONS=`npx unity-changeset@latest list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
|
LATEST_VERSIONS=`npx -y unity-changeset@latest list --json --versions --all --latest-patch --ignore-alpha --min ${MINIMUM_VERSION}`
|
||||||
if [ "${{ inputs.usePeriodVersions }}" = "true" ]; then
|
if [ "${{ inputs.usePeriodVersions }}" = "true" ]; then
|
||||||
ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
ADDITIONAL_VERSIONS=`npx -y unity-changeset@latest list --json --versions --ignore-alpha --min ${MINIMUM_VERSION} --grep '0f'`
|
||||||
else
|
else
|
||||||
ADDITIONAL_VERSIONS=[]
|
ADDITIONAL_VERSIONS=[]
|
||||||
fi
|
fi
|
||||||
@@ -66,31 +79,15 @@ jobs:
|
|||||||
needs: setup
|
needs: setup
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
max-parallel: 6
|
max-parallel: 8
|
||||||
matrix:
|
matrix:
|
||||||
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout ($${{ github.ref }})
|
- name: 🚚 Checkout ($${{ github.ref }})
|
||||||
if: github.event_name == 'push'
|
uses: actions/checkout@v6
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: 🚚 Checkout pull request (pull_request_target)
|
|
||||||
if: github.event_name == 'pull_request_target'
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: 🚚 Marge pull request (pull_request_target)
|
|
||||||
if: github.event_name == 'pull_request_target'
|
|
||||||
run: |
|
|
||||||
git config user.name "GitHub Actions"
|
|
||||||
git config user.email "actions@github.com"
|
|
||||||
git rebase ${{ github.event.pull_request.base.sha }}
|
|
||||||
git log --oneline -n 10
|
|
||||||
|
|
||||||
- name: 📥 Cache library
|
- name: 📥 Cache library
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ env.PROJECT_PATH }}/Library
|
path: ${{ env.PROJECT_PATH }}/Library
|
||||||
key: ${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
|
key: ${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
@@ -99,7 +96,7 @@ jobs:
|
|||||||
${{ env.PROJECT_PATH }}-Library-
|
${{ env.PROJECT_PATH }}-Library-
|
||||||
|
|
||||||
- name: 🛠️ Build Unity Project (Test)
|
- name: 🛠️ Build Unity Project (Test)
|
||||||
uses: game-ci/unity-builder@main
|
uses: game-ci/unity-builder@v5
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
with:
|
with:
|
||||||
customImage: ghcr.io/mob-sakai/unity3d:${{ matrix.unityVersion }}
|
customImage: ghcr.io/mob-sakai/unity3d:${{ matrix.unityVersion }}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
||||||
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
"com.unity.ide.rider": "3.0.31",
|
"com.unity.ide.rider": "3.0.36",
|
||||||
"com.unity.test-framework": "1.1.33",
|
"com.unity.test-framework": "1.1.33",
|
||||||
"com.unity.modules.animation": "1.0.0",
|
"com.unity.modules.animation": "1.0.0",
|
||||||
"com.unity.modules.physics": "1.0.0"
|
"com.unity.modules.physics": "1.0.0"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.ide.rider": {
|
"com.unity.ide.rider": {
|
||||||
"version": "3.0.31",
|
"version": "3.0.36",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,3 +1,27 @@
|
|||||||
|
## [4.12.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.12.1...v4.12.2) (2026-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add `meshCleared` flag to optimize mesh clearing ([859fa20](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/859fa20d297c3f44e3361f20dbb7ce966407e03e))
|
||||||
|
* fix Unity6.5 compile errors and warnings ([a5ee687](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a5ee6878212be2fc4d7b48879426f239e8753009)), closes [#400](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/400)
|
||||||
|
* potential access to UIParticleRenderer that has already been destroyed ([b740dd6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b740dd662d423c6bef849662ce1b0bfbb4940ed4)), closes [#403](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/403)
|
||||||
|
* updated support for some changed menu paths ([f8ac986](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f8ac9869f141238169730e74f5d65c4fc6081f51)), closes [#397](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/397)
|
||||||
|
|
||||||
|
## [4.12.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.12.0...v4.12.1) (2026-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ignore "EditorOnly" tagged gameObjects on refresh ([031d46a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/031d46a3216c942d2d1a6ccfadf5f0b9e3ce3006))
|
||||||
|
|
||||||
|
# [4.12.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.4...v4.12.0) (2026-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* explicit null checks ([5384f61](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5384f61c569e9f78ff9d5b45acfc6f5c2f021a87))
|
||||||
|
|
||||||
## [4.11.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.3...v4.11.4) (2025-12-24)
|
## [4.11.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.3...v4.11.4) (2025-12-24)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,12 +76,21 @@ namespace Coffee.UIExtensions
|
|||||||
for (var j = 0; j < mats.Count; j++)
|
for (var j = 0; j < mats.Count; j++)
|
||||||
{
|
{
|
||||||
var mat = mats[j];
|
var mat = mats[j];
|
||||||
if (!mat || !mat.shader) continue;
|
if (mat == null || mat.shader == null) continue;
|
||||||
|
|
||||||
|
#if UNITY_6000_5_OR_NEWER
|
||||||
|
for (var i = 0; i < mat.shader.GetPropertyCount(); i++)
|
||||||
|
#else
|
||||||
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#if UNITY_6000_5_OR_NEWER
|
||||||
|
var name = mat.shader.GetPropertyName(i);
|
||||||
|
var type = (AnimatableProperty.ShaderPropertyType)mat.shader.GetPropertyType(i);
|
||||||
|
#else
|
||||||
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
||||||
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
||||||
|
#endif
|
||||||
if (!s_Names.Add(name)) continue;
|
if (!s_Names.Add(name)) continue;
|
||||||
|
|
||||||
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -8,12 +9,11 @@ using UnityEngine;
|
|||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.Overlays;
|
using UnityEditor.Overlays;
|
||||||
#else
|
#else
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
#endif
|
#endif
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.SceneManagement;
|
using UnityEditor.SceneManagement;
|
||||||
@@ -49,6 +49,7 @@ namespace Coffee.UIExtensions
|
|||||||
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
||||||
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
||||||
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
|
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
|
||||||
|
private static readonly GUIContent s_Remove = new GUIContent("Remove");
|
||||||
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
|
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
|
||||||
private static readonly List<Material> s_TempMaterials = new List<Material>();
|
private static readonly List<Material> s_TempMaterials = new List<Material>();
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ namespace Coffee.UIExtensions
|
|||||||
private ReorderableList _ro;
|
private ReorderableList _ro;
|
||||||
private bool _showMax;
|
private bool _showMax;
|
||||||
private bool _is3DScaleMode;
|
private bool _is3DScaleMode;
|
||||||
|
private GameObject[] _gameObjects;
|
||||||
|
|
||||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||||
#if UNITY_2018 || UNITY_2019
|
#if UNITY_2018 || UNITY_2019
|
||||||
@@ -110,7 +112,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
var ps = sp.GetArrayElementAtIndex(index).objectReferenceValue as ParticleSystem;
|
var ps = sp.GetArrayElementAtIndex(index).objectReferenceValue as ParticleSystem;
|
||||||
var materialCount = 0;
|
var materialCount = 0;
|
||||||
if (ps && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
if (ps != null && ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||||
{
|
{
|
||||||
materialCount = psr.sharedMaterials.Length;
|
materialCount = psr.sharedMaterials.Length;
|
||||||
}
|
}
|
||||||
@@ -124,7 +126,7 @@ namespace Coffee.UIExtensions
|
|||||||
var p = sp.GetArrayElementAtIndex(index);
|
var p = sp.GetArrayElementAtIndex(index);
|
||||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||||
var ps = p.objectReferenceValue as ParticleSystem;
|
var ps = p.objectReferenceValue as ParticleSystem;
|
||||||
if (!ps || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
if (ps == null || !ps.TryGetComponent<ParticleSystemRenderer>(out var psr)) return;
|
||||||
|
|
||||||
rect.x += 15;
|
rect.x += 15;
|
||||||
rect.width -= 15;
|
rect.width -= 15;
|
||||||
@@ -183,6 +185,13 @@ namespace Coffee.UIExtensions
|
|||||||
y.hasMultipleDifferentValues ||
|
y.hasMultipleDifferentValues ||
|
||||||
z.hasMultipleDifferentValues;
|
z.hasMultipleDifferentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add temporary ParticleSystem for preview if enabled.
|
||||||
|
if (UIParticleProjectSettings.s_PreviewOnSelectOnSelect)
|
||||||
|
{
|
||||||
|
_gameObjects = targets.OfType<UIParticle>().Select(x => x.gameObject).ToArray();
|
||||||
|
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -191,13 +200,16 @@ namespace Coffee.UIExtensions
|
|||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
var current = target as UIParticle;
|
var current = target as UIParticle;
|
||||||
if (!current) return;
|
if (current == null) return;
|
||||||
|
|
||||||
Profiler.BeginSample("(UIP:E) OnInspectorGUI");
|
Profiler.BeginSample("(UIP:E) OnInspectorGUI");
|
||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
|
|
||||||
// Maskable
|
// Maskable
|
||||||
EditorGUILayout.PropertyField(_maskable);
|
if (_maskable != null)
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(_maskable);
|
||||||
|
}
|
||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||||
@@ -267,7 +279,7 @@ namespace Coffee.UIExtensions
|
|||||||
Profiler.BeginSample("(UIP:E) Non-UI built-in shader is not supported.");
|
Profiler.BeginSample("(UIP:E) Non-UI built-in shader is not supported.");
|
||||||
foreach (var mat in s_TempMaterials)
|
foreach (var mat in s_TempMaterials)
|
||||||
{
|
{
|
||||||
if (!mat || !mat.shader) continue;
|
if (mat == null || mat.shader == null) continue;
|
||||||
var shader = mat.shader;
|
var shader = mat.shader;
|
||||||
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
||||||
{
|
{
|
||||||
@@ -286,7 +298,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
foreach (var mat in s_TempMaterials)
|
foreach (var mat in s_TempMaterials)
|
||||||
{
|
{
|
||||||
if (!mat || !mat.shader) continue;
|
if (mat == null || mat.shader == null) continue;
|
||||||
var shader = mat.shader;
|
var shader = mat.shader;
|
||||||
if (!s_Shaders.Add(shader)) continue;
|
if (!s_Shaders.Add(shader)) continue;
|
||||||
|
|
||||||
@@ -344,6 +356,10 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Remove the temporary ParticleSystem.
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +498,7 @@ namespace Coffee.UIExtensions
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool FixButton(bool show, string text)
|
private static bool FixButton(bool show, string text, GUIContent buttonText = null)
|
||||||
{
|
{
|
||||||
if (!show) return false;
|
if (!show) return false;
|
||||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
||||||
@@ -490,7 +506,7 @@ namespace Coffee.UIExtensions
|
|||||||
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
||||||
using (new EditorGUILayout.VerticalScope())
|
using (new EditorGUILayout.VerticalScope())
|
||||||
{
|
{
|
||||||
return GUILayout.Button(s_ContentFix, GUILayout.Width(30));
|
return GUILayout.Button(buttonText ?? s_ContentFix, GUILayout.ExpandWidth(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,22 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
internal class UIParticleMenu
|
internal class UIParticleMenu
|
||||||
{
|
{
|
||||||
[MenuItem("GameObject/UI/Particle System (Empty)", false, 2018)]
|
#if UNITY_6000_5_OR_NEWER
|
||||||
|
private const string k_MenuPathToCreateParticleSystem = "GameObject/Visual Effects/Particle System";
|
||||||
|
#else
|
||||||
|
private const string k_MenuPathToCreateParticleSystem = "GameObject/Effects/Particle System";
|
||||||
|
#endif
|
||||||
|
#if UNITY_6000_3_OR_NEWER
|
||||||
|
private const string k_MenuPathForUgui = "GameObject/UI (Canvas)";
|
||||||
|
#else
|
||||||
|
private const string k_MenuPathForUgui = "GameObject/UI";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[MenuItem(k_MenuPathForUgui + "/Particle System (Empty)", false, 2018)]
|
||||||
private static void AddParticleEmpty(MenuCommand menuCommand)
|
private static void AddParticleEmpty(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
// Create empty UI element.
|
// Create empty UI element.
|
||||||
EditorApplication.ExecuteMenuItem("GameObject/UI/Image");
|
EditorApplication.ExecuteMenuItem(k_MenuPathForUgui + "/Image");
|
||||||
var ui = Selection.activeGameObject;
|
var ui = Selection.activeGameObject;
|
||||||
Object.DestroyImmediate(ui.GetComponent<Image>());
|
Object.DestroyImmediate(ui.GetComponent<Image>());
|
||||||
|
|
||||||
@@ -21,7 +32,7 @@ namespace Coffee.UIExtensions
|
|||||||
uiParticle.rectTransform.sizeDelta = Vector2.zero;
|
uiParticle.rectTransform.sizeDelta = Vector2.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("GameObject/UI/Particle System", false, 2019)]
|
[MenuItem(k_MenuPathForUgui + "/Particle System", false, 2019)]
|
||||||
private static void AddParticle(MenuCommand menuCommand)
|
private static void AddParticle(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
// Create empty UIEffect.
|
// Create empty UIEffect.
|
||||||
@@ -29,7 +40,7 @@ namespace Coffee.UIExtensions
|
|||||||
var uiParticle = Selection.activeGameObject.GetComponent<UIParticle>();
|
var uiParticle = Selection.activeGameObject.GetComponent<UIParticle>();
|
||||||
|
|
||||||
// Create ParticleSystem.
|
// Create ParticleSystem.
|
||||||
EditorApplication.ExecuteMenuItem("GameObject/Effects/Particle System");
|
EditorApplication.ExecuteMenuItem(k_MenuPathToCreateParticleSystem);
|
||||||
var ps = Selection.activeGameObject;
|
var ps = Selection.activeGameObject;
|
||||||
ps.transform.SetParent(uiParticle.transform, false);
|
ps.transform.SetParent(uiParticle.transform, false);
|
||||||
ps.transform.localPosition = Vector3.zero;
|
ps.transform.localPosition = Vector3.zero;
|
||||||
|
|||||||
@@ -183,9 +183,14 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
- **Time Scale Multiplier:** Time scale multiplier.
|
- **Time Scale Multiplier:** Time scale multiplier.
|
||||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||||
|
|
||||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
> [!TIPS]
|
||||||
|
> Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||||
and z-position.
|
and z-position.
|
||||||
|
|
||||||
|
> [!TIPS]
|
||||||
|
> When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||||
|
> The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Basic Usage
|
### Basic Usage
|
||||||
@@ -195,6 +200,10 @@ and z-position.
|
|||||||
2. Adjust the ParticleSystem as you like.
|
2. Adjust the ParticleSystem as you like.
|
||||||

|

|
||||||
|
|
||||||
|
> [!Tips]
|
||||||
|
> Adding a `UIParticle` to the parent is the recommended setup rather than attaching it directly to the `ParticleSystem`.
|
||||||
|
> When using `ParticleSystem.emission.rateOverDistance`, it is recommended to move the transform of `UIParticle` rather than the `ParticleSystem`.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
### Usage with Your Existing ParticleSystem Prefab
|
### Usage with Your Existing ParticleSystem Prefab
|
||||||
@@ -256,13 +265,34 @@ uiParticle.Stop();
|
|||||||
- **Unscaled Time:** Update with unscaled delta time.
|
- **Unscaled Time:** Update with unscaled delta time.
|
||||||
- **OnAttracted**: An event called when attracting is complete (per particle).
|
- **OnAttracted**: An event called when attracting is complete (per particle).
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
### Component: ParticleSystemPreviewer
|
||||||
|
|
||||||
|
`ParticleSystemPreviewer` is used to preview a ParticleSystem in the editor.
|
||||||
|
|
||||||
|
- When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||||
|
- The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||||
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Project Settings
|
### Project Settings
|
||||||
|
|
||||||

|
You can adjust the project-wide settings for `UI Particle`. (`Edit > Project Settings > UI > UI Particle`)
|
||||||
|
|
||||||
- Click `Edit > Project Settings` to open the Project Settings window and then select `UI > UI Particle` category.
|

|
||||||
|
|
||||||
|
#### Settings
|
||||||
|
|
||||||
|
- **Enable Linear To Gamma**: Automatically correct the color space of the mesh.
|
||||||
|
|
||||||
|
#### Editor
|
||||||
|
|
||||||
|
- **Hide Generated Component**: Automatically hide the generated `UIParticleRenderer` component and `UIParticle BakingCamera`.
|
||||||
|
|
||||||
|
- **Preview On Select**: When selecting UIParticle, a temporary ParticleSystem is generated for preview.
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
|||||||
@@ -37,37 +37,17 @@ namespace Coffee.UIExtensions
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ShaderPropertyType.Color:
|
case ShaderPropertyType.Color:
|
||||||
var color = mpb.GetColor(id);
|
material.SetColor(id, mpb.GetColor(id));
|
||||||
if (color != default)
|
|
||||||
{
|
|
||||||
material.SetColor(id, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Vector:
|
case ShaderPropertyType.Vector:
|
||||||
var vector = mpb.GetVector(id);
|
material.SetVector(id, mpb.GetVector(id));
|
||||||
if (vector != default)
|
|
||||||
{
|
|
||||||
material.SetVector(id, vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Float:
|
case ShaderPropertyType.Float:
|
||||||
case ShaderPropertyType.Range:
|
case ShaderPropertyType.Range:
|
||||||
var value = mpb.GetFloat(id);
|
material.SetFloat(id, mpb.GetFloat(id));
|
||||||
if (!Mathf.Approximately(value, 0))
|
|
||||||
{
|
|
||||||
material.SetFloat(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ShaderPropertyType.Texture:
|
case ShaderPropertyType.Texture:
|
||||||
var tex = mpb.GetTexture(id);
|
material.SetTexture(id, mpb.GetTexture(id));
|
||||||
if (tex != default(Texture))
|
|
||||||
{
|
|
||||||
material.SetTexture(id, tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,33 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ComponentExtensions
|
internal static class ComponentExtensions
|
||||||
{
|
{
|
||||||
|
#if !UNITY_2019_2_OR_NEWER
|
||||||
|
public static bool TryGetComponent<T>(this GameObject self, out T component)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null)
|
||||||
|
{
|
||||||
|
component = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = self.GetComponent<T>();
|
||||||
|
return component != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetComponent<T>(this Component self, out T component)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null)
|
||||||
|
{
|
||||||
|
component = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.gameObject.TryGetComponent(out component);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -38,7 +65,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||||
where T : Component
|
where T : Component
|
||||||
{
|
{
|
||||||
if (!self || results == null || depth < 0) return;
|
if (self == null || results == null || depth < 0) return;
|
||||||
|
|
||||||
var tr = self.transform;
|
var tr = self.transform;
|
||||||
if (tr.TryGetComponent<T>(out var t))
|
if (tr.TryGetComponent<T>(out var t))
|
||||||
@@ -59,7 +86,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||||
{
|
{
|
||||||
if (!self) return null;
|
if (self == null) return null;
|
||||||
return self.TryGetComponent<T>(out var component)
|
return self.TryGetComponent<T>(out var component)
|
||||||
? component
|
? component
|
||||||
: self.gameObject.AddComponent<T>();
|
: self.gameObject.AddComponent<T>();
|
||||||
@@ -166,7 +193,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
#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
|
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||||
{
|
{
|
||||||
if (!self) return null;
|
if (self == null) return null;
|
||||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||||
|
|
||||||
var current = self.transform;
|
var current = self.transform;
|
||||||
@@ -186,7 +213,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||||
{
|
{
|
||||||
return context && context.GetType() != typeof(T);
|
return context != null && context.GetType() != typeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static Texture2D GetActualTexture(this Sprite self)
|
public static Texture2D GetActualTexture(this Sprite self)
|
||||||
{
|
{
|
||||||
if (!self) return null;
|
if (self == null) return null;
|
||||||
|
|
||||||
var ret = s_GetActiveAtlasTextureMethod(self);
|
var ret = s_GetActiveAtlasTextureMethod(self);
|
||||||
return ret ? ret : self.texture;
|
return ret != null ? ret : self.texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -43,7 +43,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||||
{
|
{
|
||||||
if (!self) return null;
|
if (self == null) return null;
|
||||||
|
|
||||||
return s_GetActiveAtlasMethod(self);
|
return s_GetActiveAtlasMethod(self);
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static Texture2D GetActualTexture(this Sprite self)
|
internal static Texture2D GetActualTexture(this Sprite self)
|
||||||
{
|
{
|
||||||
return self ? self.texture : null;
|
return self != null ? self.texture : null;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ namespace Coffee.UIParticleInternal
|
|||||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
{
|
{
|
||||||
|
[Tooltip("When enabled, this settings asset will be added to PlayerSettings.preloadedAssets in build.\n\n" +
|
||||||
|
"When disable, you should load this settings via Resources, AssetBundles or Addressables to use.")]
|
||||||
|
[SerializeField]
|
||||||
|
[Header("Advanced")]
|
||||||
|
[HideInInspector]
|
||||||
|
private bool m_PreLoadSettingsInBuild = true;
|
||||||
|
|
||||||
|
protected static bool s_BuildingPlayer;
|
||||||
|
|
||||||
private class Postprocessor : AssetPostprocessor
|
private class Postprocessor : AssetPostprocessor
|
||||||
{
|
{
|
||||||
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
||||||
@@ -22,12 +31,35 @@ namespace Coffee.UIParticleInternal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
private class ExcludeFromBuild : IPreprocessBuildWithReport, IPostprocessBuildWithReport
|
||||||
{
|
{
|
||||||
int IOrderedCallback.callbackOrder => 0;
|
int IOrderedCallback.callbackOrder => 0;
|
||||||
|
|
||||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
Initialize();
|
||||||
|
s_BuildingPlayer = true;
|
||||||
|
|
||||||
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
|
{
|
||||||
|
var settings = GetDefaultSettings(t);
|
||||||
|
if (!settings || settings.m_PreLoadSettingsInBuild) continue;
|
||||||
|
|
||||||
|
PlayerSettings.SetPreloadedAssets(
|
||||||
|
PlayerSettings.GetPreloadedAssets()
|
||||||
|
.Where(x => x && x.GetType() != t)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
Debug.Log($"[PreloadedProjectSettings] Build started: removed '{settings.name}' " +
|
||||||
|
$"({t.Name}) from PreloadedAssets. " +
|
||||||
|
$"It will be restored after build completes.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
s_BuildingPlayer = false;
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,18 +69,21 @@ namespace Coffee.UIParticleInternal
|
|||||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
{
|
{
|
||||||
var defaultSettings = GetDefaultSettings(t);
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
if (!defaultSettings)
|
if (defaultSettings == null)
|
||||||
{
|
{
|
||||||
// When create a new instance, automatically set it as default settings.
|
if (!s_BuildingPlayer)
|
||||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
{
|
||||||
SetDefaultSettings(defaultSettings);
|
// When create a new instance, automatically set it as default settings.
|
||||||
|
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||||
|
SetDefaultSettings(defaultSettings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (GetPreloadedSettings(t).Length != 1)
|
else if (GetPreloadedSettings(t).Length != 1)
|
||||||
{
|
{
|
||||||
SetDefaultSettings(defaultSettings);
|
if (!s_BuildingPlayer) SetDefaultSettings(defaultSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultSettings)
|
if (defaultSettings != null)
|
||||||
{
|
{
|
||||||
defaultSettings.OnInitialize();
|
defaultSettings.OnInitialize();
|
||||||
}
|
}
|
||||||
@@ -66,22 +101,22 @@ namespace Coffee.UIParticleInternal
|
|||||||
private static Object[] GetPreloadedSettings(Type type)
|
private static Object[] GetPreloadedSettings(Type type)
|
||||||
{
|
{
|
||||||
return PlayerSettings.GetPreloadedAssets()
|
return PlayerSettings.GetPreloadedAssets()
|
||||||
.Where(x => x && x.GetType() == type)
|
.Where(x => x != null && x.GetType() == type)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||||
{
|
{
|
||||||
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
?? AssetDatabase.FindAssets($"t:{type.Name}")
|
||||||
.Select(AssetDatabase.GUIDToAssetPath)
|
.Select(AssetDatabase.GUIDToAssetPath)
|
||||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||||
.FirstOrDefault(x => x && x.GetType() == type);
|
.FirstOrDefault(x => x != null && x.GetType() == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||||
{
|
{
|
||||||
if (!asset) return;
|
if (asset == null) return;
|
||||||
|
|
||||||
var type = asset.GetType();
|
var type = asset.GetType();
|
||||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||||
@@ -103,7 +138,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||||
var projectSettings = GetPreloadedSettings(type);
|
var projectSettings = GetPreloadedSettings(type);
|
||||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||||
.Where(x => x)
|
.Where(x => x != null)
|
||||||
.Except(projectSettings.Except(new[] { asset }))
|
.Except(projectSettings.Except(new[] { asset }))
|
||||||
.Append(asset)
|
.Append(asset)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
@@ -120,6 +155,35 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal abstract class PreloadedProjectSettingsEditor : Editor
|
||||||
|
{
|
||||||
|
private SerializedProperty _preLoadSettingsInBuild;
|
||||||
|
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
_preLoadSettingsInBuild = serializedObject.FindProperty("m_PreLoadSettingsInBuild");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DrawPreLoadSettingsInBuild(string packageName)
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(_preLoadSettingsInBuild);
|
||||||
|
if (!_preLoadSettingsInBuild.boolValue)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
$"{target.GetType().Name} asset will not be built in.\n" +
|
||||||
|
$"please load manually from Resources, AssetBundle, or Addressables before using {packageName}.",
|
||||||
|
MessageType.Warning);
|
||||||
|
if (GUILayout.Button("Ping"))
|
||||||
|
{
|
||||||
|
EditorGUIUtility.PingObject(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -133,31 +197,33 @@ namespace Coffee.UIParticleInternal
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private string _jsonText;
|
private string _jsonText;
|
||||||
|
|
||||||
public static bool hasInstance => s_Instance;
|
public static bool hasInstance => s_Instance != null;
|
||||||
|
|
||||||
public static T instance
|
public static T instance
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (s_Instance) return s_Instance;
|
if (s_Instance != null) return s_Instance;
|
||||||
|
|
||||||
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||||
if (s_Instance) return s_Instance;
|
if (s_Instance != null) return s_Instance;
|
||||||
|
|
||||||
s_Instance = CreateInstance<T>();
|
s_Instance = CreateInstance<T>();
|
||||||
if (!s_Instance)
|
if (s_Instance == null)
|
||||||
{
|
{
|
||||||
s_Instance = null;
|
s_Instance = null;
|
||||||
return s_Instance;
|
return s_Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDefaultSettings(s_Instance);
|
if (!s_BuildingPlayer) SetDefaultSettings(s_Instance);
|
||||||
return s_Instance;
|
return s_Instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||||
{
|
{
|
||||||
|
if (!this) return;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case PlayModeStateChange.ExitingEditMode:
|
case PlayModeStateChange.ExitingEditMode:
|
||||||
@@ -174,7 +240,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
public static T instance => s_Instance != null ? s_Instance : s_Instance = CreateInstance<T>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -183,7 +249,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
protected virtual void OnEnable()
|
protected virtual void OnEnable()
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
var isDefaultSettings = s_Instance == null || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||||
if (!isDefaultSettings)
|
if (!isDefaultSettings)
|
||||||
{
|
{
|
||||||
DestroyImmediate(this, true);
|
DestroyImmediate(this, true);
|
||||||
@@ -191,9 +257,12 @@ namespace Coffee.UIParticleInternal
|
|||||||
}
|
}
|
||||||
|
|
||||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
|
#else
|
||||||
|
if (s_Instance && s_Instance != this)
|
||||||
|
{
|
||||||
|
Destroy(s_Instance);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s_Instance) return;
|
|
||||||
s_Instance = this as T;
|
s_Instance = this as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +291,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public override void OnGUI(string searchContext)
|
public override void OnGUI(string searchContext)
|
||||||
{
|
{
|
||||||
if (!_target)
|
if (_target == null)
|
||||||
{
|
{
|
||||||
if (_editor)
|
if (_editor)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
private static void Clear()
|
private static void Clear()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using Conditional = System.Diagnostics.ConditionalAttribute;
|
|||||||
|
|
||||||
namespace Coffee.UIParticleInternal
|
namespace Coffee.UIParticleInternal
|
||||||
{
|
{
|
||||||
internal static class Logging
|
internal static class Logger
|
||||||
{
|
{
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||||
@@ -48,7 +48,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||||
{
|
{
|
||||||
if (!enable) return;
|
if (!enable) return;
|
||||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
@@ -56,7 +56,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
public static void Log(object tag, object message, Object context = null)
|
public static void Log(object tag, object message, Object context = null)
|
||||||
{
|
{
|
||||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Log, tag, message, context != null ? context : tag as Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ENABLE_COFFEE_LOGGER
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
@@ -64,13 +64,13 @@ namespace Coffee.UIParticleInternal
|
|||||||
#endif
|
#endif
|
||||||
public static void LogWarning(object tag, object message, Object context = null)
|
public static void LogWarning(object tag, object message, Object context = null)
|
||||||
{
|
{
|
||||||
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Warning, tag, message, context != null ? context : tag as Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LogError(object tag, object message, Object context = null)
|
public static void LogError(object tag, object message, Object context = null)
|
||||||
{
|
{
|
||||||
#if ENABLE_COFFEE_LOGGER
|
#if ENABLE_COFFEE_LOGGER
|
||||||
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
Log_Internal(LogType.Error, tag, message, context != null ? context : tag as Object);
|
||||||
#else
|
#else
|
||||||
Debug.LogError($"{tag}: {message}", context);
|
Debug.LogError($"{tag}: {message}", context);
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 8255313895da84e7cbdc876be3795334
|
guid: 4f9f22bb079324476b1473030ad9fec3
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -13,7 +13,9 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static int count => s_Repository.count;
|
public static int count => s_Repository.count;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
public static Func<string, Shader> onShaderFind = Shader.Find;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
@@ -48,7 +50,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
s_Repository.Get(hash, ref material, x => new Material(onShaderFind(x))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||||
}, shaderName);
|
}, shaderName);
|
||||||
@@ -61,7 +63,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
s_Repository.Get(hash, ref material, x => new Material(onShaderFind(x.shaderName))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||||
shaderKeywords = x.keywords
|
shaderKeywords = x.keywords
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
public static T[] FindObjectsOfType<T>() where T : Object
|
public static T[] FindObjectsOfType<T>() where T : Object
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
#if UNITY_6000_4_OR_NEWER
|
||||||
|
return Object.FindObjectsByType<T>(FindObjectsInactive.Include);
|
||||||
|
#elif UNITY_2023_1_OR_NEWER
|
||||||
return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
#else
|
#else
|
||||||
return Object.FindObjectsOfType<T>();
|
return Object.FindObjectsOfType<T>();
|
||||||
@@ -29,7 +31,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static void Destroy(Object obj)
|
public static void Destroy(Object obj)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (obj == null) return;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying)
|
if (!Application.isPlaying)
|
||||||
{
|
{
|
||||||
@@ -44,24 +46,19 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static void DestroyImmediate(Object obj)
|
public static void DestroyImmediate(Object obj)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (obj == null) return;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (Application.isEditor)
|
Object.DestroyImmediate(obj, true);
|
||||||
{
|
#else
|
||||||
Object.DestroyImmediate(obj);
|
Object.Destroy(obj);
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("UNITY_EDITOR")]
|
[Conditional("UNITY_EDITOR")]
|
||||||
public static void SetDirty(Object obj)
|
public static void SetDirty(Object obj)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!obj) return;
|
if (obj == null) return;
|
||||||
EditorUtility.SetDirty(obj);
|
EditorUtility.SetDirty(obj);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -112,16 +109,16 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (Misc.isBatchOrBuilding) return;
|
if (Misc.isBatchOrBuilding) return;
|
||||||
|
|
||||||
var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
|
var types = TypeCache.GetTypesWithAttribute(typeof(IconAttribute));
|
||||||
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
var script = scripts.FirstOrDefault(x => x.GetClass() == type);
|
var script = scripts.FirstOrDefault(x => x.GetClass() == type);
|
||||||
if (!script) continue;
|
if (script == null) continue;
|
||||||
|
|
||||||
var path = type.GetCustomAttribute<IconAttribute>()?._path;
|
var path = type.GetCustomAttribute<IconAttribute>()?._path;
|
||||||
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||||
if (!icon) continue;
|
if (icon == null) continue;
|
||||||
|
|
||||||
s_SetIconForObject(script, icon);
|
s_SetIconForObject(script, icon);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are no instances in the pool, create a new one.
|
// If there are no instances in the pool, create a new one.
|
||||||
Logging.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
Logger.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||||
return _pool.Get();
|
return _pool.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
if (instance == null) return; // Ignore if already pooled or null.
|
if (instance == null) return; // Ignore if already pooled or null.
|
||||||
|
|
||||||
_pool.Release(instance);
|
_pool.Release(instance);
|
||||||
Logging.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
Logger.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||||
instance = default; // Set the reference to null.
|
instance = default; // Set the reference to null.
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -80,7 +80,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are no instances in the pool, create a new one.
|
// 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}).");
|
Logger.Log(this, $"A new instance is created (pooled: {_pool.Count}, created: {++_count}).");
|
||||||
return _onCreate();
|
return _onCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
_onReturn(instance); // Return the instance to the pool.
|
_onReturn(instance); // Return the instance to the pool.
|
||||||
_pool.Push(instance);
|
_pool.Push(instance);
|
||||||
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
Logger.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||||
instance = default; // Set the reference to null.
|
instance = default; // Set the reference to null.
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
||||||
if (_cache.TryGetValue(hash, out var entry))
|
if (_cache.TryGetValue(hash, out var entry))
|
||||||
{
|
{
|
||||||
if (!entry.storedObject)
|
if (entry.storedObject == null)
|
||||||
{
|
{
|
||||||
Release(ref entry.storedObject);
|
Release(ref entry.storedObject);
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
@@ -103,7 +103,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Release(ref obj);
|
Release(ref obj);
|
||||||
++entry.reference;
|
++entry.reference;
|
||||||
obj = entry.storedObject;
|
obj = entry.storedObject;
|
||||||
Logging.Log(_name, $"Get(total#{count}): {entry}");
|
Logger.Log(_name, $"Get(total#{count}): {entry}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
@@ -116,7 +116,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
private void Add(Hash128 hash, ref T obj, T newObject)
|
private void Add(Hash128 hash, ref T obj, T newObject)
|
||||||
{
|
{
|
||||||
if (!newObject)
|
if (newObject == null)
|
||||||
{
|
{
|
||||||
Release(ref obj);
|
Release(ref obj);
|
||||||
obj = newObject;
|
obj = newObject;
|
||||||
@@ -130,8 +130,8 @@ namespace Coffee.UIParticleInternal
|
|||||||
newEntry.hash = hash;
|
newEntry.hash = hash;
|
||||||
newEntry.reference = 1;
|
newEntry.reference = 1;
|
||||||
_cache[hash] = newEntry;
|
_cache[hash] = newEntry;
|
||||||
_objectKey[newObject.GetInstanceID()] = hash;
|
_objectKey[newObject.GetHashCode()] = hash;
|
||||||
Logging.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
Logger.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
||||||
Release(ref obj);
|
Release(ref obj);
|
||||||
obj = newObject;
|
obj = newObject;
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
@@ -146,23 +146,23 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
// Find and release the entry.
|
// Find and release the entry.
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||||
var id = obj.GetInstanceID();
|
var id = obj.GetHashCode();
|
||||||
if (_objectKey.TryGetValue(id, out var hash)
|
if (_objectKey.TryGetValue(id, out var hash)
|
||||||
&& _cache.TryGetValue(hash, out var entry))
|
&& _cache.TryGetValue(hash, out var entry))
|
||||||
{
|
{
|
||||||
entry.reference--;
|
entry.reference--;
|
||||||
if (entry.reference <= 0 || !entry.storedObject)
|
if (entry.reference <= 0 || entry.storedObject == null)
|
||||||
{
|
{
|
||||||
Remove(entry);
|
Remove(entry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
Logger.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
Logger.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = null;
|
obj = null;
|
||||||
@@ -175,10 +175,10 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
Profiler.BeginSample("(COF)[ObjectRepository] Remove");
|
Profiler.BeginSample("(COF)[ObjectRepository] Remove");
|
||||||
_cache.Remove(entry.hash);
|
_cache.Remove(entry.hash);
|
||||||
_objectKey.Remove(entry.storedObject.GetInstanceID());
|
_objectKey.Remove(entry.storedObject.GetHashCode());
|
||||||
_pool.Push(entry);
|
_pool.Push(entry);
|
||||||
entry.reference = 0;
|
entry.reference = 0;
|
||||||
Logging.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
Logger.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
||||||
entry.Release(_onRelease);
|
entry.Release(_onRelease);
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public void Release(Action<T> onRelease)
|
public void Release(Action<T> onRelease)
|
||||||
{
|
{
|
||||||
reference = 0;
|
reference = 0;
|
||||||
if (storedObject)
|
if (storedObject != null)
|
||||||
{
|
{
|
||||||
onRelease?.Invoke(storedObject);
|
onRelease?.Invoke(storedObject);
|
||||||
}
|
}
|
||||||
|
|||||||
88
Packages/src/Runtime/Internal/Utilities/TypeCache.cs
Normal file
88
Packages/src/Runtime/Internal/Utilities/TypeCache.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#if !UNITY_2019_2_OR_NEWER
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
public static class TypeCache
|
||||||
|
{
|
||||||
|
private static readonly object s_Lock = new object();
|
||||||
|
private static readonly Dictionary<Type, Type[]> s_DerivedTypesCache = new Dictionary<Type, Type[]>();
|
||||||
|
private static readonly Dictionary<Type, Type[]> s_AttributeTypesCache = new Dictionary<Type, Type[]>();
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesDerivedFrom(Type baseType)
|
||||||
|
{
|
||||||
|
lock (s_Lock)
|
||||||
|
{
|
||||||
|
if (s_DerivedTypesCache.TryGetValue(baseType, out var cached))
|
||||||
|
{
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = new List<Type>();
|
||||||
|
foreach (var t in GetAllLoadableTypes())
|
||||||
|
{
|
||||||
|
if (t != baseType && baseType.IsAssignableFrom(t))
|
||||||
|
{
|
||||||
|
types.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_DerivedTypesCache[baseType] = types.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesWithAttribute(Type attr)
|
||||||
|
{
|
||||||
|
lock (s_Lock)
|
||||||
|
{
|
||||||
|
if (s_AttributeTypesCache.TryGetValue(attr, out var cached))
|
||||||
|
{
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = new List<Type>();
|
||||||
|
foreach (var t in GetAllLoadableTypes())
|
||||||
|
{
|
||||||
|
if (t.GetCustomAttributes(attr, inherit: true).Length > 0)
|
||||||
|
{
|
||||||
|
types.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_AttributeTypesCache[attr] = types.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Type> GetAllLoadableTypes()
|
||||||
|
{
|
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
{
|
||||||
|
Type[] types;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
types = assembly.GetTypes();
|
||||||
|
}
|
||||||
|
catch (ReflectionTypeLoadException ex)
|
||||||
|
{
|
||||||
|
types = ex.Types;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (types == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in types)
|
||||||
|
{
|
||||||
|
if (t != null)
|
||||||
|
{
|
||||||
|
yield return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
11
Packages/src/Runtime/Internal/Utilities/TypeCache.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/TypeCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc1207b657ed74ec19e459664d06925f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -20,7 +21,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
static UIExtraCallbacks()
|
static UIExtraCallbacks()
|
||||||
{
|
{
|
||||||
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
Logger.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,9 +68,17 @@ namespace Coffee.UIParticleInternal
|
|||||||
if (s_IsInitializedAfterCanvasRebuild) return;
|
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||||
s_IsInitializedAfterCanvasRebuild = true;
|
s_IsInitializedAfterCanvasRebuild = true;
|
||||||
|
|
||||||
|
// Explicitly set `Canvas.willRenderCanvases += CanvasUpdateRegistry.PerformUpdate`.
|
||||||
CanvasUpdateRegistry.IsRebuildingLayout();
|
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||||
|
#if TMP_ENABLE
|
||||||
|
// Explicitly set `Canvas.willRenderCanvases += TMP_UpdateManager.DoRebuilds`.
|
||||||
|
typeof(TMPro.TMP_UpdateManager)
|
||||||
|
.GetProperty("instance", BindingFlags.NonPublic | BindingFlags.Static)
|
||||||
|
.GetValue(null);
|
||||||
|
#endif
|
||||||
|
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||||
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
Logger.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||||
message: "InitializeAfterCanvasRebuild");
|
message: "InitializeAfterCanvasRebuild");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
222
Packages/src/Runtime/ParticleSystemPreviewer.cs
Normal file
222
Packages/src/Runtime/ParticleSystemPreviewer.cs
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||||
|
[ExecuteAlways]
|
||||||
|
internal class ParticleSystemPreviewer : MonoBehaviour
|
||||||
|
{
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[CustomEditor(typeof(ParticleSystemPreviewer))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
internal class ParticleSystemPreviewerEditor : Editor
|
||||||
|
{
|
||||||
|
private GameObject[] _gameObjects;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
_gameObjects = targets.OfType<ParticleSystemPreviewer>().Select(x => x.gameObject).ToArray();
|
||||||
|
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForPermanent(_gameObjects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class manages temporary ParticleSystems for preview purposes.
|
||||||
|
/// When previewing in the editor, it is common to place an empty ParticleSystem as the root, but it consumes memory at runtime if included in the build.
|
||||||
|
/// The temporary ParticleSystems created by this class only exist when the specified GameObject is selected, and are automatically deleted when the selection is cleared.
|
||||||
|
/// </summary>
|
||||||
|
internal class ParticleSystemPreviewSystem : ScriptableSingleton<ParticleSystemPreviewSystem>
|
||||||
|
{
|
||||||
|
private const HideFlags k_TemporaryHideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private List<GameObject> m_PreviewObjects = new List<GameObject>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(GameObject[] targets)
|
||||||
|
{
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
Register(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(GameObject target)
|
||||||
|
{
|
||||||
|
if (!target) return;
|
||||||
|
if (EditorApplication.isPlaying) return;
|
||||||
|
if (instance.m_PreviewObjects.Contains(target)) return;
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var _)) return;
|
||||||
|
|
||||||
|
// Create temporary ParticleSystem for preview.
|
||||||
|
var ps = target.AddComponent<ParticleSystem>();
|
||||||
|
ps.hideFlags = k_TemporaryHideFlags;
|
||||||
|
|
||||||
|
var emission = ps.emission;
|
||||||
|
emission.enabled = false;
|
||||||
|
var shape = ps.shape;
|
||||||
|
shape.enabled = false;
|
||||||
|
|
||||||
|
if (target.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||||
|
{
|
||||||
|
psr.enabled = false;
|
||||||
|
psr.hideFlags = k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.m_PreviewObjects.Add(target);
|
||||||
|
EditorUtility.SetDirty(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
public static void Unregister(GameObject target)
|
||||||
|
{
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
var index = instance.m_PreviewObjects.IndexOf(target);
|
||||||
|
if (index < 0) return;
|
||||||
|
|
||||||
|
instance.m_PreviewObjects.RemoveAt(index);
|
||||||
|
if (HasTemporaryParticleSystem(target))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
private static void RemoveParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var ps))
|
||||||
|
{
|
||||||
|
Misc.DestroyImmediate(ps);
|
||||||
|
EditorUtility.SetDirty(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var psr))
|
||||||
|
{
|
||||||
|
Misc.DestroyImmediate(psr);
|
||||||
|
EditorUtility.SetDirty(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the specified GameObject has a temporary ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HasTemporaryParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
return target
|
||||||
|
&& instance.m_PreviewObjects.Contains(target)
|
||||||
|
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||||
|
&& ps.hideFlags == k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the specified GameObject has a permanent ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HasPermanentParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
return target
|
||||||
|
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||||
|
&& ps.hideFlags != k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
Selection.selectionChanged -= OnSelectionChanged;
|
||||||
|
Selection.selectionChanged += OnSelectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
Selection.selectionChanged -= OnSelectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectionChanged()
|
||||||
|
{
|
||||||
|
var selectedGameObjects = Selection.gameObjects;
|
||||||
|
for (var i = m_PreviewObjects.Count - 1; 0 <= i; i--)
|
||||||
|
{
|
||||||
|
var go = m_PreviewObjects[i];
|
||||||
|
if (!go)
|
||||||
|
{
|
||||||
|
m_PreviewObjects.RemoveAt(i);
|
||||||
|
}
|
||||||
|
else if (!selectedGameObjects.Contains(go))
|
||||||
|
{
|
||||||
|
Unregister(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawWarningForTemporary(GameObject[] gameObjects)
|
||||||
|
{
|
||||||
|
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasTemporaryParticleSystem)) return;
|
||||||
|
|
||||||
|
if (WarningButton("The temporary ParticleSystem for preview is attached.\n" +
|
||||||
|
"It will be removed when exiting edit mode.", "Remove"))
|
||||||
|
{
|
||||||
|
foreach (var go in gameObjects)
|
||||||
|
{
|
||||||
|
if (HasTemporaryParticleSystem(go))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawWarningForPermanent(GameObject[] gameObjects)
|
||||||
|
{
|
||||||
|
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasPermanentParticleSystem)) return;
|
||||||
|
|
||||||
|
if (WarningButton("The permanent ParticleSystem is attached.\n" +
|
||||||
|
"It will be included in build.", "Remove"))
|
||||||
|
{
|
||||||
|
foreach (var go in gameObjects)
|
||||||
|
{
|
||||||
|
if (HasPermanentParticleSystem(go))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(go);
|
||||||
|
Unregister(go);
|
||||||
|
Register(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool WarningButton(string message, string buttonText)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.HelpBox(message, MessageType.Warning, true);
|
||||||
|
var clicked = GUILayout.Button(EditorGUIUtility.TrTempContent(buttonText));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/ParticleSystemPreviewer.cs.meta
Normal file
11
Packages/src/Runtime/ParticleSystemPreviewer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b171deb49fb7b471291108ad7e1c9baa
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -358,6 +358,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
_isScaleStored = false;
|
_isScaleStored = false;
|
||||||
UIParticleUpdater.Unregister(this);
|
UIParticleUpdater.Unregister(this);
|
||||||
|
_renderers.RemoveAll(r => r == null);
|
||||||
_renderers.ForEach(r => r.Reset());
|
_renderers.ForEach(r => r.Reset());
|
||||||
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
|
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
|
||||||
|
|
||||||
@@ -471,7 +472,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < _renderers.Count; i++)
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
{
|
{
|
||||||
var r = _renderers[i];
|
var r = _renderers[i];
|
||||||
if (!r || !r.material) continue;
|
if (r == null || r.material == null) continue;
|
||||||
result.Add(r.material);
|
result.Add(r.material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,7 +490,7 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
||||||
{
|
{
|
||||||
if (!instance) return;
|
if (instance == null) return;
|
||||||
|
|
||||||
var childCount = transform.childCount;
|
var childCount = transform.childCount;
|
||||||
for (var i = 0; i < childCount; i++)
|
for (var i = 0; i < childCount; i++)
|
||||||
@@ -518,7 +519,7 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetParticleSystemPrefab(GameObject prefab)
|
public void SetParticleSystemPrefab(GameObject prefab)
|
||||||
{
|
{
|
||||||
if (!prefab) return;
|
if (prefab == null) return;
|
||||||
|
|
||||||
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
||||||
}
|
}
|
||||||
@@ -538,12 +539,17 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void RefreshParticles(GameObject root)
|
private void RefreshParticles(GameObject root)
|
||||||
{
|
{
|
||||||
if (!root) return;
|
if (root == null) return;
|
||||||
root.GetComponentsInChildren(true, particles);
|
root.GetComponentsInChildren(true, particles);
|
||||||
for (var i = particles.Count - 1; 0 <= i; i--)
|
for (var i = particles.Count - 1; 0 <= i; i--)
|
||||||
{
|
{
|
||||||
var ps = particles[i];
|
var ps = particles[i];
|
||||||
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
|
if (!ps
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
|| ps.hideFlags == HideFlags.HideAndDontSave // Dummy ParticleSystems for preview.
|
||||||
|
|| ps.gameObject.CompareTag("EditorOnly") // Ignore "EditorOnly" tagged ParticleSystems.
|
||||||
|
#endif
|
||||||
|
|| ps.GetComponentInParent<UIParticle>(true) != this) // Ignore ParticleSystems that are not under this UIParticle.
|
||||||
{
|
{
|
||||||
particles.RemoveAt(i);
|
particles.RemoveAt(i);
|
||||||
}
|
}
|
||||||
@@ -591,7 +597,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < particleSystems.Count; i++)
|
for (var i = 0; i < particleSystems.Count; i++)
|
||||||
{
|
{
|
||||||
var ps = particleSystems[i];
|
var ps = particleSystems[i];
|
||||||
if (!ps) continue;
|
if (ps == null) continue;
|
||||||
|
|
||||||
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
||||||
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
||||||
@@ -642,7 +648,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < _renderers.Count; i++)
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
{
|
{
|
||||||
var r = _renderers[i];
|
var r = _renderers[i];
|
||||||
if (r) continue;
|
if (r != null) continue;
|
||||||
|
|
||||||
RefreshParticles(particles);
|
RefreshParticles(particles);
|
||||||
break;
|
break;
|
||||||
@@ -652,7 +658,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < _renderers.Count; i++)
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
{
|
{
|
||||||
var r = _renderers[i];
|
var r = _renderers[i];
|
||||||
if (!r) continue;
|
if (r == null) continue;
|
||||||
|
|
||||||
r.UpdateMesh(bakeCamera);
|
r.UpdateMesh(bakeCamera);
|
||||||
}
|
}
|
||||||
@@ -681,7 +687,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < _renderers.Count; i++)
|
for (var i = 0; i < _renderers.Count; i++)
|
||||||
{
|
{
|
||||||
var r = _renderers[i];
|
var r = _renderers[i];
|
||||||
if (!r) continue;
|
if (r == null) continue;
|
||||||
r.maskable = maskable;
|
r.maskable = maskable;
|
||||||
r.SetMaterialDirty();
|
r.SetMaterialDirty();
|
||||||
}
|
}
|
||||||
@@ -694,7 +700,7 @@ namespace Coffee.UIExtensions
|
|||||||
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_renderers[index])
|
if (_renderers[index] == null)
|
||||||
{
|
{
|
||||||
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
||||||
}
|
}
|
||||||
@@ -704,13 +710,13 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
private Camera GetBakeCamera()
|
private Camera GetBakeCamera()
|
||||||
{
|
{
|
||||||
if (!canvas) return Camera.main;
|
if (canvas == null) return Camera.main;
|
||||||
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
if (!useCustomView && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.rootCanvas.worldCamera)
|
||||||
{
|
{
|
||||||
return canvas.rootCanvas.worldCamera;
|
return canvas.rootCanvas.worldCamera;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bakeCamera)
|
if (_bakeCamera != null)
|
||||||
{
|
{
|
||||||
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
_bakeCamera.orthographicSize = useCustomView ? customViewSize : 10;
|
||||||
return _bakeCamera;
|
return _bakeCamera;
|
||||||
@@ -729,7 +735,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create baking camera.
|
// Create baking camera.
|
||||||
if (!_bakeCamera)
|
if (_bakeCamera == null)
|
||||||
{
|
{
|
||||||
var go = new GameObject("[generated] UIParticle BakingCamera");
|
var go = new GameObject("[generated] UIParticle BakingCamera");
|
||||||
go.SetActive(false);
|
go.SetActive(false);
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
|
||||||
{
|
{
|
||||||
var isUI = uiParticle && uiParticle.enabled;
|
var isUI = uiParticle != null && uiParticle.enabled;
|
||||||
var psPos = particleSystem.transform.position;
|
var psPos = particleSystem.transform.position;
|
||||||
var attractorPos = transform.position;
|
var attractorPos = transform.position;
|
||||||
var dstPos = attractorPos;
|
var dstPos = attractorPos;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
@@ -9,12 +10,14 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
[Header("Setting")]
|
[Header("Setting")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
internal bool m_EnableLinearToGamma = true;
|
[Tooltip("Automatically correct the color space of the mesh.")]
|
||||||
|
[FormerlySerializedAs("m_EnableLinearToGamma")]
|
||||||
|
internal bool m_AutoColorCorrection = true;
|
||||||
|
|
||||||
public static bool enableLinearToGamma
|
public static bool autoColorCorrection
|
||||||
{
|
{
|
||||||
get => instance.m_EnableLinearToGamma;
|
get => instance.m_AutoColorCorrection;
|
||||||
set => instance.m_EnableLinearToGamma = value;
|
set => instance.m_AutoColorCorrection = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -25,10 +28,16 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private bool m_HideGeneratedObjects = true;
|
private bool m_HideGeneratedObjects = true;
|
||||||
|
|
||||||
public static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
[Tooltip("When selecting UIParticle, a temporary ParticleSystem is generated for preview.")]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_PreviewOnSelect = true;
|
||||||
|
|
||||||
|
internal static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
||||||
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
||||||
: HideFlags.DontSave | HideFlags.NotEditable;
|
: HideFlags.DontSave | HideFlags.NotEditable;
|
||||||
|
|
||||||
|
internal static bool s_PreviewOnSelectOnSelect => instance.m_PreviewOnSelect;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[SettingsProvider]
|
[SettingsProvider]
|
||||||
private static SettingsProvider CreateSettingsProvider()
|
private static SettingsProvider CreateSettingsProvider()
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Coffee.UIExtensions
|
|||||||
private int _index;
|
private int _index;
|
||||||
private bool _isPrevStored;
|
private bool _isPrevStored;
|
||||||
private bool _isTrail;
|
private bool _isTrail;
|
||||||
|
private bool _meshCleared;
|
||||||
private Bounds _lastBounds;
|
private Bounds _lastBounds;
|
||||||
private Material _materialForRendering;
|
private Material _materialForRendering;
|
||||||
private Material _modifiedMaterial;
|
private Material _modifiedMaterial;
|
||||||
@@ -55,7 +56,7 @@ namespace Coffee.UIExtensions
|
|||||||
s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
|
s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
|
||||||
s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
|
s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
|
||||||
s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
|
s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
|
||||||
if (canvas)
|
if (canvas != null)
|
||||||
{
|
{
|
||||||
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
||||||
for (var i = 0; i < 4; ++i)
|
for (var i = 0; i < 4; ++i)
|
||||||
@@ -95,7 +96,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!_materialForRendering)
|
if (_materialForRendering == null)
|
||||||
{
|
{
|
||||||
_materialForRendering = base.materialForRendering;
|
_materialForRendering = base.materialForRendering;
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
public void Reset(int index = -1)
|
public void Reset(int index = -1)
|
||||||
{
|
{
|
||||||
if (_renderer)
|
if (_renderer != null)
|
||||||
{
|
{
|
||||||
_renderer.enabled = true;
|
_renderer.enabled = true;
|
||||||
}
|
}
|
||||||
@@ -121,7 +122,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
//_emitter = null;
|
//_emitter = null;
|
||||||
if (this && isActiveAndEnabled)
|
if (isActiveAndEnabled)
|
||||||
{
|
{
|
||||||
material = null;
|
material = null;
|
||||||
canvasRenderer.Clear();
|
canvasRenderer.Clear();
|
||||||
@@ -140,7 +141,7 @@ namespace Coffee.UIExtensions
|
|||||||
base.OnEnable();
|
base.OnEnable();
|
||||||
|
|
||||||
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
||||||
if (!s_CombineInstances[0].mesh)
|
if (s_CombineInstances[0].mesh == null)
|
||||||
{
|
{
|
||||||
s_CombineInstances[0].mesh = new Mesh
|
s_CombineInstances[0].mesh = new Mesh
|
||||||
{
|
{
|
||||||
@@ -205,9 +206,9 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hash = new Hash128(
|
var hash = new Hash128(
|
||||||
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
modifiedMaterial ? (uint)modifiedMaterial.GetHashCode() : 0,
|
||||||
texture ? (uint)texture.GetInstanceID() : 0,
|
texture ? (uint)texture.GetHashCode() : 0,
|
||||||
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
0 < _parent.m_AnimatableProperties.Length ? (uint)GetHashCode() : 0,
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||||
#else
|
#else
|
||||||
@@ -285,15 +286,38 @@ namespace Coffee.UIExtensions
|
|||||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
// Skip clearing the mesh if it's already cleared.
|
||||||
|
if (_meshCleared) return;
|
||||||
|
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||||
workerMesh.Clear();
|
workerMesh.Clear();
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
_lastBounds = new Bounds();
|
_lastBounds = new Bounds();
|
||||||
|
_meshCleared = true;
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset custom data.
|
||||||
|
// var customData = _particleSystem.customData;
|
||||||
|
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom1) == ParticleSystemCustomDataMode.Disabled)
|
||||||
|
// {
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom1, 0, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom1, 1, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom1, 2, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom1, 3, 0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!customData.enabled || customData.GetMode(ParticleSystemCustomData.Custom2) == ParticleSystemCustomDataMode.Disabled)
|
||||||
|
// {
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom2, 0, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom2, 1, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom2, 2, 0);
|
||||||
|
// customData.SetVector(ParticleSystemCustomData.Custom2, 3, 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
_meshCleared = false;
|
||||||
var main = _particleSystem.main;
|
var main = _particleSystem.main;
|
||||||
var scale = GetWorldScale();
|
var scale = GetWorldScale();
|
||||||
var psPos = _particleSystem.transform.position;
|
var psPos = _particleSystem.transform.position;
|
||||||
@@ -420,7 +444,7 @@ namespace Coffee.UIExtensions
|
|||||||
_lastBounds = bounds;
|
_lastBounds = bounds;
|
||||||
|
|
||||||
// Convert linear color to gamma color.
|
// Convert linear color to gamma color.
|
||||||
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
if (UIParticleProjectSettings.autoColorCorrection && canvas.ShouldGammaToLinearInMesh())
|
||||||
{
|
{
|
||||||
workerMesh.LinearToGamma();
|
workerMesh.LinearToGamma();
|
||||||
}
|
}
|
||||||
@@ -713,7 +737,7 @@ namespace Coffee.UIExtensions
|
|||||||
if (s_Mpb.isEmpty) return;
|
if (s_Mpb.isEmpty) return;
|
||||||
|
|
||||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||||
if (!materialForRendering) return;
|
if (materialForRendering == null) return;
|
||||||
|
|
||||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,25 +16,25 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
public static void Register(UIParticle particle)
|
public static void Register(UIParticle particle)
|
||||||
{
|
{
|
||||||
if (!particle) return;
|
if (particle == null) return;
|
||||||
s_ActiveParticles.Add(particle);
|
s_ActiveParticles.Add(particle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unregister(UIParticle particle)
|
public static void Unregister(UIParticle particle)
|
||||||
{
|
{
|
||||||
if (!particle) return;
|
if (particle == null) return;
|
||||||
s_ActiveParticles.Remove(particle);
|
s_ActiveParticles.Remove(particle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Register(UIParticleAttractor attractor)
|
public static void Register(UIParticleAttractor attractor)
|
||||||
{
|
{
|
||||||
if (!attractor) return;
|
if (attractor == null) return;
|
||||||
s_ActiveAttractors.Add(attractor);
|
s_ActiveAttractors.Add(attractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unregister(UIParticleAttractor attractor)
|
public static void Unregister(UIParticleAttractor attractor)
|
||||||
{
|
{
|
||||||
if (!attractor) return;
|
if (attractor == null) return;
|
||||||
s_ActiveAttractors.Remove(attractor);
|
s_ActiveAttractors.Remove(attractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||||
{
|
{
|
||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
if (uip == null || uip.canvas == null || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||||
|
|
||||||
uip.UpdateTransformScale();
|
uip.UpdateTransformScale();
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
@@ -81,7 +81,7 @@ namespace Coffee.UIExtensions
|
|||||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||||
{
|
{
|
||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip || !uip.canvas) continue;
|
if (uip == null || uip.canvas == null) continue;
|
||||||
|
|
||||||
uip.UpdateTransformScale();
|
uip.UpdateTransformScale();
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ namespace Coffee.UIExtensions
|
|||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip.useMeshSharing || uip.groupId != groupId) continue;
|
if (!uip.useMeshSharing || uip.groupId != groupId) continue;
|
||||||
if (uip.isPrimary) return uip;
|
if (uip.isPrimary) return uip;
|
||||||
if (!primary && uip.canSimulate) primary = uip;
|
if (primary == null && uip.canSimulate) primary = uip;
|
||||||
}
|
}
|
||||||
|
|
||||||
return primary;
|
return primary;
|
||||||
|
|||||||
@@ -84,15 +84,15 @@ namespace Coffee.UIParticleInternal
|
|||||||
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
||||||
|
|
||||||
// Render queue: ascending
|
// Render queue: ascending
|
||||||
var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
var aMat = aRenderer.sharedMaterial != null ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||||
var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
var bMat = bRenderer.sharedMaterial != null ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||||
if (!aMat && !bMat) return 0;
|
if (aMat == null && bMat == null) return 0;
|
||||||
if (!aMat) return -1;
|
if (aMat == null) return -1;
|
||||||
if (!bMat) return 1;
|
if (bMat == null) return 1;
|
||||||
|
|
||||||
if (sortByMaterial)
|
if (sortByMaterial)
|
||||||
{
|
{
|
||||||
return aMat.GetInstanceID() - bMat.GetInstanceID();
|
return aMat.GetHashCode() - bMat.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aMat.renderQueue != bMat.renderQueue)
|
if (aMat.renderQueue != bMat.renderQueue)
|
||||||
@@ -131,7 +131,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
for (var i = 0; i < list.Count; i++)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
if (list[i].GetInstanceID() == ps.GetInstanceID())
|
if (list[i].GetHashCode() == ps.GetHashCode())
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static Texture2D GetTextureForSprite(this ParticleSystem self)
|
public static Texture2D GetTextureForSprite(this ParticleSystem self)
|
||||||
{
|
{
|
||||||
if (!self) return null;
|
if (self == null) return null;
|
||||||
|
|
||||||
// Get sprite's texture.
|
// Get sprite's texture.
|
||||||
var tsaModule = self.textureSheetAnimation;
|
var tsaModule = self.textureSheetAnimation;
|
||||||
@@ -151,7 +151,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
for (var i = 0; i < tsaModule.spriteCount; i++)
|
for (var i = 0; i < tsaModule.spriteCount; i++)
|
||||||
{
|
{
|
||||||
var sprite = tsaModule.GetSprite(i);
|
var sprite = tsaModule.GetSprite(i);
|
||||||
if (!sprite) continue;
|
if (sprite == null) continue;
|
||||||
|
|
||||||
return sprite.GetActualTexture();
|
return sprite.GetActualTexture();
|
||||||
}
|
}
|
||||||
@@ -163,14 +163,14 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
foreach (var p in self)
|
foreach (var p in self)
|
||||||
{
|
{
|
||||||
if (!p) continue;
|
if (p == null) continue;
|
||||||
action.Invoke(p);
|
action.Invoke(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
|
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
|
||||||
{
|
{
|
||||||
if (!self || list == null || list.Count == 0) return null;
|
if (self == null || list == null || list.Count == 0) return null;
|
||||||
|
|
||||||
for (var i = 0; i < list.Count; i++)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -183,7 +183,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
|
public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
|
||||||
{
|
{
|
||||||
if (!self || !parent) return false;
|
if (self == null || parent == null) return false;
|
||||||
|
|
||||||
var subEmitters = parent.subEmitters;
|
var subEmitters = parent.subEmitters;
|
||||||
if (!subEmitters.enabled) return false; // No sub emitters.
|
if (!subEmitters.enabled) return false; // No sub emitters.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
if (!m_Origin) return;
|
if (m_Origin == null) return;
|
||||||
m_Origin.SetActive(false);
|
m_Origin.SetActive(false);
|
||||||
|
|
||||||
var parent = m_Origin.transform.parent;
|
var parent = m_Origin.transform.parent;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class UIElementDragger : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
|||||||
break;
|
break;
|
||||||
case Target.Custom:
|
case Target.Custom:
|
||||||
_rectTransform.localPosition += delta;
|
_rectTransform.localPosition += delta;
|
||||||
if (m_CustomTarget)
|
if (m_CustomTarget != null)
|
||||||
{
|
{
|
||||||
if (m_UseCanvasScale)
|
if (m_UseCanvasScale)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,12 +40,8 @@
|
|||||||
Lighting Off
|
Lighting Off
|
||||||
ZWrite Off
|
ZWrite Off
|
||||||
ZTest [unity_GUIZTestMode]
|
ZTest [unity_GUIZTestMode]
|
||||||
Fog
|
Fog { Mode Off }
|
||||||
{
|
|
||||||
Mode Off
|
|
||||||
}
|
|
||||||
Blend One One
|
Blend One One
|
||||||
|
|
||||||
ColorMask [_ColorMask]
|
ColorMask [_ColorMask]
|
||||||
|
|
||||||
Pass
|
Pass
|
||||||
@@ -76,6 +72,7 @@
|
|||||||
fixed4 color : COLOR;
|
fixed4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
|
float4 mask : TEXCOORD2;
|
||||||
UNITY_VERTEX_OUTPUT_STEREO
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,16 +81,43 @@
|
|||||||
float4 _MainTex_ST;
|
float4 _MainTex_ST;
|
||||||
fixed4 _TextureSampleAdd;
|
fixed4 _TextureSampleAdd;
|
||||||
float4 _ClipRect;
|
float4 _ClipRect;
|
||||||
|
float _UIMaskSoftnessX;
|
||||||
|
float _UIMaskSoftnessY;
|
||||||
|
int _UIVertexColorAlwaysGammaSpace;
|
||||||
|
|
||||||
|
half3 _UIGammaToLinear(half3 value)
|
||||||
|
{
|
||||||
|
half3 low = 0.0849710 * value - 0.000163029;
|
||||||
|
half3 high = value * (value * (value * 0.265885 + 0.736584) - 0.00980184) + 0.00319697;
|
||||||
|
|
||||||
|
// We should be 0.5 away from any actual gamma value stored in an 8 bit channel
|
||||||
|
const half3 split = (half3)0.0725490; // Equals 18.5 / 255
|
||||||
|
return (value < split) ? low : high;
|
||||||
|
}
|
||||||
|
|
||||||
v2f vert(appdata_t v)
|
v2f vert(appdata_t v)
|
||||||
{
|
{
|
||||||
v2f OUT;
|
v2f OUT;
|
||||||
UNITY_SETUP_INSTANCE_ID(v);
|
UNITY_SETUP_INSTANCE_ID(v);
|
||||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
||||||
|
float4 vPosition = UnityObjectToClipPos(v.vertex);
|
||||||
OUT.worldPosition = v.vertex;
|
OUT.worldPosition = v.vertex;
|
||||||
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
|
OUT.vertex = vPosition;
|
||||||
|
|
||||||
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
|
float2 pixelSize = vPosition.w;
|
||||||
|
pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
|
||||||
|
|
||||||
|
float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
|
||||||
|
float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
|
||||||
|
OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
|
||||||
|
OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));
|
||||||
|
|
||||||
|
if (_UIVertexColorAlwaysGammaSpace)
|
||||||
|
{
|
||||||
|
#ifndef UNITY_COLORSPACE_GAMMA
|
||||||
|
v.color.rgb = _UIGammaToLinear(v.color.rgb);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
OUT.color = v.color * _Color;
|
OUT.color = v.color * _Color;
|
||||||
return OUT;
|
return OUT;
|
||||||
@@ -101,17 +125,26 @@
|
|||||||
|
|
||||||
fixed4 frag(v2f IN) : SV_Target
|
fixed4 frag(v2f IN) : SV_Target
|
||||||
{
|
{
|
||||||
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
|
//Round up the alpha color coming from the interpolator (to 1.0/256.0 steps)
|
||||||
|
//The incoming alpha could have numerical instability, which makes it very sensible to
|
||||||
|
//HDR color transparency blend, when it blends with the world's texture.
|
||||||
|
const half alphaPrecision = half(0xff);
|
||||||
|
const half invAlphaPrecision = half(1.0 / alphaPrecision);
|
||||||
|
IN.color.a = round(IN.color.a * alphaPrecision) * invAlphaPrecision;
|
||||||
|
|
||||||
|
half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
|
||||||
|
|
||||||
#ifdef UNITY_UI_CLIP_RECT
|
#ifdef UNITY_UI_CLIP_RECT
|
||||||
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
|
||||||
|
color.a *= m.x * m.y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UNITY_UI_ALPHACLIP
|
#ifdef UNITY_UI_ALPHACLIP
|
||||||
clip (color.a - 0.001);
|
clip(color.a - 0.001);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
color.rgb *= color.a;
|
color.rgb *= color.a;
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
ENDCG
|
ENDCG
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "com.coffee.ui-particle",
|
"name": "com.coffee.ui-particle",
|
||||||
"displayName": "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.",
|
"description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
|
||||||
"version": "4.11.4",
|
"version": "4.12.2",
|
||||||
"unity": "2018.2",
|
"unity": "2018.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
Reference in New Issue
Block a user