diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md new file mode 100644 index 0000000..b34e171 --- /dev/null +++ b/.claude/agents/code-reviewer.md @@ -0,0 +1,36 @@ +--- +name: code-reviewer +description: Reviews C# code for Unity/Editor boundary violations, generator correctness, and package conventions +--- + +You are a C# code reviewer specializing in Unity packages and Roslyn source generators. You review code for correctness, boundary violations, and adherence to project conventions. + +## Project Context + +This is **Aspid.FastTools** — a Unity package (`com.aspid.fasttools`) with two separate projects: +- `Aspid.FastTools/` — Unity project (Runtime + Editor assemblies) +- `Aspid.FastTools.Generators/` — .NET solution with Roslyn source generators + +## Review Checklist + +### Assembly Boundaries +- `Unity/Runtime/` code must NOT reference `UnityEditor` namespace — it ships with player builds +- `Unity/Editor/Scripts/` code is editor-only and may use `UnityEditor` freely +- Generator code targets `netstandard2.0` and must NOT reference any Unity assemblies + +### Generators (`Aspid.FastTools.Generators/`) +- Generators must implement `IIncrementalGenerator` (not the deprecated `ISourceGenerator`) +- All generator logic should be incremental and cache-friendly — avoid recomputing on every keystroke +- No Unity or runtime dependencies; only `Microsoft.CodeAnalysis.CSharp` and `Aspid.Generators.Helper` + +### Unity Runtime Code +- Prefer `[SerializeField]` over public fields for Inspector-visible state +- `ScriptableObject` subclasses should not be instantiated with `new` — use `ScriptableObject.CreateInstance` +- Extension methods on `VisualElement` should follow the fluent pattern already established in `VisualElementExtensions.*` + +### General C# Quality +- Nullable annotations must be consistent — the project has `enable` +- Avoid boxing of value types in hot paths (ProfilerMarkers, EnumValues iteration) +- Partial classes must all reside in files named consistently with the partial suffix pattern used elsewhere + +Report issues grouped by severity: **Error** (breaks compilation or runtime), **Warning** (likely bug or convention violation), **Info** (minor improvement). diff --git a/.claude/agents/uss-bem-checker.md b/.claude/agents/uss-bem-checker.md new file mode 100644 index 0000000..68d6283 --- /dev/null +++ b/.claude/agents/uss-bem-checker.md @@ -0,0 +1,80 @@ +--- +name: uss-bem-checker +description: Reviews USS stylesheets and the C# strings that reference them against the Aspid.FastTools BEM grammar (class names) and the positional grammar (custom properties). Use after edits to any *.uss file or to any code holding USS class names / `--aspid-*` variables (Constants.cs, AspidStyles.cs, component .cs files). +--- + +You are a strict reviewer of UIToolkit USS conventions for the **Aspid.FastTools** Unity package. Both grammars below are mandatory and documented in the project root `CLAUDE.md`. Your only job is to verify that every USS class name and every custom property follows them, and to flag legacy forms. + +## Scope + +Files to review (only what was changed unless the user widens the scope): + +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/**/*.uss` +- C# files that emit class strings or read custom properties: + - `Unity/Editor/Scripts/Ids/Constants.cs` (`Constants.Drawer.*`, `Constants.Registry.*`, `Constants.Selector.*`) + - `Unity/Editor/Scripts/VisualElements/Internal/Styles/AspidStyles.cs` + - Component `.cs` under `Unity/Editor/Scripts/VisualElements/Internal/Components/**/` +- Anywhere a literal `aspid-fasttools-...` or `--aspid-...` appears. + +## Grammar #1 — USS class names (BEM) + +Format: `aspid-fasttools-{block}[__{element}][--{modifier}]` + +Rules to enforce: + +1. The prefix `aspid-fasttools-` is mandatory and joined to the block by a single `-`. +2. Block — kebab-case (`id-registry`, `enum-values`, `serializable-type`). +3. Element — joined to block with `__` (double underscore): `aspid-fasttools-id-drawer__add-button`. +4. Modifier — joined with `--` (double dash): `aspid-fasttools-id-registry__warning--visible`, `aspid-fasttools-status--error`. +5. Inside any segment use kebab-case only — never `camelCase`, never single `_`. +6. Utility/state classes (`status`, `theme`) are blocks of their own: `aspid-fasttools-status--error`, `aspid-fasttools-theme--dark`. + +**Legacy form to flag and propose migrating:** classes that use a single `-` between block and element instead of `__` (e.g. `aspid-fasttools-id-drawer-add-button`). The CLAUDE.md says: migrate when touching surrounding code; new classes must follow BEM from the start. So: +- If the diff *adds* a non-BEM class → reject. +- If the diff *modifies code around* a legacy class → suggest migrating it as part of the change, but don't block. + +## Grammar #2 — USS custom properties (positional) + +Format: `--{prefix}-{group}-{role}[-{state}][-{tone}]` + +Rules to enforce: + +| Slot | Allowed values | Required | +|---|---|---| +| `prefix` | `aspid` (palette shared between Aspid packages) or `aspid-fasttools` (product-specific) | yes | +| `group` | `colors`, `icons`, `metrics`, `prop` | yes | +| `role` | `bg`, `shade`, `text`, `border`, `icon`, `status`, `gradient`, `label_size`, `line_size`, `theme`, … | yes | +| `state` | `success`, `warning`, `error`, `info`, `hover`, `pressed`, … | optional | +| `tone` | `darkness`, `dark`, `light`, `lightness` | optional | + +Additional rules: + +1. Slot separator is `-`. Compound words **inside one slot** use `_` (e.g. `label_size`, `line_size`) — never two independent concepts in one slot. +2. Order is **state → tone**: `--aspid-colors-status-success-darkness`, never `darkness-success`. +3. Color roles: + - `bg` — surface palette. + - `shade` — generic content palette (text/border/icon-tint share the same shade swatch when not specialised). + - `text` / `border` / `icon` — specialised, component-local roles. + - `status` — `success` / `warning` / `error` / `info`. +4. `prop` group is for inline component parameters (e.g. `--aspid-fasttools-prop-theme`), not palette tokens. +5. Palette variables are declared on `:root`. Component-scoped variables on the component's selector. + +The reference implementation is `Aspid-FastTools-Default-Dark.uss` — palette tokens there are the source of truth. + +## How to review + +For each USS file or code string in scope: + +1. Extract every class name (`.aspid-fasttools-...`) and every custom property (`--aspid-...`). +2. For each, validate against the matching grammar above. +3. Categorise findings as: + - **Block** — adds a new non-conforming name. Must be fixed before merge. + - **Migrate** — touches surrounding code that already contains a legacy form. Suggest the rewrite, don't block. + - **OK** — conforming. +4. Report concisely: + - File path + line. + - The offending name. + - Which rule it breaks. + - The corrected form. + +Do not propose stylistic changes (colors, spacing, ordering). Stay narrowly inside the two grammars and the legacy-migration rule. If the change does not touch USS classes or custom properties, return "No USS naming issues found." in one line. diff --git a/.claude/hooks/rebuild-generators-on-change.sh b/.claude/hooks/rebuild-generators-on-change.sh new file mode 100755 index 0000000..ae0c9e8 --- /dev/null +++ b/.claude/hooks/rebuild-generators-on-change.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# PostToolUse hook: rebuild Roslyn source generators after edits inside the +# main generator project, then redeploy the DLL into the Unity package. +# +# Path-scoped on purpose: +# - Triggers ONLY for *.cs under Aspid.FastTools.Generators/Aspid.FastTools.Generators/ +# - Skips Unity-side edits (Aspid.FastTools/Assets/...), tests, and the Sample project. +# - Skipping Unity edits matches the rule "do not run dotnet build for Unity-only edits". +# +# Build success -> exit 0 (silent). +# Path mismatch -> exit 0 (silent). +# Build failure -> exit 2 with stderr piped through, so the assistant sees it. + +set -uo pipefail + +file_path=$(jq -r '.tool_input.file_path // empty' 2>/dev/null) + +case "$file_path" in + */Aspid.FastTools.Generators/Aspid.FastTools.Generators/*.cs) ;; + *) exit 0 ;; +esac + +cd "$CLAUDE_PROJECT_DIR" || exit 0 + +dotnet build \ + Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj \ + -c Release --nologo -v quiet 1>&2 || exit 2 diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..548c507 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,26 @@ +{ + "extraKnownMarketplaces": { + "unicli": { + "source": { + "source": "github", + "repo": "yucchiy/UniCli" + } + } + }, + "enabledPlugins": { + "unicli@unicli": true + }, + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit|Write", + "hooks": [ + { + "type": "command", + "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/rebuild-generators-on-change.sh\"" + } + ] + } + ] + } +} diff --git a/.claude/skills/build-generator/SKILL.md b/.claude/skills/build-generator/SKILL.md new file mode 100644 index 0000000..a2763a1 --- /dev/null +++ b/.claude/skills/build-generator/SKILL.md @@ -0,0 +1,13 @@ +--- +name: build-generator +description: Build Roslyn source generators and deploy the resulting DLL into the Unity package +user-invocable: true +--- + +Build the Aspid.FastTools source generators and deploy to Unity: + +1. Run `dotnet build Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj -c Release` from the repository root +2. Copy `Aspid.FastTools.Generators/Aspid.FastTools.Generators/bin/Release/netstandard2.0/Aspid.FastTools.Generators.dll` to `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll` +3. Report the result: build output, any errors, and confirm the DLL was copied successfully + +Arguments: $ARGUMENTS (optional: pass `Debug` to build in Debug configuration instead of Release) diff --git a/.claude/skills/sync-readmes/SKILL.md b/.claude/skills/sync-readmes/SKILL.md new file mode 100644 index 0000000..15dd420 --- /dev/null +++ b/.claude/skills/sync-readmes/SKILL.md @@ -0,0 +1,81 @@ +--- +name: sync-readmes +description: Verify and update Aspid.FastTools README files against the actual codebase — namespaces, public API, CreateAssetMenu paths — keeping EN/RU and root/Documentation copies in sync +user-invocable: true +--- + +The package ships **eight** README files that drift from the code easily. Use this skill whenever the user asks to "check / update / sync READMEs", or after any change that touches: namespaces of public types, public API surface, `[CreateAssetMenu]` paths, source generator output, or sample structure. + +## Files in scope + +**Main READMEs (mirror each other 1:1 except for image paths and one heading):** + +| Path | Locale | Image base path | +|---|---|---| +| `README.md` | EN | `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/` | +| `README_RU.md` | RU | `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/` | +| `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md` | EN | `Images/` | +| `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md` | RU | `Images/` | + +The Documentation copies have an extra `## Source Code` / `## Исходный код` block linking to the GitHub repo — the root copies don't. Otherwise the body is identical character-for-character. + +**Sample READMEs (one EN + one RU per sample):** + +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples/Types/` +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples/Ids/` +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples/EnumValues/` +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples/ProfilerMarkers/` +- `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples/VisualElements/` + +## Workflow + +### 1. Verify against source before editing + +For every fact the README states, prove it from the code: + +| Claim | Verify with | +|---|---| +| Namespace of a public type | `grep -rn "namespace " --include="*.cs"` then locate the file declaring the type | +| `[CreateAssetMenu]` menu path | `grep -rn "CreateAssetMenu\|menuName" --include="*.cs"` | +| Public method signature / return value | Read the source file directly; do not infer from name | +| Generated code shape (`IdStructGenerator`, `ProfilerMarkersGenerator`) | Read `Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/.../*Body.cs` | +| Class actually exists | `find … -name ".cs"` — not all helper classes documented in old READMEs still exist (e.g. there is **no** `AspidEditorGUILayout`) | + +Common drift points discovered historically: + +- **Namespaces split per feature.** Public types live in `Aspid.FastTools` (root: `IId`, `UniqueIdAttribute`, `StringIdRegistry`), `Aspid.FastTools.Types`, `Aspid.FastTools.Enums`, `Aspid.FastTools.Ids`, `Aspid.FastTools.UIElements`. Editor helpers split similarly: `Aspid.FastTools.Editors` for `SerializedProperty` extensions / IMGUI scopes / `GetScriptName`, but per-feature editor code lives in `Aspid.FastTools.{Feature}.Editors`. A `using Aspid.FastTools;` line in a `SerializableType` example is wrong — it must be `using Aspid.FastTools.Types;`. +- **Two ID registries.** `StringIdRegistry` (in `Aspid.FastTools`) keeps int↔string at runtime; `IdRegistry` (in `Aspid.FastTools.Ids`) is int-only at runtime with names stripped from player builds. Don't conflate them. Their menu paths differ: `Aspid/FastTools/String Id Registry` vs `Aspid/FastTools/Id Registry`. `StringIdRegistry.GetId` returns `-1` (not `0`) when not found; the lookup-by-id method is `GetNameId(int)`, not `GetName(int)`. Neither registry exposes public `Add`, `Remove`, or `Rename` — those live behind the registry inspector / `RegistryEditorCore`. +- **Sample asset menu order.** Samples use `Aspid/Samples/FastTools/` (Samples first), not `Aspid/FastTools/Samples/`. Always re-grep `[CreateAssetMenu]` instead of trusting the existing README. + +### 2. Apply edits to all matching files + +Most edits hit all four main READMEs (EN root, EN Documentation, RU root, RU Documentation). Apply the same change to each — they must stay textually identical inside their respective body except for the image paths and the `## Source Code` heading. + +For RU edits, follow the existing RU translation conventions in the file: `Namespace` → `Пространство имён`, `Description` → `Описание`, code identifiers and English technical terms like `runtime`, `partial struct`, `Inspector` stay in English. + +When updating sample READMEs, edit both the EN and RU copy in the same sample folder. + +### 3. Sanity-check after editing + +Run these commands from the repo root and skim the output: + +```bash +# All using statements in samples — these are ground truth for namespaces +grep -rn "^using Aspid" Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples --include="*.cs" | sort -u + +# All CreateAssetMenu paths in the package +grep -rn "menuName" Aspid.FastTools/Assets/Plugins/Aspid/FastTools --include="*.cs" + +# Confirm both READMEs of a pair stay aligned (count sections) +grep -c "^## " README.md Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md +grep -c "^## " README_RU.md Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md +``` + +Then visually diff each pair of matched files (EN root vs EN Documentation; RU root vs RU Documentation) — only image paths and the `## Source Code` block should differ. + +## Arguments + +`$ARGUMENTS` (optional): +- empty — full audit and update of all eight READMEs; +- `--check` — audit only, report findings without editing; +- a feature name (`ids`, `types`, `enums`, `visualelements`, `profilermarkers`, `imgui`, `serializedproperty`) — narrow the audit/update to that section. diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000..b5e8cfd --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,44 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review, reopened] + # Optional: Only run on specific file changes + # paths: + # - "src/**/*.ts" + # - "src/**/*.tsx" + # - "src/**/*.js" + # - "src/**/*.jsx" + +jobs: + claude-review: + # Optional: Filter by PR author + # if: | + # github.event.pull_request.user.login == 'external-contributor' || + # github.event.pull_request.user.login == 'new-developer' || + # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' + plugins: 'code-review@claude-code-plugins' + prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000..6b15fac --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,50 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. + # prompt: 'Update the pull request description to include a summary of changes.' + + # Optional: Add claude_args to customize behavior and configuration + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + # claude_args: '--allowed-tools Bash(gh pr *)' + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca6f4bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.claude/settings.local.json +.worktrees/ + +# UPM convention: `Samples~` is hidden from Unity importer but must be tracked. +# Override global `*~` ignore. +!Samples~/ +!Samples~/** diff --git a/Aspid.UnityFastTools.Generators/.gitignore b/Aspid.FastTools.Generators/.gitignore similarity index 100% rename from Aspid.UnityFastTools.Generators/.gitignore rename to Aspid.FastTools.Generators/.gitignore diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Sample/Aspid.UnityFastTools.Generators.Sample.csproj b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Sample/Aspid.FastTools.Generators.Sample.csproj similarity index 61% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Sample/Aspid.UnityFastTools.Generators.Sample.csproj rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators.Sample/Aspid.FastTools.Generators.Sample.csproj index c7d1c6e..c971c51 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Sample/Aspid.UnityFastTools.Generators.Sample.csproj +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Sample/Aspid.FastTools.Generators.Sample.csproj @@ -3,13 +3,13 @@ net6.0 enable - UnityFastToolsGenerators.Sample + Aspid.FastTools.Sample 6000.2.7f2 9 - + diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Tests/Aspid.UnityFastTools.Generators.Tests.csproj b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/Aspid.FastTools.Generators.Tests.csproj similarity index 81% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Tests/Aspid.UnityFastTools.Generators.Tests.csproj rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/Aspid.FastTools.Generators.Tests.csproj index 963f078..e4d8ac9 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators.Tests/Aspid.UnityFastTools.Generators.Tests.csproj +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/Aspid.FastTools.Generators.Tests.csproj @@ -6,7 +6,7 @@ false - UnityFastToolsGenerators.Tests + Aspid.FastTools.Tests @@ -20,7 +20,7 @@ - + diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/IdStructGeneratorTests.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/IdStructGeneratorTests.cs new file mode 100644 index 0000000..4f8fe98 --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.Tests/IdStructGeneratorTests.cs @@ -0,0 +1,147 @@ +using Xunit; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Aspid.FastTools.Generators.IdStruct; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Generators.Tests +{ + public class IdStructGeneratorTests + { + private const string IIdDefinition = "namespace Aspid.FastTools.Ids { public interface IId { int Id { get; } } }"; + + private static GeneratorDriverRunResult RunGenerator(string source) + { + var syntaxTree = CSharpSyntaxTree.ParseText(source); + var iidTree = CSharpSyntaxTree.ParseText(IIdDefinition); + + var references = new[] + { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location) + }; + + var compilation = CSharpCompilation.Create("TestCompilation", + syntaxTrees: new[] { syntaxTree, iidTree }, + references: references, + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var generator = new IdStructGenerator(); + GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out _); + + return driver.GetRunResult(); + } + + [Fact] + public void Test_Generator_DoesNotCrash_OnEmptySource() + { + var result = RunGenerator("namespace Test { }"); + + Assert.Empty(result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error)); + Assert.Empty(result.Results[0].GeneratedSources); + } + + [Fact] + public void Struct_WithIId_InNamespace_GeneratesIdFieldAndProperty() + { + const string source = @" +namespace Sample +{ + public partial struct Foo : global::Aspid.FastTools.Ids.IId { } +} +"; + var result = RunGenerator(source); + var generated = result.Results[0].GeneratedSources; + + Assert.Single(generated); + var source0 = generated[0]; + + Assert.EndsWith(".IId.g.cs", source0.HintName); + var text = source0.SourceText.ToString(); + Assert.Contains("partial struct Foo", text); + Assert.Contains("private int _id;", text); + Assert.Contains("public int Id =>", text); + } + + [Fact] + public void Struct_WithoutPartial_NotGenerated() + { + const string source = @" +namespace Sample +{ + public struct Foo : global::Aspid.FastTools.Ids.IId + { + public int Id => 0; + } +} +"; + var result = RunGenerator(source); + var generated = result.Results[0].GeneratedSources; + + Assert.Empty(generated); + } + + [Fact] + public void Struct_WithoutIId_NotGenerated() + { + const string source = @" +namespace Sample +{ + public interface IMarker { } + public partial struct Foo : IMarker { } +} +"; + var result = RunGenerator(source); + var generated = result.Results[0].GeneratedSources; + + Assert.Empty(generated); + } + + [Fact] + public void TwoStructsSameName_DifferentNamespaces_NoHintNameCollision() + { + const string source = @" +namespace SampleA +{ + public partial struct Foo : global::Aspid.FastTools.Ids.IId { } +} + +namespace SampleB +{ + public partial struct Foo : global::Aspid.FastTools.Ids.IId { } +} +"; + var result = RunGenerator(source); + var generated = result.Results[0].GeneratedSources; + + Assert.Equal(2, generated.Length); + + var hintNames = generated.Select(s => s.HintName).ToArray(); + Assert.NotEqual(hintNames[0], hintNames[1]); + Assert.Contains(hintNames, h => h.Contains("SampleA")); + Assert.Contains(hintNames, h => h.Contains("SampleB")); + } + + [Fact] + public void NestedStruct_WrappedInPartialOuterClass() + { + const string source = @" +namespace Sample +{ + public partial class Outer + { + public partial struct Inner : global::Aspid.FastTools.Ids.IId { } + } +} +"; + var result = RunGenerator(source); + var generated = result.Results[0].GeneratedSources; + + Assert.Single(generated); + var text = generated[0].SourceText.ToString(); + Assert.Contains("partial class Outer", text); + Assert.Contains("partial struct Inner", text); + } + } +} diff --git a/Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.sln b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.sln similarity index 64% rename from Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.sln rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators.sln index aa25b9e..29d5927 100644 --- a/Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.sln +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators.sln @@ -1,10 +1,10 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators\Aspid.UnityFastTools.Generators.csproj", "{CB9D8D51-7D86-4B84-A0DB-73E418962DA7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators", "Aspid.FastTools.Generators\Aspid.FastTools.Generators.csproj", "{CB9D8D51-7D86-4B84-A0DB-73E418962DA7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators.Sample", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators.Sample\Aspid.UnityFastTools.Generators.Sample.csproj", "{2835DD81-D105-4C2E-AE03-BC7D064C29D1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators.Sample", "Aspid.FastTools.Generators.Sample\Aspid.FastTools.Generators.Sample.csproj", "{2835DD81-D105-4C2E-AE03-BC7D064C29D1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.UnityFastTools.Generators.Tests", "UnityFastToolsGenerators\Aspid.UnityFastTools.Generators.Tests\Aspid.UnityFastTools.Generators.Tests.csproj", "{F4953608-2F14-4B2E-B91C-B3FDFC81B180}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspid.FastTools.Generators.Tests", "Aspid.FastTools.Generators.Tests\Aspid.FastTools.Generators.Tests.csproj", "{F4953608-2F14-4B2E-B91C-B3FDFC81B180}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.csproj b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj similarity index 91% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.csproj rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj index 74888a7..e04492e 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Aspid.UnityFastTools.Generators.csproj +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Aspid.FastTools.Generators.csproj @@ -3,9 +3,9 @@ netstandard2.0 enable - 13 + latest true - UnityFastToolsGenerators + Aspid.FastTools diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Descriptions/General.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Descriptions/General.cs new file mode 100644 index 0000000..201eb71 --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Descriptions/General.cs @@ -0,0 +1,8 @@ +using Aspid.Generators.Helper; + +namespace Aspid.FastTools.Descriptions; + +public static class General +{ + public static readonly string ProfilerMarkerGeneratedCode = $"""{Classes.GeneratedCodeAttribute}("Aspid.FastTools.Generators.ProfilerMarkersGenerator", "1.0.0")"""; +} \ No newline at end of file diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Bodies/IdStructBody.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Bodies/IdStructBody.cs new file mode 100644 index 0000000..42b61ad --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Bodies/IdStructBody.cs @@ -0,0 +1,50 @@ +using System.Text; +using Microsoft.CodeAnalysis; +using Aspid.Generators.Helper; +using Aspid.FastTools.Generators.IdStruct.Data; + +namespace Aspid.FastTools.Generators.IdStruct.Bodies; + +public static class IdStructBody +{ + public static void GenerateCode(in SourceProductionContext context, in IdStructData data) + { + var hasNamespace = data.Namespace != null; + var nestedDepth = data.ContainingTypes.Length; + + var code = new CodeWriter() + .AppendLine("// ") + .AppendLine() + .AppendLineIf(hasNamespace, $"namespace {data.Namespace}") + .BeginBlockIf(hasNamespace); + + var nestedNames = new StringBuilder(); + foreach (var containing in data.ContainingTypes) + { + code.AppendLine($"partial {containing.Keyword} {containing.Name}") + .BeginBlock(); + nestedNames.Append(containing.Name).Append('.'); + } + + code.AppendLine($"partial struct {data.StructName}") + .BeginBlock() + .AppendLine("#if UNITY_EDITOR") + .AppendLine("[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]") + .AppendLine("[global::UnityEngine.SerializeField] private string __stringId;") + .AppendLine("#endif") + .AppendLine("[global::UnityEngine.SerializeField] private int _id;") + .AppendLine("public int Id => _id;") + .EndBlock(); + + for (var i = 0; i < nestedDepth; i++) + code.EndBlock(); + + code.EndBlockIf(hasNamespace); + + var hintName = hasNamespace + ? $"{data.Namespace}.{nestedNames}{data.StructName}.IId.g.cs" + : $"{nestedNames}{data.StructName}.IId.g.cs"; + + context.AddSource(hintName, code.GetSourceText()); + } +} diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/ContainingTypeInfo.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/ContainingTypeInfo.cs new file mode 100644 index 0000000..d04dc9a --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/ContainingTypeInfo.cs @@ -0,0 +1,23 @@ +using System; + +namespace Aspid.FastTools.Generators.IdStruct.Data; + +public readonly struct ContainingTypeInfo(string name, string keyword) : IEquatable +{ + public readonly string Name = name; + public readonly string Keyword = keyword; + + public bool Equals(ContainingTypeInfo other) => + Name == other.Name && Keyword == other.Keyword; + + public override bool Equals(object? obj) => + obj is ContainingTypeInfo other && Equals(other); + + public override int GetHashCode() + { + unchecked + { + return (Name.GetHashCode() * 397) ^ Keyword.GetHashCode(); + } + } +} diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/IdStructData.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/IdStructData.cs new file mode 100644 index 0000000..9719f2e --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/Data/IdStructData.cs @@ -0,0 +1,82 @@ +using System; +using Microsoft.CodeAnalysis; +using System.Collections.Immutable; + +namespace Aspid.FastTools.Generators.IdStruct.Data; + +public readonly struct IdStructData : IEquatable +{ + public readonly string StructName; + public readonly string? Namespace; + public readonly ImmutableArray ContainingTypes; + + public IdStructData(INamedTypeSymbol symbol) + { + StructName = symbol.Name; + Namespace = symbol.ContainingNamespace.IsGlobalNamespace + ? null + : symbol.ContainingNamespace.ToDisplayString(); + + if (symbol.ContainingType is null) + { + ContainingTypes = ImmutableArray.Empty; + return; + } + + var builder = ImmutableArray.CreateBuilder(); + var current = symbol.ContainingType; + while (current is not null) + { + builder.Add(new ContainingTypeInfo(current.Name, GetKeyword(current))); + current = current.ContainingType; + } + + builder.Reverse(); + ContainingTypes = builder.ToImmutable(); + } + + private static string GetKeyword(INamedTypeSymbol symbol) + { + if (symbol.IsRecord) + return symbol.IsValueType ? "record struct" : "record"; + + return symbol.TypeKind switch + { + TypeKind.Class => "class", + TypeKind.Struct => "struct", + TypeKind.Interface => "interface", + _ => throw new InvalidOperationException($"Unsupported containing type kind: {symbol.TypeKind}"), + }; + } + + public bool Equals(IdStructData other) + { + if (StructName != other.StructName) return false; + if (Namespace != other.Namespace) return false; + if (ContainingTypes.Length != other.ContainingTypes.Length) return false; + + for (var i = 0; i < ContainingTypes.Length; i++) + { + if (!ContainingTypes[i].Equals(other.ContainingTypes[i])) return false; + } + + return true; + } + + public override bool Equals(object? obj) => + obj is IdStructData other && Equals(other); + + public override int GetHashCode() + { + unchecked + { + var hash = StructName.GetHashCode(); + hash = (hash * 397) ^ (Namespace?.GetHashCode() ?? 0); + + foreach (var ct in ContainingTypes) + hash = (hash * 397) ^ ct.GetHashCode(); + + return hash; + } + } +} diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/IdStructGenerator.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/IdStructGenerator.cs new file mode 100644 index 0000000..e690f23 --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/IdStruct/IdStructGenerator.cs @@ -0,0 +1,50 @@ +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Aspid.FastTools.Generators.IdStruct.Data; +using Aspid.FastTools.Generators.IdStruct.Bodies; + +namespace Aspid.FastTools.Generators.IdStruct; + +[Generator(LanguageNames.CSharp)] +public class IdStructGenerator : IIncrementalGenerator +{ + private const string IIdFullName = "Aspid.FastTools.Ids.IId"; + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var provider = context.SyntaxProvider + .CreateSyntaxProvider(Predicate, Transform) + .Where(static d => d.HasValue) + .Select(static (d, _) => d!.Value); + + context.RegisterSourceOutput(provider, static (ctx, data) => IdStructBody.GenerateCode(ctx, data)); + } + + private static bool Predicate(SyntaxNode node, CancellationToken _) + { + if (node is not StructDeclarationSyntax structDecl) return false; + if (!structDecl.Modifiers.Any(SyntaxKind.PartialKeyword)) return false; + return structDecl.BaseList is { Types.Count: > 0 }; + } + + private static IdStructData? Transform(GeneratorSyntaxContext context, CancellationToken ct) + { + var structDecl = (StructDeclarationSyntax)context.Node; + + if (context.SemanticModel.GetDeclaredSymbol(structDecl, ct) is not INamedTypeSymbol symbol) + return null; + + var iidInterface = context.SemanticModel.Compilation.GetTypeByMetadataName(IIdFullName); + if (iidInterface == null) return null; + + foreach (var iface in symbol.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(iface, iidInterface)) + return new IdStructData(symbol); + } + + return null; + } +} diff --git a/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Bodies/ExtensionClassBody.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Bodies/ExtensionClassBody.cs new file mode 100644 index 0000000..f3b935b --- /dev/null +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Bodies/ExtensionClassBody.cs @@ -0,0 +1,161 @@ +using System.Linq; +using Microsoft.CodeAnalysis; +using Aspid.Generators.Helper; +using System.Collections.Generic; +using System.Collections.Immutable; +using Aspid.FastTools.Generators.ProfilerMarkers.Data; +using static Aspid.Generators.Helper.Classes; +using static Aspid.FastTools.Descriptions.General; +using static Aspid.Generators.Helper.Unity.UnityClasses; + +namespace Aspid.FastTools.Generators.ProfilerMarkers.Bodies; + +public static class ExtensionClassBody +{ + public static void GenerateCode(in SourceProductionContext context, in ImmutableArray markerCalls) + { + var markerCallTypes = markerCalls + .GroupBy(markerCall => markerCall.NamedTypeSymbol, SymbolEqualityComparer.Default) + .Select(group => new MarkerCallType((INamedTypeSymbol)group.Key!, group.ToImmutableArray())); + + foreach (var markerCallType in markerCallTypes) + GenerateCode(context, markerCallType); + } + + private static void GenerateCode(in SourceProductionContext context, in MarkerCallType type) + { + var symbol = (INamedTypeSymbol)type.Symbol; + var typeName = symbol.Name; + + var hasNamespaceName = !symbol.ContainingNamespace.IsGlobalNamespace; + var namespaceName = hasNamespaceName ? symbol.ContainingNamespace.ToDisplayString() : null; + + var markerCallMembers = type.MarkerCalls + .GroupBy(markerCall => markerCall.MethodSymbol, SymbolEqualityComparer.Default) + .Select(grouping => new MarkerCallMember((IMethodSymbol)grouping.Key!, grouping.ToImmutableArray())) + .ToImmutableArray(); + + var arityPart = symbol.Arity > 0 ? $"_{symbol.Arity}" : string.Empty; + var className = $"__{typeName}{arityPart}ProfilerMarkerExtensions"; + var typeParameters = symbol.TypeParameters; + var isGeneric = typeParameters.Length > 0; + var typeParamList = isGeneric + ? "<" + string.Join(", ", typeParameters.Select(p => p.Name)) + ">" + : string.Empty; + var constraintsClause = BuildConstraintsClause(typeParameters); + + var code = new CodeWriter() + .AppendLine("// ") + .AppendLine() + .AppendLineIf(hasNamespaceName, $"namespace {namespaceName}") + .BeginBlockIf(hasNamespaceName) + .AppendLine($"[{ProfilerMarkerGeneratedCode}]") + .AppendLine($"internal static class {className}") + .BeginBlock() + .AppendProfilerMarkers(symbol, markerCallMembers, typeParamList, constraintsClause, isGeneric) + .AppendWithoutMessage(symbol, markerCallMembers, typeParamList, constraintsClause, isGeneric) + .EndBlock() + .EndBlockIf(hasNamespaceName); + + var hintName = $"{className}.g.cs"; + context.AddSource(hintName, code.GetSourceText()); + } + + private static CodeWriter AppendProfilerMarkers( + this CodeWriter code, + INamedTypeSymbol symbol, + ImmutableArray markerCallMembers, + string typeParamList, + string constraintsClause, + bool isGeneric) + { + if (isGeneric) + { + code.AppendLine($"private static class Markers{typeParamList}{constraintsClause}") + .BeginBlock(); + } + + var fieldVisibility = isGeneric ? "public" : "private"; + + foreach (var markerCallMember in markerCallMembers) + { + var orderedMarkerCalls = markerCallMember.MarkerCalls + .OrderBy(markerCall => markerCall.Line); + + foreach (var markerCall in orderedMarkerCalls) + { + var markerValueExpression = BuildMarkerValueExpression(symbol, markerCall); + code.AppendMultiline( + $""" + [{ProfilerMarkerGeneratedCode}] + {fieldVisibility} static readonly {ProfilerMarker} {markerCall.MarkerName} = new({markerValueExpression}); + + """); + } + } + + if (isGeneric) + code.EndBlock().AppendLine(); + + return code; + } + + private static CodeWriter AppendWithoutMessage( + this CodeWriter code, + INamedTypeSymbol symbol, + ImmutableArray markerCallMembers, + string typeParamList, + string constraintsClause, + bool isGeneric) + { + code.AppendLine($"[{ProfilerMarkerGeneratedCode}]") + .AppendLine($"public static {ProfilerMarker}.AutoScope Marker{typeParamList}(this {symbol.ToDisplayStringGlobal()} _, [{CallerLineNumberAttribute}] int line = -1){constraintsClause}") + .BeginBlock(); + + var prefix = isGeneric ? $"Markers{typeParamList}." : string.Empty; + foreach (var markerCall in markerCallMembers.SelectMany(member => member.MarkerCalls)) + code.AppendLine($"if (line is {markerCall.Line}) return {prefix}{markerCall.MarkerName}.Auto();"); + + code.AppendLine() + .AppendLine($"throw new {Exception}();") + .EndBlock(); + + return code; + } + + private static string BuildMarkerValueExpression(INamedTypeSymbol symbol, MarkerCall markerCall) + { + if (symbol.TypeParameters.Length is 0) + return $"\"{symbol.Name}.{markerCall.Label} ({markerCall.Line})\""; + + var typeArgs = string.Join(", ", symbol.TypeParameters.Select(p => $"{{typeof({p.Name}).Name}}")); + return $"$\"{symbol.Name}<{typeArgs}>.{markerCall.Label} ({markerCall.Line})\""; + } + + private static string BuildConstraintsClause(ImmutableArray typeParameters) + { + if (typeParameters.Length is 0) return string.Empty; + + var clauses = new List(); + foreach (var tp in typeParameters) + { + var constraints = new List(); + + if (tp.HasReferenceTypeConstraint) constraints.Add("class"); + else if (tp.HasUnmanagedTypeConstraint) constraints.Add("unmanaged"); + else if (tp.HasValueTypeConstraint) constraints.Add("struct"); + + if (tp.HasNotNullConstraint) constraints.Add("notnull"); + + foreach (var ct in tp.ConstraintTypes) + constraints.Add(ct.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); + + if (tp.HasConstructorConstraint) constraints.Add("new()"); + + if (constraints.Count > 0) + clauses.Add($"where {tp.Name} : {string.Join(", ", constraints)}"); + } + + return clauses.Count is 0 ? string.Empty : " " + string.Join(" ", clauses); + } +} diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs similarity index 61% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs index dd3ea86..e713d1f 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCall.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis; -namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data; +namespace Aspid.FastTools.Generators.ProfilerMarkers.Data; public readonly struct MarkerCall( INamedTypeSymbol namedTypeSymbol, @@ -12,7 +12,7 @@ public readonly struct MarkerCall( public readonly int Line = line; public readonly IMethodSymbol MethodSymbol = methodSymbol; public readonly INamedTypeSymbol NamedTypeSymbol = namedTypeSymbol; - - public readonly string MarkerName = markerName + "_line_" + line; - public readonly string MarkerValue = $"{namedTypeSymbol.Name}.{markerValue} ({line})"; -} \ No newline at end of file + + public readonly string MarkerName = markerName + "_Marker_Line_" + line; + public readonly string Label = markerValue; +} diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs similarity index 82% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs index f0a01d7..8f3b9b5 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallMember.cs @@ -1,7 +1,7 @@ using Microsoft.CodeAnalysis; using System.Collections.Immutable; -namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data; +namespace Aspid.FastTools.Generators.ProfilerMarkers.Data; public readonly struct MarkerCallMember( IMethodSymbol methodSymbol, diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs similarity index 61% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs index af2d3c7..b268bff 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/Data/MarkerCallType.cs @@ -1,12 +1,12 @@ using Microsoft.CodeAnalysis; using System.Collections.Immutable; -namespace UnityFastToolsGenerators.Generators.ProfilerMarkers.Data; +namespace Aspid.FastTools.Generators.ProfilerMarkers.Data; public readonly struct MarkerCallType( - ISymbol symbol, + INamedTypeSymbol symbol, ImmutableArray markerCalls) { - public readonly ISymbol Symbol = symbol; + public readonly INamedTypeSymbol Symbol = symbol; public readonly ImmutableArray MarkerCalls = markerCalls; } \ No newline at end of file diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs similarity index 76% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs index 846c545..da074a5 100644 --- a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs +++ b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Generators/ProfilerMarkers/ProfilerMarkersGenerator.cs @@ -2,10 +2,10 @@ using Microsoft.CodeAnalysis; using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Syntax; -using UnityFastToolsGenerators.Generators.ProfilerMarkers.Data; -using UnityFastToolsGenerators.Generators.ProfilerMarkers.Bodies; +using Aspid.FastTools.Generators.ProfilerMarkers.Data; +using Aspid.FastTools.Generators.ProfilerMarkers.Bodies; -namespace UnityFastToolsGenerators.Generators.ProfilerMarkers; +namespace Aspid.FastTools.Generators.ProfilerMarkers; [Generator(LanguageNames.CSharp)] public class ProfilerMarkersGenerator : IIncrementalGenerator @@ -25,7 +25,7 @@ private static bool Predicate(SyntaxNode node, CancellationToken _) { if (node is not InvocationExpressionSyntax invocation) return false; if (invocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression) return false; - + return memberAccessExpression.Name is IdentifierNameSyntax { Identifier.ValueText: "Marker" @@ -39,35 +39,47 @@ private static bool Predicate(SyntaxNode node, CancellationToken _) if (invocation.Expression is not MemberAccessExpressionSyntax memberAccessExpression) return null; if (memberAccessExpression.Name is not IdentifierNameSyntax idName || idName.Identifier.ValueText is not "Marker") return null; if (context.SemanticModel.GetEnclosingSymbol(invocation.SpanStart) is not IMethodSymbol enclosing) return null; - + var namedTypeSymbol = enclosing.ContainingType; if (namedTypeSymbol is null) return null; - var markerName = enclosing.AssociatedSymbol is IPropertySymbol property - ? property.Name - : enclosing.MethodKind is MethodKind.Constructor - ? "Ctor" - : enclosing.Name; - + var markerName = ResolveMarkerName(enclosing); var markerValue = markerName; - - if (invocation.Parent is MemberAccessExpressionSyntax memberAccessExpressionWithName + + if (invocation.Parent is MemberAccessExpressionSyntax memberAccessExpressionWithName && memberAccessExpressionWithName.Name is IdentifierNameSyntax { Identifier.ValueText: "WithName" } && memberAccessExpressionWithName.Parent is InvocationExpressionSyntax invocationExpressionWithName && invocationExpressionWithName.ArgumentList.Arguments.FirstOrDefault()?.Expression is LiteralExpressionSyntax literalExpressionWithName) { markerValue = literalExpressionWithName.Token.ValueText; } - + var lineSpan = invocation.GetLocation().GetLineSpan(); var lineNumber = lineSpan.StartLinePosition.Line + 1; - + return new MarkerCall(namedTypeSymbol, enclosing, lineNumber, markerName, markerValue); } + private static string ResolveMarkerName(IMethodSymbol enclosing) + { + if (enclosing.AssociatedSymbol is IPropertySymbol property) + { + return property.ExplicitInterfaceImplementations.Length > 0 + ? property.ExplicitInterfaceImplementations[0].Name + : property.Name; + } + + if (enclosing.MethodKind is MethodKind.Constructor) + return "Ctor"; + + return enclosing.ExplicitInterfaceImplementations.Length > 0 + ? enclosing.ExplicitInterfaceImplementations[0].Name + : enclosing.Name; + } + private static void GenerateCode(SourceProductionContext context, ImmutableArray markerCalls) { if (markerCalls.Length is 0) return; ExtensionClassBody.GenerateCode(context, markerCalls); } -} \ No newline at end of file +} diff --git a/Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Properties/launchSettings.json b/Aspid.FastTools.Generators/Aspid.FastTools.Generators/Properties/launchSettings.json similarity index 100% rename from Aspid.UnityFastTools.Generators/UnityFastToolsGenerators/Aspid.UnityFastTools.Generators/Properties/launchSettings.json rename to Aspid.FastTools.Generators/Aspid.FastTools.Generators/Properties/launchSettings.json diff --git a/Aspid.FastTools.Generators/CLAUDE.md b/Aspid.FastTools.Generators/CLAUDE.md new file mode 100644 index 0000000..23beb6c --- /dev/null +++ b/Aspid.FastTools.Generators/CLAUDE.md @@ -0,0 +1,122 @@ +# Aspid.FastTools.Generators + +Standalone .NET solution containing Roslyn source generators for the `com.aspid.fasttools` Unity package. + +## Commands + +```bash +# Build and auto-deploy DLL into Unity package +dotnet build -c Release + +# Run generator unit tests +dotnet test +``` + +`Directory.Build.targets` copies the compiled DLL to `../Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll` on build. + +A repo-level PostToolUse hook (`.claude/hooks/rebuild-generators-on-change.sh`) also runs `dotnet build` automatically after any `Edit`/`Write` to `*.cs` under `Aspid.FastTools.Generators/Aspid.FastTools.Generators/`. The hook intentionally **does not** trigger for tests, the Sample project, or Unity-side edits — keep that scope if you modify it. + +## Solution Structure + +``` +Aspid.FastTools.Generators/ ← generator implementation +Aspid.FastTools.Generators.Tests/ ← unit tests (Roslyn test helpers) +Aspid.FastTools.Generators.Sample/ ← manual smoke-test project +Aspid.FastTools.Generators.sln +Directory.Build.targets +``` + +## Target Framework + +`netstandard2.0` — required by Roslyn. No Unity assemblies, no runtime packages. + +## Dependencies + +| Package | Role | +|---|---| +| `Microsoft.CodeAnalysis.CSharp` 4.3.0 | Roslyn semantic model and syntax | +| `Aspid.Generators.Helper` | `CodeWriter` utility for emitting source | +| `Aspid.Generators.Helper.Unity` | Unity-specific analysis helpers | +| `SourceGenerator.Foundations` 2.0.13 | Incremental generator infrastructure | + +## Generator Implementation Pattern + +All generators implement `IIncrementalGenerator` (never the deprecated `ISourceGenerator`). + +### Three-Stage Pipeline + +``` +Predicate (SyntaxNode) → Transform (SemanticModel) → GenerateCode (SourceProductionContext) +``` + +**1. Predicate** — cheap syntax-only filter, no semantic model: +```csharp +private static bool Predicate(SyntaxNode node, CancellationToken _) +{ + if (node is not StructDeclarationSyntax s) return false; + if (!s.Modifiers.Any(SyntaxKind.PartialKeyword)) return false; + return s.BaseList is { Types.Count: > 0 }; +} +``` + +**2. Transform** — semantic extraction, returns a readonly struct or `null`: +```csharp +private static IdStructData? Transform(GeneratorSyntaxContext ctx, CancellationToken _) +{ + var symbol = ctx.SemanticModel.GetDeclaredSymbol(...); + // resolve IId by metadata name, check AllInterfaces + return new IdStructData(symbol); +} +``` + +**3. GenerateCode** — emit source using `CodeWriter`: +```csharp +public static void GenerateCode(in SourceProductionContext context, in IdStructData data) +{ + var code = new CodeWriter() + .AppendLine("// ") + ... + .ToString(); + context.AddSource($"{data.StructName}.IId.g.cs", code); +} +``` + +### Data Structures + +Carry semantic results between pipeline stages as `readonly struct` — they must be value-comparable for Roslyn's caching to work correctly. + +```csharp +public readonly struct IdStructData(INamedTypeSymbol symbol) +{ + public readonly string StructName = symbol.Name; + public readonly string? Namespace = symbol.ContainingNamespace.IsGlobalNamespace + ? null + : symbol.ContainingNamespace.ToDisplayString(); +} +``` + +### Generated File Naming + +| Generator | Pattern | +|---|---| +| `IdStructGenerator` | `{StructName}.IId.g.cs` | +| `ProfilerMarkersGenerator` | `__{TypeName}{Arity}ProfilerMarkerExtensions.g.cs` | + +All generated files begin with `// `. + +## Existing Generators + +### ProfilerMarkersGenerator + +Finds every `.Marker()` call site, extracts enclosing type + method + line number, and generates `private static readonly ProfilerMarker` fields unique to each call site. Marker name: `"{markerName}_line_{line}"`. Marker display value: `"{TypeName}.{member} ({line})"`. Supports `.WithName(string)` override. + +### IdStructGenerator + +Finds `partial struct` types implementing `Aspid.FastTools.Ids.IId` and generates boilerplate: serialized `_id` field, `Id` property, editor-only `__stringId` field. Supports nested types — generated code is wrapped in matching `partial class`/`partial struct`/`partial record` containing-type declarations. + +## Conventions + +- Generator class → `[Generator(LanguageNames.CSharp)]` attribute +- Generated members → `[ProfilerMarkerGeneratedCode]` or equivalent visibility attribute from `Descriptions/General.cs` +- Namespace handling → always check `IsGlobalNamespace` before emitting `namespace` block +- Avoid LINQ in hot Predicate/Transform paths — allocations defeat incremental caching diff --git a/Aspid.FastTools.Generators/Directory.Build.targets b/Aspid.FastTools.Generators/Directory.Build.targets new file mode 100644 index 0000000..f176b58 --- /dev/null +++ b/Aspid.FastTools.Generators/Directory.Build.targets @@ -0,0 +1,11 @@ + + + + + <_UnityDestination>$(MSBuildThisFileDirectory)../Aspid.FastTools/Assets/Plugins/Aspid/FastTools/ + + + + + + diff --git a/Aspid.UnityFastTools/.gitignore b/Aspid.FastTools/.gitignore similarity index 100% rename from Aspid.UnityFastTools/.gitignore rename to Aspid.FastTools/.gitignore diff --git a/Aspid.UnityFastTools/Assets/Plugins.meta b/Aspid.FastTools/Assets/Plugins.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins.meta rename to Aspid.FastTools/Assets/Plugins.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid.meta b/Aspid.FastTools/Assets/Plugins/Aspid.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid.meta rename to Aspid.FastTools/Assets/Plugins/Aspid.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Aspid.UnityFastTools.Generators.dll b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll similarity index 99% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Aspid.UnityFastTools.Generators.dll rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll index 95a75d7..74791c1 100644 Binary files a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Aspid.UnityFastTools.Generators.dll and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll differ diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Aspid.UnityFastTools.Generators.dll.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Aspid.UnityFastTools.Generators.dll.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.ProfilerMarkers.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.ProfilerMarkers.png rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.ProfilerMarkers.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.ProfilerMarkers.png.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png new file mode 100644 index 0000000..a332f4e Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png.meta new file mode 100644 index 0000000..683f8d2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: b0d82cbe15d4842dd9d7c31cb4040e88 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png new file mode 100644 index 0000000..5c97940 Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png.meta new file mode 100644 index 0000000..7553ff5 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: 648f40dc17f7a46a99e35e8dcf5318e7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.VisualElement.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.VisualElement.png rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.VisualElement.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.VisualElement.png.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md new file mode 100644 index 0000000..7cf7985 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md @@ -0,0 +1,525 @@ +# Aspid.FastTools + +**Aspid.FastTools** is a set of tools designed to minimize routine code writing in Unity. + +## Source Code + +[[Aspid.FastTools](https://github.com/VPDPersonal/Aspid.FastTools)] + + +--- + +## Integration + +Install Aspid.FastTools using one of the following methods: + +- **Download .unitypackage** — Visit the [Release page on GitHub](https://github.com/VPDPersonal/Aspid.FastTools/releases) and download the latest version, `Aspid.FastTools.X.X.X.unitypackage`. Import it into your project. +- **Via UPM** (Unity Package Manager) integrate the following packages: + - `https://github.com/VPDPersonal/Aspid.Internal.Unity.git` + - `https://github.com/VPDPersonal/Aspid.FastTools.git?path=Aspid.FastTools/Assets/Plugins/Aspid/FastTools` + +--- + +## Namespaces + +| Namespace | Description | +|-----------|-------------| +| `Aspid.FastTools.Types` | `SerializableType`, `SerializableType`, `ComponentTypeSelector`, `TypeSelectorAttribute` | +| `Aspid.FastTools.Enums` | `EnumValues` | +| `Aspid.FastTools.Ids` | `IId`, `UniqueIdAttribute`, `IdRegistry` | +| `Aspid.FastTools.UIElements` | Runtime `VisualElement` fluent extensions | +| `Aspid.FastTools.Editors` | Editor helpers — `SerializedProperty` extensions, IMGUI scopes, `GetScriptName` | +| `Aspid.FastTools.Types.Editors` · `.Enums.Editors` · `.Ids.Editors` · `.UIElements.Editors` | Per-feature editor code (property drawers, registry inspector, editor-only `VisualElement` extensions) | + +--- + +## ProfilerMarker + +Provides source-generated `ProfilerMarker` registration. The generator creates a static marker per call-site, identified by the calling method and line number. + +```csharp +using UnityEngine; + +public class MyBehaviour : MonoBehaviour +{ + private void Update() + { + DoSomething1(); + DoSomething2(); + } + + private void DoSomething1() + { + using var _ = this.Marker(); + // Some code + } + + private void DoSomething2() + { + using (this.Marker()) + { + // Some code + using var _ = this.Marker().WithName("Calculate"); + // Some code + } + } +} +``` + +### Generated code + +```csharp +using System; +using Unity.Profiling; +using System.Runtime.CompilerServices; + +internal static class __MyBehaviourProfilerMarkerExtensions +{ + private static readonly ProfilerMarker DoSomething1_line_13 = new("MyBehaviour.DoSomething1 (13)"); + private static readonly ProfilerMarker DoSomething2_line_19 = new("MyBehaviour.DoSomething2 (19)"); + private static readonly ProfilerMarker DoSomething2_line_22 = new("MyBehaviour.Calculate (22)"); + + public static ProfilerMarker.AutoScope Marker(this MyBehaviour _, [CallerLineNumberAttribute] int line = -1) + { + if (line is 13) return DoSomething1_line_13.Auto(); + if (line is 19) return DoSomething2_line_19.Auto(); + if (line is 22) return DoSomething2_line_22.Auto(); + + throw new Exception(); + } +} +``` + +### Result + +![Aspid.FastTools.ProfilerMarkers.png](Images/Aspid.FastTools.ProfilerMarkers.png) + +--- + +## Serializable Type System + +Allows serializing a `System.Type` reference in the Unity Inspector. The selected type is stored as an assembly-qualified name and resolved lazily on first access. + +### SerializableType + +Two variants are available: + +- **`SerializableType`** — stores any type (base type is `object`) +- **`SerializableType`** — stores a type constrained to `T` or its subclasses + +Both support implicit conversion to `System.Type`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private SerializableType _anyType; + [SerializeField] private SerializableType _behaviourType; + + private void Start() + { + Type type1 = _anyType; // implicit operator + Type type2 = _behaviourType.Type; // explicit property + + var instance = (MonoBehaviour)gameObject.AddComponent(type2); + } +} +``` +![Aspid.FastTools.SerializableType.png](Images/Aspid.FastTools.SerializableType.png) +### ComponentTypeSelector + +A serializable struct that renders a type-switching dropdown in the Inspector. Add it as a field to a base class — picking a subtype rewrites `m_Script` on the `SerializedObject`, effectively changing the component or ScriptableObject to the chosen subtype. + +The dropdown is automatically constrained to subtypes of the class that declares the field. No additional configuration is required. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public abstract class BaseEnemy : MonoBehaviour +{ + [SerializeField] private ComponentTypeSelector _typeSelector; +} + +public class FastEnemy : BaseEnemy { } +public class TankEnemy : BaseEnemy { } +``` + +--- + +### TypeSelectorAttribute + +An editor-only `PropertyAttribute` that restricts the type selection popup to specific base types. Applied to `string` fields that store assembly-qualified type names. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class TypeSelectorAttribute : PropertyAttribute +{ + public TypeSelectorAttribute() // base type: object + public TypeSelectorAttribute(Type type) + public TypeSelectorAttribute(params Type[] types) + public TypeSelectorAttribute(string assemblyQualifiedName) + public TypeSelectorAttribute(params string[] assemblyQualifiedNames) + + public TypeAllow Allow { get; set; } // default: TypeAllow.None +} + +[Flags] +public enum TypeAllow +{ + None = 0, + Abstract = 1, + Interface = 2, + All = Abstract | Interface +} +``` + +| Property | Description | +|----------|-------------| +| `Allow` | Which special type categories (abstract classes, interfaces) the picker includes in addition to plain concrete classes. Default: `TypeAllow.None` | + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [TypeSelector(typeof(IMyInterface))] + [SerializeField] private string _typeName; + + // Include abstract types and interfaces in the picker + [TypeSelector(typeof(object), Allow = TypeAllow.All)] + [SerializeField] private string _anyType; +} +``` + +### Type Selector Window + +The Inspector shows a button that opens a searchable popup window with: + +- Hierarchical namespace organization +- Text search with filtering +- Keyboard navigation (Arrow keys, Enter, Escape) +- Navigation history (back button) +- Assembly disambiguation for types with identical names + +![Aspid.FastTools.TypeSelectorWindow.png](Images/Aspid.FastTools.TypeSelectorWindow.png) +--- + +## Enum System + +Provides serializable enum-to-value mappings configurable from the Inspector. + +### EnumValues\ + +A serializable collection of `EnumValue` entries with a configurable default value. Implements `IEnumerable>`. + +```csharp +[Serializable] +public sealed class EnumValues : IEnumerable> +``` + +| Member | Description | +|--------|-------------| +| `TValue GetValue(Enum enumValue)` | Returns the mapped value, or `_defaultValue` if not found | +| `bool Equals(Enum, Enum)` | Equality check with proper `[Flags]` support | + +Supports `[Flags]` enums: `Equals` uses `HasFlag` and treats `0`-valued members correctly. + +```csharp +using UnityEngine; +using Aspid.FastTools.Enums; + +public enum Direction { Left, Right, Up, Down } + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private EnumValues _directionSprites; + + private void SetIcon(Direction dir) + { + var sprite = _directionSprites.GetValue(dir); + _image.sprite = sprite; + } +} +``` + +In the Inspector, select the enum type in the `EnumValues` header, then assign a value for each enum member. Right-click the property to open a context menu with **Populate Missing Enum Members** — it appends an entry for every enum member not yet in the list, seeded with the current Default Value. + +--- + +## ID System + +> **Beta:** the ID System is currently in beta. The public API, generated code layout and editor workflow may change in future releases. + +Maps an asset-assignable name to a stable integer ID. Use the resulting `int` in `switch` statements and `Dictionary` keys without paying for string lookups at runtime. + +A single `IdRegistry` ScriptableObject maps string names to stable integer IDs and provides full `int ↔ string` lookups at runtime. + +### Setup + +**1.** Declare a `partial struct` implementing `IId`. The source generator adds the required fields and property automatically: + +```csharp +using Aspid.FastTools.Ids; + +public partial struct EnemyId : IId { } +``` + +Generated code: + +```csharp +public partial struct EnemyId +{ + [SerializeField] private string __stringId; // editor-only field, stripped from player builds + [SerializeField] private int _id; + + public int Id => _id; +} +``` + +**2.** Create the registry asset and bind it to the struct type in its Inspector: +- `Assets → Create → Aspid → Id Registry` + +**3.** Use the struct as a serialized field. The Inspector shows a dropdown of registered names; the selector window also lets you create new entries on the fly: + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +[CreateAssetMenu] +public class EnemyDefinition : ScriptableObject +{ + [UniqueId] [SerializeField] private EnemyId _id; +} +``` + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +public class EnemySpawner : MonoBehaviour +{ + [SerializeField] private EnemyId _targetEnemy; + + private void Spawn() + { + int id = _targetEnemy.Id; // stable integer, safe for switch / Dictionary + } +} +``` + +### UniqueIdAttribute + +Marks a field as requiring a unique value across all assets of the declaring type. The Inspector shows a warning if two assets share the same ID. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class UniqueIdAttribute : PropertyAttribute { } +``` + +### IdRegistry + +`ScriptableObject` in `Aspid.FastTools.Ids` that stores `(int, string)` entries and keeps the lookup tables available at runtime. Each name is assigned a stable, auto-incrementing ID that never changes when other entries are added or removed. + +| Member | Description | +|--------|-------------| +| `bool TryGetId(string name, out int id)` | Returns `true` and the ID when found; otherwise `false` | +| `bool TryGetName(int id, out string name)` | Returns `true` and the name when found; otherwise `false` and `string.Empty` | +| `bool Contains(int id)` | Whether an ID is registered | +| `bool Contains(string name)` | Whether a name is registered | +| `int Count` | Number of entries | +| `IReadOnlyList Ids` · `IReadOnlyList IdNames` | Registered IDs / names, in registration order | +| `IEnumerator> GetEnumerator()` | Iterate `(id, name)` pairs | + +The registry derives from `ScriptableObject` directly and exposes a generic counterpart `IdRegistry` (with `T : struct, IId`) that adds typed `Contains(T)` and `TryGetName(T, out string)` overloads. Edits — adding, renaming, removing entries — happen through the registry inspector and `RegistryEditorCore`, not via a public runtime API. + +--- + +## SerializedProperty Extensions + +Chainable extensions on `SerializedProperty` for synchronizing the owning `SerializedObject`, writing typed values, and reflecting on the underlying field. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +property + .Update() + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +The package covers: + +- **Update / Apply** — `Update`, `UpdateIfRequiredOrScript`, `ApplyModifiedProperties`. +- **Typed setters** — `SetValue` (generic dispatch) and `SetXxx` for `int`/`uint`/`long`/`ulong`/`float`/`double`/`bool`/`string`/`Color`/`Gradient`/`Hash128`/`Rect`/`RectInt`/`Bounds`/`BoundsInt`/`Vector2..4` (and `Vector2/3Int`)/`Quaternion`/`AnimationCurve`/`EntityId` (Unity 6.2+). Each comes with a paired `SetXxxAndApply` variant. +- **Enum setters** — `SetEnumFlag` and `SetEnumIndex` (each + `AndApply`). +- **Arrays** — `SetArraySize`, `AddArraySize`, `RemoveArraySize` (each + `AndApply`). +- **References** — `SetManagedReference`, `SetObjectReference`, `SetExposedReference`, and `SetBoxed` (Unity 6+). +- **Reflection helpers** — `GetPropertyType`, `GetMemberInfo`, `GetClassInstance` for resolving the C# member and runtime instance behind a property. + +> Full method-by-method reference: [SerializedPropertyExtensions.md](SerializedPropertyExtensions.md) + +--- + +## IMGUI Layout Scopes + +```csharp +using Aspid.FastTools.Editors; +``` + +Three `ref struct` scopes — `VerticalScope`, `HorizontalScope`, `ScrollViewScope` — wrap `EditorGUILayout.Begin*` / `End*`. Each exposes a `Rect` property and calls the matching `End*` method on `Dispose`: + +```csharp +using (VerticalScope.Begin()) +{ + EditorGUILayout.LabelField("Item 1"); + EditorGUILayout.LabelField("Item 2"); +} + +using (HorizontalScope.Begin()) +{ + EditorGUILayout.LabelField("Left"); + EditorGUILayout.LabelField("Right"); +} + +var scrollPos = Vector2.zero; +using (ScrollViewScope.Begin(ref scrollPos)) +{ + EditorGUILayout.LabelField("Scrollable content"); +} +``` + +Capture the group rect with the `out`-overload when needed: + +```csharp +using (VerticalScope.Begin(out var rect, GUI.skin.box)) +{ + EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.1f)); + EditorGUILayout.LabelField("Boxed content"); +} +``` + +All `Begin` overloads match the corresponding `EditorGUILayout.Begin*` signatures (optional `GUIStyle`, `GUILayoutOption[]`, scroll view options, etc.). + +--- + +## VisualElement Extensions + +Fluent extension methods for building UIToolkit trees in code. All methods return `T` (the element itself) for chaining. + +```csharp +using Aspid.FastTools.UIElements; // runtime extensions +using Aspid.FastTools.UIElements.Editors; // editor-only extensions (e.g. AddOpenScriptCommand) +``` + +### Quick reference + +The package covers: + +- **Core element operations** — name, visibility, tooltip, user data, picking mode, data source, and `AddChild`/`InsertChild` helpers. +- **Focus** — `SetFocus`, `SetBlur`, `SetTabIndex`, `SetFocusable`. +- **USS** — `AddClass`/`RemoveClass`/`ToggleInClass`/`EnableInClass`, `AddStyleSheets[FromResource]`. +- **Styles** — every `IStyle` property: layout, size, spacing, font, text, color, border, background, transform (incl. Unity 6.3+ aspect/filter/material), transition, overflow, slice, cursor. +- **Specialized elements** — `TextElement`, `ITextEdition`, `ITextSelection`, `BaseField`, `BaseBoolField` (Toggle), `INotifyValueChanged` (with optional `Unity.Mathematics` types), `IMixedValueSupport`, `Button`, `Slider`/`BaseSlider`, `ProgressBar`, `HelpBox`, `Foldout`, `Image`, `IMGUIContainer`, plus the full `ListView`/`TreeView`/`MultiColumn*` surface. +- **Editor-only commands** — `AddOpenScriptCommand`, `BindTo`/`BindPropertyTo`, `EnumField`/`EnumFlagsField` `Initialize`, and `PropertyField` value-change subscriptions. +- **USS custom-style helpers** — `ICustomStyle.TryGetByEnum` for parsing string USS properties as enums. + +> Full method-by-method reference: [VisualElementExtensions.md](VisualElementExtensions.md) + +### Full example + +```csharp +using UnityEditor; +using UnityEngine; +using Aspid.FastTools.Editors; // GetScriptName +using Aspid.FastTools.UIElements; // runtime VisualElement extensions +using Aspid.FastTools.UIElements.Editors; // AddOpenScriptCommand +using UnityEngine.UIElements; + +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + const string iconPath = "Editor/MyIcon"; + + var scriptName = target.GetScriptName(); + var dark = new Color(0.15f, 0.15f, 0.15f); + var light = new Color(0.75f, 0.75f, 0.75f); + + return new VisualElement() + .SetName("Header") + .SetBackgroundColor(dark) + .SetFlexDirection(FlexDirection.Row) + .SetPadding(top: 5, bottom: 5, left: 10, right: 10) + .SetBorderRadius(topLeft: 10, topRight: 10, bottomLeft: 10, bottomRight: 10) + .AddChild(new Image() + .SetName("Icon") + .AddOpenScriptCommand(target) + .SetImageFromResource(iconPath) + .SetSize(width: 40, height: 40)) + .AddChild(new Label(scriptName) + .SetName("Title") + .SetFlexGrow(1) + .SetFontSize(16) + .SetMargin(left: 10) + .SetColor(light) + .SetAlignSelf(Align.Center) + .SetOverflow(Overflow.Hidden) + .SetWhiteSpace(WhiteSpace.NoWrap) + .SetTextOverflow(TextOverflow.Ellipsis) + .SetUnityFontStyleAndWeight(FontStyle.Bold)); + } +} +``` + +### Result + +![Aspid.FastTools.VisualElement.png](Images/Aspid.FastTools.VisualElement.png) + +--- + +## Editor Helper Extensions + +Utility methods for getting display names of Unity objects in custom editors. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +public static string GetScriptName(this Object obj) +``` + +Returns the display name of a Unity object: +- If the type has `[AddComponentMenu]`, returns `ObjectNames.GetInspectorTitle(obj)` +- Otherwise returns `ObjectNames.NicifyVariableName(typeName)` + +```csharp +public static string GetScriptNameWithIndex(this Component targetComponent) +``` + +Returns the display name with a count suffix when multiple components of the same type exist on the same GameObject. For example, if two `AudioSource` components are attached, the second returns `"Audio Source (2)"`. + +```csharp +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + // "My Behaviour" — or "Custom Name" if [AddComponentMenu("Custom Name")] is present + var name = target.GetScriptName(); + + // "My Behaviour (2)" when a second component of the same type exists + var nameWithIndex = ((Component)target).GetScriptNameWithIndex(); + + return new Label(name); + } +} +``` diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/README.md.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md new file mode 100644 index 0000000..53748bb --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md @@ -0,0 +1,525 @@ +# Aspid.FastTools + +**Aspid.FastTools** — набор инструментов, предназначенных для минимизации рутинного написания кода в Unity. + +## Исходный код + +[[Aspid.FastTools](https://github.com/VPDPersonal/Aspid.FastTools)] + + +--- + +## Интеграция + +Установите Aspid.FastTools одним из следующих способов: + +- **Скачать .unitypackage** — Перейдите на [страницу релизов GitHub](https://github.com/VPDPersonal/Aspid.FastTools/releases) и скачайте последнюю версию `Aspid.FastTools.X.X.X.unitypackage`. Импортируйте его в проект. +- **Через UPM** (Unity Package Manager) подключите следующие пакеты: + - `https://github.com/VPDPersonal/Aspid.Internal.Unity.git` + - `https://github.com/VPDPersonal/Aspid.FastTools.git?path=Aspid.FastTools/Assets/Plugins/Aspid/FastTools` + +--- + +## Пространства имён + +| Пространство имён | Описание | +|-------------------|----------| +| `Aspid.FastTools.Types` | `SerializableType`, `SerializableType`, `ComponentTypeSelector`, `TypeSelectorAttribute` | +| `Aspid.FastTools.Enums` | `EnumValues` | +| `Aspid.FastTools.Ids` | `IId`, `UniqueIdAttribute`, `IdRegistry` | +| `Aspid.FastTools.UIElements` | Runtime fluent-расширения `VisualElement` | +| `Aspid.FastTools.Editors` | Редакторские утилиты — расширения `SerializedProperty`, IMGUI-области, `GetScriptName` | +| `Aspid.FastTools.Types.Editors` · `.Enums.Editors` · `.Ids.Editors` · `.UIElements.Editors` | Редакторский код по фичам (property drawers, инспектор реестров, editor-only расширения `VisualElement`) | + +--- + +## ProfilerMarker + +Предоставляет регистрацию `ProfilerMarker` через source generation. Генератор создаёт статический маркер для каждого места вызова, идентифицируемый по вызывающему методу и номеру строки. + +```csharp +using UnityEngine; + +public class MyBehaviour : MonoBehaviour +{ + private void Update() + { + DoSomething1(); + DoSomething2(); + } + + private void DoSomething1() + { + using var _ = this.Marker(); + // Некоторый код + } + + private void DoSomething2() + { + using (this.Marker()) + { + // Некоторый код + using var _ = this.Marker().WithName("Calculate"); + // Некоторый код + } + } +} +``` + +### Сгенерированный код + +```csharp +using System; +using Unity.Profiling; +using System.Runtime.CompilerServices; + +internal static class __MyBehaviourProfilerMarkerExtensions +{ + private static readonly ProfilerMarker DoSomething1_line_13 = new("MyBehaviour.DoSomething1 (13)"); + private static readonly ProfilerMarker DoSomething2_line_19 = new("MyBehaviour.DoSomething2 (19)"); + private static readonly ProfilerMarker DoSomething2_line_22 = new("MyBehaviour.Calculate (22)"); + + public static ProfilerMarker.AutoScope Marker(this MyBehaviour _, [CallerLineNumberAttribute] int line = -1) + { + if (line is 13) return DoSomething1_line_13.Auto(); + if (line is 19) return DoSomething2_line_19.Auto(); + if (line is 22) return DoSomething2_line_22.Auto(); + + throw new Exception(); + } +} +``` + +### Результат + +![Aspid.FastTools.ProfilerMarkers.png](Images/Aspid.FastTools.ProfilerMarkers.png) + +--- + +## Система сериализуемых типов + +Позволяет сериализовать ссылку на `System.Type` в Unity Inspector. Выбранный тип хранится как assembly-qualified name и разрешается лениво при первом обращении. + +### SerializableType + +Доступны два варианта: + +- **`SerializableType`** — хранит любой тип (базовый тип — `object`) +- **`SerializableType`** — хранит тип, ограниченный `T` или его подклассами + +Оба поддерживают неявное преобразование в `System.Type`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private SerializableType _anyType; + [SerializeField] private SerializableType _behaviourType; + + private void Start() + { + Type type1 = _anyType; // неявный оператор + Type type2 = _behaviourType.Type; // явное свойство + + var instance = (MonoBehaviour)gameObject.AddComponent(type2); + } +} +``` +![Aspid.FastTools.SerializableType.png](Images/Aspid.FastTools.SerializableType.png) +### ComponentTypeSelector + +Сериализуемая структура, добавляющая в Inspector выпадающий список для смены типа объекта. Добавьте её как поле в базовый класс — при выборе подтипа редактор перезаписывает `m_Script` на `SerializedObject`, фактически превращая компонент или ScriptableObject в выбранный подтип. + +Список автоматически ограничивается подтипами класса, в котором объявлено поле. Дополнительная настройка не требуется. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public abstract class BaseEnemy : MonoBehaviour +{ + [SerializeField] private ComponentTypeSelector _typeSelector; +} + +public class FastEnemy : BaseEnemy { } +public class TankEnemy : BaseEnemy { } +``` + +--- + +### TypeSelectorAttribute + +Атрибут `PropertyAttribute`, доступный только в редакторе, ограничивающий всплывающее окно выбора типа конкретными базовыми типами. Применяется к полям `string`, хранящим assembly-qualified имена типов. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class TypeSelectorAttribute : PropertyAttribute +{ + public TypeSelectorAttribute() // базовый тип: object + public TypeSelectorAttribute(Type type) + public TypeSelectorAttribute(params Type[] types) + public TypeSelectorAttribute(string assemblyQualifiedName) + public TypeSelectorAttribute(params string[] assemblyQualifiedNames) + + public TypeAllow Allow { get; set; } // по умолчанию: TypeAllow.None +} + +[Flags] +public enum TypeAllow +{ + None = 0, + Abstract = 1, + Interface = 2, + All = Abstract | Interface +} +``` + +| Свойство | Описание | +|----------|----------| +| `Allow` | Какие специальные категории типов (абстрактные классы, интерфейсы) включаются в список выбора в дополнение к обычным конкретным классам. По умолчанию: `TypeAllow.None` | + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [TypeSelector(typeof(IMyInterface))] + [SerializeField] private string _typeName; + + // Включить абстрактные типы и интерфейсы в список выбора + [TypeSelector(typeof(object), Allow = TypeAllow.All)] + [SerializeField] private string _anyType; +} +``` + +### Окно выбора типа + +В Inspector отображается кнопка, открывающая всплывающее окно с поиском, которое включает: + +- Иерархическую организацию по пространствам имён +- Текстовый поиск с фильтрацией +- Навигацию с клавиатуры (стрелки, Enter, Escape) +- Историю навигации (кнопка «назад») +- Разрешение неоднозначности для типов с одинаковыми именами из разных сборок + +![Aspid.FastTools.TypeSelectorWindow.png](Images/Aspid.FastTools.TypeSelectorWindow.png) +--- + +## Система перечислений + +Предоставляет сериализуемые отображения enum → значение, настраиваемые через Inspector. + +### EnumValues\ + +Сериализуемая коллекция записей `EnumValue` с настраиваемым значением по умолчанию. Реализует `IEnumerable>`. + +```csharp +[Serializable] +public sealed class EnumValues : IEnumerable> +``` + +| Член | Описание | +|------|----------| +| `TValue GetValue(Enum enumValue)` | Возвращает сопоставленное значение или `_defaultValue`, если не найдено | +| `bool Equals(Enum, Enum)` | Проверка равенства с поддержкой `[Flags]` | + +Поддерживает `[Flags]`-перечисления: `Equals` использует `HasFlag` и корректно обрабатывает члены со значением `0`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Enums; + +public enum Direction { Left, Right, Up, Down } + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private EnumValues _directionSprites; + + private void SetIcon(Direction dir) + { + var sprite = _directionSprites.GetValue(dir); + _image.sprite = sprite; + } +} +``` + +В Inspector выберите тип перечисления в заголовке `EnumValues`, затем назначьте значение для каждого члена перечисления. Нажмите правой кнопкой мыши по свойству, чтобы открыть контекстное меню с пунктом **Populate Missing Enum Members** — он добавит записи для всех отсутствующих членов перечисления, используя текущее Default Value как начальное значение. + +--- + +## Система ID + +> **Бета:** Система ID находится в бета-версии. Публичный API, структура генерируемого кода и редакторский UX могут измениться в будущих релизах. + +Сопоставляет имя, назначаемое в активе, со стабильным целочисленным ID. Получившийся `int` подходит для `switch` и ключей `Dictionary` без затрат на строковые поиски в рантайме. + +Единственный ScriptableObject `IdRegistry` сопоставляет строковые имена стабильным целочисленным ID и предоставляет полные `int ↔ string` поиски в рантайме. + +### Использование + +**1.** Объявите `partial struct`, реализующий `IId`. Генератор исходников автоматически добавит необходимые поля и свойство: + +```csharp +using Aspid.FastTools.Ids; + +public partial struct EnemyId : IId { } +``` + +Сгенерированный код: + +```csharp +public partial struct EnemyId +{ + [SerializeField] private string __stringId; // editor-only поле, вырезается из player-сборок + [SerializeField] private int _id; + + public int Id => _id; +} +``` + +**2.** Создайте ассет реестра и привяжите его к вашему типу структуры в Inspector: +- `Assets → Create → Aspid → Id Registry` + +**3.** Используйте структуру как сериализуемое поле. В Inspector отображается выпадающий список зарегистрированных имён; окно селектора также позволяет создавать новые записи на лету: + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +[CreateAssetMenu] +public class EnemyDefinition : ScriptableObject +{ + [UniqueId] [SerializeField] private EnemyId _id; +} +``` + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +public class EnemySpawner : MonoBehaviour +{ + [SerializeField] private EnemyId _targetEnemy; + + private void Spawn() + { + int id = _targetEnemy.Id; // стабильный integer, безопасен для switch / Dictionary + } +} +``` + +### UniqueIdAttribute + +Помечает поле как требующее уникального значения среди всех ассетов объявляющего типа. Inspector показывает предупреждение, если два ассета используют одинаковый ID. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class UniqueIdAttribute : PropertyAttribute { } +``` + +### IdRegistry + +`ScriptableObject` из `Aspid.FastTools.Ids`, хранящий записи `(int, string)` и поддерживающий таблицы поиска доступными во рантайме. Каждому имени назначается стабильный, автоинкрементный ID, который не изменяется даже при добавлении или удалении других записей. + +| Член | Описание | +|------|----------| +| `bool TryGetId(string name, out int id)` | Возвращает `true` и найденный ID; иначе `false` | +| `bool TryGetName(int id, out string name)` | Возвращает `true` и найденное имя; иначе `false` и `string.Empty` | +| `bool Contains(int id)` | Зарегистрирован ли ID | +| `bool Contains(string name)` | Зарегистрировано ли имя | +| `int Count` | Количество записей | +| `IReadOnlyList Ids` · `IReadOnlyList IdNames` | Зарегистрированные ID / имена в порядке регистрации | +| `IEnumerator> GetEnumerator()` | Итерация по парам `(id, name)` | + +Реестр наследуется напрямую от `ScriptableObject` и предоставляет генерик-аналог `IdRegistry` (с `T : struct, IId`), добавляющий типизированные перегрузки `Contains(T)` и `TryGetName(T, out string)`. Редактирование — добавление, переименование, удаление записей — выполняется через инспектор реестра и `RegistryEditorCore`, а не через публичный runtime API. + +--- + +## Расширения SerializedProperty + +Цепочные расширения над `SerializedProperty` для синхронизации владеющего `SerializedObject`, записи типизированных значений и рефлексии над полем-источником. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +property + .Update() + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +Пакет покрывает: + +- **Update / Apply** — `Update`, `UpdateIfRequiredOrScript`, `ApplyModifiedProperties`. +- **Типизированные сеттеры** — `SetValue` (обобщённый диспетчер) и `SetXxx` для `int`/`uint`/`long`/`ulong`/`float`/`double`/`bool`/`string`/`Color`/`Gradient`/`Hash128`/`Rect`/`RectInt`/`Bounds`/`BoundsInt`/`Vector2..4` (и `Vector2/3Int`)/`Quaternion`/`AnimationCurve`/`EntityId` (Unity 6.2+). К каждому идёт парный вариант `SetXxxAndApply`. +- **Enum-сеттеры** — `SetEnumFlag` и `SetEnumIndex` (каждый + `AndApply`). +- **Массивы** — `SetArraySize`, `AddArraySize`, `RemoveArraySize` (каждый + `AndApply`). +- **Ссылки** — `SetManagedReference`, `SetObjectReference`, `SetExposedReference`, а также `SetBoxed` (Unity 6+). +- **Рефлексионные хелперы** — `GetPropertyType`, `GetMemberInfo`, `GetClassInstance` для разрешения C#-члена и runtime-экземпляра, стоящих за property. + +> Полный справочник по методам: [SerializedPropertyExtensions_RU.md](SerializedPropertyExtensions_RU.md) + +--- + +## IMGUI-области разметки + +```csharp +using Aspid.FastTools.Editors; +``` + +Три `ref struct`-области — `VerticalScope`, `HorizontalScope`, `ScrollViewScope` — оборачивают `EditorGUILayout.Begin*` / `End*`. Каждая предоставляет свойство `Rect` и вызывает соответствующий метод `End*` в `Dispose`: + +```csharp +using (VerticalScope.Begin()) +{ + EditorGUILayout.LabelField("Item 1"); + EditorGUILayout.LabelField("Item 2"); +} + +using (HorizontalScope.Begin()) +{ + EditorGUILayout.LabelField("Left"); + EditorGUILayout.LabelField("Right"); +} + +var scrollPos = Vector2.zero; +using (ScrollViewScope.Begin(ref scrollPos)) +{ + EditorGUILayout.LabelField("Scrollable content"); +} +``` + +Получить rect области через перегрузку с `out`-параметром: + +```csharp +using (VerticalScope.Begin(out var rect, GUI.skin.box)) +{ + EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.1f)); + EditorGUILayout.LabelField("Boxed content"); +} +``` + +Все перегрузки `Begin` соответствуют сигнатурам `EditorGUILayout.Begin*` (опциональные `GUIStyle`, `GUILayoutOption[]`, параметры scroll view и т.д.). + +--- + +## Расширения VisualElement + +Fluent-методы расширения для построения UIToolkit-деревьев в коде. Все методы возвращают `T` (сам элемент) для цепочки вызовов. + +```csharp +using Aspid.FastTools.UIElements; // runtime-расширения +using Aspid.FastTools.UIElements.Editors; // editor-only расширения (например, AddOpenScriptCommand) +``` + +### Краткий справочник + +Пакет покрывает: + +- **Основные операции с элементом** — имя, видимость, tooltip, user data, picking mode, data source, а также хелперы `AddChild`/`InsertChild`. +- **Фокус** — `SetFocus`, `SetBlur`, `SetTabIndex`, `SetFocusable`. +- **USS** — `AddClass`/`RemoveClass`/`ToggleInClass`/`EnableInClass`, `AddStyleSheets[FromResource]`. +- **Стили** — все свойства `IStyle`: разметка, размер, отступы, шрифт, текст, цвет, рамка, фон, трансформации (вкл. aspect/filter/material с Unity 6.3+), переходы, overflow, slice, cursor. +- **Специализированные элементы** — `TextElement`, `ITextEdition`, `ITextSelection`, `BaseField`, `BaseBoolField` (Toggle), `INotifyValueChanged` (с опциональными типами `Unity.Mathematics`), `IMixedValueSupport`, `Button`, `Slider`/`BaseSlider`, `ProgressBar`, `HelpBox`, `Foldout`, `Image`, `IMGUIContainer`, а также полная поверхность `ListView`/`TreeView`/`MultiColumn*`. +- **Editor-only команды** — `AddOpenScriptCommand`, `BindTo`/`BindPropertyTo`, `Initialize` для `EnumField`/`EnumFlagsField`, подписка на изменения у `PropertyField`. +- **USS custom-style helpers** — `ICustomStyle.TryGetByEnum` для парсинга строковых USS-свойств в enum. + +> Полный справочник по методам: [VisualElementExtensions_RU.md](VisualElementExtensions_RU.md) + +### Полный пример + +```csharp +using UnityEditor; +using UnityEngine; +using Aspid.FastTools.Editors; // GetScriptName +using Aspid.FastTools.UIElements; // runtime-расширения VisualElement +using Aspid.FastTools.UIElements.Editors; // AddOpenScriptCommand +using UnityEngine.UIElements; + +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + const string iconPath = "Editor/MyIcon"; + + var scriptName = target.GetScriptName(); + var dark = new Color(0.15f, 0.15f, 0.15f); + var light = new Color(0.75f, 0.75f, 0.75f); + + return new VisualElement() + .SetName("Header") + .SetBackgroundColor(dark) + .SetFlexDirection(FlexDirection.Row) + .SetPadding(top: 5, bottom: 5, left: 10, right: 10) + .SetBorderRadius(topLeft: 10, topRight: 10, bottomLeft: 10, bottomRight: 10) + .AddChild(new Image() + .SetName("Icon") + .AddOpenScriptCommand(target) + .SetImageFromResource(iconPath) + .SetSize(width: 40, height: 40)) + .AddChild(new Label(scriptName) + .SetName("Title") + .SetFlexGrow(1) + .SetFontSize(16) + .SetMargin(left: 10) + .SetColor(light) + .SetAlignSelf(Align.Center) + .SetOverflow(Overflow.Hidden) + .SetWhiteSpace(WhiteSpace.NoWrap) + .SetTextOverflow(TextOverflow.Ellipsis) + .SetUnityFontStyleAndWeight(FontStyle.Bold)); + } +} +``` + +### Результат + +![Aspid.FastTools.VisualElement.png](Images/Aspid.FastTools.VisualElement.png) + +--- + +## Вспомогательные расширения для редактора + +Утилитарные методы для получения отображаемых имён объектов Unity в пользовательских редакторах. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +public static string GetScriptName(this Object obj) +``` + +Возвращает отображаемое имя объекта Unity: +- Если тип имеет `[AddComponentMenu]`, возвращает `ObjectNames.GetInspectorTitle(obj)` +- В противном случае возвращает `ObjectNames.NicifyVariableName(typeName)` + +```csharp +public static string GetScriptNameWithIndex(this Component targetComponent) +``` + +Возвращает отображаемое имя с числовым суффиксом, если на одном GameObject присутствует несколько компонентов одного типа. Например, если прикреплены два компонента `AudioSource`, второй вернёт `"Audio Source (2)"`. + +```csharp +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + // "My Behaviour" — или "Custom Name", если присутствует [AddComponentMenu("Custom Name")] + var name = target.GetScriptName(); + + // "My Behaviour (2)" при наличии второго компонента того же типа + var nameWithIndex = ((Component)target).GetScriptNameWithIndex(); + + return new Label(name); + } +} +``` diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md.meta new file mode 100644 index 0000000..a1ba8c4 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9b6c3feaf2078463b98fab80105c4ed8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md new file mode 100644 index 0000000..c22b34c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md @@ -0,0 +1,124 @@ +# SerializedProperty Extensions — full reference + +Chainable extension methods on `SerializedProperty` for synchronizing the owning `SerializedObject`, setting values, and reflecting on the underlying field. + +```csharp +using Aspid.FastTools.Editors; +``` + +All extensions are generic over `T : SerializedProperty` and return the same property instance, so calls can be chained freely. + +## Update / Apply + +Thin wrappers around the matching `SerializedObject` methods on `property.serializedObject`. + +```csharp +property + .Update() + .SetInt(42) + .ApplyModifiedProperties(); +``` + +| Method | Description | +|--------|-------------| +| `Update()` | Calls `serializedObject.Update()` | +| `UpdateIfRequiredOrScript()` | Calls `serializedObject.UpdateIfRequiredOrScript()` | +| `ApplyModifiedProperties()` | Calls `serializedObject.ApplyModifiedProperties()` | + +## SetValue / SetXxx — typed setters + +For each supported type four variants exist: + +| Variant | Behavior | +|---------|----------| +| `SetValue(value)` | Generic dispatch — picks the right typed setter based on the value's runtime type, returns `property` | +| `SetValueAndApply(value)` | `SetValue(value)` followed by `ApplyModifiedProperties()` | +| `SetXxx(value)` | Typed setter (e.g. `SetInt`) that writes to the matching `SerializedProperty.xxxValue` field | +| `SetXxxAndApply(value)` | `SetXxx(value)` followed by `ApplyModifiedProperties()` | + +### Supported types + +| Method family | Unity type | Notes | +|---------------|------------|-------| +| `SetInt` | `int` | | +| `SetUint` | `uint` | | +| `SetLong` | `long` | | +| `SetUlong` | `ulong` | | +| `SetFloat` | `float` | | +| `SetDouble` | `double` | | +| `SetBool` | `bool` | | +| `SetString` | `string` | | +| `SetColor` | `Color` | | +| `SetGradient` | `Gradient` | | +| `SetHash128` | `Hash128` | | +| `SetRect` / `SetRectInt` | `Rect` / `RectInt` | | +| `SetBounds` / `SetBoundsInt` | `Bounds` / `BoundsInt` | | +| `SetVector2` / `SetVector2Int` | `Vector2` / `Vector2Int` | | +| `SetVector3` / `SetVector3Int` | `Vector3` / `Vector3Int` | | +| `SetVector4` | `Vector4` | | +| `SetQuaternion` | `Quaternion` | | +| `SetAnimationCurve` | `AnimationCurve` | | +| `SetEntityId` | `Unity.Entities.EntityId` | Unity 6.2+. The apply-variant is named `SetEntityIdApply` *(method name preserves the source typo: missing `And`)* | + +### Enum setters + +Enum values do not flow through `SetValue` — use the explicit pair below depending on whether the field is a `[Flags]` enum: + +| Method | Description | +|--------|-------------| +| `SetEnumFlag(int)` / `SetEnumFlagAndApply(int)` | Writes to `enumValueFlag` | +| `SetEnumIndex(int)` / `SetEnumIndexAndApply(int)` | Writes to `enumValueIndex` | + +### Example + +```csharp +SerializedProperty property = GetProperty(); + +// Equivalent forms +property.SetValue(10).ApplyModifiedProperties(); +property.SetValueAndApply(10); +property.SetInt(10).ApplyModifiedProperties(); +property.SetIntAndApply(10); + +// Chain multiple setters +property + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +## Array operations + +| Method | Description | +|--------|-------------| +| `SetArraySize(int)` / `SetArraySizeAndApply(int)` | Sets `property.arraySize` | +| `AddArraySize(int = 1)` / `AddArraySizeAndApply(int = 1)` | Increases `arraySize` by the given amount (default `1`) | +| `RemoveArraySize(int = 1)` / `RemoveArraySizeAndApply(int = 1)` | Decreases `arraySize` by the given amount (default `1`) | + +## Reference setters + +| Method | Description | Notes | +|--------|-------------|-------| +| `SetManagedReference(object)` / `SetManagedReferenceAndApply(object)` | Writes to `managedReferenceValue` (target must be a `[SerializeReference]` field) | | +| `SetObjectReference(Object)` / `SetObjectReferenceAndApply(Object)` | Writes to `objectReferenceValue` | | +| `SetExposedReference(Object)` / `SetExposedReferenceAndApply(Object)` | Writes to `exposedReferenceValue` | | +| `SetBoxed(object)` / `SetBoxedAndApply(object)` | Writes to `boxedValue` | Unity 6+ | + +## Reflection helpers + +For drawer / inspector code that needs to inspect the runtime type or instance behind a property: + +| Method | Returns | Description | +|--------|---------|-------------| +| `GetPropertyType()` | `Type` or `null` | Returns the `FieldType` / `PropertyType` of the C# member that backs the property. `null` if the member can't be resolved. | +| `GetMemberInfo()` | `MemberInfo` or `null` | Locates the field/property on the owning class whose name matches `SerializedProperty.name`. Walks base classes via `TypeExtensions.GetMembersInfosIncludingBaseClasses`. | +| `GetClassInstance()` | `object` | Walks `propertyPath` from the root `targetObject` and returns the runtime instance that directly contains this property. Supports nested objects, arrays, and `List` fields. | + +```csharp +public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) +{ + var declaringType = property.GetPropertyType(); + var owner = property.GetClassInstance(); + // … +} +``` diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md.meta new file mode 100644 index 0000000..78b1558 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d89b4f8675a09411280afbba6c1aaf33 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md new file mode 100644 index 0000000..f97bf98 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md @@ -0,0 +1,124 @@ +# Расширения SerializedProperty — полный справочник + +Цепочные методы расширения над `SerializedProperty` для синхронизации владеющего `SerializedObject`, установки значений и рефлексии над полем-источником. + +```csharp +using Aspid.FastTools.Editors; +``` + +Все расширения обобщены по `T : SerializedProperty` и возвращают тот же экземпляр, поэтому вызовы можно свободно объединять в цепочки. + +## Update / Apply + +Тонкие обёртки над одноимёнными методами `SerializedObject` у `property.serializedObject`. + +```csharp +property + .Update() + .SetInt(42) + .ApplyModifiedProperties(); +``` + +| Метод | Описание | +|-------|----------| +| `Update()` | Вызывает `serializedObject.Update()` | +| `UpdateIfRequiredOrScript()` | Вызывает `serializedObject.UpdateIfRequiredOrScript()` | +| `ApplyModifiedProperties()` | Вызывает `serializedObject.ApplyModifiedProperties()` | + +## SetValue / SetXxx — типизированные сеттеры + +Для каждого поддерживаемого типа существуют четыре варианта: + +| Вариант | Поведение | +|---------|-----------| +| `SetValue(value)` | Обобщённый диспетчер — выбирает нужный типизированный сеттер по runtime-типу значения, возвращает `property` | +| `SetValueAndApply(value)` | `SetValue(value)` плюс `ApplyModifiedProperties()` | +| `SetXxx(value)` | Типизированный сеттер (например, `SetInt`), пишущий в соответствующее поле `SerializedProperty.xxxValue` | +| `SetXxxAndApply(value)` | `SetXxx(value)` плюс `ApplyModifiedProperties()` | + +### Поддерживаемые типы + +| Семейство методов | Unity-тип | Примечания | +|-------------------|-----------|------------| +| `SetInt` | `int` | | +| `SetUint` | `uint` | | +| `SetLong` | `long` | | +| `SetUlong` | `ulong` | | +| `SetFloat` | `float` | | +| `SetDouble` | `double` | | +| `SetBool` | `bool` | | +| `SetString` | `string` | | +| `SetColor` | `Color` | | +| `SetGradient` | `Gradient` | | +| `SetHash128` | `Hash128` | | +| `SetRect` / `SetRectInt` | `Rect` / `RectInt` | | +| `SetBounds` / `SetBoundsInt` | `Bounds` / `BoundsInt` | | +| `SetVector2` / `SetVector2Int` | `Vector2` / `Vector2Int` | | +| `SetVector3` / `SetVector3Int` | `Vector3` / `Vector3Int` | | +| `SetVector4` | `Vector4` | | +| `SetQuaternion` | `Quaternion` | | +| `SetAnimationCurve` | `AnimationCurve` | | +| `SetEntityId` | `Unity.Entities.EntityId` | Unity 6.2+. Apply-вариант называется `SetEntityIdApply` *(имя метода сохраняет опечатку из исходника: пропущено `And`)* | + +### Enum-сеттеры + +Значения enum не идут через `SetValue` — используйте явную пару ниже в зависимости от того, является ли поле `[Flags]`-перечислением: + +| Метод | Описание | +|-------|----------| +| `SetEnumFlag(int)` / `SetEnumFlagAndApply(int)` | Пишет в `enumValueFlag` | +| `SetEnumIndex(int)` / `SetEnumIndexAndApply(int)` | Пишет в `enumValueIndex` | + +### Пример + +```csharp +SerializedProperty property = GetProperty(); + +// Эквивалентные формы +property.SetValue(10).ApplyModifiedProperties(); +property.SetValueAndApply(10); +property.SetInt(10).ApplyModifiedProperties(); +property.SetIntAndApply(10); + +// Цепочка из нескольких сеттеров +property + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +## Операции с массивами + +| Метод | Описание | +|-------|----------| +| `SetArraySize(int)` / `SetArraySizeAndApply(int)` | Устанавливает `property.arraySize` | +| `AddArraySize(int = 1)` / `AddArraySizeAndApply(int = 1)` | Увеличивает `arraySize` на указанное количество (по умолчанию `1`) | +| `RemoveArraySize(int = 1)` / `RemoveArraySizeAndApply(int = 1)` | Уменьшает `arraySize` на указанное количество (по умолчанию `1`) | + +## Сеттеры ссылок + +| Метод | Описание | Примечания | +|-------|----------|------------| +| `SetManagedReference(object)` / `SetManagedReferenceAndApply(object)` | Пишет в `managedReferenceValue` (поле должно быть помечено `[SerializeReference]`) | | +| `SetObjectReference(Object)` / `SetObjectReferenceAndApply(Object)` | Пишет в `objectReferenceValue` | | +| `SetExposedReference(Object)` / `SetExposedReferenceAndApply(Object)` | Пишет в `exposedReferenceValue` | | +| `SetBoxed(object)` / `SetBoxedAndApply(object)` | Пишет в `boxedValue` | Unity 6+ | + +## Рефлексионные хелперы + +Для drawer-/inspector-кода, которому нужно получить runtime-тип или экземпляр, стоящий за property: + +| Метод | Возвращает | Описание | +|-------|------------|----------| +| `GetPropertyType()` | `Type` или `null` | Возвращает `FieldType` / `PropertyType` C#-члена, стоящего за property. `null`, если член не удаётся разрешить. | +| `GetMemberInfo()` | `MemberInfo` или `null` | Находит field/property на классе-владельце, имя которого совпадает с `SerializedProperty.name`. Обходит базовые классы через `TypeExtensions.GetMembersInfosIncludingBaseClasses`. | +| `GetClassInstance()` | `object` | Идёт по `propertyPath` от корневого `targetObject` и возвращает runtime-экземпляр, который непосредственно содержит это property. Поддерживает вложенные объекты, массивы и `List`-поля. | + +```csharp +public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) +{ + var declaringType = property.GetPropertyType(); + var owner = property.GetClassInstance(); + // … +} +``` diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md.meta new file mode 100644 index 0000000..76e5ed2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bf2b6a386bf354961a0a7bb99ff06b10 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md new file mode 100644 index 0000000..c6a44b5 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md @@ -0,0 +1,600 @@ +# VisualElement Extensions — full reference + +Fluent extension methods for building UIToolkit trees in code. All methods return `T` (the element itself) for chaining. + +```csharp +using Aspid.FastTools.UIElements; // runtime extensions +using Aspid.FastTools.UIElements.Editors; // editor-only extensions (e.g. AddOpenScriptCommand) +``` + +## Core element operations + +```csharp +element + .SetName("MyElement") + .SetVisible(true) + .SetTooltip("Tooltip text") + .AddChild(new Label("Hello")) + .AddChildren(child1, child2, child3); +``` + +| Method | Description | +|--------|-------------| +| `SetName(string)` | Sets `element.name` | +| `SetVisible(bool)` | Sets `element.visible` | +| `SetTooltip(string)` | Sets `element.tooltip` | +| `SetUserData(object)` | Sets `element.userData` | +| `SetEnabledSelf(bool)` | Sets `element.enabledSelf` | +| `SetPickingMode(PickingMode)` | Sets `element.pickingMode` | +| `SetUsageHints(UsageHints)` | Sets `element.usageHints` | +| `SetViewDataKey(string)` | Sets `element.viewDataKey` | +| `SetLanguageDirection(LanguageDirection)` | Sets `element.languageDirection` | +| `SetDisablePlayModeTint(bool)` | Sets `element.disablePlayModeTint` | +| `SetDataSource(object)` | Sets `element.dataSource` | +| `SetDataSourceType(Type)` | Sets `element.dataSourceType` | +| `SetDataSourcePath(PropertyPath)` | Sets `element.dataSourcePath` | +| `AddChild(VisualElement)` | Appends a child, returns the parent | +| `AddChildren(params VisualElement[])` | Appends multiple children | +| `AddChildren(IEnumerable)` | Appends from a sequence | +| `AddChildren(List)` | Appends from a list | +| `AddChildren(Span)` | Appends from a span | +| `AddChildren(ReadOnlySpan)` | Appends from a read-only span | +| `InsertChild(int, VisualElement)` | Inserts a child at the specified index | +| `InsertChildren(int, params VisualElement[])` | Inserts multiple children starting at an index | +| `InsertChildren(int, IEnumerable)` | Inserts from a sequence | +| `InsertChildren(int, List)` | Inserts from a list | +| `InsertChildren(int, Span)` | Inserts from a span | +| `InsertChildren(int, ReadOnlySpan)` | Inserts from a read-only span | + +> `RegisterCallbackOnce` and `RegisterCallbackOnce` are available on all Unity versions (polyfill included for versions prior to 2023.1). + +## Focusable + +| Method | Description | +|--------|-------------| +| `SetFocus()` | Attempts to give focus to the element | +| `SetBlur()` | Tells the element to release focus | +| `IsFocus()` | Returns whether the element currently has keyboard focus | +| `SetTabIndex(int)` | Sets `element.tabIndex` | +| `SetFocusable(bool)` | Sets `element.focusable` | +| `SetDelegatesFocus(bool)` | Sets `element.delegatesFocus` | + +## USS & class operations + +| Method | Description | +|--------|-------------| +| `AddClass(string)` | Adds a USS class | +| `RemoveClass(string)` | Removes a USS class | +| `ClearClasses()` | Removes all USS classes | +| `ToggleInClass(string)` | Toggles a USS class on/off | +| `EnableInClass(string, bool)` | Adds or removes a USS class based on a condition | +| `AddStyleSheets(StyleSheet)` | Adds a `StyleSheet` | +| `RemoveStyleSheets(StyleSheet)` | Removes a `StyleSheet` | +| `AddStyleSheetsFromResource(string)` | Adds a stylesheet loaded via `Resources.Load` | +| `RemoveStyleSheetsFromResource(string)` | Removes a stylesheet loaded via `Resources.Load` | + +## Style extensions — by category + +All style methods are also available on `IStyle` directly (same method names, operate on the style object). + +### Layout + +| Method | Style property | +|--------|---------------| +| `SetFlexBasis(StyleLength)` | `flexBasis` | +| `SetFlexGrow(StyleFloat)` | `flexGrow` | +| `SetFlexShrink(StyleFloat)` | `flexShrink` | +| `SetFlexWrap(StyleEnum)` | `flexWrap` | +| `SetFlexDirection(FlexDirection)` | `flexDirection` | +| `SetAlignSelf(StyleEnum)` | `alignSelf` | +| `SetAlignItems(StyleEnum)` | `alignItems` | +| `SetAlignContent(StyleEnum)` | `alignContent` | +| `SetJustifyContent(StyleEnum)` | `justifyContent` | +| `SetPosition(StyleEnum)` | `position` | + +### Size + +| Method | Description | +|--------|-------------| +| `SetSize(StyleLength)` | Sets both width and height | +| `SetSize(width?, height?)` | Sets width and/or height independently | +| `SetMinSize(StyleLength)` | Sets both minWidth and minHeight | +| `SetMinSize(width?, height?)` | | +| `SetMaxSize(StyleLength)` | Sets both maxWidth and maxHeight | +| `SetMaxSize(width?, height?)` | | +| `SetWidth(StyleLength)` | `width` | +| `SetMinWidth(StyleLength)` | `minWidth` | +| `SetMaxWidth(StyleLength)` | `maxWidth` | +| `SetHeight(StyleLength)` | `height` | +| `SetMinHeight(StyleLength)` | `minHeight` | +| `SetMaxHeight(StyleLength)` | `maxHeight` | + +### Spacing + +All spacing methods have a uniform-value overload, a per-side overload (`top`, `right`, `bottom`, `left`), single-side setters, and X/Y-axis pair setters. + +| Method | Style properties | +|--------|------------------| +| `SetMargin(…)` / `SetPadding(…)` / `SetDistance(…)` | `Top/Right/Bottom/Left` (uniform or per-side) | +| `SetMarginX/Y` · `SetPaddingX/Y` · `SetDistanceX/Y` | Sets the horizontal (X = `Left`+`Right`) or vertical (Y = `Top`+`Bottom`) pair | +| `SetMarginTop/Right/Bottom/Left` | Single-side margin | +| `SetPaddingTop/Right/Bottom/Left` | Single-side padding | +| `SetDistanceTop/Right/Bottom/Left` *(via `SetTop` / `SetRight` / `SetBottom` / `SetLeft`)* | Single-side absolute offset (`top` / `right` / `bottom` / `left` style properties) | + +> `SetDistance` is the wrapper for the four `top`/`right`/`bottom`/`left` style properties used by absolute positioning. `SetTop`, `SetRight`, `SetBottom`, `SetLeft` are direct single-property aliases. + +### Font + +| Method | Style property | +|--------|---------------| +| `SetUnityFont(StyleFont)` | `unityFont` | +| `SetFontSize(StyleLength)` | `fontSize` | +| `SetUnityFontDefinition(StyleFontDefinition)` | `unityFontDefinition` | +| `SetUnityFontStyleAndWeight(StyleEnum)` | `unityFontStyleAndWeight` | + +### Font style presets + +Convenience methods for toggling bold / italic without overwriting the other flag: + +| Method | Description | +|--------|-------------| +| `SetNormalUnityFontStyleAndWeight()` | Resets to `FontStyle.Normal` | +| `AddBoldUnityFontStyleAndWeight()` | Adds bold, preserving italic | +| `RemoveBoldUnityFontStyleAndWeight()` | Removes bold, preserving italic | +| `AddItalicUnityFontStyleAndWeight()` | Adds italic, preserving bold | +| `RemoveItalicUnityFontStyleAndWeight()` | Removes italic, preserving bold | + +### Text + +| Method | Style property | Notes | +|--------|---------------|-------| +| `SetWorldSpacing(StyleLength)` | `wordSpacing` | | +| `SetLetterSpacing(StyleLength)` | `letterSpacing` | | +| `SetUnityTextAlign(TextAnchor)` | `unityTextAlign` | | +| `SetTextShadow(StyleTextShadow)` | `textShadow` | | +| `SetUnityTextOutlineColor(StyleColor)` | `unityTextOutlineColor` | | +| `SetUnityTextOutlineWidth(StyleFloat)` | `unityTextOutlineWidth` | | +| `SetUnityParagraphSpacing(StyleLength)` | `unityParagraphSpacing` | | +| `SetTextOverflow(StyleEnum)` | `textOverflow` | | +| `SetUnityTextOverflowPosition(TextOverflowPosition)` | `unityTextOverflowPosition` | | +| `SetUnityTextGenerator(TextGeneratorType)` | `unityTextGenerator` | Unity 6+ | +| `SetUnityEditorTextRenderingMode(EditorTextRenderingMode)` | `unityEditorTextRenderingMode` | Unity 6+ | +| `SetUnityTextAutoSize(StyleTextAutoSize)` | `unityTextAutoSize` | Unity 6.2+ | +| `SetWhiteSpace(StyleEnum)` | `whiteSpace` | | + +### Color & Opacity + +| Method | Style property | +|--------|---------------| +| `SetColor(StyleColor)` | `color` | +| `SetColor(string)` | `color` parsed from an HTML string (`"#RRGGBB"` or a named color) | +| `SetOpacity(StyleFloat)` | `opacity` | + +### Border + +| Method | Description | +|--------|-------------| +| `SetBorderColor(StyleColor)` | All sides | +| `SetBorderColor(top?, right?, bottom?, left?)` | Per side | +| `SetBorderColorX(StyleColor)` · `SetBorderColorY(StyleColor)` | Horizontal (left + right) or vertical (top + bottom) pair | +| `SetBorderColorTop/Right/Bottom/Left(StyleColor)` | Single side | +| `SetBorderRadius(StyleLength)` | All corners | +| `SetBorderRadius(topLeft?, topRight?, bottomLeft?, bottomRight?)` | Per corner | +| `SetBorderRadiusTop(StyleLength)` · `SetBorderRadiusBottom(StyleLength)` | Top or bottom corner pair | +| `SetBorderRadiusTopLeft/TopRight/BottomLeft/BottomRight(StyleLength)` | Single corner | +| `SetBorderWidth(StyleFloat)` | All sides | +| `SetBorderWidth(top?, right?, bottom?, left?)` | Per side | +| `SetBorderWidthX(StyleFloat)` · `SetBorderWidthY(StyleFloat)` | Horizontal or vertical pair | +| `SetBorderWidthTop/Right/Bottom/Left(StyleFloat)` | Single side | + +### Background + +| Method | Style property | +|--------|---------------| +| `SetBackgroundColor(StyleColor)` | `backgroundColor` | +| `SetBackgroundColor(string)` | `backgroundColor` parsed from an HTML string (`"#RRGGBB"` or a named color) | +| `SetBackgroundImage(StyleBackground)` | `backgroundImage` | +| `SetBackgroundImageFromResource(string)` | Loads a `Texture2D` via `Resources.Load` and assigns it to `backgroundImage` | +| `SetBackgroundSize(StyleBackgroundSize)` | `backgroundSize` | +| `SetBackgroundRepeat(StyleBackgroundRepeat)` | `backgroundRepeat` | +| `SetBackgroundPosition(StyleBackgroundPosition)` | Both X and Y | +| `SetBackgroundPosition(x?, y?)` | Independently | +| `SetBackgroundPositionX(StyleBackgroundPosition)` | `backgroundPositionX` | +| `SetBackgroundPositionY(StyleBackgroundPosition)` | `backgroundPositionY` | +| `SetUnityBackgroundImageTintColor(StyleColor)` | `unityBackgroundImageTintColor` | + +### Transform + +| Method | Style property | +|--------|---------------| +| `SetScale(StyleScale)` | `scale` | +| `SetRotate(StyleRotate)` | `rotate` | +| `SetTranslate(StyleTranslate)` | `translate` | +| `SetTransformOrigin(StyleTransformOrigin)` | `transformOrigin` | + +### Aspect, Filter & Material + +Available on Unity 6000.3+. + +| Method | Style property | +|--------|---------------| +| `SetAspectRation(StyleRatio)` | `aspectRatio` *(method name preserves the source typo)* | +| `SetFilter(StyleList)` | `filter` | +| `SetUnityMaterial(StyleMaterialDefinition)` | `unityMaterial` | + +### Transition + +| Method | Style property | +|--------|---------------| +| `SetTransitionDelay(StyleList)` | `transitionDelay` | +| `SetTransitionDuration(StyleList)` | `transitionDuration` | +| `SetTransitionProperty(StyleList)` | `transitionProperty` | +| `SetTransitionTimingFunction(StyleList)` | `transitionTimingFunction` | + +### Overflow & Visibility + +| Method | Style property | +|--------|---------------| +| `SetOverflow(StyleEnum)` | `overflow` | +| `SetUnityOverflowClipBox(StyleEnum)` | `unityOverflowClipBox` | +| `SetVisibility(StyleEnum)` | `visibility` | +| `SetDisplay(DisplayStyle)` | `display` | + +### Unity Slice + +| Method | Description | +|--------|-------------| +| `SetUnitySlice(StyleInt)` | All sides | +| `SetUnitySlice(top?, right?, bottom?, left?)` | Per side | +| `SetUnitySliceX(StyleInt)` · `SetUnitySliceY(StyleInt)` | Horizontal (left + right) or vertical (top + bottom) pair | +| `SetUnitySliceTop/Right/Bottom/Left(StyleInt)` | Single side | +| `SetUnitySliceScale(StyleFloat)` | `unitySliceScale` | +| `SetUnitySliceType(StyleEnum)` | Unity 6+ | + +### Cursor + +| Method | Style property | +|--------|---------------| +| `SetCursor(StyleCursor)` | `cursor` | + +## Specialized element extensions + +### TextElement + +```csharp +label + .SetText("Hello World") + .SetEnableRichText(true) + .SetParseEscapeSequences(true); +``` + +| Method | Description | +|--------|-------------| +| `SetText(string)` | Sets the displayed text | +| `SetEnableRichText(bool)` | Enables rich-text tag parsing | +| `SetEmojiFallbackSupport(bool)` | Enables emoji fallback rendering | +| `SetParseEscapeSequences(bool)` | Whether escape sequences (e.g. `\n`) are parsed | +| `SetDisplayTooltipWhenElided(bool)` | Shows the elided text in a tooltip on hover | + +### ITextEdition (TextField, IntegerField, …) + +```csharp +textField + .SetPlaceholder("Search…") + .SetMaxLength(64) + .SetIsDelayed(true); +``` + +| Method | Description | +|--------|-------------| +| `SetMaxLength(int)` | Maximum number of characters | +| `SetMaskChar(char)` | Character used to mask password input | +| `SetIsDelayed(bool)` | Defers value change until focus loss / Enter | +| `SetIsReadOnly(bool)` | Disables editing | +| `SetIsPassword(bool)` | Toggles password mode (uses mask char) | +| `SetPlaceholder(string)` | Placeholder text shown when empty | +| `SetAutoCorrection(bool)` | Enables auto-correction (mobile) | +| `SetHideMobileInput(bool)` | Hides the mobile soft input | +| `SetHideSoftKeyboard(bool)` | Hides the on-screen soft keyboard | +| `SetHidePlaceholderOnFocus(bool)` | Removes the placeholder on focus | +| `SetKeyboardType(TouchScreenKeyboardType)` | Sets the touch-screen keyboard type | + +### ITextSelection + +```csharp +textField + .SetIsSelectable(true) + .SetSelectAllOnFocus(true) + .AddOnCursorIndexChange(() => Debug.Log(textField.cursorIndex)); +``` + +| Method | Description | +|--------|-------------| +| `AddOnCursorIndexChange(Action)` / `RemoveOnCursorIndexChange(Action)` | Cursor-index change subscription | +| `AddOnSelectIndexChange(Action)` / `RemoveOnSelectIndexChange(Action)` | Selection-index change subscription | +| `SetCursorIndex(int)` | Sets the current cursor index | +| `SetSelectIndex(int)` | Sets the current selection anchor | +| `SetIsSelectable(bool)` | Whether text can be selected | +| `SetSelectAllOnFocus(bool)` | Selects all text on focus | +| `SetSelectAllOnMouseUp(bool)` | Selects all text on mouse release | +| `SetDoubleClickSelectsWord(bool)` | Double-click selects the word under cursor | +| `SetTripleClickSelectsLine(bool)` | Triple-click selects the line under cursor | + +### BaseField\ + +```csharp +field.SetLabel("My Field"); +field.SetValue(42); +``` + +### BaseBoolField (Toggle) + +```csharp +toggle + .SetLabel("Enabled") + .SetText("Show advanced settings") + .SetToggleOnLabelClick(true); +``` + +| Method | Description | +|--------|-------------| +| `SetText(string)` | Sets the label next to the toggle box | +| `SetLabel(string)` | Sets the field-level label | +| `SetToggleOnLabelClick(bool)` | Whether clicking the label toggles the value | + +### INotifyValueChanged\ + +```csharp +field.SetValue(42, notify: false); // sets value without raising ChangeEvent +field.AddValueChanged(evt => Debug.Log(evt.newValue)); +field.RemoveValueChanged(myCallback); +``` + +Typed overloads are provided for `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `short`, `ushort`, `byte`, `sbyte`, `float`, `double`, `decimal`, `char`, `string`, `bool`, `Color`, `Vector2/3/4`, `Vector2Int/3Int`, `Rect/RectInt`, `Bounds/BoundsInt`, `Hash128`, `GUID`, `Quaternion`, `Matrix4x4`, `Gradient`, `AnimationCurve`, `Delegate`, `Enum`, `Object`, `object`, plus a generic `SetValue` fallback. + +> When the `com.unity.mathematics` package is installed, the `ASPID_FASTTOOLS_UNITY_MATHEMATICS_INTEGRATION` define is set automatically and adds `SetValue` / `AddValueChanged` / `RemoveValueChanged` overloads for `int2/3/4` (and `intMxN`), `float2/3/4` (and `floatMxN`), `bool2/3/4` (and `boolMxN`), and `quaternion`. + +### IMixedValueSupport + +```csharp +field.SetShowMixedValue(true); // shows the mixed-value indicator +``` + +### Button + +```csharp +button + .AddClicked(() => Debug.Log("Clicked")) + .SetClickable(new Clickable(() => { })) + .SetIconImage(myBackground); +``` + +| Method | Description | +|--------|-------------| +| `AddClicked(Action)` | Subscribes to `Button.clicked` | +| `RemoveClicked(Action)` | Unsubscribes from `Button.clicked` | +| `SetClickable(Clickable)` | Sets `Button.clickable` | +| `SetIconImage(Background)` | Sets `Button.iconImage` | + +### Slider / BaseSlider\ + +```csharp +slider + .SetLowValue(0f) + .SetHighValue(100f) + .SetShowInputField(true); +``` + +| Method | Description | +|--------|-------------| +| `SetLowValue(TValue)` | Sets the minimum slider value | +| `SetHighValue(TValue)` | Sets the maximum slider value | +| `SetFill(bool)` | Whether the track is filled up to the current value | +| `SetInverted(bool)` | Reverses the slider direction | +| `SetPageSize(float)` | Controls how much the value changes per page step | +| `SetShowInputField(bool)` | Shows a numeric input field alongside the slider | +| `SetDirection(SliderDirection)` | Sets the slider orientation | + +### ProgressBar + +```csharp +progressBar.SetTitle("Loading...").SetLowValue(0f).SetHighValue(100f); +``` + +| Method | Description | +|--------|-------------| +| `SetTitle(string)` | Sets the title displayed in the center | +| `SetLowValue(float)` | Sets the minimum value | +| `SetHighValue(float)` | Sets the maximum value | + +### HelpBox + +```csharp +helpBox + .SetText("Something went wrong") + .SetMessageType(HelpBoxMessageType.Warning); +``` + +| Method | Description | +|--------|-------------| +| `SetText(string)` | Sets the help-box message text | +| `SetMessageType(HelpBoxMessageType)` | Sets the icon / severity (`None` / `Info` / `Warning` / `Error`) | + +### Foldout + +```csharp +foldout + .SetText("Section Title") + .SetToggleOnLabelClick(true) + .SetValue(true); +``` + +| Method | Description | +|--------|-------------| +| `SetText(string)` | Sets the foldout title | +| `SetToggleOnLabelClick(bool)` | Whether clicking the title toggles expansion | + +### Image + +```csharp +image + .SetImage(myTexture) + .SetTintColor(Color.white) + .SetScaleMode(ScaleMode.ScaleToFit); +``` + +| Method | Description | +|--------|-------------| +| `SetImage(Texture)` | Sets `Image.image` | +| `SetImageFromResource(string)` | Loads a texture via `Resources.Load` | +| `SetSprite(Sprite)` | Sets `Image.sprite` | +| `SetSpriteFromResource(string)` | Loads a sprite via `Resources.Load` | +| `SetVectorImage(VectorImage)` | Sets `Image.vectorImage` | +| `SetVectorImageFromResource(string)` | Loads a vector image via `Resources.Load` | +| `SetUv(Rect)` | Sets the UV rect | +| `SetSourceRect(Rect)` | Sets the source rect | +| `SetTintColor(Color)` | Sets the image tint | +| `SetScaleMode(ScaleMode)` | Sets the scale mode | + +### IMGUIContainer + +```csharp +container + .SetOnGUIHandler(() => GUILayout.Label("IMGUI")) + .SetCullingEnabled(true); +``` + +| Method | Description | +|--------|-------------| +| `SetOnGUIHandler(Action)` | Replaces the `onGUIHandler` callback | +| `AddOnGUIHandler(Action)` | Subscribes to `onGUIHandler` | +| `RemoveOnGUIHandler(Action)` | Unsubscribes from `onGUIHandler` | +| `SetCullingEnabled(bool)` | Skips `onGUIHandler` when the element is offscreen | +| `SetContextType(ContextType)` | Sets the IMGUI context type | + +### Collection views (ListView, TreeView, MultiColumn variants) + +Common methods are spread across multiple targeted extensions: + +- `BaseVerticalCollectionViewExtensions` — applies to **all** collection views (ListView, TreeView, MultiColumn variants). +- `BaseListViewExtensions` — applies to ListView and MultiColumnListView. +- `BaseTreeViewExtensions` — applies to TreeView and MultiColumnTreeView. +- `ListViewExtensions` / `TreeViewExtensions` — `MakeItem`/`BindItem`/`UnbindItem`/`DestroyItem` factories per view. +- `MultiColumnListViewExtensions` / `MultiColumnTreeViewExtensions` — multi-column-specific helpers. + +```csharp +listView + .SetItemsSource(items) + .SetMakeItem(() => new Label()) + .SetBindItem((el, i) => ((Label)el).SetText(items[i])) + .SetSelectionType(SelectionType.Single) + .AddSelectionChanged(selected => Debug.Log(selected)); +``` + +#### Source, layout and behavior — `BaseVerticalCollectionView` + +| Method | Description | Notes | +|--------|-------------|-------| +| `SetItemsSource(IList)` | Underlying data source | | +| `SetReorderable(bool)` | Enables drag-to-reorder | | +| `SetSelectedIndex(int)` | Selects a specific index | | +| `SetSelectionType(SelectionType)` | None / Single / Multiple | | +| `SetFixedItemHeight(float)` | Fixed item height (for `FixedHeight` virtualization) | | +| `SetVirtualizationMethod(CollectionVirtualizationMethod)` | `FixedHeight` or `DynamicHeight` | | +| `SetHorizontalScrollingEnabled(bool)` | Enables horizontal scrolling | | +| `SetShowAlternatingRowBackgrounds(AlternatingRowBackground)` | Zebra striping mode | | +| `SetMakeFooter(Func)` · `AddMakeFooter` · `RemoveMakeFooter` | Footer factory | Unity 6+ | +| `SetMakeHeader(Func)` · `AddMakeHeader` · `RemoveMakeHeader` | Header factory | Unity 6+ | +| `SetMakeNoneElement(Func)` · `AddMakeNoneElement` · `RemoveMakeNoneElement` | Empty-state factory | Unity 6+ | + +#### Events — `BaseVerticalCollectionView` + +| Method | Description | +|--------|-------------| +| `AddItemsChosen(Action>)` / `RemoveItemsChosen` | Items confirmed (e.g. double-click / Enter) | +| `AddSelectionChanged(Action>)` / `RemoveSelectionChanged` | Selection changed (objects) | +| `AddSelectedIndicesChanged(Action>)` / `RemoveSelectedIndicesChanged` | Selection changed (indices) | +| `AddItemIndexChanged(Action)` / `RemoveItemIndexChanged` | Item moved (drag-reorder) | +| `AddItemsSourceChanged(Action)` / `RemoveItemsSourceChanged` | `itemsSource` reference changed | +| `AddCanStartDrag(Func)` / `RemoveCanStartDrag` | Custom drag-start gating | +| `AddSetupDragAndDrop(Func)` / `RemoveSetupDragAndDrop` | Drag-and-drop preparation | +| `AddSetupDragAndDrop(Func)` / `RemoveSetupDragAndDrop` | Drag-and-drop visual mode | +| `AddHandleDrop(Func)` / `RemoveHandleDrop` | Drop handling | + +#### `BaseListView`-specific + +| Method | Description | +|--------|-------------| +| `SetAllowAdd(bool)` · `SetAllowRemove(bool)` | Toggles built-in add/remove buttons | +| `SetHeaderTitle(string)` | Title shown when foldout header is on | +| `SetShowFoldoutHeader(bool)` | Wraps the list in a `Foldout` | +| `SetShowAddRemoveFooter(bool)` | Toggles the add/remove footer | +| `SetShowBoundCollectionSize(bool)` | Shows the collection-size field | +| `SetReorderMode(ListViewReorderMode)` | `Simple` or `Animated` | +| `SetBindingSourceSelectionMode(BindingSourceSelectionMode)` | Auto-assign / manual | +| `SetOnAdd(Action)` · `AddOnAdd` · `RemoveOnAdd` | Custom add-button callback | +| `SetOnRemove(Action)` · `AddOnRemove` · `RemoveOnRemove` | Custom remove-button callback | +| `SetOverridingAddButtonBehavior(Action)` · `AddOverridingAddButtonBehavior` · `RemoveOverridingAddButtonBehavior` | Replace default add-button click | +| `AddItemsAdded(Action>)` / `RemoveItemsAdded` | Items added by index | +| `AddItemsRemoved(Action>)` / `RemoveItemsRemoved` | Items removed by index | + +#### `BaseTreeView`-specific + +| Method | Description | +|--------|-------------| +| `SetAutoExpand(bool)` | Auto-expand new nodes | +| `AddItemExpandedChanged(Action)` / `RemoveItemExpandedChanged` | Subscription to expansion changes | + +#### `ListView` / `TreeView` item factories + +These methods are duplicated across `ListViewExtensions` and `TreeViewExtensions` (each operating on its own view type). + +| Method | Description | +|--------|-------------| +| `SetMakeItem(Func)` · `AddMakeItem` · `RemoveMakeItem` | Item factory | +| `SetBindItem(Action)` · `AddBindItem` · `RemoveBindItem` | Item binding | +| `SetUnbindItem(Action)` · `AddUnbindItem` · `RemoveUnbindItem` | Item unbinding | +| `SetDestroyItem(Action)` · `AddDestroyItem` · `RemoveDestroyItem` | Item teardown | +| `SetItemTemplate(VisualTreeAsset)` | UXML template used to build items | + +#### `MultiColumnListView` / `MultiColumnTreeView` + +| Method | Description | +|--------|-------------| +| `SetSortingMode(ColumnSortingMode)` | Built-in sorting mode for the column header | + +## Editor commands (editor-only) + +```csharp +using Aspid.FastTools.UIElements.Editors; + +image.AddOpenScriptCommand(target); +// Double-clicking the element opens the script for 'target' in the IDE +``` + +| Method | Target | Description | +|--------|--------|-------------| +| `AddOpenScriptCommand(Object)` | `VisualElement` | Registers a double-click handler that opens the source script for the given `MonoBehaviour` / `ScriptableObject` in the IDE. | +| `BindTo(SerializedObject)` | `VisualElement` | Calls `BindingExtensions.Bind` on the element. | +| `BindTo(SerializedObject, string propertyPath)` | `IBindable` | Sets `bindingPath` and binds to the given `SerializedObject`. | +| `BindPropertyTo(SerializedProperty)` | `IBindable` | Calls `BindingExtensions.BindProperty` with the supplied property. | +| `Initialize(Enum defaultValue, bool includeObsoleteValues = false)` | `EnumField` / `EnumFlagsField` | Initializes the field to the supplied default enum value. | +| `AddValueChanged(EventCallback)` / `RemoveValueChanged(...)` | `PropertyField` | Subscribes / unsubscribes to property change notifications. | + +## USS custom-style helpers (`ICustomStyle`) + +```csharp +using Aspid.FastTools.UIElements; + +private static readonly CustomStyleProperty ThemeProperty = new("--aspid-fasttools-prop-theme"); + +void OnCustomStyleResolved(CustomStyleResolvedEvent evt) +{ + if (evt.customStyle.TryGetByEnum(ThemeProperty, out ThemeStyle.Type theme)) + ApplyTheme(theme); +} +``` + +| Method | Description | +|--------|-------------| +| `ICustomStyle.TryGetByEnum(CustomStyleProperty, out T)` | Resolves a string-typed USS custom property and parses it case-insensitively as the enum `T`. Used by every `*Style` struct that exposes a USS-driven enum (`ThemeStyle`, `StatusStyle`, `AspidLabelSizeStyle`, etc.). | diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md.meta new file mode 100644 index 0000000..9a0b54f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a732922edf5904ae49ce09e54bf91bf6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md new file mode 100644 index 0000000..92e5d2a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md @@ -0,0 +1,600 @@ +# Расширения VisualElement — полный справочник + +Fluent-методы расширения для построения UIToolkit-деревьев в коде. Все методы возвращают `T` (сам элемент) для цепочки вызовов. + +```csharp +using Aspid.FastTools.UIElements; // runtime-расширения +using Aspid.FastTools.UIElements.Editors; // editor-only расширения (например, AddOpenScriptCommand) +``` + +## Основные операции с элементами + +```csharp +element + .SetName("MyElement") + .SetVisible(true) + .SetTooltip("Текст подсказки") + .AddChild(new Label("Hello")) + .AddChildren(child1, child2, child3); +``` + +| Метод | Описание | +|-------|----------| +| `SetName(string)` | Устанавливает `element.name` | +| `SetVisible(bool)` | Устанавливает `element.visible` | +| `SetTooltip(string)` | Устанавливает `element.tooltip` | +| `SetUserData(object)` | Устанавливает `element.userData` | +| `SetEnabledSelf(bool)` | Устанавливает `element.enabledSelf` | +| `SetPickingMode(PickingMode)` | Устанавливает `element.pickingMode` | +| `SetUsageHints(UsageHints)` | Устанавливает `element.usageHints` | +| `SetViewDataKey(string)` | Устанавливает `element.viewDataKey` | +| `SetLanguageDirection(LanguageDirection)` | Устанавливает `element.languageDirection` | +| `SetDisablePlayModeTint(bool)` | Устанавливает `element.disablePlayModeTint` | +| `SetDataSource(object)` | Устанавливает `element.dataSource` | +| `SetDataSourceType(Type)` | Устанавливает `element.dataSourceType` | +| `SetDataSourcePath(PropertyPath)` | Устанавливает `element.dataSourcePath` | +| `AddChild(VisualElement)` | Добавляет дочерний элемент, возвращает родителя | +| `AddChildren(params VisualElement[])` | Добавляет несколько дочерних элементов | +| `AddChildren(IEnumerable)` | Добавляет из последовательности | +| `AddChildren(List)` | Добавляет из списка | +| `AddChildren(Span)` | Добавляет из span | +| `AddChildren(ReadOnlySpan)` | Добавляет из read-only span | +| `InsertChild(int, VisualElement)` | Вставляет дочерний элемент по указанному индексу | +| `InsertChildren(int, params VisualElement[])` | Вставляет несколько дочерних элементов начиная с индекса | +| `InsertChildren(int, IEnumerable)` | Вставляет из последовательности | +| `InsertChildren(int, List)` | Вставляет из списка | +| `InsertChildren(int, Span)` | Вставляет из span | +| `InsertChildren(int, ReadOnlySpan)` | Вставляет из read-only span | + +> `RegisterCallbackOnce` и `RegisterCallbackOnce` доступны на всех версиях Unity (пакет содержит polyfill для версий до 2023.1). + +## Focusable + +| Метод | Описание | +|-------|----------| +| `SetFocus()` | Устанавливает фокус на элемент | +| `SetBlur()` | Снимает фокус с элемента | +| `IsFocus()` | Возвращает, находится ли элемент в фокусе | +| `SetTabIndex(int)` | Устанавливает `element.tabIndex` | +| `SetFocusable(bool)` | Устанавливает `element.focusable` | +| `SetDelegatesFocus(bool)` | Устанавливает `element.delegatesFocus` | + +## USS и операции с классами + +| Метод | Описание | +|-------|----------| +| `AddClass(string)` | Добавляет USS-класс | +| `RemoveClass(string)` | Удаляет USS-класс | +| `ClearClasses()` | Удаляет все USS-классы | +| `ToggleInClass(string)` | Переключает USS-класс вкл/выкл | +| `EnableInClass(string, bool)` | Добавляет или удаляет USS-класс по условию | +| `AddStyleSheets(StyleSheet)` | Добавляет `StyleSheet` | +| `RemoveStyleSheets(StyleSheet)` | Удаляет `StyleSheet` | +| `AddStyleSheetsFromResource(string)` | Добавляет таблицу стилей через `Resources.Load` | +| `RemoveStyleSheetsFromResource(string)` | Удаляет таблицу стилей, загруженную через `Resources.Load` | + +## Расширения стилей — по категориям + +Все методы стилей также доступны напрямую на `IStyle` (те же имена методов, работают с объектом стиля). + +### Разметка + +| Метод | Свойство стиля | +|-------|----------------| +| `SetFlexBasis(StyleLength)` | `flexBasis` | +| `SetFlexGrow(StyleFloat)` | `flexGrow` | +| `SetFlexShrink(StyleFloat)` | `flexShrink` | +| `SetFlexWrap(StyleEnum)` | `flexWrap` | +| `SetFlexDirection(FlexDirection)` | `flexDirection` | +| `SetAlignSelf(StyleEnum)` | `alignSelf` | +| `SetAlignItems(StyleEnum)` | `alignItems` | +| `SetAlignContent(StyleEnum)` | `alignContent` | +| `SetJustifyContent(StyleEnum)` | `justifyContent` | +| `SetPosition(StyleEnum)` | `position` | + +### Размер + +| Метод | Описание | +|-------|----------| +| `SetSize(StyleLength)` | Устанавливает ширину и высоту одновременно | +| `SetSize(width?, height?)` | Устанавливает ширину и/или высоту независимо | +| `SetMinSize(StyleLength)` | Устанавливает minWidth и minHeight одновременно | +| `SetMinSize(width?, height?)` | | +| `SetMaxSize(StyleLength)` | Устанавливает maxWidth и maxHeight одновременно | +| `SetMaxSize(width?, height?)` | | +| `SetWidth(StyleLength)` | `width` | +| `SetMinWidth(StyleLength)` | `minWidth` | +| `SetMaxWidth(StyleLength)` | `maxWidth` | +| `SetHeight(StyleLength)` | `height` | +| `SetMinHeight(StyleLength)` | `minHeight` | +| `SetMaxHeight(StyleLength)` | `maxHeight` | + +### Отступы + +Все методы отступов имеют перегрузку с единым значением, перегрузку по сторонам (`top`, `right`, `bottom`, `left`), сеттеры по одной стороне и сеттеры по парам осей X/Y. + +| Метод | Свойства стиля | +|-------|----------------| +| `SetMargin(…)` / `SetPadding(…)` / `SetDistance(…)` | `Top/Right/Bottom/Left` (общее значение или per-side) | +| `SetMarginX/Y` · `SetPaddingX/Y` · `SetDistanceX/Y` | Устанавливает горизонтальную (X = `Left`+`Right`) или вертикальную (Y = `Top`+`Bottom`) пару | +| `SetMarginTop/Right/Bottom/Left` | Margin одной стороны | +| `SetPaddingTop/Right/Bottom/Left` | Padding одной стороны | +| `SetDistanceTop/Right/Bottom/Left` *(через `SetTop` / `SetRight` / `SetBottom` / `SetLeft`)* | Смещение одной стороны для абсолютного позиционирования (свойства `top` / `right` / `bottom` / `left`) | + +> `SetDistance` — обёртка для четырёх свойств `top`/`right`/`bottom`/`left`, используемых при абсолютном позиционировании. `SetTop`, `SetRight`, `SetBottom`, `SetLeft` — это прямые алиасы для одного свойства. + +### Шрифт + +| Метод | Свойство стиля | +|-------|----------------| +| `SetUnityFont(StyleFont)` | `unityFont` | +| `SetFontSize(StyleLength)` | `fontSize` | +| `SetUnityFontDefinition(StyleFontDefinition)` | `unityFontDefinition` | +| `SetUnityFontStyleAndWeight(StyleEnum)` | `unityFontStyleAndWeight` | + +### Пресеты стиля шрифта + +Удобные методы для переключения bold / italic без перезаписи другого флага: + +| Метод | Описание | +|-------|----------| +| `SetNormalUnityFontStyleAndWeight()` | Сбрасывает в `FontStyle.Normal` | +| `AddBoldUnityFontStyleAndWeight()` | Добавляет bold, сохраняя italic | +| `RemoveBoldUnityFontStyleAndWeight()` | Убирает bold, сохраняя italic | +| `AddItalicUnityFontStyleAndWeight()` | Добавляет italic, сохраняя bold | +| `RemoveItalicUnityFontStyleAndWeight()` | Убирает italic, сохраняя bold | + +### Текст + +| Метод | Свойство стиля | Примечания | +|-------|---------------|------------| +| `SetWorldSpacing(StyleLength)` | `wordSpacing` | | +| `SetLetterSpacing(StyleLength)` | `letterSpacing` | | +| `SetUnityTextAlign(TextAnchor)` | `unityTextAlign` | | +| `SetTextShadow(StyleTextShadow)` | `textShadow` | | +| `SetUnityTextOutlineColor(StyleColor)` | `unityTextOutlineColor` | | +| `SetUnityTextOutlineWidth(StyleFloat)` | `unityTextOutlineWidth` | | +| `SetUnityParagraphSpacing(StyleLength)` | `unityParagraphSpacing` | | +| `SetTextOverflow(StyleEnum)` | `textOverflow` | | +| `SetUnityTextOverflowPosition(TextOverflowPosition)` | `unityTextOverflowPosition` | | +| `SetUnityTextGenerator(TextGeneratorType)` | `unityTextGenerator` | Unity 6+ | +| `SetUnityEditorTextRenderingMode(EditorTextRenderingMode)` | `unityEditorTextRenderingMode` | Unity 6+ | +| `SetUnityTextAutoSize(StyleTextAutoSize)` | `unityTextAutoSize` | Unity 6.2+ | +| `SetWhiteSpace(StyleEnum)` | `whiteSpace` | | + +### Цвет и прозрачность + +| Метод | Свойство стиля | +|-------|----------------| +| `SetColor(StyleColor)` | `color` | +| `SetColor(string)` | `color`, разобранный из HTML-строки (`"#RRGGBB"` или именованный цвет) | +| `SetOpacity(StyleFloat)` | `opacity` | + +### Рамка + +| Метод | Описание | +|-------|----------| +| `SetBorderColor(StyleColor)` | Все стороны | +| `SetBorderColor(top?, right?, bottom?, left?)` | По стороне | +| `SetBorderColorX(StyleColor)` · `SetBorderColorY(StyleColor)` | Горизонтальная (left + right) или вертикальная (top + bottom) пара | +| `SetBorderColorTop/Right/Bottom/Left(StyleColor)` | Одна сторона | +| `SetBorderRadius(StyleLength)` | Все углы | +| `SetBorderRadius(topLeft?, topRight?, bottomLeft?, bottomRight?)` | По углу | +| `SetBorderRadiusTop(StyleLength)` · `SetBorderRadiusBottom(StyleLength)` | Пара верхних или нижних углов | +| `SetBorderRadiusTopLeft/TopRight/BottomLeft/BottomRight(StyleLength)` | Один угол | +| `SetBorderWidth(StyleFloat)` | Все стороны | +| `SetBorderWidth(top?, right?, bottom?, left?)` | По стороне | +| `SetBorderWidthX(StyleFloat)` · `SetBorderWidthY(StyleFloat)` | Горизонтальная или вертикальная пара | +| `SetBorderWidthTop/Right/Bottom/Left(StyleFloat)` | Одна сторона | + +### Фон + +| Метод | Свойство стиля | +|-------|----------------| +| `SetBackgroundColor(StyleColor)` | `backgroundColor` | +| `SetBackgroundColor(string)` | `backgroundColor`, разобранный из HTML-строки (`"#RRGGBB"` или именованный цвет) | +| `SetBackgroundImage(StyleBackground)` | `backgroundImage` | +| `SetBackgroundImageFromResource(string)` | Загружает `Texture2D` через `Resources.Load` и присваивает его в `backgroundImage` | +| `SetBackgroundSize(StyleBackgroundSize)` | `backgroundSize` | +| `SetBackgroundRepeat(StyleBackgroundRepeat)` | `backgroundRepeat` | +| `SetBackgroundPosition(StyleBackgroundPosition)` | X и Y одновременно | +| `SetBackgroundPosition(x?, y?)` | Независимо | +| `SetBackgroundPositionX(StyleBackgroundPosition)` | `backgroundPositionX` | +| `SetBackgroundPositionY(StyleBackgroundPosition)` | `backgroundPositionY` | +| `SetUnityBackgroundImageTintColor(StyleColor)` | `unityBackgroundImageTintColor` | + +### Трансформации + +| Метод | Свойство стиля | +|-------|----------------| +| `SetScale(StyleScale)` | `scale` | +| `SetRotate(StyleRotate)` | `rotate` | +| `SetTranslate(StyleTranslate)` | `translate` | +| `SetTransformOrigin(StyleTransformOrigin)` | `transformOrigin` | + +### Aspect, Filter и Material + +Доступно начиная с Unity 6000.3+. + +| Метод | Свойство стиля | +|-------|----------------| +| `SetAspectRation(StyleRatio)` | `aspectRatio` *(имя метода сохраняет опечатку из исходника)* | +| `SetFilter(StyleList)` | `filter` | +| `SetUnityMaterial(StyleMaterialDefinition)` | `unityMaterial` | + +### Анимации переходов + +| Метод | Свойство стиля | +|-------|----------------| +| `SetTransitionDelay(StyleList)` | `transitionDelay` | +| `SetTransitionDuration(StyleList)` | `transitionDuration` | +| `SetTransitionProperty(StyleList)` | `transitionProperty` | +| `SetTransitionTimingFunction(StyleList)` | `transitionTimingFunction` | + +### Переполнение и видимость + +| Метод | Свойство стиля | +|-------|----------------| +| `SetOverflow(StyleEnum)` | `overflow` | +| `SetUnityOverflowClipBox(StyleEnum)` | `unityOverflowClipBox` | +| `SetVisibility(StyleEnum)` | `visibility` | +| `SetDisplay(DisplayStyle)` | `display` | + +### Unity Slice + +| Метод | Описание | +|-------|----------| +| `SetUnitySlice(StyleInt)` | Все стороны | +| `SetUnitySlice(top?, right?, bottom?, left?)` | По стороне | +| `SetUnitySliceX(StyleInt)` · `SetUnitySliceY(StyleInt)` | Горизонтальная (left + right) или вертикальная (top + bottom) пара | +| `SetUnitySliceTop/Right/Bottom/Left(StyleInt)` | Одна сторона | +| `SetUnitySliceScale(StyleFloat)` | `unitySliceScale` | +| `SetUnitySliceType(StyleEnum)` | Unity 6+ | + +### Курсор + +| Метод | Свойство стиля | +|-------|----------------| +| `SetCursor(StyleCursor)` | `cursor` | + +## Расширения для специализированных элементов + +### TextElement + +```csharp +label + .SetText("Hello World") + .SetEnableRichText(true) + .SetParseEscapeSequences(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetText(string)` | Устанавливает отображаемый текст | +| `SetEnableRichText(bool)` | Включает разбор тегов rich-text | +| `SetEmojiFallbackSupport(bool)` | Включает emoji-fallback при рендеринге | +| `SetParseEscapeSequences(bool)` | Обрабатывать ли escape-последовательности (например, `\n`) | +| `SetDisplayTooltipWhenElided(bool)` | Показывать обрезанный текст в подсказке при наведении | + +### ITextEdition (TextField, IntegerField, …) + +```csharp +textField + .SetPlaceholder("Поиск…") + .SetMaxLength(64) + .SetIsDelayed(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetMaxLength(int)` | Максимальное число символов | +| `SetMaskChar(char)` | Символ для маскировки пароля | +| `SetIsDelayed(bool)` | Откладывает изменение значения до потери фокуса / Enter | +| `SetIsReadOnly(bool)` | Запрещает редактирование | +| `SetIsPassword(bool)` | Включает password-режим (использует mask char) | +| `SetPlaceholder(string)` | Текст-плейсхолдер для пустого поля | +| `SetAutoCorrection(bool)` | Включает автокоррекцию (mobile) | +| `SetHideMobileInput(bool)` | Скрывает мобильный soft input | +| `SetHideSoftKeyboard(bool)` | Скрывает экранную клавиатуру | +| `SetHidePlaceholderOnFocus(bool)` | Убирает плейсхолдер при фокусе | +| `SetKeyboardType(TouchScreenKeyboardType)` | Тип touch-screen клавиатуры | + +### ITextSelection + +```csharp +textField + .SetIsSelectable(true) + .SetSelectAllOnFocus(true) + .AddOnCursorIndexChange(() => Debug.Log(textField.cursorIndex)); +``` + +| Метод | Описание | +|-------|----------| +| `AddOnCursorIndexChange(Action)` / `RemoveOnCursorIndexChange(Action)` | Подписка на изменение позиции курсора | +| `AddOnSelectIndexChange(Action)` / `RemoveOnSelectIndexChange(Action)` | Подписка на изменение якоря выделения | +| `SetCursorIndex(int)` | Текущая позиция курсора | +| `SetSelectIndex(int)` | Текущий якорь выделения | +| `SetIsSelectable(bool)` | Можно ли выделять текст | +| `SetSelectAllOnFocus(bool)` | Выделять весь текст при фокусе | +| `SetSelectAllOnMouseUp(bool)` | Выделять весь текст при отпускании мыши | +| `SetDoubleClickSelectsWord(bool)` | Двойной клик выделяет слово | +| `SetTripleClickSelectsLine(bool)` | Тройной клик выделяет строку | + +### BaseField\ + +```csharp +field.SetLabel("My Field"); +field.SetValue(42); +``` + +### BaseBoolField (Toggle) + +```csharp +toggle + .SetLabel("Включено") + .SetText("Показать расширенные настройки") + .SetToggleOnLabelClick(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetText(string)` | Устанавливает текст рядом с чекбоксом | +| `SetLabel(string)` | Устанавливает label поля | +| `SetToggleOnLabelClick(bool)` | Переключать ли значение по клику на label | + +### INotifyValueChanged\ + +```csharp +field.SetValue(42, notify: false); // устанавливает значение без генерации ChangeEvent +field.AddValueChanged(evt => Debug.Log(evt.newValue)); +field.RemoveValueChanged(myCallback); +``` + +Типизированные перегрузки доступны для `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `short`, `ushort`, `byte`, `sbyte`, `float`, `double`, `decimal`, `char`, `string`, `bool`, `Color`, `Vector2/3/4`, `Vector2Int/3Int`, `Rect/RectInt`, `Bounds/BoundsInt`, `Hash128`, `GUID`, `Quaternion`, `Matrix4x4`, `Gradient`, `AnimationCurve`, `Delegate`, `Enum`, `Object`, `object`, плюс обобщённый fallback `SetValue`. + +> При установленном пакете `com.unity.mathematics` автоматически выставляется define `ASPID_FASTTOOLS_UNITY_MATHEMATICS_INTEGRATION` и добавляются перегрузки `SetValue` / `AddValueChanged` / `RemoveValueChanged` для `int2/3/4` (и `intMxN`), `float2/3/4` (и `floatMxN`), `bool2/3/4` (и `boolMxN`), а также `quaternion`. + +### IMixedValueSupport + +```csharp +field.SetShowMixedValue(true); // показывает индикатор смешанного значения +``` + +### Button + +```csharp +button + .AddClicked(() => Debug.Log("Clicked")) + .SetClickable(new Clickable(() => { })) + .SetIconImage(myBackground); +``` + +| Метод | Описание | +|-------|----------| +| `AddClicked(Action)` | Подписка на `Button.clicked` | +| `RemoveClicked(Action)` | Отписка от `Button.clicked` | +| `SetClickable(Clickable)` | Устанавливает `Button.clickable` | +| `SetIconImage(Background)` | Устанавливает `Button.iconImage` | + +### Slider / BaseSlider\ + +```csharp +slider + .SetLowValue(0f) + .SetHighValue(100f) + .SetShowInputField(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetLowValue(TValue)` | Устанавливает минимальное значение слайдера | +| `SetHighValue(TValue)` | Устанавливает максимальное значение слайдера | +| `SetFill(bool)` | Заполнение трека до текущего значения | +| `SetInverted(bool)` | Инвертирует направление слайдера | +| `SetPageSize(float)` | Шаг изменения значения при постраничной навигации | +| `SetShowInputField(bool)` | Показывает числовое поле ввода рядом со слайдером | +| `SetDirection(SliderDirection)` | Устанавливает ориентацию слайдера | + +### ProgressBar + +```csharp +progressBar.SetTitle("Загрузка...").SetLowValue(0f).SetHighValue(100f); +``` + +| Метод | Описание | +|-------|----------| +| `SetTitle(string)` | Устанавливает заголовок, отображаемый в центре | +| `SetLowValue(float)` | Устанавливает минимальное значение | +| `SetHighValue(float)` | Устанавливает максимальное значение | + +### HelpBox + +```csharp +helpBox + .SetText("Что-то пошло не так") + .SetMessageType(HelpBoxMessageType.Warning); +``` + +| Метод | Описание | +|-------|----------| +| `SetText(string)` | Текст сообщения help-box | +| `SetMessageType(HelpBoxMessageType)` | Иконка / уровень (`None` / `Info` / `Warning` / `Error`) | + +### Foldout + +```csharp +foldout + .SetText("Section Title") + .SetToggleOnLabelClick(true) + .SetValue(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetText(string)` | Заголовок foldout | +| `SetToggleOnLabelClick(bool)` | Переключать ли раскрытие по клику на заголовок | + +### Image + +```csharp +image + .SetImage(myTexture) + .SetTintColor(Color.white) + .SetScaleMode(ScaleMode.ScaleToFit); +``` + +| Метод | Описание | +|-------|----------| +| `SetImage(Texture)` | Устанавливает `Image.image` | +| `SetImageFromResource(string)` | Загружает текстуру через `Resources.Load` | +| `SetSprite(Sprite)` | Устанавливает `Image.sprite` | +| `SetSpriteFromResource(string)` | Загружает sprite через `Resources.Load` | +| `SetVectorImage(VectorImage)` | Устанавливает `Image.vectorImage` | +| `SetVectorImageFromResource(string)` | Загружает vector image через `Resources.Load` | +| `SetUv(Rect)` | Устанавливает UV-rect | +| `SetSourceRect(Rect)` | Устанавливает source rect | +| `SetTintColor(Color)` | Цветовой tint изображения | +| `SetScaleMode(ScaleMode)` | Режим масштабирования | + +### IMGUIContainer + +```csharp +container + .SetOnGUIHandler(() => GUILayout.Label("IMGUI")) + .SetCullingEnabled(true); +``` + +| Метод | Описание | +|-------|----------| +| `SetOnGUIHandler(Action)` | Заменяет коллбэк `onGUIHandler` | +| `AddOnGUIHandler(Action)` | Подписка на `onGUIHandler` | +| `RemoveOnGUIHandler(Action)` | Отписка от `onGUIHandler` | +| `SetCullingEnabled(bool)` | Пропускает `onGUIHandler`, когда элемент за пределами экрана | +| `SetContextType(ContextType)` | Устанавливает тип контекста IMGUI | + +### Collection-views (ListView, TreeView, MultiColumn-варианты) + +Общие методы распределены по нескольким специализированным расширениям: + +- `BaseVerticalCollectionViewExtensions` — применяется ко **всем** collection-views (ListView, TreeView, MultiColumn-варианты). +- `BaseListViewExtensions` — применяется к ListView и MultiColumnListView. +- `BaseTreeViewExtensions` — применяется к TreeView и MultiColumnTreeView. +- `ListViewExtensions` / `TreeViewExtensions` — фабрики `MakeItem`/`BindItem`/`UnbindItem`/`DestroyItem` для своего вью. +- `MultiColumnListViewExtensions` / `MultiColumnTreeViewExtensions` — хелперы для multi-column-вариантов. + +```csharp +listView + .SetItemsSource(items) + .SetMakeItem(() => new Label()) + .SetBindItem((el, i) => ((Label)el).SetText(items[i])) + .SetSelectionType(SelectionType.Single) + .AddSelectionChanged(selected => Debug.Log(selected)); +``` + +#### Источник, layout и поведение — `BaseVerticalCollectionView` + +| Метод | Описание | Примечания | +|-------|----------|------------| +| `SetItemsSource(IList)` | Источник данных | | +| `SetReorderable(bool)` | Включает drag-reorder | | +| `SetSelectedIndex(int)` | Выбирает элемент по индексу | | +| `SetSelectionType(SelectionType)` | None / Single / Multiple | | +| `SetFixedItemHeight(float)` | Фиксированная высота элемента (для виртуализации `FixedHeight`) | | +| `SetVirtualizationMethod(CollectionVirtualizationMethod)` | `FixedHeight` или `DynamicHeight` | | +| `SetHorizontalScrollingEnabled(bool)` | Включает горизонтальную прокрутку | | +| `SetShowAlternatingRowBackgrounds(AlternatingRowBackground)` | Режим зебра-полос | | +| `SetMakeFooter(Func)` · `AddMakeFooter` · `RemoveMakeFooter` | Фабрика подвала | Unity 6+ | +| `SetMakeHeader(Func)` · `AddMakeHeader` · `RemoveMakeHeader` | Фабрика заголовка | Unity 6+ | +| `SetMakeNoneElement(Func)` · `AddMakeNoneElement` · `RemoveMakeNoneElement` | Фабрика empty-state | Unity 6+ | + +#### События — `BaseVerticalCollectionView` + +| Метод | Описание | +|-------|----------| +| `AddItemsChosen(Action>)` / `RemoveItemsChosen` | Подтверждение элементов (двойной клик / Enter) | +| `AddSelectionChanged(Action>)` / `RemoveSelectionChanged` | Изменение выделения (объекты) | +| `AddSelectedIndicesChanged(Action>)` / `RemoveSelectedIndicesChanged` | Изменение выделения (индексы) | +| `AddItemIndexChanged(Action)` / `RemoveItemIndexChanged` | Перемещение элемента (drag-reorder) | +| `AddItemsSourceChanged(Action)` / `RemoveItemsSourceChanged` | Смена ссылки `itemsSource` | +| `AddCanStartDrag(Func)` / `RemoveCanStartDrag` | Кастомный gating старта drag | +| `AddSetupDragAndDrop(Func)` / `RemoveSetupDragAndDrop` | Подготовка drag-and-drop | +| `AddSetupDragAndDrop(Func)` / `RemoveSetupDragAndDrop` | Визуальный режим drag-and-drop | +| `AddHandleDrop(Func)` / `RemoveHandleDrop` | Обработка drop | + +#### Только для `BaseListView` + +| Метод | Описание | +|-------|----------| +| `SetAllowAdd(bool)` · `SetAllowRemove(bool)` | Включают встроенные кнопки add/remove | +| `SetHeaderTitle(string)` | Заголовок при включённом foldout-header | +| `SetShowFoldoutHeader(bool)` | Оборачивает список в `Foldout` | +| `SetShowAddRemoveFooter(bool)` | Показывает footer с add/remove | +| `SetShowBoundCollectionSize(bool)` | Поле размера коллекции | +| `SetReorderMode(ListViewReorderMode)` | `Simple` или `Animated` | +| `SetBindingSourceSelectionMode(BindingSourceSelectionMode)` | Auto-assign / manual | +| `SetOnAdd(Action)` · `AddOnAdd` · `RemoveOnAdd` | Кастомный коллбэк add-кнопки | +| `SetOnRemove(Action)` · `AddOnRemove` · `RemoveOnRemove` | Кастомный коллбэк remove-кнопки | +| `SetOverridingAddButtonBehavior(Action)` · `AddOverridingAddButtonBehavior` · `RemoveOverridingAddButtonBehavior` | Подменяет дефолтное поведение add | +| `AddItemsAdded(Action>)` / `RemoveItemsAdded` | Добавление элементов по индексам | +| `AddItemsRemoved(Action>)` / `RemoveItemsRemoved` | Удаление элементов по индексам | + +#### Только для `BaseTreeView` + +| Метод | Описание | +|-------|----------| +| `SetAutoExpand(bool)` | Авто-разворачивание новых узлов | +| `AddItemExpandedChanged(Action)` / `RemoveItemExpandedChanged` | Подписка на изменение раскрытия | + +#### Item-фабрики `ListView` / `TreeView` + +Эти методы дублируются в `ListViewExtensions` и `TreeViewExtensions` (каждое работает со своим типом view). + +| Метод | Описание | +|-------|----------| +| `SetMakeItem(Func)` · `AddMakeItem` · `RemoveMakeItem` | Фабрика элементов | +| `SetBindItem(Action)` · `AddBindItem` · `RemoveBindItem` | Привязка элемента | +| `SetUnbindItem(Action)` · `AddUnbindItem` · `RemoveUnbindItem` | Отвязка элемента | +| `SetDestroyItem(Action)` · `AddDestroyItem` · `RemoveDestroyItem` | Уничтожение элемента | +| `SetItemTemplate(VisualTreeAsset)` | UXML-шаблон, по которому строятся элементы | + +#### `MultiColumnListView` / `MultiColumnTreeView` + +| Метод | Описание | +|-------|----------| +| `SetSortingMode(ColumnSortingMode)` | Встроенный режим сортировки заголовка колонки | + +## Команды редактора (только для редактора) + +```csharp +using Aspid.FastTools.UIElements.Editors; + +image.AddOpenScriptCommand(target); +// Двойной клик на элемент открывает скрипт 'target' в IDE +``` + +| Метод | Цель | Описание | +|-------|------|----------| +| `AddOpenScriptCommand(Object)` | `VisualElement` | Регистрирует обработчик двойного клика, открывающий исходный скрипт `MonoBehaviour` / `ScriptableObject` в IDE. | +| `BindTo(SerializedObject)` | `VisualElement` | Вызывает `BindingExtensions.Bind` на элементе. | +| `BindTo(SerializedObject, string propertyPath)` | `IBindable` | Устанавливает `bindingPath` и привязывается к указанному `SerializedObject`. | +| `BindPropertyTo(SerializedProperty)` | `IBindable` | Вызывает `BindingExtensions.BindProperty` для переданного property. | +| `Initialize(Enum defaultValue, bool includeObsoleteValues = false)` | `EnumField` / `EnumFlagsField` | Инициализирует поле указанным значением enum по умолчанию. | +| `AddValueChanged(EventCallback)` / `RemoveValueChanged(...)` | `PropertyField` | Подписка / отписка от уведомлений об изменении свойства. | + +## USS custom-style helpers (`ICustomStyle`) + +```csharp +using Aspid.FastTools.UIElements; + +private static readonly CustomStyleProperty ThemeProperty = new("--aspid-fasttools-prop-theme"); + +void OnCustomStyleResolved(CustomStyleResolvedEvent evt) +{ + if (evt.customStyle.TryGetByEnum(ThemeProperty, out ThemeStyle.Type theme)) + ApplyTheme(theme); +} +``` + +| Метод | Описание | +|-------|----------| +| `ICustomStyle.TryGetByEnum(CustomStyleProperty, out T)` | Резолвит USS custom-property со строковым значением и парсит её регистронезависимо как enum `T`. Используется во всех `*Style`-структурах с USS-driven enum (`ThemeStyle`, `StatusStyle`, `AspidLabelSizeStyle` и т. д.). | diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md.meta new file mode 100644 index 0000000..33dbcc0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a181f7da19b70437eb557c0cda2dad2a +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues.meta similarity index 77% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues.meta index a72d9f7..2580f46 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c6490710e847c4157a38f045d5205648 +guid: 7c561c66bd9a74b5b910a51cbf1bcca3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs.meta similarity index 67% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs.meta index f833786..d27664c 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: 55b0a716a25414d609e45c84c5e34851 +guid: e9d7c8b6a5f4e3d2c1b0a9f8e7d6c5b4 +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab new file mode 100644 index 0000000..3b8c25c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab @@ -0,0 +1,112 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1234567890123456789 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234567890123456789} + - component: {fileID: 3234567890123456789} + m_Layer: 0 + m_Name: DamageDealer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2234567890123456789 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3234567890123456789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3bd9644f273549748da7b083e4de1b37, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.EnumValues::Aspid.FastTools.Samples.EnumValues.DamageDealer + _damageMultipliers: + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _defaultValue: 1 + _values: + - _key: Physical + _value: 1 + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Fire + _value: 1.5 + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Ice + _value: 0.8 + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Poison + _value: 0.6 + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _damageColors: + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _defaultValue: {r: 1, g: 1, b: 1, a: 1} + _values: + - _key: Physical + _value: {r: 0.85, g: 0.85, b: 0.85, a: 1} + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Fire + _value: {r: 1, g: 0.5, b: 0.1, a: 1} + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Ice + _value: {r: 0.4, g: 0.8, b: 1, a: 1} + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Poison + _value: {r: 0.5, g: 0.9, b: 0.3, a: 1} + _enumType: Aspid.FastTools.Samples.EnumValues.DamageType, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _speedMultipliersByStatus: + _enumType: Aspid.FastTools.Samples.EnumValues.StatusEffect, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _defaultValue: 1 + _values: + - _key: Burning, Slowed + _value: 0.4 + _enumType: Aspid.FastTools.Samples.EnumValues.StatusEffect, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Burning + _value: 1 + _enumType: Aspid.FastTools.Samples.EnumValues.StatusEffect, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Frozen + _value: 0.2 + _enumType: Aspid.FastTools.Samples.EnumValues.StatusEffect, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - _key: Slowed + _value: 0.5 + _enumType: Aspid.FastTools.Samples.EnumValues.StatusEffect, Aspid.FastTools.Samples.EnumValues, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _currentDamageType: 1 + _activeEffects: 5 + _baseDamage: 10 diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/Types/Prefabs/TypeSelectorTest.prefab.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab.meta similarity index 74% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/Types/Prefabs/TypeSelectorTest.prefab.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab.meta index cfdabfd..78d6e5a 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/Types/Prefabs/TypeSelectorTest.prefab.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Prefabs/EnumValues.prefab.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d6fe21a6dc34048eea8586d6afdbd9f2 +guid: b6af73ff1ec54f22b2b637c93cf4287b PrefabImporter: externalObjects: {} userData: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md new file mode 100644 index 0000000..f080c2e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md @@ -0,0 +1,21 @@ +# EnumValues Sample + +A tiny combat damage system that maps enum members to typed values through `EnumValues`. `DamageDealer` picks a `DamageType` and `StatusEffect` in the Inspector, then on `Space` applies damage — pulling the damage multiplier, log color, and speed modifier from three `EnumValues` fields. + +Look at: +- `Scripts/DamageDealer.cs:9` — `EnumValues` mapping `DamageType` to damage multiplier. +- `Scripts/DamageDealer.cs:10` — `EnumValues` mapping `DamageType` to debug log color. +- `Scripts/DamageDealer.cs:14` — `EnumValues` keyed on `[Flags]` enum `StatusEffect`; composite entries like `Burning | Slowed` must come before single-flag entries (see the inline comment). +- `Scripts/DamageDealer.cs:30` — `GetValue` call on the Flags-keyed field. +- `Scripts/StatusEffect.cs` — `[Flags]` enum used by the third mapping. + +## How to run + +Open `Scenes/EnumValues.unity` and enter Play Mode. The scene hosts a `DamageDealer` wired up from `Prefabs/EnumValues.prefab`, which is pre-seeded with: + +- `_damageMultipliers`: `Physical = 1.0`, `Fire = 1.5`, `Ice = 0.8`, `Poison = 0.6`. +- `_damageColors`: grey / orange / cyan / acid-green per `DamageType`. +- `_speedMultipliersByStatus`: `Burning | Slowed = 0.4` **first**, then `Burning = 1.0`, `Frozen = 0.2`, `Slowed = 0.5` — composite-first ordering is what makes the combined flag resolve to `0.4` instead of falling through to the first single-flag match. +- `_currentDamageType = Fire`, `_activeEffects = Burning | Slowed`, `_baseDamage = 10`. + +Press `Space` and the Console prints `Fire hit: 15 dmg (speed mod: 0.40)` in orange. Change the enums in the Inspector (or toggle flags in `_activeEffects`) to see different lookups. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md.meta new file mode 100644 index 0000000..7aa3b86 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5fb2e3aa6c2a846b4b53ffdd69fccf9b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md new file mode 100644 index 0000000..3d47f2d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md @@ -0,0 +1,21 @@ +# Пример EnumValues + +Маленькая система боевого урона, которая сопоставляет члены enum типизированным значениям через `EnumValues`. `DamageDealer` выбирает `DamageType` и `StatusEffect` в Inspector, а по нажатию `Space` наносит урон — извлекая множитель урона, цвет лога и модификатор скорости из трёх полей `EnumValues`. + +Смотрите: +- `Scripts/DamageDealer.cs:9` — `EnumValues`, сопоставляющий `DamageType` множителю урона. +- `Scripts/DamageDealer.cs:10` — `EnumValues`, сопоставляющий `DamageType` цвету отладочного лога. +- `Scripts/DamageDealer.cs:14` — `EnumValues` по `[Flags]` enum `StatusEffect`; композитные записи вроде `Burning | Slowed` должны идти до одиночных флагов (см. комментарий рядом). +- `Scripts/DamageDealer.cs:30` — вызов `GetValue` на Flags-поле. +- `Scripts/StatusEffect.cs` — `[Flags]` enum, используемый в третьем сопоставлении. + +## Как запустить + +Откройте `Scenes/EnumValues.unity` и войдите в Play Mode. В сцене есть `DamageDealer`, подключённый из `Prefabs/EnumValues.prefab`, который предзаполнен: + +- `_damageMultipliers`: `Physical = 1.0`, `Fire = 1.5`, `Ice = 0.8`, `Poison = 0.6`. +- `_damageColors`: серый / оранжевый / голубой / ядовито-зелёный по `DamageType`. +- `_speedMultipliersByStatus`: `Burning | Slowed = 0.4` **первой**, затем `Burning = 1.0`, `Frozen = 0.2`, `Slowed = 0.5` — порядок с композитом впереди именно и гарантирует, что комбинация флагов разрешается в `0.4`, а не проваливается на первое совпадение одиночного флага. +- `_currentDamageType = Fire`, `_activeEffects = Burning | Slowed`, `_baseDamage = 10`. + +Нажмите `Space` — в Console появится оранжевое `Fire hit: 15 dmg (speed mod: 0.40)`. Меняйте значения enum в Inspector (или переключайте флаги в `_activeEffects`), чтобы увидеть другие варианты поиска. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md.meta new file mode 100644 index 0000000..cb485b4 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7a3b1c4d5e6f7081929304a5b6c7d8e9 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes.meta similarity index 77% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes.meta index 78aeed3..c445a59 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c5527f6f042e7408ebabfc82d150433b +guid: d68d6fc528e76449db0a639caa762203 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity new file mode 100644 index 0000000..8eeccc3 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity @@ -0,0 +1,449 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &100001 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 100003} + - component: {fileID: 100002} + - component: {fileID: 100004} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &100002 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + m_Enabled: 1 + serializedVersion: 13 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 10, y: 10} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShapeRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &100003 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &100004 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &200001 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 200004} + - component: {fileID: 200002} + - component: {fileID: 200003} + - component: {fileID: 200005} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &200002 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 +--- !u!20 &200003 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &200004 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &200005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!1001 &1501333895 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_Name + value: EnumValues + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: b6af73ff1ec54f22b2b637c93cf4287b, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 200004} + - {fileID: 100003} + - {fileID: 1501333895} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity.meta new file mode 100644 index 0000000..8d581a2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scenes/EnumValues.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbdae9a1d49d4a6ca82c5a3ab5bc1d24 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts.meta similarity index 67% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts.meta index c1b162f..46f29a9 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: 7f88981b89c7a48f196d36c976c31f20 +guid: d3bd9c0a75f8b4c77986e2aeb360dc13 +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef similarity index 76% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef index 5199cfd..9e824ff 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef @@ -1,8 +1,8 @@ { - "name": "Aspid.UnityFastTools.ProfilerMarkers", + "name": "Aspid.FastTools.Samples.EnumValues", "rootNamespace": "", "references": [ - "GUID:7c010b89992542508a6b6189977e64d4" + "Aspid.FastTools.Unity" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef.meta new file mode 100644 index 0000000..46d73b1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/Aspid.FastTools.Samples.EnumValues.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fe2fa73e3f3d499f8e95516349d3768a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs new file mode 100644 index 0000000..957d980 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using Aspid.FastTools.Enums; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.EnumValues +{ + public sealed class DamageDealer : MonoBehaviour + { + [SerializeField] private EnumValues _damageMultipliers; + [SerializeField] private EnumValues _damageColors; + + // Flag combinations (e.g. Burning | Slowed) match via HasFlag and first-hit wins, so list + // composite entries BEFORE their constituent flags — otherwise the single-flag entry matches first. + [SerializeField] private EnumValues _speedMultipliersByStatus; + + [SerializeField] private DamageType _currentDamageType = DamageType.Physical; + [SerializeField] private StatusEffect _activeEffects = StatusEffect.None; + [SerializeField] private float _baseDamage = 10f; + + private void Update() + { + if (!Input.GetKeyDown(KeyCode.Space)) return; + DealDamage(); + } + + private void DealDamage() + { + var multiplier = _damageMultipliers.GetValue(_currentDamageType); + var color = _damageColors.GetValue(_currentDamageType); + var speedMod = _speedMultipliersByStatus.GetValue(_activeEffects); + var finalDamage = _baseDamage * multiplier; + var colorHex = ColorUtility.ToHtmlStringRGB(color); + + Debug.Log($"{_currentDamageType} hit: {finalDamage} dmg (speed mod: {speedMod:F2})"); + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs.meta new file mode 100644 index 0000000..2f16782 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageDealer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3bd9644f273549748da7b083e4de1b37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs new file mode 100644 index 0000000..3a42c2f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs @@ -0,0 +1,11 @@ +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.EnumValues +{ + public enum DamageType + { + Physical, + Fire, + Ice, + Poison, + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs.meta new file mode 100644 index 0000000..7b7289d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/DamageType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8617fbe193994a1d9ffd71e02ac3c5b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs new file mode 100644 index 0000000..8922e13 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs @@ -0,0 +1,17 @@ +using System; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.EnumValues +{ + [Flags] + public enum StatusEffect + { + None = 0, + Burning = 1, + Frozen = 2, + Slowed = 4, + Stunned = 8, + // Combinations such as Burning | Slowed are matched via HasFlag semantics in EnumValues + // and can be registered as their own entry with a dedicated value. + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs.meta new file mode 100644 index 0000000..52cb56f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/EnumValues/Scripts/StatusEffect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f66e403cd7044cc96c00ad003ccc68a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids.meta new file mode 100644 index 0000000..d3271a0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ba755d592364471fa27430d0b3b2299 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data.meta new file mode 100644 index 0000000..81bb9e9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aabb1122334455667788990011223344 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset new file mode 100644 index 0000000..f117b9f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70e390d14588e72409a6a95aca1461a7, type: 3} + m_Name: IdRegistry_EnemyId + m_EditorClassIdentifier: Aspid.FastTools.Unity::Aspid.FastTools.Ids.IdRegistry + _targetStructType: Aspid.FastTools.Samples.Ids.EnemyId, Aspid.FastTools.Samples.Ids, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _nextId: 5 + _ids: 01000000020000000300000004000000 + _names: + - fly_enemy_dragon + - walk_enemy_goblin + - walk_enemy_orc + - walk_enemy_skeleton diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset.meta new file mode 100644 index 0000000..ae394d4 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/IdRegistry_EnemyId.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b547b6a17aa54f5f8c80dd0aa23d0e2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset new file mode 100644 index 0000000..ba1dde9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e77fd8a034ac6974fb9fa4c49aae4, type: 3} + m_Name: fly_enemy_dragon + m_EditorClassIdentifier: Aspid.FastTools.Samples.Ids::Aspid.FastTools.Samples.Ids.EnemyDefinition + _id: + __stringId: fly_enemy_dragon + _id: 1 + _displayName: Dragon + _maxHealth: 500 + _moveSpeed: 4 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset.meta new file mode 100644 index 0000000..5fa2fe1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/fly_enemy_dragon.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edca3936962f4004af0272178ad75bfd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset new file mode 100644 index 0000000..c258690 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e77fd8a034ac6974fb9fa4c49aae4, type: 3} + m_Name: walk_enemy_goblin + m_EditorClassIdentifier: Aspid.FastTools.Samples.Ids::Aspid.FastTools.Samples.Ids.EnemyDefinition + _id: + __stringId: walk_enemy_goblin + _id: 2 + _displayName: Goblin + _maxHealth: 80 + _moveSpeed: 3.5 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset.meta new file mode 100644 index 0000000..1a10750 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_goblin.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d92adbaedb324bff9fcbe616fbf03416 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset new file mode 100644 index 0000000..91665de --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e77fd8a034ac6974fb9fa4c49aae4, type: 3} + m_Name: walk_enemy_orc + m_EditorClassIdentifier: Aspid.FastTools.Samples.Ids::Aspid.FastTools.Samples.Ids.EnemyDefinition + _id: + __stringId: walk_enemy_orc + _id: 3 + _displayName: Orc + _maxHealth: 150 + _moveSpeed: 2 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset.meta new file mode 100644 index 0000000..5c039b9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_orc.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc61e5b486184ad4b3ed8c54016f6d5f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset new file mode 100644 index 0000000..cbf097d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 953e77fd8a034ac6974fb9fa4c49aae4, type: 3} + m_Name: walk_enemy_skeleton + m_EditorClassIdentifier: Aspid.FastTools.Samples.Ids::Aspid.FastTools.Samples.Ids.EnemyDefinition + _id: + __stringId: walk_enemy_skeleton + _id: 4 + _displayName: Skeleton + _maxHealth: 60 + _moveSpeed: 3 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset.meta new file mode 100644 index 0000000..0de4d09 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Data/walk_enemy_skeleton.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56ba102dc1764873b64e5f7803207cc6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs.meta new file mode 100644 index 0000000..8b71e2a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbcc1122334455667788990011223344 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab new file mode 100644 index 0000000..7963311 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab @@ -0,0 +1,54 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1234567890123456789 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234567890123456789} + - component: {fileID: 3234567890123456789} + m_Layer: 0 + m_Name: Ids + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2234567890123456789 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3234567890123456789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ce0efc593ee24a5d97d8511d669c9de7, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.Ids::Aspid.FastTools.Samples.Ids.EnemySpawner + _catalog: + - {fileID: 11400000, guid: edca3936962f4004af0272178ad75bfd, type: 2} + - {fileID: 11400000, guid: d92adbaedb324bff9fcbe616fbf03416, type: 2} + - {fileID: 11400000, guid: fc61e5b486184ad4b3ed8c54016f6d5f, type: 2} + - {fileID: 11400000, guid: 56ba102dc1764873b64e5f7803207cc6, type: 2} + _spawnTarget: + __stringId: walk_enemy_orc + _id: 3 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab.meta new file mode 100644 index 0000000..059c269 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Prefabs/Ids.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bbe54125698a41cb8a8dab897d567ff8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md new file mode 100644 index 0000000..84c3064 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md @@ -0,0 +1,30 @@ +# Ids Sample + +Demonstrates the `IId` / `IdRegistry` / `[UniqueId]` trio: fields show a human-readable string in the Inspector while serializing as a stable integer, and the Inspector catches collisions at edit-time. + +## How it works + +- `IId` — a marker interface declaring the `int Id { get; }` property. +- `IdRegistry` — a `ScriptableObject` that binds a struct type to a list of `(Id, Name)` entries and keeps the name ↔ int map available at runtime. The property drawer renders a dropdown sourced from this registry. +- `[UniqueId]` — validates at edit-time that no two `ScriptableObject` assets share the same resolved integer ID. + +## Scenario + +An enemy catalog. Each `EnemyDefinition` asset holds a unique `EnemyId` plus display data (`_displayName`, `_maxHealth`, `_moveSpeed`). An `EnemySpawner` picks a target `EnemyId` via dropdown and looks the matching asset up in its catalog on `Start()`. + +Look at: + +- `Scripts/EnemyId.cs` — `partial struct : IId`. `IdStructGenerator` emits `__stringId`, `_id`, and the `Id` property. +- `Scripts/EnemyDefinition.cs:10` — `[UniqueId]` on a serialized `EnemyId` field prevents duplicate IDs across assets. +- `Data/IdRegistry_EnemyId.asset` — the registry binding names (`fly_enemy_dragon`, `walk_enemy_goblin`, `walk_enemy_orc`, `walk_enemy_skeleton`) to stable ints. +- `Scripts/EnemySpawner.cs:9` — dropdown-selected `EnemyId` resolved to `int` at runtime via `.Id`. + +## How to run + +Open `Scenes/Ids.unity` — it contains an `EnemySpawner` GameObject (also available as `Prefabs/Ids.prefab`). Wire it up once: + +1. Drag the four `Data/*_enemy_*.asset` files into the spawner's `Catalog` array. +2. Pick a target enemy from the `Spawn Target` dropdown — the picker is sourced from `IdRegistry_EnemyId`. +3. Enter Play Mode — the Console logs the resolved `EnemyDefinition` (display name, HP, move speed). Switch the dropdown to see different lookups. + +To create more entries, open `Data/IdRegistry_EnemyId.asset` to add registry rows, then `Assets > Create > Aspid > FastTools > Samples > Enemy Definition` for the asset side. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md.meta new file mode 100644 index 0000000..55d313e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 79a0f34c9d7ac4d45a00d0f1a9909de4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md new file mode 100644 index 0000000..4cacef1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md @@ -0,0 +1,30 @@ +# Пример Ids + +Демонстрирует связку `IId` / `IdRegistry` / `[UniqueId]`: поля показывают человекочитаемую строку в Inspector, а сериализуются как стабильное целое число, и Inspector ловит коллизии прямо при редактировании. + +## Как это работает + +- `IId` — маркерный интерфейс, объявляющий свойство `int Id { get; }`. +- `IdRegistry` — `ScriptableObject`, связывающий тип-структуру со списком записей `(Id, Name)` и сохраняющий отображение имя ↔ int доступным во рантайме. Property drawer отрисовывает выпадающий список, источником которого является этот реестр. +- `[UniqueId]` — валидирует во время редактирования, что ни два `ScriptableObject`-актива не имеют одинакового результирующего целочисленного ID. + +## Сценарий + +Каталог врагов. Каждый актив `EnemyDefinition` хранит уникальный `EnemyId` плюс данные для отображения (`_displayName`, `_maxHealth`, `_moveSpeed`). `EnemySpawner` выбирает целевой `EnemyId` через выпадающий список и ищет соответствующий актив в своём каталоге в `Start()`. + +Смотрите: + +- `Scripts/EnemyId.cs` — `partial struct : IId`. `IdStructGenerator` генерирует `__stringId`, `_id` и свойство `Id`. +- `Scripts/EnemyDefinition.cs:10` — `[UniqueId]` на сериализованном поле `EnemyId` предотвращает дублирование ID между активами. +- `Data/IdRegistry_EnemyId.asset` — реестр, связывающий имена (`fly_enemy_dragon`, `walk_enemy_goblin`, `walk_enemy_orc`, `walk_enemy_skeleton`) со стабильными целочисленными значениями. +- `Scripts/EnemySpawner.cs:9` — выбранный из списка `EnemyId`, преобразуется в `int` во время выполнения через `.Id`. + +## Как запустить + +Откройте `Scenes/Ids.unity` — в сцене лежит GameObject `EnemySpawner` (также доступен как `Prefabs/Ids.prefab`). Подключите его один раз: + +1. Перетащите четыре актива `Data/*_enemy_*.asset` в массив `Catalog` спавнера. +2. Выберите цель в выпадающем списке `Spawn Target` — список берётся из `IdRegistry_EnemyId`. +3. Войдите в Play Mode — в Console появится лог найденного `EnemyDefinition` (display name, HP, move speed). Меняйте значение в списке, чтобы увидеть другие варианты поиска. + +Чтобы добавить новые записи, откройте `Data/IdRegistry_EnemyId.asset` для строк реестра и `Assets > Create > Aspid > FastTools > Samples > Enemy Definition` — для соответствующих ассетов. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md.meta new file mode 100644 index 0000000..bdd6ddd --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ad6e4f7081924b3c5d6e7f80910a1b2c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes.meta new file mode 100644 index 0000000..9ba291b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ccdd1122334455667788990011223344 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity similarity index 75% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity index 42337b6..4731c20 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scenes/Visual Elements.unity +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity @@ -119,7 +119,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &1956111 +--- !u!1 &100001 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -127,9 +127,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1956113} - - component: {fileID: 1956112} - - component: {fileID: 1956114} + - component: {fileID: 100003} + - component: {fileID: 100002} + - component: {fileID: 100004} m_Layer: 0 m_Name: Directional Light m_TagString: Untagged @@ -137,22 +137,22 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!108 &1956112 +--- !u!108 &100002 Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} m_Enabled: 1 - serializedVersion: 11 + serializedVersion: 13 m_Type: 1 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 + m_CookieSize2D: {x: 10, y: 10} m_Shadows: m_Type: 2 m_Resolution: -1 @@ -197,18 +197,18 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0 + m_ShapeRadius: 0 m_ShadowAngle: 0 m_LightUnit: 1 m_LuxAtDistance: 1 m_EnableSpotReflector: 1 ---- !u!4 &1956113 +--- !u!4 &100003 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} serializedVersion: 2 m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} @@ -217,13 +217,13 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!114 &1956114 +--- !u!114 &100004 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} @@ -246,7 +246,7 @@ MonoBehaviour: m_ShadowLayerMask: 1 m_RenderingLayers: 1 m_ShadowRenderingLayers: 1 ---- !u!1 &628555577 +--- !u!1 &200001 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -254,10 +254,10 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 628555580} - - component: {fileID: 628555579} - - component: {fileID: 628555578} - - component: {fileID: 628555581} + - component: {fileID: 200004} + - component: {fileID: 200002} + - component: {fileID: 200003} + - component: {fileID: 200005} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -265,21 +265,21 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!81 &628555578 +--- !u!81 &200002 AudioListener: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 ---- !u!20 &628555579 +--- !u!20 &200003 Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 1 @@ -324,13 +324,13 @@ Camera: m_OcclusionCulling: 1 m_StereoConvergence: 10 m_StereoSeparation: 0.022 ---- !u!4 &628555580 +--- !u!4 &200004 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1, z: -10} @@ -339,13 +339,13 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &628555581 +--- !u!114 &200005 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} @@ -383,54 +383,67 @@ MonoBehaviour: m_VarianceClampScale: 0.9 m_ContrastAdaptiveSharpening: 0 m_Version: 2 ---- !u!1 &642957226 -GameObject: +--- !u!1001 &1455822910 +PrefabInstance: m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 642957227} - - component: {fileID: 642957228} - m_Layer: 0 - m_Name: Visual Element Inspector - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &642957227 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 642957226} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -0, y: 0, z: -0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &642957228 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 642957226} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dcfbfa43e527425e8881c33eec85bec3, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp-firstpass::Aspid.UnityFastTools.Samples.VisualElements.VisualElementInspector + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_Name + value: Ids + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: bbe54125698a41cb8a8dab897d567ff8, type: 3} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 m_Roots: - - {fileID: 628555580} - - {fileID: 1956113} - - {fileID: 642957227} + - {fileID: 200004} + - {fileID: 100003} + - {fileID: 1455822910} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity.meta new file mode 100644 index 0000000..bad758d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scenes/Ids.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a978c0327ba8450696b7a546a1c26959 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts.meta new file mode 100644 index 0000000..3926b38 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b48604dab5254cd296df004a49949ff +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Runtime/Aspid.UnityFastTools.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef similarity index 74% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Runtime/Aspid.UnityFastTools.asmdef rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef index f0f15e4..113ba78 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Runtime/Aspid.UnityFastTools.asmdef +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef @@ -1,7 +1,9 @@ { - "name": "Aspid.UnityFastTools", + "name": "Aspid.FastTools.Samples.Ids", "rootNamespace": "", - "references": [], + "references": [ + "Aspid.FastTools.Unity" + ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef.meta new file mode 100644 index 0000000..a62fec6 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/Aspid.FastTools.Samples.Ids.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 34984631d7b44f53aa977da146924369 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs new file mode 100644 index 0000000..7910e72 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs @@ -0,0 +1,22 @@ +using UnityEngine; +using Aspid.FastTools.Ids; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Ids +{ + [CreateAssetMenu(fileName = "New Enemy Definition", menuName = "Aspid/FastTools/Samples/Enemy Definition")] + public class EnemyDefinition : ScriptableObject + { + [UniqueId] + [SerializeField] private EnemyId _id; + + [SerializeField] private string _displayName; + [SerializeField] private int _maxHealth; + [SerializeField] private float _moveSpeed; + + public EnemyId Id => _id; + public string DisplayName => _displayName; + public int MaxHealth => _maxHealth; + public float MoveSpeed => _moveSpeed; + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs.meta new file mode 100644 index 0000000..43009ab --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 953e77fd8a034ac6974fb9fa4c49aae4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs new file mode 100644 index 0000000..632905f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs @@ -0,0 +1,11 @@ +using System; +using Aspid.FastTools.Ids; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Ids +{ + // Declaring `partial struct : IId` triggers IdStructGenerator, which emits __stringId, _id, + // and the Id property — so consumers only ever write the one-liner below. + [Serializable] + public partial struct EnemyId : IId { } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs.meta new file mode 100644 index 0000000..9b79001 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemyId.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d2651027ff84fa5a6f13b1bc0ab8978 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs new file mode 100644 index 0000000..52e3c67 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Ids +{ + public class EnemySpawner : MonoBehaviour + { + [SerializeField] private EnemyDefinition[] _catalog; + [SerializeField] private EnemyId _spawnTarget; + + private void Start() + { + foreach (var enemy in _catalog) + { + if (enemy.Id.Id != _spawnTarget.Id) continue; + + Debug.Log($"Spawning {enemy.DisplayName} — HP: {enemy.MaxHealth}, Speed: {enemy.MoveSpeed}"); + return; + } + + Debug.LogWarning($"No EnemyDefinition found for id {_spawnTarget.Id}"); + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs.meta new file mode 100644 index 0000000..4729ced --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Ids/Scripts/EnemySpawner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce0efc593ee24a5d97d8511d669c9de7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs.meta new file mode 100644 index 0000000..9f9d905 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67e55e4b150b9426293f6e52bf919fdd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab new file mode 100644 index 0000000..d4c819d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab @@ -0,0 +1,46 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1234567890123456789 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234567890123456789} + - component: {fileID: 3234567890123456789} + m_Layer: 0 + m_Name: FrameProfiler + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2234567890123456789 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3234567890123456789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 81773b495ca84416af8f5b4210f650f6, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.ProfilerMarkers::Aspid.FastTools.Samples.ProfilerMarkers.FrameProfiler diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab.meta new file mode 100644 index 0000000..3370b57 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Prefabs/ProfilerMarkers.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4d438180f96141d9b383946bbf647c1c +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md new file mode 100644 index 0000000..098fb27 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md @@ -0,0 +1,61 @@ +# ProfilerMarkers Sample + +Demonstrates the three supported usage forms of `this.Marker()`. In every +form the Aspid.FastTools source generator replaces each call site with a +unique `ProfilerMarker` keyed by `(type, method, line)`. `.WithName(...)` +is optional — when omitted, the generator auto-names the marker after the +enclosing type and method. + +## Supported forms + +1. **Block `using`-statement with an explicit name.** Marker scope is the + block; the full display name is `"{TypeName}.{WithName} ({line})"`, so + pass the short suffix only. + ```csharp + using (this.Marker().WithName("Physics")) // Profiler: "FrameProfiler.Physics ()" + SimulatePhysics(); + ``` +2. **`using`-declaration without `WithName`.** Marker scope is the rest of + the enclosing block; the generator auto-names the marker after the + enclosing method. + ```csharp + using var _ = this.Marker(); // Profiler: "FrameProfiler.SimulateInput ()" + ``` +3. **Combined form.** A method-wide `using`-declaration paired with a + nested `using`-statement — useful when you want one outer marker for the + whole method and a narrower marker around a hot sub-step. Both get + auto-named after the method; their different line numbers produce + distinct Profiler entries. + ```csharp + using var _ = this.Marker(); // Profiler: "FrameProfiler.SimulateAudio ()" + using (this.Marker()) // Profiler: "FrameProfiler.SimulateAudio ()" + { + // Some code. + } + ``` + +## How to run + +1. Open `Scenes/ProfilerMarkers.unity` — it already contains a `FrameProfiler` + GameObject. The `Prefabs/ProfilerMarkers.prefab` variant can be dropped + into your own scenes. +2. Open `Window → Analysis → Profiler`. +3. Enter Play Mode and inspect the CPU track for the named markers. + +## Where to look + +- `Scripts/FrameProfiler.cs:19,22,25` — three top-level markers with explicit + names in `Update` (`FrameProfiler.Physics`, `FrameProfiler.AI`, + `FrameProfiler.Render`). +- `Scripts/FrameProfiler.cs:44` — nested `FrameProfiler.AI.Agent` marker + emitted once per loop iteration in `SimulateAI`, appearing under the `AI` + scope. +- `Scripts/FrameProfiler.cs:68` — `using`-declaration form without `WithName` + in `SimulateInput`; the generator names the marker after the method. +- `Scripts/FrameProfiler.cs:84,87` — combined form in `SimulateAudio`: an + outer method-wide `using`-declaration plus a nested `using`-statement + around `MixAudio()`. + +Every `using` scope (statement or declaration) starts and ends the +generated marker automatically, so the Profiler shows precise self-time +for every phase. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md.meta new file mode 100644 index 0000000..95a29bc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b168656911e1546e5b8b5036803240be +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md new file mode 100644 index 0000000..554a954 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md @@ -0,0 +1,61 @@ +# Пример ProfilerMarkers + +Демонстрирует три поддерживаемые формы вызова `this.Marker()`. В каждой +форме source-генератор Aspid.FastTools заменяет место вызова уникальным +`ProfilerMarker`, привязанным к `(type, method, line)`. `.WithName(...)` +не обязателен — если его не указать, генератор автоматически назовёт +маркер по имени содержащего типа и метода. + +## Поддерживаемые формы + +1. **Блок `using`-statement с явным именем.** Область маркера — блок; + полное отображаемое имя имеет вид `"{TypeName}.{WithName} ({line})"`, + поэтому в `WithName` передавайте только короткий суффикс. + ```csharp + using (this.Marker().WithName("Physics")) // Profiler: "FrameProfiler.Physics ()" + SimulatePhysics(); + ``` +2. **`using`-declaration без `WithName`.** Область маркера — остаток + содержащего блока; генератор именует маркер по имени содержащего + метода. + ```csharp + using var _ = this.Marker(); // Profiler: "FrameProfiler.SimulateInput ()" + ``` +3. **Комбинированная форма.** Метод-широкий `using`-declaration в паре с + вложенным `using`-statement — удобно, когда нужен один внешний маркер + на весь метод и более узкий — на «горячий» подэтап. Оба маркера + получают автоимя по методу; разные номера строк дают разные записи в + Profiler. + ```csharp + using var _ = this.Marker(); // Profiler: "FrameProfiler.SimulateAudio ()" + using (this.Marker()) // Profiler: "FrameProfiler.SimulateAudio ()" + { + // Некоторый код. + } + ``` + +## Как запустить + +1. Откройте `Scenes/ProfilerMarkers.unity` — в сцене уже есть GameObject с + `FrameProfiler`. Вариант `Prefabs/ProfilerMarkers.prefab` можно добавить + в собственные сцены. +2. Откройте `Window → Analysis → Profiler`. +3. Войдите в Play Mode и осмотрите CPU-трек на наличие именованных маркеров. + +## Где смотреть + +- `Scripts/FrameProfiler.cs:19,22,25` — три маркера верхнего уровня с явными + именами в `Update` (`FrameProfiler.Physics`, `FrameProfiler.AI`, + `FrameProfiler.Render`). +- `Scripts/FrameProfiler.cs:44` — вложенный маркер `FrameProfiler.AI.Agent` + в `SimulateAI`, генерируемый раз за итерацию цикла, отображается под + областью `AI`. +- `Scripts/FrameProfiler.cs:68` — форма `using`-declaration без `WithName` + в `SimulateInput`; генератор именует маркер по имени метода. +- `Scripts/FrameProfiler.cs:84,87` — комбинированная форма в + `SimulateAudio`: внешний метод-широкий `using`-declaration плюс + вложенный `using`-statement вокруг `MixAudio()`. + +Каждый блок `using` (statement или declaration) автоматически запускает и +завершает сгенерированный маркер, поэтому Profiler показывает точное +self-time для каждой фазы. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md.meta new file mode 100644 index 0000000..9118597 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9c5d3e6f70819203b4c5d6e7f8091a2b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity similarity index 89% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity index 404b967..750900c 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scenes/Profiler Markers.unity +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity @@ -119,7 +119,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &1956111 +--- !u!1 &100001 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -127,9 +127,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1956113} - - component: {fileID: 1956112} - - component: {fileID: 1956114} + - component: {fileID: 100003} + - component: {fileID: 100002} + - component: {fileID: 100004} m_Layer: 0 m_Name: Directional Light m_TagString: Untagged @@ -137,22 +137,22 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!108 &1956112 +--- !u!108 &100002 Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} m_Enabled: 1 - serializedVersion: 11 + serializedVersion: 13 m_Type: 1 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 + m_CookieSize2D: {x: 10, y: 10} m_Shadows: m_Type: 2 m_Resolution: -1 @@ -197,18 +197,18 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0 + m_ShapeRadius: 0 m_ShadowAngle: 0 m_LightUnit: 1 m_LuxAtDistance: 1 m_EnableSpotReflector: 1 ---- !u!4 &1956113 +--- !u!4 &100003 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} serializedVersion: 2 m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} @@ -217,17 +217,17 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!114 &1956114 +--- !u!114 &100004 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1956111} + m_GameObject: {fileID: 100001} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} - m_Name: + m_Name: m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData m_UsePipelineSettings: 1 m_AdditionalLightsShadowResolutionTier: 2 @@ -246,7 +246,7 @@ MonoBehaviour: m_ShadowLayerMask: 1 m_RenderingLayers: 1 m_ShadowRenderingLayers: 1 ---- !u!1 &628555577 +--- !u!1 &200001 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -254,10 +254,10 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 628555580} - - component: {fileID: 628555579} - - component: {fileID: 628555578} - - component: {fileID: 628555581} + - component: {fileID: 200004} + - component: {fileID: 200002} + - component: {fileID: 200003} + - component: {fileID: 200005} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -265,21 +265,21 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!81 &628555578 +--- !u!81 &200002 AudioListener: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 ---- !u!20 &628555579 +--- !u!20 &200003 Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 1 @@ -324,13 +324,13 @@ Camera: m_OcclusionCulling: 1 m_StereoConvergence: 10 m_StereoSeparation: 0.022 ---- !u!4 &628555580 +--- !u!4 &200004 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1, z: -10} @@ -339,17 +339,17 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &628555581 +--- !u!114 &200005 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 628555577} + m_GameObject: {fileID: 200001} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} - m_Name: + m_Name: m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData m_RenderShadows: 1 m_RequiresDepthTextureOption: 2 @@ -383,7 +383,7 @@ MonoBehaviour: m_VarianceClampScale: 0.9 m_ContrastAdaptiveSharpening: 0 m_Version: 2 ---- !u!1 &642957226 +--- !u!1 &300001 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -391,46 +391,46 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 642957227} - - component: {fileID: 642957228} + - component: {fileID: 300002} + - component: {fileID: 300003} m_Layer: 0 - m_Name: Marker Test + m_Name: FrameProfiler m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &642957227 +--- !u!4 &300002 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 642957226} + m_GameObject: {fileID: 300001} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -0, y: 0, z: -0} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &642957228 +--- !u!114 &300003 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 642957226} + m_GameObject: {fileID: 300001} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 199696d16b85e4112a63975aa9dcfd55, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp-firstpass::Aspid.UnityFastTools.Samples.ProfilerMarkers.MarkerTest + m_Script: {fileID: 11500000, guid: 81773b495ca84416af8f5b4210f650f6, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.ProfilerMarkers::Aspid.FastTools.Samples.ProfilerMarkers.FrameProfiler --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 m_Roots: - - {fileID: 628555580} - - {fileID: 1956113} - - {fileID: 642957227} + - {fileID: 200004} + - {fileID: 100003} + - {fileID: 300002} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity.meta new file mode 100644 index 0000000..7adfa9b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scenes/ProfilerMarkers.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 345b39adb7834b58b853bfeee78228bb +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef new file mode 100644 index 0000000..092138d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Aspid.FastTools.Samples.ProfilerMarkers", + "rootNamespace": "", + "references": [ + "Aspid.FastTools.Unity" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef.meta new file mode 100644 index 0000000..99365ca --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/Aspid.FastTools.Samples.ProfilerMarkers.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 240a32c5c53f4b2dafe608de70ef1eb2 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs new file mode 100644 index 0000000..02b328b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs @@ -0,0 +1,107 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.ProfilerMarkers +{ + public sealed class FrameProfiler : MonoBehaviour + { + [SerializeField] [Min(1)] private int _physicsLoad = 5000; + [SerializeField] [Min(1)] private int _aiAgents = 20; + [SerializeField] [Min(1)] private int _aiStepsPerAgent = 500; + [SerializeField] [Min(1)] private int _renderLoad = 3000; + [SerializeField] [Min(1)] private int _inputLoad = 1500; + [SerializeField] [Min(1)] private int _audioLoad = 2000; + + private void Update() + { + // Every call site of this.Marker() becomes a unique ProfilerMarker. + // Display name: "{TypeName}.{WithName-or-method} ({line})". + using (this.Marker().WithName("Physics")) // Profiler: FrameProfiler.Physics (19) + SimulatePhysics(); + + using (this.Marker().WithName("AI")) // Profiler: FrameProfiler.AI (22) + SimulateAI(); + + using (this.Marker().WithName("Render")) // Profiler: FrameProfiler.Render (25) + SimulateRender(); + + SimulateInput(); + SimulateAudio(); + } + + private void SimulatePhysics() + { + var sum = 0f; + for (var i = 0; i < _physicsLoad; i++) + sum += Mathf.Sqrt(i); + _ = sum; + } + + private void SimulateAI() + { + for (var agent = 0; agent < _aiAgents; agent++) + { + using (this.Marker().WithName("AI.Agent")) // Profiler: FrameProfiler.AI.Agent (44) + StepAgent(); + } + } + + private void StepAgent() + { + var sum = 0f; + for (var i = 0; i < _aiStepsPerAgent; i++) + sum += Mathf.Sin(i); + _ = sum; + } + + private void SimulateRender() + { + var sum = 0f; + for (var i = 0; i < _renderLoad; i++) + sum += Mathf.Cos(i); + _ = sum; + } + + // using-declaration without .WithName(): auto-named after the method. + private void SimulateInput() + { + using var _ = this.Marker(); // Profiler: FrameProfiler.SimulateInput (68) + DoInputWork(); + } + + private void DoInputWork() + { + var sum = 0f; + for (var i = 0; i < _inputLoad; i++) + sum += Mathf.Tan(i); + _ = sum; + } + + // Combined form: outer method-wide using-declaration + nested using-statement. + // Both auto-named after the method; distinct because their line numbers differ. + private void SimulateAudio() + { + using var _ = this.Marker(); // Profiler: FrameProfiler.SimulateAudio (84) + PrepareAudio(); + + using (this.Marker()) // Profiler: FrameProfiler.SimulateAudio (87) + MixAudio(); + } + + private void PrepareAudio() + { + var sum = 0f; + for (var i = 0; i < _audioLoad; i++) + sum += Mathf.Sqrt(i); + _ = sum; + } + + private void MixAudio() + { + var sum = 0f; + for (var i = 0; i < _audioLoad; i++) + sum += Mathf.Cos(i); + _ = sum; + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs.meta new file mode 100644 index 0000000..209bacc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/ProfilerMarkers/Scripts/FrameProfiler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81773b495ca84416af8f5b4210f650f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types.meta new file mode 100644 index 0000000..ccc47fc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5549194b371a41d08e429360a65e08ff +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs.meta new file mode 100644 index 0000000..84e9ac9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7c22acfa3b44fdeba05b6ac683bbc1b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab new file mode 100644 index 0000000..fc0897f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1234567890123456789 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234567890123456789} + - component: {fileID: 3234567890123456789} + m_Layer: 0 + m_Name: AbilitySelector + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2234567890123456789 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3234567890123456789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1234567890123456789} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5c99d520a5f74297b09811a16d0e65fd, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.Types::Aspid.FastTools.Samples.Types.AbilitySelector + _abilityType: + _assemblyQualifiedName: Aspid.FastTools.Samples.Types.Dash, Aspid.FastTools.Samples.Types, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + _modifierTypes: + - Aspid.FastTools.Samples.Types.CooldownReductionModifier, Aspid.FastTools.Samples.Types, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - Aspid.FastTools.Samples.Types.DoubleDamageModifier, Aspid.FastTools.Samples.Types, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + - Aspid.FastTools.Samples.Types.RangeBoostModifier, Aspid.FastTools.Samples.Types, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab.meta new file mode 100644 index 0000000..7a58b3f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/AbilitySelector.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c922b4c1592c4065b541f02f0acc425b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab new file mode 100644 index 0000000..c5d0184 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab @@ -0,0 +1,47 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9120107065992179554 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3305627272239008027} + - component: {fileID: 9066011880317238500} + m_Layer: 0 + m_Name: Enemy + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3305627272239008027 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9120107065992179554} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &9066011880317238500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9120107065992179554} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0667ffc8ad8b4dbba538545a568350f3, type: 3} + m_Name: + m_EditorClassIdentifier: Aspid.FastTools.Samples.Types::Aspid.FastTools.Samples.Types.FastEnemy + _health: 100 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab.meta new file mode 100644 index 0000000..c782e27 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Prefabs/Enemy.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f2ebce908ab18403bbddb4e5101b460a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md new file mode 100644 index 0000000..038dca6 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md @@ -0,0 +1,21 @@ +# Types Sample + +A tiny ability system that demonstrates polymorphic type selection in the Unity Inspector using `SerializableType`, `TypeSelectorAttribute`, and `ComponentTypeSelector`. The player picks an `Ability` subclass and a list of `AbilityModifier` subclasses; enemies use `ComponentTypeSelector` so the concrete enemy script can be hot-swapped from the Inspector. + +Look at: + +- `Scripts/Abilities/AbilitySelector.cs:20` — `SerializableType` field, constrained picker for a single subtype. +- `Scripts/Abilities/AbilitySelector.cs:25` — `[TypeSelector(typeof(AbilityModifier))]` on a `string[]` field. +- `Scripts/Enemies/EnemyBase.cs:18` — `ComponentTypeSelector` declaration that swaps the attached script in place. + +Both Type drawers ship a UIToolkit and an IMGUI rendering path. Parallel `IMGUI*` variants force the IMGUI path so you can compare them side by side or migrate IMGUI-only projects: + +- `Scripts/Abilities/IMGUIAbilitySelector.cs` + `Scripts/Editor/IMGUIAbilitySelectorEditor.cs` — same `SerializableType` / `[TypeSelector]` fields rendered via `OnInspectorGUI`. +- `Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs` (+ `IMGUIFastEnemy`, `IMGUITankEnemy`) + `Scripts/Editor/IMGUIEnemyBaseEditor.cs` — IMGUI counterpart of the `ComponentTypeSelector` swap flow. + +## How to run + +Open `Scenes/Types.unity` — it contains two prefab instances: + +- **AbilitySelector** (`Prefabs/AbilitySelector.prefab`) — an `AbilitySelector` with `Dash` pre-picked and all three modifiers filled in. Enter Play Mode to see the Console log the activated ability and each applied modifier. +- **Enemy** (`Prefabs/Enemy.prefab`) — a `FastEnemy` wired up through `ComponentTypeSelector`. Select it in the Hierarchy and use the type dropdown at the top of the Inspector to swap between `FastEnemy` and `TankEnemy` in place; the `Health` field persists across the swap. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md.meta new file mode 100644 index 0000000..851455a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c7e265c2e7c3641f4bfa4ade9da6a940 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md new file mode 100644 index 0000000..7ebc335 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md @@ -0,0 +1,21 @@ +# Пример Types + +Маленькая система способностей, демонстрирующая полиморфный выбор типа в Unity Inspector с помощью `SerializableType`, `TypeSelectorAttribute` и `ComponentTypeSelector`. Игрок выбирает наследника `Ability` и список наследников `AbilityModifier`; для врагов используется `ComponentTypeSelector`, чтобы конкретный скрипт врага можно было заменить «на лету» из Inspector. + +Смотрите: + +- `Scripts/Abilities/AbilitySelector.cs:20` — поле `SerializableType`, ограниченный выбор одного подтипа. +- `Scripts/Abilities/AbilitySelector.cs:25` — `[TypeSelector(typeof(AbilityModifier))]` на поле `string[]`. +- `Scripts/Enemies/EnemyBase.cs:18` — объявление `ComponentTypeSelector`, заменяющее прикреплённый скрипт по месту. + +Оба Type-drawer’а поддерживают и UIToolkit, и IMGUI. Параллельные `IMGUI*`-варианты принудительно используют IMGUI-путь — удобно для сравнения или миграции IMGUI-проектов: + +- `Scripts/Abilities/IMGUIAbilitySelector.cs` + `Scripts/Editor/IMGUIAbilitySelectorEditor.cs` — те же поля `SerializableType` / `[TypeSelector]`, отрисованные через `OnInspectorGUI`. +- `Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs` (+ `IMGUIFastEnemy`, `IMGUITankEnemy`) + `Scripts/Editor/IMGUIEnemyBaseEditor.cs` — IMGUI-эквивалент потока подмены через `ComponentTypeSelector`. + +## Как запустить + +Откройте `Scenes/Types.unity` — в сцене два prefab-инстанса: + +- **AbilitySelector** (`Prefabs/AbilitySelector.prefab`) — `AbilitySelector` с предвыбранной способностью `Dash` и тремя заполненными модификаторами. Войдите в Play Mode, чтобы увидеть в Console лог активированной способности и каждого применённого модификатора. +- **Enemy** (`Prefabs/Enemy.prefab`) — `FastEnemy`, подключённый через `ComponentTypeSelector`. Выделите его в Hierarchy и используйте выпадающий список выбора типа в верхней части Inspector, чтобы переключиться между `FastEnemy` и `TankEnemy` по месту; значение `Health` сохраняется при замене. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md.meta new file mode 100644 index 0000000..2fee21c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8b4c2d5e6f7081923a4b5c6d7e8f9012 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes.meta new file mode 100644 index 0000000..34e5f9f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity new file mode 100644 index 0000000..dccc62e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity @@ -0,0 +1,507 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &100001 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 100003} + - component: {fileID: 100002} + - component: {fileID: 100004} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &100002 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + m_Enabled: 1 + serializedVersion: 13 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 10, y: 10} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShapeRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &100003 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &100004 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &200001 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 200004} + - component: {fileID: 200002} + - component: {fileID: 200003} + - component: {fileID: 200005} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &200002 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 +--- !u!20 &200003 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &200004 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &200005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200001} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!1001 &970635237 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3305627272239008027, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9120107065992179554, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} + propertyPath: m_Name + value: Enemy + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f2ebce908ab18403bbddb4e5101b460a, type: 3} +--- !u!1001 &1794465240 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_Name + value: AbilitySelector + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2234567890123456789, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: c922b4c1592c4065b541f02f0acc425b, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 200004} + - {fileID: 100003} + - {fileID: 1794465240} + - {fileID: 970635237} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity.meta new file mode 100644 index 0000000..b944dbc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scenes/Types.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a551a863bae542399c669640b76d544b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts.meta new file mode 100644 index 0000000..6a7f9fb --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bb5f0e994a694cc68a6ad846fb3c94e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities.meta new file mode 100644 index 0000000..444e390 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5f15b5a12db04b76a37194e14b45df5d +timeCreated: 1776546281 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs new file mode 100644 index 0000000..f2de744 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public abstract class Ability : MonoBehaviour + { + public abstract void Activate(); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs.meta new file mode 100644 index 0000000..260241d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Ability.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f81a50759684a12a0e30c2af6f84e7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs new file mode 100644 index 0000000..0b8bbd0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs @@ -0,0 +1,55 @@ +using System; +using UnityEngine; +using Aspid.FastTools.Types; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + // Demonstrates two complementary ways to pick a System.Type from the Inspector: + // + // 1. SerializableType — strongly typed wrapper, constrained via generic parameter. + // Resolution is cached; implicit conversion to Type? is free. + // 2. [TypeSelector] + string — annotate a raw string field to get the same picker window. + // Useful when you want multiple base constraints + // or want to opt out of the wrapper allocation. + // + // Both forms store the assembly-qualified name and resolve lazily at first access. + public sealed class AbilitySelector : MonoBehaviour + { + // Picker is constrained to Ability subtypes by the generic argument. + [SerializeField] private SerializableType _abilityType; + + // Array field + attribute: each element is its own picker constrained to AbilityModifier. + // Allow defaults to TypeAllow.None — abstract bases and interfaces are hidden; + // set Allow = TypeAllow.Abstract / Interface / All to opt in. + [TypeSelector(typeof(AbilityModifier))] + [SerializeField] private string[] _modifierTypes; + + private void Start() + { + // .Type performs the lazy GetType() lookup and caches the result. + // Returns null if the stored assembly-qualified name no longer resolves + // (e.g., the type was renamed). + var abilityType = _abilityType.Type; + if (abilityType is null) return; + + // Implicit conversion is guaranteed safe: the picker only offers Ability subtypes. + var ability = (Ability)gameObject.AddComponent(abilityType); + ability.Activate(); + + // Raw-string form: resolve manually via Type.GetType. + // Skip silently on unresolved names to keep the sample self-contained — + // production code should log or surface the missing type. + foreach (var qualifiedName in _modifierTypes) + { + var modifierType = Type.GetType(qualifiedName); + if (modifierType is null) continue; + + // Modifiers are plain C# classes (not components) — Activator.CreateInstance + // is appropriate here; AddComponent would fail for non-UnityEngine.Object types. + var modifier = (AbilityModifier)Activator.CreateInstance(modifierType); + modifier.Apply(); + } + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs.meta new file mode 100644 index 0000000..80bc5b0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/AbilitySelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5c99d520a5f74297b09811a16d0e65fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs new file mode 100644 index 0000000..1002567 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class Dash : Ability + { + public override void Activate() => + Debug.Log("Dash performed!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs.meta new file mode 100644 index 0000000..d5b874d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Dash.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd1b54437b9541c1b53f6820cf40e7a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs new file mode 100644 index 0000000..627fca2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class Fireball : Ability + { + public override void Activate() => + Debug.Log("Fireball launched!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs.meta new file mode 100644 index 0000000..db60c1d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Fireball.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f86571f0dfa54afa89d3e98721bc6c1b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs new file mode 100644 index 0000000..66ca581 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class Heal : Ability + { + public override void Activate() => + Debug.Log("Heal cast!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs.meta new file mode 100644 index 0000000..d3a8bed --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/Heal.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df96ad82595246f284ec3aad4a445e6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs new file mode 100644 index 0000000..ea85607 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using Aspid.FastTools.Types; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + // Demonstrates the IMGUI rendering path for Aspid.FastTools Type drawers. + // + // The same SerializableType and [TypeSelector] fields used by the UIToolkit-based + // AbilitySelector sample are reused here, but the companion editor + // (IMGUIAbilitySelectorEditor) overrides OnInspectorGUI without CreateInspectorGUI, + // forcing Unity to render the inspector — and every nested Type picker — through + // the IMGUI code path (TypeIMGUIPropertyDrawer). + // + // Useful when migrating projects that still rely on IMGUI editors, or when verifying + // that both rendering paths stay visually and behaviourally aligned. + public sealed class IMGUIAbilitySelector : MonoBehaviour + { + // Picker is constrained to Ability subtypes by the generic argument. + [SerializeField] private SerializableType _primaryAbility; + + // Array field + attribute: each element is its own picker constrained to AbilityModifier. + // Allow defaults to TypeAllow.None — abstract bases and interfaces are hidden; + // set Allow = TypeAllow.Abstract / Interface / All to opt in. + [TypeSelector(typeof(AbilityModifier))] + [SerializeField] private string[] _modifierTypes; + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs.meta new file mode 100644 index 0000000..a2cff07 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Abilities/IMGUIAbilitySelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3f17c8b29d04e7eaa2d9a1c75b8e404 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef new file mode 100644 index 0000000..b537bd2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Aspid.FastTools.Samples.Types", + "rootNamespace": "", + "references": [ + "Aspid.FastTools.Unity" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef.meta new file mode 100644 index 0000000..a57965b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Aspid.FastTools.Samples.Types.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 56ba1765a6eb4975ada12506d8c4afda +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor.meta new file mode 100644 index 0000000..89a7efd --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d6a8b3f2c45418792e07c8541b9d2e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef new file mode 100644 index 0000000..a6f07de --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "Aspid.FastTools.Samples.Types.Editor", + "references": [ + "GUID:56ba1765a6eb4975ada12506d8c4afda", + "GUID:7c010b89992542508a6b6189977e64d4", + "GUID:94dcbbdbbd3ca48b891ee4fc8455c434" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef.meta new file mode 100644 index 0000000..20ba97a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/Aspid.FastTools.Samples.Types.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f7b30a1e2c5d4ee0b34c1f2a7e9d4068 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs new file mode 100644 index 0000000..2fad35d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs @@ -0,0 +1,23 @@ +using UnityEditor; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types.Editors +{ + // Forces IMGUI rendering for the IMGUIAbilitySelector inspector. + // + // Unity decides between IMGUI and UIToolkit at the Editor level: when + // CreateInspectorGUI is NOT overridden but OnInspectorGUI is, the entire inspector — + // including every nested PropertyDrawer — falls back to the IMGUI path. That routes + // SerializableType and [TypeSelector] fields through TypeIMGUIPropertyDrawer.OnGUI + // instead of CreatePropertyGUI, demonstrating the IMGUI rendering of the picker. + [CustomEditor(typeof(IMGUIAbilitySelector))] + internal sealed class IMGUIAbilitySelectorEditor : Editor + { + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawPropertiesExcluding(serializedObject, "m_Script"); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs.meta new file mode 100644 index 0000000..08ada24 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIAbilitySelectorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e2c44a7b91f4dc9a06d45f7c81b09a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs new file mode 100644 index 0000000..1a51790 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types.Editors +{ + // Forces IMGUI rendering for IMGUIEnemyBase and every concrete subtype. + // + // editorForChildClasses: true makes this editor apply to IMGUIFastEnemy / IMGUITankEnemy + // too, so swapping the component's m_Script via ComponentTypeSelector keeps the inspector + // in IMGUI mode after Unity rebuilds the editor for the new subtype. Without that flag, + // the post-swap subtype would fall back to the default UIToolkit inspector. + [CustomEditor(typeof(IMGUIEnemyBase), editorForChildClasses: true)] + internal sealed class IMGUIEnemyBaseEditor : Editor + { + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawPropertiesExcluding(serializedObject, "m_Script"); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs.meta new file mode 100644 index 0000000..9a35112 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Editor/IMGUIEnemyBaseEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b7e1d2a5c4f48a3a05e7c41b9d28a36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies.meta new file mode 100644 index 0000000..b27daeb --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7b2295ff4cc94122ad458718856ad4a0 +timeCreated: 1776546314 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs new file mode 100644 index 0000000..fd90625 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using Aspid.FastTools.Types; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + // Demonstrates ComponentTypeSelector: a serialized marker that adds an Inspector + // dropdown letting you swap this component's script to any subtype of EnemyBase + // (FastEnemy, TankEnemy, ...) without removing and re-adding the component. + // + // The picker auto-discovers subtypes via the field's declaring class — no + // configuration needed. Selection rewrites m_Script on the SerializedObject, + // so all fields persist where the new subtype declares a matching name. + public abstract class EnemyBase : MonoBehaviour + { + // The struct itself is empty; it only carries a PropertyDrawer. + // Place one field per root class — typically at the top of the Inspector. + [SerializeField] private ComponentTypeSelector _enemyType; + + [SerializeField] [Min(0)] private float _health = 100f; + + protected float Health => _health; + + public abstract void Attack(); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs.meta new file mode 100644 index 0000000..5877749 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/EnemyBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 171cf8180e114d27bfbbd9e73261652f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs new file mode 100644 index 0000000..1080395 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class FastEnemy : EnemyBase + { + [SerializeField] [Min(0)] private float _speed = 25f; + + public override void Attack() => + Debug.Log("Fast enemy strikes!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs.meta new file mode 100644 index 0000000..bc20a6f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/FastEnemy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0667ffc8ad8b4dbba538545a568350f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI.meta new file mode 100644 index 0000000..d8c9d0e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b5e9a17b3ed13840b378e2bcd037e43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs new file mode 100644 index 0000000..b11c559 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using Aspid.FastTools.Types; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + // Demonstrates the IMGUI rendering path for ComponentTypeSelector. + // + // The mechanic mirrors the EnemyBase / Fast/Tank Enemy hierarchy: a single + // serialized ComponentTypeSelector field surfaces a subtype dropdown in the Inspector, + // and selecting a subtype rewrites m_Script in place — fields with matching names persist. + // + // The companion IMGUIEnemyBaseEditor (with editorForChildClasses: true) overrides + // OnInspectorGUI without CreateInspectorGUI, so every subclass renders through IMGUI + // and the picker goes through ComponentTypeSelectorPropertyDrawer.OnGUI instead of + // CreatePropertyGUI. + public abstract class IMGUIEnemyBase : MonoBehaviour + { + [SerializeField] private ComponentTypeSelector _enemyType; + + [SerializeField] [Min(0)] private float _health = 100f; + + protected float Health => _health; + + public abstract void Attack(); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs.meta new file mode 100644 index 0000000..d77aeda --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIEnemyBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a3b9c7e1d2f48a6b95c3e1d27a8b604 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs new file mode 100644 index 0000000..f0bd5fd --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class IMGUIFastEnemy : IMGUIEnemyBase + { + [SerializeField] [Min(0)] private float _speed = 25f; + + public override void Attack() => + Debug.Log("Fast IMGUI enemy strikes!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs.meta new file mode 100644 index 0000000..6fc9c2e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUIFastEnemy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c8e91a4b73f4d62a85e9f3d7c41b80a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs new file mode 100644 index 0000000..d8ea793 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class IMGUITankEnemy : IMGUIEnemyBase + { + [SerializeField] [Min(0)] private float _armor = 50f; + + public override void Attack() => + Debug.Log("IMGUI tank attacks!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs.meta new file mode 100644 index 0000000..a118ddb --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/IMGUI/IMGUITankEnemy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c5b3e2d1a987456b8e063c41d27a8b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs new file mode 100644 index 0000000..55d9369 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class TankEnemy : EnemyBase + { + [SerializeField] [Min(0)] private float _armor = 50f; + + public override void Attack() => + Debug.Log("Tank attacks!"); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs.meta new file mode 100644 index 0000000..c43eeee --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Enemies/TankEnemy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fbf86c93e134055adf1f2a443bd502c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers.meta new file mode 100644 index 0000000..76fee5e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d74d3a5c5ac44c18858299d4cc480df1 +timeCreated: 1776546333 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs new file mode 100644 index 0000000..8355285 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs @@ -0,0 +1,8 @@ +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public abstract class AbilityModifier + { + public abstract void Apply(); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs.meta new file mode 100644 index 0000000..bab24a3 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/AbilityModifier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 96e6f60018cc4efab26e8543e24da49b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs new file mode 100644 index 0000000..71e1cdc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class CooldownReductionModifier : AbilityModifier + { + public override void Apply() => + Debug.Log($"{nameof(CooldownReductionModifier)} applied."); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs.meta new file mode 100644 index 0000000..2da45e2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/CooldownReductionModifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f3b09571b8549df90b7841e94f07410 +timeCreated: 1776546350 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs new file mode 100644 index 0000000..b57e900 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class DoubleDamageModifier : AbilityModifier + { + public override void Apply() => + Debug.Log($"{nameof(DoubleDamageModifier)} applied."); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs.meta new file mode 100644 index 0000000..20f076e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/DoubleDamageModifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 44b4b7f2062c4b138266c17847aa2b02 +timeCreated: 1776546354 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs new file mode 100644 index 0000000..f83907e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.Types +{ + public sealed class RangeBoostModifier : AbilityModifier + { + public override void Apply() => + Debug.Log($"{nameof(RangeBoostModifier)} applied."); + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs.meta new file mode 100644 index 0000000..93b4b78 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/Types/Scripts/Modifiers/RangeBoostModifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a6d9ae55ba3148508c5c58f03ac9b54e +timeCreated: 1776546345 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements.meta new file mode 100644 index 0000000..efd874d --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd811fb9dcc9c49898350cf0a1f5657e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md new file mode 100644 index 0000000..989c282 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md @@ -0,0 +1,16 @@ +# VisualElements Sample + +A custom UIToolkit Inspector for an `AbilityConfig` ScriptableObject that showcases the fluent `VisualElement` extension API — building a card-style inspector entirely in code, with a status badge that reacts to Mana Cost edits. + +Look at: + +- `Scripts/Editor/AbilityConfigEditor.cs:23` — `CreateInspectorGUI` composes the card from plain `VisualElement` / `Label` / `HelpBox` chained with the Aspid fluent extensions (`.SetPadding`, `.SetBorderRadius`, `.SetBorderColor`, `.SetFlexDirection`, `.AddChild`). +- `Scripts/Editor/AbilityConfigEditor.cs:38` — `target.GetScriptName()` (from `Aspid.FastTools.Editors`) is used as the header title. +- `Scripts/Editor/AbilityConfigEditor.cs:65` — `PropertyField(...).AddValueChanged(_ => UpdateState())` re-runs the badge / help-box logic on every Mana Cost edit. +- `Scripts/Editor/AbilityConfigEditor.cs:88` — `UpdateState()` flips the badge text/color and toggles `helpBox.SetDisplay(...)` whenever `ManaCost is 0`. + +To try it: + +1. Select `ScriptableObjects/fireball_1.asset` (paid) or `ScriptableObjects/fireball_free.asset` in the Project window — the custom inspector appears in the Inspector panel. +2. Edit the fields. Set `Mana Cost` to `0` to see the status badge switch to "FREE" and the warning help box appear inline. +3. Or create your own via `Assets > Create > Aspid > FastTools > Samples > Ability Config`. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md.meta new file mode 100644 index 0000000..5efd556 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4e6850127fdae442c85dc56d37cd070f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md new file mode 100644 index 0000000..13a947c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md @@ -0,0 +1,16 @@ +# Пример VisualElements + +Кастомный UIToolkit Inspector для `ScriptableObject` `AbilityConfig`, демонстрирующий fluent-API расширений `VisualElement` — карточный inspector, собранный целиком в коде, со статус-бейджем, реагирующим на правки Mana Cost. + +Смотрите: + +- `Scripts/Editor/AbilityConfigEditor.cs:23` — `CreateInspectorGUI` собирает карточку из обычных `VisualElement` / `Label` / `HelpBox` с цепочкой Aspid fluent-расширений (`.SetPadding`, `.SetBorderRadius`, `.SetBorderColor`, `.SetFlexDirection`, `.AddChild`). +- `Scripts/Editor/AbilityConfigEditor.cs:38` — `target.GetScriptName()` (из `Aspid.FastTools.Editors`) используется как заголовок шапки. +- `Scripts/Editor/AbilityConfigEditor.cs:65` — `PropertyField(...).AddValueChanged(_ => UpdateState())` перезапускает логику бейджа и help-box при каждой правке Mana Cost. +- `Scripts/Editor/AbilityConfigEditor.cs:88` — `UpdateState()` переключает текст и цвет бейджа и `helpBox.SetDisplay(...)`, когда `ManaCost is 0`. + +Чтобы попробовать: + +1. Выберите `ScriptableObjects/fireball_1.asset` (платная) или `ScriptableObjects/fireball_free.asset` в окне Project — кастомный inspector появится в панели Inspector. +2. Отредактируйте поля. Установите `Mana Cost` в `0`, чтобы увидеть, как статус-бейдж переключится на "FREE", и появится встроенный help box с предупреждением. +3. Или создайте свой через `Assets > Create > Aspid > FastTools > Samples > Ability Config`. diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md.meta new file mode 100644 index 0000000..6807ac1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/README_RU.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: be7f508192a3b4c5d6e7f80910a1b2c3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects.meta new file mode 100644 index 0000000..e8422d2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c3b500b54c6c4141b78263db88a607d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset new file mode 100644 index 0000000..6c086f8 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6, type: 3} + m_Name: fireball_1 + m_EditorClassIdentifier: Aspid.FastTools.Samples.VisualElements::Aspid.FastTools.Samples.VisualElements.AbilityConfig + _abilityName: Fireball + _description: Hurls a ball of fire that explodes on impact. + _manaCost: 100 + _cooldown: 3.5 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset.meta new file mode 100644 index 0000000..7ffe7e5 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47df49f0b76bc4bd38c447548a7dfbee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset new file mode 100644 index 0000000..1d6e18f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6, type: 3} + m_Name: fireball_free + m_EditorClassIdentifier: Aspid.FastTools.Samples.VisualElements::Aspid.FastTools.Samples.VisualElements.AbilityConfig + _abilityName: Fireball - Free + _description: Hurls a ball of fire that explodes on impact. + _manaCost: 0 + _cooldown: 50 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset.meta new file mode 100644 index 0000000..16cf7d9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/ScriptableObjects/fireball_free.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts.meta new file mode 100644 index 0000000..3eb3994 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48284416efb4f482fb664e2ff9dc4f22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs new file mode 100644 index 0000000..50d5bfe --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.VisualElements +{ + [CreateAssetMenu(fileName = "New Ability Config", menuName = "Aspid/FastTools/Samples/Ability Config")] + public sealed class AbilityConfig : ScriptableObject + { + [SerializeField] private string _abilityName = "New Ability"; + [SerializeField] [TextArea] private string _description; + + [SerializeField] [Min(0)] private int _manaCost = 10; + [SerializeField] [Min(0f)] private float _cooldown = 1f; + + public int ManaCost => _manaCost; + + public float Cooldown => _cooldown; + + public string AbilityName => _abilityName; + + public string Description => _description; + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs.meta new file mode 100644 index 0000000..bef311e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/AbilityConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef new file mode 100644 index 0000000..0f91491 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Aspid.FastTools.Samples.VisualElements", + "rootNamespace": "", + "references": [ + "Aspid.FastTools.Unity" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef.meta new file mode 100644 index 0000000..14109c0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Aspid.FastTools.Samples.VisualElements.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6a3c7b14e2f94d71b15d0e8f2f4a1c9d +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor.meta new file mode 100644 index 0000000..f75b2e1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e59e68d2d7da84e24b1c6be44953f34b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs new file mode 100644 index 0000000..e844e62 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs @@ -0,0 +1,103 @@ +using UnityEditor; +using UnityEngine; +using UnityEditor.UIElements; +using UnityEngine.UIElements; +using Aspid.FastTools.Editors; +using Aspid.FastTools.UIElements; +using Aspid.FastTools.UIElements.Editors; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Samples.VisualElements.Editors +{ + [CustomEditor(typeof(AbilityConfig))] + internal sealed class AbilityConfigEditor : Editor + { + private static readonly Color _cardBackground = new(0.16f, 0.17f, 0.19f); + private static readonly Color _cardBorder = new(0.26f, 0.28f, 0.31f); + private static readonly Color _dividerColor = new(0.22f, 0.24f, 0.27f); + private static readonly Color _titleColor = new(0.93f, 0.93f, 0.94f); + private static readonly Color _subtleColor = new(0.58f, 0.61f, 0.66f); + private static readonly Color _accent = new(0.42f, 0.69f, 1.00f); + private static readonly Color _warning = new(1.00f, 0.76f, 0.30f); + + public override VisualElement CreateInspectorGUI() + { + var config = (AbilityConfig)target; + + var statusBadge = new Label() + .SetFontSize(10) + .SetUnityFontStyleAndWeight(FontStyle.Bold) + .SetUnityTextAlign(TextAnchor.MiddleCenter) + .SetLetterSpacing(1) + .SetPadding(top: 3, bottom: 3, left: 10, right: 10) + .SetBorderRadius(10) + .SetBorderWidth(1); + + var titles = new VisualElement() + .SetFlexGrow(1) + .AddChild(new Label(target.GetScriptName()) + .SetColor(_titleColor) + .SetFontSize(15) + .SetUnityFontStyleAndWeight(FontStyle.Bold)) + .AddChild(new Label("ABILITY CONFIGURATION") + .SetColor(_subtleColor) + .SetFontSize(10) + .SetLetterSpacing(2) + .SetMarginTop(3)); + + var header = new VisualElement() + .SetFlexDirection(FlexDirection.Row) + .SetAlignItems(Align.Center) + .SetPadding(top: 12, bottom: 12, left: 14, right: 14) + .AddChild(titles) + .AddChild(statusBadge); + + var divider = new VisualElement() + .SetHeight(1) + .SetBackgroundColor(_dividerColor); + + var helpBox = new HelpBox() + .SetText("This ability costs no mana — is that intentional?") + .SetMessageType(HelpBoxMessageType.Warning) + .SetMarginTop(8) + .SetBorderRadius(6); + + var manaCostField = new PropertyField(serializedObject.FindProperty("_manaCost")) + .AddValueChanged(_ => UpdateState()); + + var body = new VisualElement() + .SetPadding(top: 12, bottom: 12, left: 14, right: 14) + .AddChild(new PropertyField(serializedObject.FindProperty("_abilityName"))) + .AddChild(new PropertyField(serializedObject.FindProperty("_description"))) + .AddChild(new PropertyField(serializedObject.FindProperty("_cooldown"))) + .AddChild(manaCostField) + .AddChild(helpBox); + + var card = new VisualElement() + .SetBackgroundColor(_cardBackground) + .SetBorderColor(_cardBorder) + .SetBorderWidth(1) + .SetBorderRadius(10) + .AddChild(header) + .AddChild(divider) + .AddChild(body); + + UpdateState(); + return card; + + void UpdateState() + { + var manaCost = config.ManaCost; + var isFree = manaCost is 0; + var color = isFree ? _warning : _accent; + + statusBadge + .SetText(isFree ? "FREE" : $"{manaCost} MP") + .SetColor(color) + .SetBorderColor(color); + + helpBox.SetDisplay(isFree ? DisplayStyle.Flex : DisplayStyle.None); + } + } + } +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs.meta new file mode 100644 index 0000000..26a6038 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/AbilityConfigEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scripts/Editor/Aspid.UnityFastTools.VisualElements.Editor.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef similarity index 72% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scripts/Editor/Aspid.UnityFastTools.VisualElements.Editor.asmdef rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef index ad6ee98..7c4ce85 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/VisualElements/Scripts/Editor/Aspid.UnityFastTools.VisualElements.Editor.asmdef +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef @@ -1,10 +1,10 @@ { - "name": "Aspid.UnityFastTools.VisualElements.Editor", - "rootNamespace": "", + "name": "Aspid.FastTools.Samples.VisualElements.Editor", "references": [ + "GUID:d8b63aba1907145bea998dd612889d6b", "GUID:7c010b89992542508a6b6189977e64d4", "GUID:94dcbbdbbd3ca48b891ee4fc8455c434", - "GUID:0acbb74fa21d2442393a327f6c8d5639" + "GUID:6a3c7b14e2f94d71b15d0e8f2f4a1c9d" ], "includePlatforms": [ "Editor" diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef.meta new file mode 100644 index 0000000..1d07f6c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Samples~/VisualElements/Scripts/Editor/Aspid.FastTools.Samples.VisualElements.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8b2f4c9e7a1d4862a97b5f3e1c2d8e7a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source.meta new file mode 100644 index 0000000..cd7ea7a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c1865534b470439a979710a6ee77f7dc +timeCreated: 1772957434 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef new file mode 100644 index 0000000..d15c03b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef @@ -0,0 +1,3 @@ +{ + "name": "Aspid.FastTools" +} diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef.meta similarity index 76% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef.meta index 379034d..ea49f73 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Samples/ProfilerMarkers/Scripts/Aspid.UnityFastTools.ProfilerMarkers.asmdef.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Aspid.FastTools.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 72fb96818833940038502bdd77f5dff9 +guid: c8f809693df904cca816d5d7a67dff48 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions.meta new file mode 100644 index 0000000..64fdaf8 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b03005925b304e1a90f79d4f1bda93bf +timeCreated: 1772957451 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs new file mode 100644 index 0000000..30773f3 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs @@ -0,0 +1,45 @@ +#nullable enable +using System; +using System.Reflection; +using System.Collections.Generic; + +// ReSharper disable once CheckNamespace +namespace Aspid.FastTools.Reflection +{ + public static class TypeExtensions + { + /// + /// Returns the members of and its base classes in declaration order (base → derived), + /// matching the Unity inspector's traversal order. + /// + /// The type to inspect. + /// The binding flags used to filter members. is forced on internally to avoid duplicate members from base classes. + /// Optional ancestor type at which to stop walking the chain. When null, walks all the way to the root type. + /// A flat list of instances ordered from the topmost base class down to . + public static IReadOnlyList GetMembersInfosIncludingBaseClasses(this Type type, BindingFlags bindingFlags, Type? stopAt = null) + { + var currentType = type; + var typeChain = new List(); + + while (currentType != stopAt) + { + if (currentType is null) break; + + typeChain.Add(currentType); + currentType = currentType.BaseType; + } + + // Iterate base → derived so members appear in declaration order (matches Unity inspector) + typeChain.Reverse(); + + if (!bindingFlags.HasFlag(BindingFlags.DeclaredOnly)) + bindingFlags |= BindingFlags.DeclaredOnly; + + var members = new List(); + foreach (var t in typeChain) + members.AddRange(t.GetMembers(bindingFlags)); + + return members; + } + } +} diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Editor/IMGUI/AspidEditorGUILayout.cs.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs.meta similarity index 64% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Editor/IMGUI/AspidEditorGUILayout.cs.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs.meta index 13fe3e3..efd43cd 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Editor/IMGUI/AspidEditorGUILayout.cs.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Source/Extensions/TypeExtensions.cs.meta @@ -1,11 +1,11 @@ fileFormatVersion: 2 -guid: f7b5767a90834361a58536b70283e74b +guid: 6dcae9cf24b04569bd40b0f0224b715c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {fileID: 2800000, guid: daa63609570f146cfa1b178f6d6c8bda, type: 3} + icon: {fileID: 2800000, guid: 2d380e9402a9f4c5b8eb637f9f40c400, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity.meta diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Editor.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor.meta similarity index 100% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Source/Editor.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor.meta diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources.meta new file mode 100644 index 0000000..915c6e0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c03e99f7975a44b6ae45192a73b498e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons.meta new file mode 100644 index 0000000..8e8cf88 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 13b76b63bb7a462f8956f3eee824d2e4 +timeCreated: 1777461222 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png new file mode 100644 index 0000000..444a013 Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png differ diff --git a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Resources/Editor/Aspid.UnityFastTools Icon.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png.meta similarity index 98% rename from Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Resources/Editor/Aspid.UnityFastTools Icon.png.meta rename to Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png.meta index 91a7f78..97b77e5 100644 --- a/Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Resources/Editor/Aspid.UnityFastTools Icon.png.meta +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_blue_1020x1008.png.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: daa63609570f146cfa1b178f6d6c8bda +guid: 16cb73b44172a4ea9bf2d058c90a9614 TextureImporter: internalIDToNameTable: [] externalObjects: {} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png new file mode 100644 index 0000000..5875c9b Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png.meta new file mode 100644 index 0000000..f447b5a --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_green_1020x1008.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: 2d380e9402a9f4c5b8eb637f9f40c400 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png new file mode 100644 index 0000000..161865f Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png.meta new file mode 100644 index 0000000..2103427 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_red_1020x1008.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: ec5938e9935444547813083d1e9c6392 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png new file mode 100644 index 0000000..1114ab5 Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png.meta new file mode 100644 index 0000000..730f0d1 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/aspid_icon_medium_yellow_1020x1008.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: 45e1e8af6ec4a47f192980d99bf0dbb9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png new file mode 100644 index 0000000..249989d Binary files /dev/null and b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png differ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png.meta new file mode 100644 index 0000000..8bdde85 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/Icons/open_button_icon.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: 3666b4404e4ca46f3b92a61a42a557ba +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI.meta new file mode 100644 index 0000000..b97b6de --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a96d1d061b50406a82df4b7fda53a110 +timeCreated: 1777206331 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss new file mode 100644 index 0000000..2c59e3c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss @@ -0,0 +1,386 @@ +:root { + /* ---------------------------------- ICONS ---------------------------------- */ + --aspid-icons-status-success: resource("Icons/aspid_icon_medium_green_1020x1008"); + --aspid-icons-status-warning: resource("Icons/aspid_icon_medium_yellow_1020x1008"); + --aspid-icons-status-error: resource("Icons/aspid_icon_medium_red_1020x1008"); + --aspid-icons-status-info: resource("Icons/aspid_icon_medium_blue_1020x1008"); + + /* ------------------------------- BACKGROUNDS ------------------------------- */ + --aspid-colors-bg-darkness: rgb(26, 26, 26); /* #1A1A1A */ + --aspid-colors-bg-dark: rgb(36, 36, 36); /* #242424 */ + --aspid-colors-bg-light: rgb(46, 46, 46); /* #2E2E2E */ + --aspid-colors-bg-lightness: rgb(56, 56, 56); /* #383838 */ + + /* ---------------------- TEXT: GENERAL (High Contrast) ---------------------- */ + --aspid-colors-text-lightness: rgb(220, 220, 220); /* #DCDCDC */ + --aspid-colors-text-light: rgb(190, 190, 190); /* #BEBEBE */ + --aspid-colors-text-dark: rgb(150, 150, 150); /* #969696 */ + --aspid-colors-text-darkness: rgb(110, 110, 110); /* #6E6E6E */ + + /* -------------------- SHADES: GENERAL (Lines & Borders) -------------------- */ + --aspid-colors-shade-darkness: rgb(45, 45, 45); /* #2D2D2D */ + --aspid-colors-shade-dark: rgb(60, 60, 60); /* #3C3C3C */ + --aspid-colors-shade-light: rgb(80, 80, 80); /* #505050 */ + --aspid-colors-shade-lightness: rgb(100, 100, 100); /* #646464 */ + + /* ---------------- STATUS: BACKGROUNDS (Deep Gemstone Bases) ---------------- */ + --aspid-colors-status-success-darkness: rgb(8, 40, 20); /* #082814 */ + --aspid-colors-status-success-dark: rgb(12, 65, 30); /* #0C411E */ + --aspid-colors-status-success-light: rgb(20, 90, 45); /* #145A2D */ + --aspid-colors-status-success-lightness: rgb(30, 120, 60); /* #1E783C */ + + --aspid-colors-status-warning-darkness: rgb(45, 30, 5); /* #2D1E05 */ + --aspid-colors-status-warning-dark: rgb(85, 55, 10); /* #55370A */ + --aspid-colors-status-warning-light: rgb(125, 85, 20); /* #7D5514 */ + --aspid-colors-status-warning-lightness: rgb(165, 115, 30); /* #A5731E */ + + --aspid-colors-status-error-darkness: rgb(50, 10, 10); /* #320A0A */ + --aspid-colors-status-error-dark: rgb(85, 20, 20); /* #551414 */ + --aspid-colors-status-error-light: rgb(125, 35, 35); /* #7D2323 */ + --aspid-colors-status-error-lightness: rgb(165, 50, 50); /* #A53232 */ + + --aspid-colors-status-info-darkness: rgb(8, 25, 50); /* #081932 */ + --aspid-colors-status-info-dark: rgb(15, 45, 85); /* #0F2D55 */ + --aspid-colors-status-info-light: rgb(25, 75, 130); /* #194B82 */ + --aspid-colors-status-info-lightness: rgb(35, 105, 180); /* #2369B4 */ + + /* --------------- STATUS ACCENTS: TEXT (Gemstone Brilliance) ---------------- */ + --aspid-colors-status-success-text-darkness: rgb(55, 110, 65); /* #376E41 */ + --aspid-colors-status-success-text-dark: rgb(85, 175, 100); /* #55AF64 */ + --aspid-colors-status-success-text-light: rgb(120, 235, 145); /* #78EB91 */ + --aspid-colors-status-success-text-lightness: rgb(180, 255, 200); /* #B4FFC8 */ + + --aspid-colors-status-warning-text-darkness: rgb(120, 85, 35); /* #785523 */ + --aspid-colors-status-warning-text-dark: rgb(185, 135, 60); /* #B9873C */ + --aspid-colors-status-warning-text-light: rgb(245, 185, 85); /* #F5B955 */ + --aspid-colors-status-warning-text-lightness: rgb(255, 235, 175); /* #FFEBAF */ + + --aspid-colors-status-error-text-darkness: rgb(125, 45, 45); /* #7D2D2D */ + --aspid-colors-status-error-text-dark: rgb(185, 65, 65); /* #B94141 */ + --aspid-colors-status-error-text-light: rgb(235, 95, 95); /* #EB5F5F */ + --aspid-colors-status-error-text-lightness: rgb(255, 175, 175); /* #FFAFAF */ + + --aspid-colors-status-info-text-darkness: rgb(40, 80, 125); /* #28507D */ + --aspid-colors-status-info-text-dark: rgb(65, 130, 185); /* #4182B9 */ + --aspid-colors-status-info-text-light: rgb(90, 185, 240); /* #5AB9F0 */ + --aspid-colors-status-info-text-lightness: rgb(190, 240, 255); /* #BEF0FF */ + + /* ---------------- STATUS ACCENTS: SHADES (Muted Gemstones) ----------------- */ + --aspid-colors-status-success-shade-darkness: rgb(25, 55, 30); /* #19371E */ + --aspid-colors-status-success-shade-dark: rgb(40, 85, 50); /* #285532 */ + --aspid-colors-status-success-shade-light: rgb(65, 130, 80); /* #418250 */ + --aspid-colors-status-success-shade-lightness: rgb(95, 190, 115); /* #5FBE73 */ + + --aspid-colors-status-warning-shade-darkness: rgb(55, 40, 20); /* #372814 */ + --aspid-colors-status-warning-shade-dark: rgb(90, 65, 30); /* #5A411E */ + --aspid-colors-status-warning-shade-light: rgb(135, 100, 50); /* #876432 */ + --aspid-colors-status-warning-shade-lightness: rgb(185, 140, 75); /* #B98C4B */ + + --aspid-colors-status-error-shade-darkness: rgb(55, 25, 25); /* #371919 */ + --aspid-colors-status-error-shade-dark: rgb(90, 45, 45); /* #5A2D2D */ + --aspid-colors-status-error-shade-light: rgb(135, 65, 65); /* #874141 */ + --aspid-colors-status-error-shade-lightness: rgb(190, 95, 95); /* #BE5F5F */ + + --aspid-colors-status-info-shade-darkness: rgb(20, 35, 55); /* #142337 */ + --aspid-colors-status-info-shade-dark: rgb(35, 65, 95); /* #23415F */ + --aspid-colors-status-info-shade-light: rgb(55, 100, 145); /* #376491 */ + --aspid-colors-status-info-shade-lightness: rgb(85, 145, 200); /* #5591C8 */ +} + +.aspid-fasttools-inspector-container { + margin-left: -10px; +} + +.aspid-fasttools-inspector-container .unity-property-field__inspector-property .unity-base-field__inspector-field { + margin-left: 0; + margin-right: 0; +} + +.aspid-fasttools-inspector-container .unity-property-field__inspector-property Toggle.unity-base-field__inspector-field { + margin-left: -1px; +} + +/* -------------------------------------------------- BACKGROUNDS --------------------------------------------------- */ +.aspid-fasttools-background { } + +.aspid-fasttools-background--rounded { + padding: 10px; + border-radius: 10px; +} + +.aspid-fasttools-background.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-bg-darkness); +} + +.aspid-fasttools-background.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-bg-dark); +} + +.aspid-fasttools-background.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-bg-light); +} + +.aspid-fasttools-background.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-bg-lightness); +} + +/* -------------------------------- SUCCESS: BACKGROUNDS -------------------------------- */ +.aspid-fasttools-background.aspid-fasttools-theme--darkness.aspid-fasttools-status--success { + background-color: var(--aspid-colors-status-success-darkness); +} + +.aspid-fasttools-background.aspid-fasttools-theme--dark.aspid-fasttools-status--success { + background-color: var(--aspid-colors-status-success-dark); +} + +.aspid-fasttools-background.aspid-fasttools-theme--light.aspid-fasttools-status--success { + background-color: var(--aspid-colors-status-success-light); +} + +.aspid-fasttools-background.aspid-fasttools-theme--lightness.aspid-fasttools-status--success { + background-color: var(--aspid-colors-status-success-lightness); +} + +/* -------------------------------- WARNING: BACKGROUNDS -------------------------------- */ +.aspid-fasttools-background.aspid-fasttools-theme--darkness.aspid-fasttools-status--warning { + background-color: var(--aspid-colors-status-warning-darkness); +} + +.aspid-fasttools-background.aspid-fasttools-theme--dark.aspid-fasttools-status--warning { + background-color: var(--aspid-colors-status-warning-dark); +} + +.aspid-fasttools-background.aspid-fasttools-theme--light.aspid-fasttools-status--warning { + background-color: var(--aspid-colors-status-warning-light); +} + +.aspid-fasttools-background.aspid-fasttools-theme--lightness.aspid-fasttools-status--warning { + background-color: var(--aspid-colors-status-warning-lightness); +} + +/* --------------------------------- ERROR: BACKGROUNDS --------------------------------- */ +.aspid-fasttools-background.aspid-fasttools-theme--darkness.aspid-fasttools-status--error { + background-color: var(--aspid-colors-status-error-darkness); +} + +.aspid-fasttools-background.aspid-fasttools-theme--dark.aspid-fasttools-status--error { + background-color: var(--aspid-colors-status-error-dark); +} + +.aspid-fasttools-background.aspid-fasttools-theme--light.aspid-fasttools-status--error { + background-color: var(--aspid-colors-status-error-light); +} + +.aspid-fasttools-background.aspid-fasttools-theme--lightness.aspid-fasttools-status--error { + background-color: var(--aspid-colors-status-error-lightness); +} + +/* --------------------------------- INFO: BACKGROUNDS ---------------------------------- */ +.aspid-fasttools-background.aspid-fasttools-theme--darkness.aspid-fasttools-status--info { + background-color: var(--aspid-colors-status-info-darkness); +} + +.aspid-fasttools-background.aspid-fasttools-theme--dark.aspid-fasttools-status--info { + background-color: var(--aspid-colors-status-info-dark); +} + +.aspid-fasttools-background.aspid-fasttools-theme--light.aspid-fasttools-status--info { + background-color: var(--aspid-colors-status-info-light); +} + +.aspid-fasttools-background.aspid-fasttools-theme--lightness.aspid-fasttools-status--info { + background-color: var(--aspid-colors-status-info-lightness); +} +/*--------------------------------------------------------------------------------------------------------------------*/ + +/* ---------------------------------------------------- LABELS ------------------------------------------------------ */ +Label.aspid-fasttools-theme--darkness { + color: var(--aspid-colors-text-darkness); +} + +Label.aspid-fasttools-theme--dark { + color: var(--aspid-colors-text-dark); +} + +Label.aspid-fasttools-theme--light { + color: var(--aspid-colors-text-light); +} + +Label.aspid-fasttools-theme--lightness { + color: var(--aspid-colors-text-lightness); +} + +/* ------------------------ SUCCESS: LABELS ------------------------*/ +Label.aspid-fasttools-theme--darkness.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-darkness); +} + +Label.aspid-fasttools-theme--dark.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-dark); +} + +Label.aspid-fasttools-theme--light.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-light); +} + +Label.aspid-fasttools-theme--lightness.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-lightness); +} + +/* ------------------------ WARNING: LABELS ------------------------*/ +Label.aspid-fasttools-theme--darkness.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-darkness); +} + +Label.aspid-fasttools-theme--dark.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-dark); +} + +Label.aspid-fasttools-theme--light.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-light); +} + +Label.aspid-fasttools-theme--lightness.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-lightness); +} + +/* ------------------------- ERROR: LABELS -------------------------*/ +Label.aspid-fasttools-theme--darkness.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-darkness); +} + +Label.aspid-fasttools-theme--dark.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-dark); +} + +Label.aspid-fasttools-theme--light.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-light); +} + +Label.aspid-fasttools-theme--lightness.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-lightness); +} + +/* ------------------------- INFO: LABELS --------------------------*/ +Label.aspid-fasttools-theme--darkness.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-darkness); +} + +Label.aspid-fasttools-theme--dark.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-dark); +} + +Label.aspid-fasttools-theme--light.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-light); +} + +Label.aspid-fasttools-theme--lightness.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-lightness); +} +/*--------------------------------------------------------------------------------------------------------------------*/ + +/* --------------------------------------------------- BUTTONS ------------------------------------------------------ */ +Button.aspid-fasttools-theme--darkness { + color: var(--aspid-colors-text-darkness); + background-color: var(--aspid-colors-bg-darkness); +} + +Button.aspid-fasttools-theme--dark { + color: var(--aspid-colors-text-dark); + background-color: var(--aspid-colors-bg-dark); +} + +Button.aspid-fasttools-theme--light { + color: var(--aspid-colors-text-light); + background-color: var(--aspid-colors-bg-lightness); +} + +Button.aspid-fasttools-theme--lightness { + color: var(--aspid-colors-text-lightness); + background-color: var(--aspid-colors-bg-lightness); +} + +/* ----------------------- SUCCESS: BUTTONS ------------------------*/ +Button.aspid-fasttools-theme--darkness.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-darkness); + background-color: var(--aspid-colors-status-success-darkness); +} + +Button.aspid-fasttools-theme--dark.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-dark); + background-color: var(--aspid-colors-status-success-dark); +} + +Button.aspid-fasttools-theme--light.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-light); + background-color: var(--aspid-colors-status-success-light); +} + +Button.aspid-fasttools-theme--lightness.aspid-fasttools-status--success { + color: var(--aspid-colors-status-success-text-lightness); + background-color: var(--aspid-colors-status-success-lightness); +} + +/* ----------------------- WARNING: BUTTONS ------------------------*/ +Button.aspid-fasttools-theme--darkness.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-darkness); + background-color: var(--aspid-colors-status-warning-darkness); +} + +Button.aspid-fasttools-theme--dark.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-dark); + background-color: var(--aspid-colors-status-warning-dark); +} + +Button.aspid-fasttools-theme--light.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-light); + background-color: var(--aspid-colors-status-warning-light); +} + +Button.aspid-fasttools-theme--lightness.aspid-fasttools-status--warning { + color: var(--aspid-colors-status-warning-text-lightness); + background-color: var(--aspid-colors-status-warning-lightness); +} + +/* ------------------------ ERROR: BUTTONS -------------------------*/ +Button.aspid-fasttools-theme--darkness.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-darkness); + background-color: var(--aspid-colors-status-error-darkness); +} + +Button.aspid-fasttools-theme--dark.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-dark); + background-color: var(--aspid-colors-status-error-dark); +} + +Button.aspid-fasttools-theme--light.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-light); + background-color: var(--aspid-colors-status-error-light); +} + +Button.aspid-fasttools-theme--lightness.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-lightness); + background-color: var(--aspid-colors-status-error-lightness); +} + +/* ------------------------ INFO: BUTTONS --------------------------*/ +Button.aspid-fasttools-theme--darkness.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-darkness); + background-color: var(--aspid-colors-status-info-darkness); +} + +Button.aspid-fasttools-theme--dark.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-dark); + background-color: var(--aspid-colors-status-info-dark); +} + +Button.aspid-fasttools-theme--light.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-light); + background-color: var(--aspid-colors-status-info-light); +} + +Button.aspid-fasttools-theme--lightness.aspid-fasttools-status--info { + color: var(--aspid-colors-status-info-text-lightness); + background-color: var(--aspid-colors-status-info-lightness); +} +/*--------------------------------------------------------------------------------------------------------------------*/ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss.meta new file mode 100644 index 0000000..7f52e45 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Aspid-FastTools-Default-Dark.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a58072b37b804991bbb887d0fd65e2f8 +timeCreated: 1775572843 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components.meta new file mode 100644 index 0000000..cc95912 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 96c5e18e9327448f9fb6ab17cd214d0c +timeCreated: 1777206343 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss new file mode 100644 index 0000000..8717fe6 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss @@ -0,0 +1,15 @@ +:root { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: absolute; + + --aspid-fasttools-colors-dot_blob-color_1: var(--aspid-colors-status-success-text-dark); + --aspid-fasttools-colors-dot_blob-color_2: var(--aspid-colors-status-warning-text-dark); + --aspid-fasttools-colors-dot_blob-color_3: var(--aspid-colors-status-error-text-dark); + + --aspid-fasttools-metrics-dot_radius: 1.55; + --aspid-fasttools-metrics-dot_spacing: 18; + --aspid-fasttools-metrics-dot_scale_reference: 420; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss.meta new file mode 100644 index 0000000..f38c2f6 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedDotsBackground.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b49b2ab57fd74e35bd5d3cbfdec0df23 +timeCreated: 1777155817 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss new file mode 100644 index 0000000..6e8ed5e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss @@ -0,0 +1,19 @@ +:root { + --aspid-fasttools-prop-animated_logo-pulse_speed: 5; + --aspid-fasttools-prop-animated_logo-pulse_hover_amplitude: 0.04; +} + +.aspid-fasttools-animated-logo__layer { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0; + transition-duration: 1.4s; + transition-timing-function: ease-in-out; +} + +.aspid-fasttools-animated-logo__layer--visible { + opacity: 1; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss.meta new file mode 100644 index 0000000..5f97430 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedLogo.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: db3a67c313db1432ead5570e0907cdbe +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss new file mode 100644 index 0000000..231ebba --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss @@ -0,0 +1,23 @@ +:root { + flex-direction: row; + flex-wrap: wrap; + + --aspid-fasttools-prop-animated_title-color_stride: 0.12; + --aspid-fasttools-prop-animated_title-color_speed: 0.4; + --aspid-fasttools-prop-animated_title-wave_stride: 0.55; + --aspid-fasttools-prop-animated_title-wave_speed: 1.6; + --aspid-fasttools-prop-animated_title-wave_amplitude: 3; + + --aspid-fasttools-colors-animated_title-color_1: var(--aspid-colors-status-success-text-dark); + --aspid-fasttools-colors-animated_title-color_2: var(--aspid-colors-status-warning-text-dark); + --aspid-fasttools-colors-animated_title-color_3: var(--aspid-colors-status-error-text-dark); +} + +.aspid-fasttools-animated-title__word { + margin-right: 14px; + flex-direction: row; +} + +.aspid-fasttools-animated-title__word > Label { + padding: 0; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss.meta new file mode 100644 index 0000000..b8d3ac9 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidAnimatedTitle.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 904e5346298574aad9c72c548d6081cc +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss new file mode 100644 index 0000000..2acfd21 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss @@ -0,0 +1,3 @@ +:root { + flex-grow: 1; +} \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss.meta new file mode 100644 index 0000000..a2dc0b2 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidBox.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6ccaac2029f54f82bbad6b8a29d72276 +timeCreated: 1777385488 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss new file mode 100644 index 0000000..d28b0ac --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss @@ -0,0 +1,127 @@ +:root { + flex-grow: 1; + display: none; + flex-shrink: 0; +} + +.aspid-fasttools-dividing-line--thin.aspid-fasttools-dividing-line--vertical { + width: 1px; + min-width: 1px; + max-width: 1px; + display: flex; +} + +.aspid-fasttools-dividing-line--medium.aspid-fasttools-dividing-line--vertical { + width: 2px; + min-width: 2px; + max-width: 2px; + display: flex; +} + +.aspid-fasttools-dividing-line--bold.aspid-fasttools-dividing-line--vertical { + width: 3px; + min-width: 3px; + max-width: 3px; + display: flex; +} + +.aspid-fasttools-dividing-line--thin.aspid-fasttools-dividing-line--horizontal { + height: 1px; + min-height: 1px; + max-height: 1px; + display: flex; +} + +.aspid-fasttools-dividing-line--medium.aspid-fasttools-dividing-line--horizontal { + height: 2px; + min-height: 2px; + max-height: 2px; + display: flex; +} + +.aspid-fasttools-dividing-line--bold.aspid-fasttools-dividing-line--horizontal { + height: 3px; + min-height: 3px; + max-height: 3px; + display: flex; +} + +.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-shade-darkness); +} + +.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-shade-dark); +} + +.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-shade-light); +} + +.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-shade-lightness); +} + +.aspid-fasttools-status--success.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-status-success-shade-darkness); +} + +.aspid-fasttools-status--success.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-status-success-shade-dark); +} + +.aspid-fasttools-status--success.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-status-success-shade-light); +} + +.aspid-fasttools-status--success.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-status-success-shade-lightness); +} + +.aspid-fasttools-status--warning.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-status-warning-shade-darkness); +} + +.aspid-fasttools-status--warning.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-status-warning-shade-dark); +} + +.aspid-fasttools-status--warning.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-status-warning-shade-light); +} + +.aspid-fasttools-status--warning.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-status-warning-shade-lightness); +} + +.aspid-fasttools-status--error.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-status-error-shade-darkness); +} + +.aspid-fasttools-status--error.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-status-error-shade-dark); +} + +.aspid-fasttools-status--error.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-status-error-shade-light); +} + +.aspid-fasttools-status--error.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-status-error-shade-lightness); +} + +.aspid-fasttools-status--info.aspid-fasttools-theme--darkness { + background-color: var(--aspid-colors-status-info-shade-darkness); +} + +.aspid-fasttools-status--info.aspid-fasttools-theme--dark { + background-color: var(--aspid-colors-status-info-shade-dark); +} + +.aspid-fasttools-status--info.aspid-fasttools-theme--light { + background-color: var(--aspid-colors-status-info-shade-light); +} + +.aspid-fasttools-status--info.aspid-fasttools-theme--lightness { + background-color: var(--aspid-colors-status-info-shade-lightness); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss.meta new file mode 100644 index 0000000..d821d66 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidDividingLine.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9d78d5a4719442e6a8a4dcecfb88191e +timeCreated: 1777229664 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss new file mode 100644 index 0000000..00d6e7b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss @@ -0,0 +1,21 @@ +:root { + color: var(--aspid-colors-text-light); + height: 30px; + margin: 0 0 5px 0; + padding: 0 10px; + overflow: hidden; + font-size: 14px; + border-width: 0; + border-radius: 10px; + flex-direction: row; + -unity-font-style: bold; + -unity-text-align: middle-left; + + --aspid-fasttools-colors-gradient-button-bg: var(--aspid-colors-bg-darkness); + --aspid-fasttools-colors-gradient-button-accent: var(--aspid-colors-status-success-text-dark); +} + +.aspid-fasttools-gradient-button__trailing-label { + margin-left: 10px; + -unity-text-align: middle-right; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss.meta new file mode 100644 index 0000000..8a2ea1e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidGradientButton.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fad030e63d05f4f058e0c736e8f3e22a +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss new file mode 100644 index 0000000..19ada11 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss @@ -0,0 +1,84 @@ +:root { + padding: 8px 12px; + border-width: 1px; + border-radius: 8px; + flex-direction: row; + align-items: center; + background-color: var(--aspid-colors-bg-dark); + border-color: var(--aspid-colors-shade-light); +} + +:root.aspid-fasttools-status--success { + background-color: var(--aspid-colors-status-success-light); + border-color: var(--aspid-colors-status-success-shade-lightness); +} + +:root.aspid-fasttools-status--warning { + background-color: var(--aspid-colors-status-warning-light); + border-color: var(--aspid-colors-status-warning-shade-lightness); +} + +:root.aspid-fasttools-status--error { + background-color: var(--aspid-colors-status-error-light); + border-color: var(--aspid-colors-status-error-shade-lightness); +} + +:root.aspid-fasttools-status--info { + background-color: var(--aspid-colors-status-info-light); + border-color: var(--aspid-colors-status-info-shade-lightness); +} + +/* --- ICON --- */ +.aspid-fasttools-help-box__icon { + min-width: 34px; + max-width: 34px; + min-height: 32px; + max-height: 32px; + margin-right: 9px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + background-image: var(--aspid-fasttools-icons-help-box); +} + +.aspid-fasttools-help-box__icon--hidden { + display: none; +} + +:root.aspid-fasttools-help-box--info { + --aspid-fasttools-icons-help-box: resource("d_console.infpicon@2x"); +} + +:root.aspid-fasttools-help-box--warning { + --aspid-fasttools-icons-help-box: resource("d_console.warnicon@2x"); +} + +:root.aspid-fasttools-help-box--error { + --aspid-fasttools-icons-help-box: resource("d_console.erroricon@2x"); +} + +/* --- TEXT --- */ +.aspid-fasttools-help-box__text-container { + flex-grow: 1; +} + +:root AspidLabel > Label { + cursor: text; + overflow: hidden; +} + +:root.aspid-fasttools-status--success AspidLabel > Label { + color: var(--aspid-colors-status-success-text-lightness); +} + +:root.aspid-fasttools-status--warning AspidLabel > Label { + color: var(--aspid-colors-status-warning-text-lightness); +} + +:root.aspid-fasttools-status--error AspidLabel > Label { + color: var(--aspid-colors-status-error-text-lightness); +} + +:root.aspid-fasttools-status--info AspidLabel > Label { + color: var(--aspid-colors-status-info-text-lightness); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss.meta new file mode 100644 index 0000000..01883be --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHelpBox.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ceaba8591b4d348ba998c9d124cf708c +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss new file mode 100644 index 0000000..e795fe7 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss @@ -0,0 +1,13 @@ +:root { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + + --aspid-fasttools-colors-hover_overlay: rgba(0, 0, 0, 0); + + --aspid-fasttools-metrics-hover_overlay_steps: 75; + --aspid-fasttools-metrics-hover_overlay_lerp_rate: 0.12; + --aspid-fasttools-metrics-hover_overlay_alpha_scale: 0.35; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss.meta new file mode 100644 index 0000000..f4726fb --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidHoverGradientOverlay.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8eca34af204014596bd08d24b161e5b7 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss new file mode 100644 index 0000000..3321a83 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss @@ -0,0 +1,71 @@ +:root { + --aspid-fasttools-prop-status: success; + --aspid-fasttools-colors-gradient: var(--aspid-colors-status-success-lightness); + --aspid-fasttools-icons-inspector-header: var(--aspid-icons-status-success); +} + +:root.aspid-fasttools-status--success { + --aspid-fasttools-colors-gradient: var(--aspid-colors-status-success-lightness); + --aspid-fasttools-icons-inspector-header: var(--aspid-icons-status-success); +} + +:root.aspid-fasttools-status--warning { + --aspid-fasttools-colors-gradient: var(--aspid-colors-status-warning-lightness); + --aspid-fasttools-icons-inspector-header: var(--aspid-icons-status-warning); +} + +:root.aspid-fasttools-status--error { + --aspid-fasttools-colors-gradient: var(--aspid-colors-status-error-lightness); + --aspid-fasttools-icons-inspector-header: var(--aspid-icons-status-error); +} + +:root.aspid-fasttools-status--info { + --aspid-fasttools-colors-gradient: var(--aspid-colors-status-info-lightness); + --aspid-fasttools-icons-inspector-header: var(--aspid-icons-status-info); +} + +.aspid-fasttools-inspector-header__container { + padding: 5px 10px; + overflow: hidden; + flex-direction: row; + transition-duration: 0.25s; + transition-timing-function: ease-in-out; +} + +.aspid-fasttools-inspector-header__text > Label, +.aspid-fasttools-inspector-header__subtext > Label { + transition-property: color; + transition-duration: 0.25s; + transition-timing-function: ease-in-out; +} + +.aspid-fasttools-inspector-header__icon { + width: 40px; + height: 40px; + margin: 0 10px 0 0; + display: flex; + flex-shrink: 0; + background-image: var(--aspid-fasttools-icons-inspector-header); +} + +.aspid-fasttools-inspector-header__text-container { + overflow: hidden; + flex-grow: 1; + align-self: center; + flex-shrink: 1; +} + +.aspid-fasttools-inspector-header__text { + --aspid-fasttools-prop-theme: light; + --aspid-fasttools-metrics-label_size: H4; +} + +.aspid-fasttools-inspector-header__subtext { + --aspid-fasttools-prop-theme: dark; + --aspid-fasttools-metrics-label_size: H6; +} + +.aspid-fasttools-inspector-header__text AspidDividingLine, +.aspid-fasttools-inspector-header__subtext AspidDividingLine { + --aspid-fasttools-metrics-line_size: none; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss.meta new file mode 100644 index 0000000..679d304 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidInspectorHeader.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2575ae7e2cae8493c9ed576520f7ca15 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss new file mode 100644 index 0000000..7bc96c0 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss @@ -0,0 +1,124 @@ +:root { + flex-direction: column; +} + +Label { + padding: 0; + flex-grow: 1; + white-space: normal +} + +AspidDividingLine { + margin: 5px 0 0 0; +} + +/* --- LABEL SIZES --- */ +.aspid-fasttools-label-size--h1 { + font-size: 36px; +} + +.aspid-fasttools-label-size--h2 { + font-size: 24px; +} + +.aspid-fasttools-label-size--h3 { + font-size: 18px; +} + +.aspid-fasttools-label-size--h4 { + font-size: 16px; +} + +.aspid-fasttools-label-size--h5 { + font-size: 14px; +} + +.aspid-fasttools-label-size--h6 { + font-size: 13px; +} + +.aspid-fasttools-label-size--h7 { + font-size: 12px; +} + +/* General Text */ +.aspid-fasttools-theme--darkness Label { + color: var(--aspid-colors-text-darkness); +} + +.aspid-fasttools-theme--dark Label { + color: var(--aspid-colors-text-dark); +} + +.aspid-fasttools-theme--light Label { + color: var(--aspid-colors-text-light); +} + +.aspid-fasttools-theme--lightness Label { + color: var(--aspid-colors-text-lightness); +} + +/* Status Text */ +AspidLabel.aspid-fasttools-status--success.aspid-fasttools-theme--darkness > Label { + color: var(--aspid-colors-status-success-text-darkness); +} + +AspidLabel.aspid-fasttools-status--success.aspid-fasttools-theme--dark > Label { + color: var(--aspid-colors-status-success-text-dark); +} + +AspidLabel.aspid-fasttools-status--success.aspid-fasttools-theme--light > Label { + color: var(--aspid-colors-status-success-text-light); +} + +AspidLabel.aspid-fasttools-status--success.aspid-fasttools-theme--lightness > Label { + color: var(--aspid-colors-status-success-text-lightness); +} + +AspidLabel.aspid-fasttools-status--warning.aspid-fasttools-theme--darkness > Label { + color: var(--aspid-colors-status-warning-text-darkness); +} + +AspidLabel.aspid-fasttools-status--warning.aspid-fasttools-theme--dark > Label { + color: var(--aspid-colors-status-warning-text-dark); +} + +AspidLabel.aspid-fasttools-status--warning.aspid-fasttools-theme--light > Label { + color: var(--aspid-colors-status-warning-text-light); +} + +AspidLabel.aspid-fasttools-status--warning.aspid-fasttools-theme--lightness > Label { + color: var(--aspid-colors-status-warning-text-lightness); +} + +AspidLabel.aspid-fasttools-status--error.aspid-fasttools-theme--darkness > Label { + color: var(--aspid-colors-status-error-text-darkness); +} + +AspidLabel.aspid-fasttools-status--error.aspid-fasttools-theme--dark > Label { + color: var(--aspid-colors-status-error-text-dark); +} + +AspidLabel.aspid-fasttools-status--error.aspid-fasttools-theme--light > Label { + color: var(--aspid-colors-status-error-text-light); +} + +AspidLabel.aspid-fasttools-status--error.aspid-fasttools-theme--lightness > Label { + color: var(--aspid-colors-status-error-text-lightness); +} + +AspidLabel.aspid-fasttools-status--info.aspid-fasttools-theme--darkness > Label { + color: var(--aspid-colors-status-info-text-darkness); +} + +AspidLabel.aspid-fasttools-status--info.aspid-fasttools-theme--dark > Label { + color: var(--aspid-colors-status-info-text-dark); +} + +AspidLabel.aspid-fasttools-status--info.aspid-fasttools-theme--light > Label { + color: var(--aspid-colors-status-info-text-light); +} + +AspidLabel.aspid-fasttools-status--info.aspid-fasttools-theme--lightness > Label { + color: var(--aspid-colors-status-info-text-lightness); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss.meta new file mode 100644 index 0000000..37cc058 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Components/Aspid-FastTools-AspidLabel.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 039c741d44a74e0c8f8a1a09759f0c4b +timeCreated: 1777301557 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums.meta new file mode 100644 index 0000000..16f7b71 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e11d6db414db47b4aa2a2e3d03262075 +timeCreated: 1778148053 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss new file mode 100644 index 0000000..6b17c21 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss @@ -0,0 +1,28 @@ +:root { + margin: 1px -2px 1px 3px; +} + +.unity-property-field__inspector-property .unity-base-field__inspector-field { + margin-left: 0; + margin-right: 0; +} + +.unity-property-field__inspector-property Toggle.unity-base-field__inspector-field { + margin-left: -1px; +} + +.aspid-fasttools-enum-values__header { + padding: 5px 5px 2px 5px; + border-width: 1px; + border-radius: 5px 5px 0 0; + border-color: var(--aspid-colors-bg-dark); + background-color: var(--aspid-colors-bg-light); +} + +.aspid-fasttools-enum-values__container { + padding: 2px 5px 5px 5px; + border-width: 0 1px 1px 1px; + border-radius: 0 0 5px 5px; + border-color: var(--aspid-colors-bg-dark); + background-color: var(--aspid-colors-bg-lightness); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss.meta new file mode 100644 index 0000000..c39aa7b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Enums/Aspid-FastTools-EnumValues.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dddaadecf670a48939d44c30e5460a21 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids.meta new file mode 100644 index 0000000..6478ace --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 44078cd255964115a4bd50eed7cbe89f +timeCreated: 1777878288 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss new file mode 100644 index 0000000..4051b4c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss @@ -0,0 +1,14 @@ +Button { + padding: 0; + min-width: 18px; + max-width: 18px; + min-height: 18px; + max-height: 18px; + margin: 0 0 0 1px; +} + +Button > VisualElement { + width: 100%; + height: 100%; + background-image: resource("d_ScriptableObject Icon"); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss.meta new file mode 100644 index 0000000..1caa955 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Field.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 63776338b4e545a9a57c9421ec4ff590 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss new file mode 100644 index 0000000..49affbc --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss @@ -0,0 +1,233 @@ +AspidInspectorHeader { + margin-top: 2px; +} + +ToolbarSearchField { + width: auto; + padding-right: 4px; + margin: 5px -1px 0 -1px; +} + +.aspid-fasttools-id-registry__toolbar { + margin: 5px -1px; + padding-bottom: 5px; + flex-direction: row; + border-width: 0; + border-bottom-width: 1px; + border-bottom-color: var(--aspid-colors-bg-lightness); +} + +IdRegistryToolbarVisualElement > VisualElement { + flex-direction: row; + align-items: center; + flex-grow: 1; + flex-basis: 0; +} + +IdRegistryToolbarVisualElement > VisualElement > Label { + flex-shrink: 0; + margin: 0 6px 0 0; + padding: 0; + font-size: 11px; + color: var(--aspid-colors-text-dark); + -unity-text-align: middle-left; +} + +IdRegistryToolbarVisualElement > VisualElement > EnumField { + flex-grow: 1; + flex-shrink: 1; + margin: 0; +} + +.aspid-fasttools-id-registry__group-foldout { + margin-top: 5px; +} + +.aspid-fasttools-id-registry__group-foldout > Toggle { + margin-left: 0; +} + +.aspid-fasttools-id-registry__list .unity-scroller--vertical { + margin-left: 5px; +} + +IdRegistryEntryVisualElement { + margin-bottom: 0; + flex-direction: column; +} + +IdRegistryEntryVisualElement > VisualElement { + padding: 5px; + margin-bottom: 3px; + min-height: 22px; + flex-direction: row; + align-items: center; + border-radius: 10px; + background-color: var(--aspid-colors-shade-dark); +} + +IdRegistryEntryVisualElement > VisualElement > Label { + margin: 0; + flex-shrink: 0; + font-size: 11px; + min-width: 50px; + padding: 2px 8px; + border-width: 1px; + border-radius: 10px; + border-color: var(--aspid-colors-bg-darkness); + -unity-text-align: middle-center; + + color: var(--aspid-colors-text-light); + background-color: var(--aspid-colors-bg-light); +} + +IdRegistryEntryVisualElement > VisualElement > Label.aspid-fasttools-status--error { + color: var(--aspid-colors-status-error-text-light); + background-color: var(--aspid-colors-status-error-dark); +} + +IdRegistryEntryVisualElement TextField { + flex-grow: 1; + flex-shrink: 1; + margin: 0 0 0 5px; + border-radius: 6px; +} + +IdRegistryEntryVisualElement Button { + margin: 0 0 0 5px; + padding: 0 0 2px 0; + flex-shrink: 0; + min-width: 20px; + max-width: 20px; + min-height: 18px; + max-height: 18px; + font-size: 14px; + border-radius: 3px; + color: var(--aspid-colors-text-lightness); + border-color: var(--aspid-colors-bg-darkness); + background-color: var(--aspid-colors-bg-light); +} + +IdRegistryEntryVisualElement .aspid-fasttools-id-registry__delete:hover { + color: var(--aspid-colors-status-error-text-light); + background-color: var(--aspid-colors-status-error-dark); + border-color: var(--aspid-colors-status-error-text-light); +} + +IdRegistryEntryVisualElement .aspid-fasttools-id-registry__confirm:enabled:hover { + color: var(--aspid-colors-status-success-text-light); + border-color: var(--aspid-colors-status-success-text-light); + background-color: var(--aspid-colors-status-success-dark); +} + +IdRegistryEntryVisualElement > Label { + color: var(--aspid-colors-status-error-text-light); + font-size: 11px; + margin: 0 0 3px 0; +} + +IdRegistryNextIdRowVisualElement { + border-width: 0; + padding-top: 5px; + margin: 5px 0 0 0; + border-top-width: 1px; + border-top-color: var(--aspid-colors-bg-lightness); +} + +IdRegistryNextIdRowVisualElement > VisualElement { + padding: 5px; + margin: 5px 0 0 0; + align-items: center; + flex-direction: row; + border-radius: 10px; + background-color: var(--aspid-colors-shade-dark); +} + +IdRegistryNextIdRowVisualElement PropertyField { + flex-grow: 1; + margin: 0 2px 0 3px; +} + +IdRegistryNextIdRowVisualElement Image { + width: 16px; + height: 16px; + display: none; + margin-left: 5px; + --unity-image: resource("console.warnicon.sml"); +} + +IdRegistryNextIdRowVisualElement Image:enabled { + display: flex; +} + +.aspid-fasttools-id-registry__add { + padding: 5px; + margin: 5px 0 0 0; + border-radius: 10px; + background-color: var(--aspid-colors-shade-dark); +} + +.aspid-fasttools-id-registry__add > VisualElement { + border-width: 0; + flex-direction: row; +} + +.aspid-fasttools-id-registry__add TextField { + margin: 0; + flex-grow: 1; + flex-shrink: 1; + border-radius: 6px; +} + +.aspid-fasttools-id-registry__add Button { + margin: 0 0 0 5px; + padding: 0 0 2px 0; + color: var(--aspid-colors-text-lightness); + flex-shrink: 0; + min-width: 20px; + max-width: 20px; + min-height: 18px; + max-height: 18px; + font-size: 14px; + border-radius: 3px; + border-color: var(--aspid-colors-bg-darkness); + background-color: var(--aspid-colors-bg-light); +} + +.aspid-fasttools-id-registry__add Button:enabled:hover { + color: var(--aspid-colors-status-success-text-light); + border-color: var(--aspid-colors-status-success-text-light); + background-color: var(--aspid-colors-status-success-dark); +} + +.aspid-fasttools-id-registry__add > Label { + color: var(--aspid-colors-status-error-text-light); + font-size: 11px; + margin: 3px 0 0 0; +} + +IdRegistryWarningVisualElement { + display: none; + flex-direction: row; + align-items: center; + padding: 5px 8px; + margin-bottom: 4px; + border-radius: 6px; + background-color: var(--aspid-colors-status-error-dark); +} + +IdRegistryWarningVisualElement.aspid-fasttools-id-registry__warning--visible { + display: flex; +} + +IdRegistryWarningVisualElement > Label { + flex-grow: 1; + font-size: 11px; + color: var(--aspid-colors-status-error-text-lightness); +} + +IdRegistryWarningVisualElement > Button { + flex-shrink: 0; + margin-left: 8px; + padding: 2px 8px; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss.meta new file mode 100644 index 0000000..39b138c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Registry.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3fba5ca171f36413d8d2a664d3e00fec +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss new file mode 100644 index 0000000..80ae55e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss @@ -0,0 +1,40 @@ +:root { + padding: 5px; +} + +ToolbarSearchField { + width: auto; + flex-shrink: 1; + margin: 5px 0 10; +} + +.aspid-fasttools-id-selector__error { + margin-top: 2px; + font-size: 11px; + white-space: normal; +} + +.aspid-fasttools-id-selector__item +{ + height: 22px; + padding-right: 6px; + flex-direction: row; + align-items: center; +} + +.aspid-fasttools-id-selector__item-name +{ + flex-grow: 1; + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; + -unity-text-align: middle-left; +} + +.aspid-fasttools-id-selector__item-id +{ + flex-shrink: 0; + font-size: 11px; + margin-left: 8px; + -unity-text-align: middle-right; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss.meta new file mode 100644 index 0000000..f6c3f0c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Ids/Aspid-FastTools-Id-Selector.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3496bde5cb21d4adaaeb383fbf4c9aef +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types.meta new file mode 100644 index 0000000..7d43d0c --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bbfde89107d740eaa6e2a61e8bb93779 +timeCreated: 1777985852 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss new file mode 100644 index 0000000..8b52281 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss @@ -0,0 +1,18 @@ +Button { + padding: 0; + min-width: 18px; + max-width: 18px; + min-height: 18px; + max-height: 18px; + margin: 0 0 0 1px; +} + +Button > VisualElement { + width: 100%; + height: 100%; + background-image: resource("d_Folder Icon"); +} + +Button > VisualElement:enabled:hover { + background-image: resource("d_FolderOpened Icon"); +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss.meta new file mode 100644 index 0000000..90e5964 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-SerializableType.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 29cdf5b29244a4657a84f50b65824d71 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss new file mode 100644 index 0000000..6a81272 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss @@ -0,0 +1,65 @@ +:root { + padding: 5px; + flex-grow: 1; + flex-direction: column; +} + +.aspid-fasttools-type-selector-header { + padding-left: 10; + height: 20px; + min-height: 20px; + align-items: center; + flex-direction: row; + margin: -5px -5px 5px; + background-color: var(--aspid-colors-bg-dark); +} + +/* -------------------------------------------------- Back Button --------------------------------------------------- */ +.aspid-fasttools-type-selector-header > Button { + margin: 0; + width: 20px; + height: 16px; + border-width: 0; + margin-right: 4px; + background-color: rgba(0, 0, 0, 0); + color: var(--aspid-colors-text-lightness); +} + +.aspid-fasttools-type-selector-header > Button:enabled:hover, +.aspid-fasttools-type-selector-header > Button:enabled:focus { + border-width: 1px; + color: var(--aspid-colors-status-info-text-lightness); + border-color: var(--aspid-colors-status-info-shade-lightness); +} +/* ------------------------------------------------------------------------------------------------------------------ */ + +/* ----------------------------------------------------- Title ------------------------------------------------------ */ +.aspid-fasttools-type-selector-header > Label { + flex-grow: 1; + -unity-font-style: bold; +} +/* ------------------------------------------------------------------------------------------------------------------ */ + +ToolbarSearchField { + width: auto; + margin-bottom: 5px; +} + +/* ------------------------------------------------------ Item ------------------------------------------------------ */ +.unity-collection-view__item { + height: 20px; + align-items: center; + padding-left: 5px; + padding-right: 5px; + flex-direction: row; +} + +.aspid-fasttools-type-selector-item-title { + color: var(--aspid-colors-text-lightness); + flex-grow: 1; +} + +.aspid-fasttools-type-selector-item-arrow { + color: var(--aspid-colors-text-light); +} +/* ------------------------------------------------------------------------------------------------------------------ */ diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss.meta new file mode 100644 index 0000000..59cd700 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Types/Aspid-FastTools-TypeSelectorWindow.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 09741cdf2939046f08938a85bc78f4ef +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows.meta new file mode 100644 index 0000000..8081311 --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 969007ba29344c1787e6d3298756778c +timeCreated: 1777206348 \ No newline at end of file diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome.meta new file mode 100644 index 0000000..ba4e3ea --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf278e6fe44f24f2eb9364608c2e6b79 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss new file mode 100644 index 0000000..80af57b --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss @@ -0,0 +1,103 @@ +:root { + --aspid-fasttools-colors-bg: rgb(0, 0, 0); +} + +AspidAnimatedDotsBackground { + background-color: var(--aspid-fasttools-colors-bg); +} + +.aspid-fasttools-welcome__scroll { + flex-grow: 1; +} + +.aspid-fasttools-welcome__content { + padding: 10px; + flex-grow: 1; + align-items: stretch; +} + +.aspid-fasttools-welcome__hero { + padding: 10px; + align-items: center; + flex-direction: row; +} + +.aspid-fasttools-welcome__logo { + width: 100px; + height: 100px; + flex-shrink: 1; + margin-right: 15px; +} + +.aspid-fasttools-welcome__hero-text { + flex-grow: 1; +} + +AspidAnimatedTitle { + margin-bottom: 5px; + font-size: 36px; + -unity-font-style: bold; +} + +.aspid-fasttools-welcome__description { + white-space: normal; + border-radius: 10px; + background-color: var(--aspid-fasttools-colors-bg); +} + +.aspid-fasttools-welcome__card { + padding: 10px; + border-radius: 10px; +} + +.aspid-fasttools-welcome__footer-link:hover { + color: var(--aspid-colors-status-success-text-light); +} + +.aspid-fasttools-welcome__card-header { + margin-bottom: 10px; + --aspid-fasttools-metrics-label_size: h2; +} + +AspidDividingLine { + opacity: 0.5; +} + +.aspid-fasttools-welcome__footer { +} + +.aspid-fasttools-welcome__footer-link { + color: var(--aspid-colors-status-success-text-dark); + font-size: 14px; + -unity-font-style: bold; +} + +.aspid-fasttools-welcome__footer-version { + color: var(--aspid-colors-text-darkness); + font-size: 14px; +} + +.aspid-fasttools-welcome__footer-version:hover { + color: var(--aspid-colors-text-light); +} + +.aspid-fasttools-welcome__toast { + color: var(--aspid-colors-status-info-text-lightness); + opacity: 0; + padding: 10px; + position: absolute; + max-width: 80%; + font-size: 14px; + white-space: normal; + border-width: 1px; + border-radius: 10px; + background-color: var(--aspid-colors-status-info-dark); + -unity-font-style: bold; + -unity-text-align: middle-center; + transition-duration: 0.3s; + transition-timing-function: ease-out; +} + +.aspid-fasttools-welcome__toast--visible { + opacity: 0.75; +} diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss.meta b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss.meta new file mode 100644 index 0000000..d0e149f --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uss.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 74929072ccf9442f6a07a76964c94928 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 + unsupportedSelectorAction: 0 diff --git a/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uxml b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uxml new file mode 100644 index 0000000..914923e --- /dev/null +++ b/Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Unity/Editor/Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.uxml @@ -0,0 +1,28 @@ + + + + +
+ + +
+
Aspid Toolkit · Brand Book v1.2
+

+ Aspid FastTools +

+

+ Dark, utilitarian design system for Unity Editor tooling. Flat surfaces layered by neutral value, + gemstone-themed semantic statuses in parallel text/shade scales, and a 4-stop background ramp + for deep content layering. +

+
+
StatusActive
+
ThemeDark
+
Stops4 — darkness · dark · light · lightness
+
SurfaceUnity 2022.3+ Editor
+
+
+ + +
+
+ 01 +

Color — The Gemstone Model

+
+

+ Color is organized into three parallel neutral ramps and four semantic status gemstones. + Every axis follows the same four-stop scale: darkness → dark → light → lightness. + Each gemstone subdivides into a deep background body fill, a vibrant text + scale for readable labels, and a muted shade scale for borders and lines. +

+ +

Neutral Surface Ramp · --aspid-colors-bg-*

+
+
Background--aspid-colors-bg
+
+
darkness#1A1A1A
+
dark#242424
+
light#2E2E2E
+
lightness#383838
+
+
+
+
Shade--aspid-colors-shade
+
+
darkness#2D2D2D
+
dark#3C3C3C
+
light#505050
+
lightness#646464
+
+
+ +

Text Ramp · --aspid-colors-text-*

+
+
Text--aspid-colors-text
+
+
Aa Aadarkness · #6E6E6E
+
Aa Aadark · #969696
+
Aa Aalight · #BEBEBE
+
Aa Aalightness · #DCDCDC
+
+
+ +

Status — Backgrounds (Deep Gemstone Bases)

+
+
Success · Emerald--status-success
+
+
darkness#082814
+
dark#0C411E
+
light#145A2D
+
lightness#1E783C
+
+
+
+
Warning · Topaz--status-warning
+
+
darkness#2D1E05
+
dark#55370A
+
light#7D5514
+
lightness#A5731E
+
+
+
+
Error · Ruby--status-error
+
+
darkness#320A0A
+
dark#551414
+
light#7D2323
+
lightness#A53232
+
+
+
+
Info · Sapphire--status-info
+
+
darkness#081932
+
dark#0F2D55
+
light#194B82
+
lightness#2369B4
+
+
+ +

Status — Text (Gemstone Brilliance)

+
+
Success Text--status-success-text
+
+
Aa Aadarkness · #376E41
+
Aa Aadark · #55AF64
+
Aa Aalight · #78EB91
+
Aa Aalightness · #B4FFC8
+
+
+
+
Warning Text--status-warning-text
+
+
Aa Aadarkness · #785523
+
Aa Aadark · #B9873C
+
Aa Aalight · #F5B955
+
Aa Aalightness · #FFEBAF
+
+
+
+
Error Text--status-error-text
+
+
Aa Aadarkness · #7D2D2D
+
Aa Aadark · #B94141
+
Aa Aalight · #EB5F5F
+
Aa Aalightness · #FFAFAF
+
+
+
+
Info Text--status-info-text
+
+
Aa Aadarkness · #28507D
+
Aa Aadark · #4182B9
+
Aa Aalight · #5AB9F0
+
Aa Aalightness · #BEF0FF
+
+
+ +

Status — Shades (Muted Gemstones · Borders & Lines)

+
+
Success Shade--status-success-shade
+
+
darkness#19371E
+
dark#285532
+
light#418250
+
lightness#5FBE73
+
+
+
+
Warning Shade--status-warning-shade
+
+
darkness#372814
+
dark#5A411E
+
light#876432
+
lightness#B98C4B
+
+
+
+
Error Shade--status-error-shade
+
+
darkness#371919
+
dark#5A2D2D
+
light#874141
+
lightness#BE5F5F
+
+
+
+
Info Shade--status-info-shade
+
+
darkness#142337
+
dark#23415F
+
light#376491
+
lightness#5591C8
+
+
+
+ + +
+
+ 02 +

Typography

+
+

+ Inherits Unity's default editor font (Inter / system sans). Sizing is exposed through + AspidLabel's seven-step scale — selectable per-element via the + aspid-fasttools-label-size--h1…h7 classes or the + --aspid-fasttools-metrics-label_size custom property. H7 is the + inspector default; larger steps are reserved for hero strips and decorative titles. +

+
+
+
Display
+
H136px
+
Hero displays · welcome screens, animated titles
+
+
+
Window Title
+
H224px
+
Editor-window titles
+
+
+
Page Title
+
H318px
+
Page-level titles inside windows
+
+
+
Inspector Header
+
H416px
+
AspidInspectorHeader title
+
+
+
Section Title
+
H514px
+
Section titles, GradientButton labels
+
+
+
Subtext
+
H613px
+
AspidInspectorHeader subtext, secondary captions
+
+
+
Default inspector body — dense and readable at 12px without ever asking for a second glance.
+
H712px
+
Default inspector body, AspidLabel base
+
+
+
+ + +
+
+ 03 +

Spacing & Radii

+
+

+ Conventions, not tokens. Spacing and radii are applied directly in component + stylesheets — there is no shared --metrics-spacing-* / --metrics-radius-* + palette. The values below are the recurring set used across Aspid-FastTools-*.uss; + new components should reuse them rather than introduce variants. +

+ +

Spacing — recurring values

+
+
+
+
+
2px
+
hairline gaps
+
+
+
+
+
+
5px
+
base unit · row gap, vertical rhythm
+
+
+
+
+
+
10px
+
group padding, container insets
+
+
+
+

+ Inspectors use a -10px left offset on + .aspid-fasttools-inspector-container to align with Unity's native chrome. +

+ +

Border Radii — actual usage

+
+
+
+
+
8px
+
AspidHelpBox
+
+
+
+
+
+
10px
+
AspidBox · GradientButton · headers
+
+
+
+
+ + +
+
+ 04 +

Elevation

+
+

+ There is no shadow language. Depth comes from value: every step up the ramp is one elevation level higher. + Backgrounds layer like sediment, not like cards floating on a page. +

+
+
+
+ Level 0 + Unity Default Grey +
+
+
+
+ Level 1 + bg-darkness +
+
+
+
+ Level 2 + bg-dark · containers +
+
+
+
+ Level 3 + bg-light · raised +
+
+
+
+ + +
+
+ 05 +

Components

+
+

+ Ten primitives compose the inspector and editor-window surfaces — five structural, + five decorative. They follow the BEM-namespaced USS convention + (aspid-fasttools-{block}__{element}--{modifier}) and share the palette declared + in Aspid-FastTools-Default-Dark.uss; per-component sheets live alongside their + C# class under Resources/UI/Components/Aspid-FastTools-{Component}.uss. +

+ +

Structural

+ +
+ + +
+
+

AspidBox

+ aspid-fasttools-background +
+

+ The rounded-10 card. Default fill is bg-dark. Variants step through the + surface ramp or pick up a status base. +

+
+
darkness
+
dark
+
light
+
lightness
+
+
+
+
success
+
warning
+
error
+
info
+
+
+ + +
+
+

AspidDividingLine

+ aspid-fasttools-dividing-line +
+

+ Structural rules that always sit below text in saturation. Use shade-dark + for neutral separators or the matching status shade for sectioned content. +

+
+ Neutral · shade-dark +
+ Success · status-success-shade-dark +
+ Warning · status-warning-shade-dark +
+ Error · status-error-shade-dark +
+ Info · status-info-shade-dark +
+
+
+ + +
+
+

AspidLabel

+ aspid-fasttools-label-size +
+

+ Content blocks. Picks the matching tone from the text or status text ramp + so labels are always 20–40% lighter than the lines around them. +

+
+
Neutral · darkness
+
Neutral · dark
+
Neutral · light
+
Neutral · lightness
+
Success · light
+
Success · lightness
+
Warning · light
+
Warning · lightness
+
Error · light
+
Error · lightness
+
Info · light
+
Info · lightness
+
+
+ + +
+
+

AspidInspectorHeader

+ aspid-fasttools-inspector-header +
+

+ Hero strip — pairs a 40px gemstone icon with an H4 title (16px) + and a dimmer H6 subtext (13px). The status icon and the + --aspid-fasttools-colors-gradient accent ride the matching status ramp; + title and subtext shift through the corresponding text tones. +

+ +
+
+ +
+
+ Validation Passed + All references are resolved and ready to ship. +
+
+
+
+ +
+
+ Stale References + Three IDs point to deleted assets. +
+
+
+
+ +
+
+ Compilation Failed + Generator produced 4 errors in IdRegistry.g.cs. +
+
+
+
+ +
+
+ Registry · 184 entries + Last sync 2026-04-27 · 14:02 +
+
+
+ + +
+
+

AspidHelpBox

+ aspid-fasttools-help-box +
+

+ Advisory strip — status-{tone}-light for the fill, + status-{tone}-shade-lightness for the border, and + status-{tone}-text-lightness for "etched" legibility on top of the + saturated body. The icon is bound through --aspid-fasttools-icons-help-box + using Unity's built-in console icons (console.infoicon / + warnicon / erroricon). +

+ +
+
+ +
+
Generator output is up to date — no recompile required.
+
+
+
+ +
+
Manual ID was set lower than the current next-id. Existing entries may collide.
+
+
+
+ +
+
Identifier is not a valid C# name. Rename before saving.
+
+
+
+ +
+
Names are stripped from player builds. Only int IDs ship at runtime.
+
+
+ +

Decorative

+ + +
+
+

AspidGradientButton

+ aspid-fasttools-gradient-button +
+

+ 14px bold button with a status-driven radial accent. Body sits on + --aspid-fasttools-colors-gradient-button-bg (defaults to + bg-darkness); the accent comes from + --aspid-fasttools-colors-gradient-button-accent — typically a + status-{tone}-text-dark swatch. Optional + __trailing-label right-aligns secondary copy. +

+
+ + + + +
+
+ + +
+
+

AspidAnimatedTitle

+ aspid-fasttools-animated-title +
+

+ Multi-word display title that cycles three accents + (color-1/2/3, defaulting to success / warning / error + text-dark) and applies a sine-wave letter offset. Tunable via + --aspid-fasttools-prop-animated-title-color_* and + --aspid-fasttools-prop-animated-title-wave_* custom properties. + Use it sparingly — welcome screens and About panels only. +

+
+ Aspid FastTools +
+
+ + +
+
+

AspidAnimatedLogo

+ aspid-fasttools-animated-logo +
+

+ Layered logo that cross-fades between sprites + (__layer / __layer--visible) and pulses on hover. + Pulse rate and hover amplitude are exposed as + --aspid-fasttools-prop-animated_logo-pulse_speed and + --aspid-fasttools-prop-animated_logo-pulse_hover_amplitude; + layer images are bound through + AspidAnimatedLogoLayerImageStyle. +

+
+ +
+
+ + +
+
+

AspidAnimatedDotsBackground

+ aspid-fasttools-animated-dots-background +
+

+ Absolute-positioned dot field for hero panels. Three blob colours + (--aspid-fasttools-colors-dot-blob-color-1/2/3) and three + metrics — dot_radius (1.55), dot_spacing (18) and + dot_scale_reference (420) — drive density and parallax response. +

+
+ animated dots · parallax ready +
+
+ + +
+
+

AspidHoverGradientOverlay

+ aspid-fasttools-hover-gradient-overlay +
+

+ Absolute overlay that paints a soft radial highlight tracking the cursor. + Tint is bound to --aspid-fasttools-colors-hover_overlay + (transparent by default); animation is shaped by + hover_overlay_steps (75), hover_overlay_lerp_rate (0.12) + and hover_overlay_alpha_scale (0.35). Drop it inside any + AspidBox / GradientButton to add hover lift without restyling the host. +

+
+
+
+
+
+
+ + +
+
+ 06 +

Principles

+
+
+
+ 01 +

Text over Lines.

+

+ Text is always 20–40% more saturated or lighter than the structural shade surrounding it. + If a label disappears into its border, the wrong tone was picked. +

+
+
+ 02 +

Grounded Saturation.

+

+ Pure whites and neons are forbidden. Depth comes from pigment richness — gemstone hues, + not luminosity. Brightness is a finite resource; spend it on text, not surfaces. +

+
+
+ 03 +

Density over Whitespace.

+

+ Designed for 320px-wide inspectors. Row heights live between 18–22px and base spacing is + a single 5px unit. Whitespace is a tool, not a default. +

+
+
+ 04 +

Status as State.

+

+ Color exists to convey status. If an element is neutral, it must stay in the neutral + grey ramp. Decorative color is not a feature of this system. +

+
+
+
+ +
+ Aspid FastTools · Brand Book v1.2 + Engineer-first · Calm · Dense · Grounded +
+
+ + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f4ca565 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,172 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Repository Overview + +**Aspid.FastTools** is a Unity package (`com.aspid.fasttools`) targeting Unity 2022.3+ that minimizes routine boilerplate code. It consists of two separate projects: + +1. **`Aspid.FastTools/`** — The Unity project containing the package source (Runtime + Editor code) +2. **`Aspid.FastTools.Generators/`** — A standalone .NET solution containing Roslyn source generators + +### Unity Package +Compilation is handled automatically by Unity's build system when the project is open. There are no CLI build scripts. + +### Building & Deploying Generators + +`Directory.Build.targets` auto-copies the compiled DLL into the Unity package on build: + +```bash +# From Aspid.FastTools.Generators/ +dotnet build -c Release +# Outputs DLL to: Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Aspid.FastTools.Generators.dll +``` + +Run tests with: +```bash +# From Aspid.FastTools.Generators/ +dotnet test +``` + +## Architecture + +### Two-Project Separation + +**Generators project** (`Aspid.FastTools.Generators/Aspid.FastTools.Generators/`): +- Contains Roslyn `IIncrementalGenerator` implementations +- `Aspid.FastTools.Generators.Tests/` — unit tests for generators +- `Aspid.FastTools.Generators.Sample/` — sample project for manual testing +- Two generators: + - `ProfilerMarkersGenerator` — generates per-call-site `ProfilerMarker` registrations based on method name and line number + - `IdStructGenerator` — generates boilerplate for ID struct types +- Dependencies: `Aspid.Generators.Helper`, `Microsoft.CodeAnalysis.CSharp`, `SourceGenerator.Foundations` + +**Unity package** (`Aspid.FastTools/Assets/Plugins/Aspid/FastTools/`): +- `Unity/Runtime/` — shipped with player builds +- `Unity/Editor/Scripts/` — editor-only code, excluded from builds +- `Unity/Editor/Resources/UI/` — editor USS stylesheets, organized by domain (`UI/Components/`, `UI/Ids/`, `UI/Types/`, `UI/Enums/`, `UI/Windows/`); shared base palette at `UI/Aspid-FastTools-Default-Dark.uss`. Files follow `Aspid-FastTools-{Feature}.uss`. +- `Unity/Editor/Resources/Icons/` — editor icon assets referenced by USS via `--aspid-icons-*` variables. +- `Source/` — pure C# extensions with no Unity dependency +- `Samples~/` — optional samples (UPM convention, tilde hides from Unity importer, imported via Package Manager) + +**Assembly boundary rule:** `Unity/Runtime/` code must NOT reference `UnityEditor` — it ships with player builds. + +**Optional Mathematics integration:** Mathematics-dependent extensions live in the satellite `Aspid.FastTools.Unity.VisualElements.Math` assembly, which references `Unity.Mathematics` directly and is gated by a `versionDefines` entry that compiles it only when `com.unity.mathematics` is installed. New Mathematics-dependent code goes there. The same `ASPID_FASTTOOLS_UNITY_MATHEMATICS_INTEGRATION` symbol is also declared on the main runtime asmdef for the rare case when a single file in `Aspid.FastTools.Unity` needs to gate Mathematics-aware behavior. + +### Assembly Definitions + +| Assembly | Location | Purpose | +|---|---|---| +| `Aspid.FastTools` | `Source/` | Pure C# type extensions | +| `Aspid.FastTools.Unity` | `Unity/Runtime/` | Runtime: Types, Enums, Ids, ProfilerMarkers, VisualElements | +| `Aspid.FastTools.Unity.VisualElements.Math` | `Unity/Runtime/VisualElements/Extensions/INotifyValueChanged/Math/` | Satellite assembly compiled only when `com.unity.mathematics` is installed; hosts `INotifyValueChanged` extensions for `float2/3/4`, `int2/3/4`, etc. | +| `Aspid.FastTools.Unity.Editor` | `Unity/Editor/Scripts/` | Editor: Enums, Extensions, IMGUI, Ids, SerializedProperties, Types, VisualElements, Welcome | + +### Key Features and Their Locations + +**ProfilerMarkers** (`Unity/Runtime/ProfilerMarkers/`): Extension method `this.Marker()` returns a `ProfilerMarker` unique to the call site. The source generator handles creating unique markers per (class, method, line). + +**SerializableType** (`Unity/Runtime/Types/`): Wraps `System.Type` for Unity Inspector serialization using assembly-qualified names with lazy resolution. `SerializableType` adds generic constraint support. + +**TypeSelector** (`Unity/Editor/Scripts/Types/`): `EditorWindow`-based hierarchical type picker with search, used as a property drawer for `SerializableType`. + +**EnumValues** (`Unity/Runtime/Enums/`): Serializable dictionary mapping enum values to arbitrary values. Handles `[Flags]` enums. + +**Id Registries** (`Unity/Runtime/Ids/`, `Unity/Editor/Scripts/Ids/`): A single `IdRegistry` (`ScriptableObject`) maps string names to stable integer IDs for a given struct type. Full `int ↔ string` mapping is available at runtime via `TryGetId` / `TryGetName` / `Contains(int)` / `Contains(string)`. + +Each struct type decorated with `[UniqueId]` / implementing `IId` is bound to exactly **one** registry — uniqueness is enforced at lookup time by `IdRegistryResolver`. The resolver lazily builds a `Type AQN → registry` index on first lookup and updates it incrementally via `AssetPostprocessor`. `UniqueIdIndex` mirrors that strategy for `[UniqueId]`-field collision checks. + +Editor UI lives in `RegistryEditorCore`, which talks directly to the registry's `SerializedObject`. Features: C#-identifier name validation, full Undo, explicit Clean-up flow for invalid entries (empty / duplicate names), Sort/Group toolbar, manual Next ID with backward-step warning, Open-Registry shortcut on the `IdStruct` drawer. + +The `IdStructGenerator` generates the struct-side boilerplate; the registry asset is created via `Assets → Create → Aspid/Id Registry/Id Registry`. + +**SerializedProperty Extensions** (`Unity/Editor/Scripts/SerializedProperties/`): Fluent chainable extensions (`.SetValue()`, `.Apply()`, reflection helpers). Split across multiple partial files. + +**VisualElement Extensions** (`Unity/Runtime/VisualElements/Extensions/`): Extensive fluent API for UIToolkit — layout, sizing, style, borders, colors, transitions, callbacks, USS, child management, etc. Organized into subdirectories by element type (`Button/`, `CallbackEventHandler/`, `Field/`, `Focusable/`, `Foldout/`, `HelpBox/`, `IMGUIContainer/`, `IMixedValueSupport/`, `INotifyValueChanged/`, `IStyle/`, `Image/`, `List/`, `ProgressBar/`, `Slider/`, `TextElement/`) plus top-level partial files (`VisualElementExtensions.cs`, `.Style.cs`, `.Style.Preset.cs`, `.Uss.cs`, `.Child.cs`). Editor-side command extensions in `Unity/Editor/Scripts/VisualElements/Extensions/`. + +**Internal Editor VisualElement Components** (`Unity/Editor/Scripts/VisualElements/Internal/`): Custom UIToolkit elements for editor UI. Layout: + +- `Components/` — concrete elements, each in its own subfolder: + - `AspidAnimatedDotsBackground/`, `AspidAnimatedTitle/` — decorative animated elements. + - `AspidAnimatedLogo/` — `AspidAnimatedLogo`, `AspidAnimatedLogoPreset`, fluent extensions, plus `Styles/` with `AspidAnimatedLogoPulseSpeedStyle`, `AspidAnimatedLogoPulseHoverAmplitudeStyle` and `AspidAnimatedLogoLayerImageStyle` (USS-driven float and Texture2D bindings). + - `AspidDividingLines/` — `AspidDividingLine`, `AspidDividingLinePreset`, fluent extensions, plus `Styles/` with `AspidDividingLineSizeStyle` and `AspidDividingLineDirectionStyle` (USS-driven enum bindings). + - `AspidLabels/` — `AspidLabel`, `AspidLabelPreset`, fluent extensions, plus `Styles/` with `AspidLabelSizeStyle` and `AspidLabelFontStyle`. + - `AspidContainers/` — `AspidBox`, `AspidBoxPreset`, fluent extensions. + - `AspidGradientButton/` — `AspidGradientButton`, `AspidGradientButtonPreset`, fluent extensions, plus `Styles/`. + - `AspidHelpBoxes/` — `AspidHelpBox`, `AspidHelpBoxPreset`, fluent extensions. + - `AspidHoverGradientOverlays/` — `AspidHoverGradientOverlay` and its `Styles/` (USS-driven hover-tracking overlay shared by other components). + - `AspidInspectorHeaders/` — `AspidInspectorHeader`, `AspidInspectorHeaderPreset`, fluent extensions, plus `Styles/`. +- `Styles/` — shared helpers used across components: `AspidStyles` (USS class/property registry), `StatusStyle`, `ThemeStyle`, `InlineStyle` (USS-vs-code precedence helper). The companion `ICustomStyleExtensions` (extension methods on `ICustomStyle`, including `TryGetByEnum`) lives in `Unity/Runtime/VisualElements/Extensions/ICustomStyle/` since it ships with player builds and is consumed by both runtime and editor styles. + +All components use `Aspid-FastTools-Default-Dark.uss` as the base stylesheet (loaded via `AspidStyles.DefaultStyleSheet`) and follow the same `.AddClass()` pattern. Theme/status/size/direction enums are exposed as nested `Type` enums on their respective `Style` structs (e.g. `ThemeStyle.Type`, `AspidLabelSizeStyle.Type`). + +**IMGUI Scopes** (`Unity/Editor/Scripts/IMGUI/`): Disposable `VerticalScope`, `HorizontalScope`, `ScrollViewScope` wrappers with `Rect` properties. + +**Editor Extensions** (`Unity/Editor/Scripts/Extensions/`): `GetScriptName()` and `GetScriptNameWithIndex()` on `MonoScript` — respects `[AddComponentMenu]` attribute and appends index suffix for duplicate components. + +**Welcome Window** (`Unity/Editor/Scripts/Welcome/`): `WelcomeWindow` (`EditorWindow`, menu `Tools/Aspid FastTools/Welcome`) + `WelcomeWindowStartup` (auto-show on first import). UXML/USS at `Resources/UI/Windows/Welcome/Aspid-FastTools-Welcome.{uxml,uss}`. Lists installable samples by reading `package.json`. + +### Editor Code Conventions + +**PropertyDrawers:** Always `internal sealed class`. Complex drawers split into a static helper `{Feature}Drawer` with `DrawIMGUI()` and `DrawUIToolkit()` methods — see `SerializableTypeDrawer.cs` as reference. + +**USS stylesheets:** Loaded via `.AddStyleSheetsFromResource("UI/{Domain}/Aspid-FastTools-{Feature}")` (e.g. `UI/Components/Aspid-FastTools-AspidLabel`, `UI/Ids/Aspid-FastTools-Id-Registry`). Component code keeps the path in a `private const string StyleSheetPath`; ID-system code centralises paths in `Constants.cs`. Styling goes in USS; code only applies `.AddClass()`. The base palette `AspidStyles.DefaultStyleSheet` (`UI/Aspid-FastTools-Default-Dark`) must be added first on new internal editor components — `AspidStyles` is the single source of truth for shared USS class/property names. + +**USS class naming (BEM):** Follow Unity's recommended Block-Element-Modifier convention (see [UIE-USS-WritingStyleSheets](https://docs.unity3d.com/6000.4/Documentation/Manual/UIE-USS-WritingStyleSheets.html)). + +Format: `aspid-fasttools-{block}[__{element}][--{modifier}]` + +- **Prefix** `aspid-fasttools-` is mandatory and joined to the block with a single `-` (matches Unity's own `unity-foldout__toggle` style — the prefix is a namespace, not a BEM block). +- **Block** — feature/component name in kebab-case: `id-registry`, `id-drawer`, `enum-values`, `serializable-type`. +- **Element** — part of a block, joined with `__`: `aspid-fasttools-id-drawer__add-button`, `aspid-fasttools-id-registry__delete`. +- **Modifier** — state or variant, joined with `--`: `aspid-fasttools-id-registry__warning--visible`, `aspid-fasttools-status--error`. +- **kebab-case inside any segment** (`add-button`, never `addButton` or `add_button`). +- **Utility/state classes** (status, theme) are blocks of their own: `aspid-fasttools-status--error`, `aspid-fasttools-theme--dark`. + +Pre-existing classes that use `-` instead of `__` between block and element (e.g. `aspid-fasttools-id-drawer-add-button`) are legacy. Migrate to BEM when touching the surrounding code; new classes must follow the rule from the start. + +**USS variable naming:** USS custom properties are design tokens with a positional grammar — not BEM (variables have no block/element/modifier). Follow Unity's separator convention from built-in `--unity-*` variables: `-` between slots, `_` for compound words inside a single slot. See [UIE-USS-UnityVariables](https://docs.unity3d.com/6000.4/Documentation/Manual/UIE-USS-UnityVariables.html). + +Format: `--{prefix}-{group}-{role}[-{state}][-{tone}]` + +| Slot | Values | Required | +|---|---|---| +| `prefix` | `aspid` (palette shared between Aspid packages) / `aspid-fasttools` (product-specific) | yes | +| `group` | `colors` · `icons` · `metrics` · `prop` | yes | +| `role` | `bg`, `shade`, `text`, `border`, `icon`, `status`, `gradient`, `label_size`, `line_size`, `theme`, … | yes | +| `state` | `success`, `warning`, `error`, `info`, `hover`, `pressed`, … | optional | +| `tone` | `darkness`, `dark`, `light`, `lightness` | optional | + +Rules: +- One word per slot, or one compound joined by `_` (`label_size`) — never two independent concepts in one slot. +- Order is `state` → `tone` (`success-darkness`, not `darkness-success`): "what is it" first, then "how bright". +- Color roles: `bg` is the surface palette; `shade` is the generic content palette (used when the role isn't specialised — text, border or icon-tint share the same shade swatch). `text`/`border`/`icon` are specialised roles for component-local variables that need their own swatch (see `Aspid-FastTools-Id-Registry-Entry-Field` style sheet for examples). `status` covers `success`/`warning`/`error`/`info` semantics. +- `prop` group is for inline component parameters (e.g. `--aspid-fasttools-prop-theme`), not palette tokens. +- Palette variables declared on `:root`; component-scoped variables on the component selector. + +Examples: +``` +--aspid-colors-bg-darkness /* surface, very dark */ +--aspid-colors-shade-lightness /* generic content, very light */ +--aspid-colors-text-light /* component-specific text colour */ +--aspid-colors-border-darkness /* component-specific border colour */ +--aspid-colors-status-success /* status base */ +--aspid-colors-status-success-darkness /* status, very dark variant */ +--aspid-icons-status-error /* status icon resource */ +--aspid-fasttools-metrics-label_size /* compound role */ +--aspid-fasttools-prop-status /* inline component param */ +``` + +All palette variables in `Aspid-FastTools-Default-Dark.uss` already follow this grammar; new variables in any other stylesheet must follow it from the start. + +**README files:** 4 files to keep in sync: root `README.md`/`README_RU.md` and `Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/README.md`/`README_RU.md`. Image paths differ between them. + +### Local Claude Code automation + +- **PostToolUse hook** (`.claude/hooks/rebuild-generators-on-change.sh`): on every `Edit`/`Write` to `*.cs` under `Aspid.FastTools.Generators/Aspid.FastTools.Generators/`, runs `dotnet build -c Release` for the generator project (which redeploys the DLL into the Unity package). Unity-side edits, tests, and the Sample project are explicitly skipped — keep that scope when changing the hook. +- **Project skills** (`.claude/skills/`): `build-generator` (manual generator build + DLL deploy), `sync-readmes` (verify README EN/RU + root/Documentation copies against the codebase). +- **Project subagents** (`.claude/agents/`): `code-reviewer` (Unity/Editor boundary + generator + package convention review), `uss-bem-checker` (validates USS class names + `--aspid-*` variables against the BEM/positional grammars above). + +### Submodule + +`Aspid.Internal.Unity` is a git submodule providing internal Unity helpers. It is referenced but not part of the main package distribution. diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..eb6b3d2 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,133 @@ +--- +name: Aspid FastTools Editor +description: Dark, utilitarian design system for Unity Editor tooling — flat surfaces layered by neutral value, gemstone-themed semantic statuses in parallel text/shade scales, and a 4-stop background ramp for deep content layering. +version: 1.1.0 +status: active +theme: dark + +colors: + # Core neutral surface ramp (darkest → lightest) + darkness: "#1A1A1A" + dark: "#242424" + light: "#2E2E2E" + lightness: "#383838" + + # Primary text ramp (Dimmed for eye comfort) + text-darkness: "#6E6E6E" + text-dark: "#969696" + text-light: "#BEBEBE" + text-lightness: "#DCDCDC" + + # Neutral "shade" ramp — used for separators and borders + shade-darkness: "#2D2D2D" + shade-dark: "#3C3C3C" + shade-light: "#505050" + shade-lightness: "#646464" + + # Gemstone Bases — deep body fills for status backgrounds + success: "#0C411E" # Emerald + warning: "#55370A" # Topaz + error: "#551414" # Ruby + info: "#0F2D55" # Sapphire + + # Success (Emerald) scale (darkness → lightness) + success-text: ["#376E41", "#55AF64", "#78EB91", "#B4FFC8"] + success-shade: ["#19371E", "#285532", "#418250", "#5FBE73"] + success-bg: ["#082814", "#0C411E", "#145A2D", "#1E783C"] + + # Warning (Topaz) scale + warning-text: ["#785523", "#B9873C", "#F5B955", "#FFEBAF"] + warning-shade: ["#372814", "#5A411E", "#876432", "#B98C4B"] + warning-bg: ["#2D1E05", "#55370A", "#7D5514", "#A5731E"] + + # Error (Ruby) scale + error-text: ["#7D2D2D", "#B94141", "#EB5F5F", "#FFAFAF"] + error-shade: ["#371919", "#5A2D2D", "#874141", "#BE5F5F"] + error-bg: ["#320A0A", "#551414", "#7D2323", "#A53232"] + + # Info (Sapphire) scale + info-text: ["#28507D", "#4182B9", "#5AB9F0", "#BEF0FF"] + info-shade: ["#142337", "#23415F", "#376491", "#5591C8"] + info-bg: ["#081932", "#0F2D55", "#194B82", "#2369B4"] + +typography: + fontFamily: "Unity default (Inter / system sans)" + + h1: + fontSize: 16px + fontWeight: "700" + usage: "Inspector header titles" + h2: + fontSize: 14px + fontWeight: "600" + usage: "Section titles" + h3: + fontSize: 12px + fontWeight: "500" + usage: "Subheaders / header subtext" + body: + fontSize: 12px + fontWeight: "400" + usage: "Default inspector body text" + +spacing: + unit: 5px + micro: 2px + sm: 5px + lg: 10px + inspector-offset: -10px + +radii: + xs: 3px + sm: 5px + lg: 10px + +elevation: + level-0: "Unity Default Grey" + level-1: "background — {colors.darkness}" + level-2: "container — {colors.dark}" + level-3: "raised — {colors.light}" + +--- + +# Aspid FastTools — Design Language + +Aspid FastTools ships as editor tooling for Unity 2022.3+, inheriting Unity's dark editor chrome while layering a disciplined, **Gemstone-themed** design language for content surfaces and status semantics. + +## Brand & Voice + +The personality is **engineer-first**: calm, dense, and grounded. The visual tone borrows from professional IDEs: deep jewel-toned backgrounds, saturated but controlled status accents, and a clear distinction between structural lines and interactive text. + +## Color System (The Gemstone Model) + +Color is organized into three parallel neutral ramps and four semantic status "Gemstones". Each axis follows a strict four-stop scale: **darkness → dark → light → lightness**. + +- **Neutral Surface Ramp.** `{darkness}` (#1A1A1A) is for recessed strips; `{dark}` (#242424) is the default card fill; `{light}` (#2E2E2E) is for raised controls. +- **General Text Ramp.** Dimmed to avoid "neon glow" on dark backgrounds. `{text-lightness}` (#DCDCDC) for primary headers; `{text-light}` (#BEBEBE) for body text. +- **Shade Ramp.** Muted neutrals used exclusively for structural borders and separators (e.g., `{shade-dark}` #3C3C3C). +- **Gemstone Statuses.** + - **Emerald (Success)**: Cold, clean green for validation and confirmed states. + - **Ruby (Error)**: Deep, saturated red for destruction and invalid inputs. + - **Topaz (Warning)**: Golden amber for advisories. + - **Sapphire (Info)**: Royal blue for neutral callouts. + +### Scaling Strategy +Each Gemstone is subdivided into: +1. **Background Scale**: Deep, low-chroma body fills for containers. +2. **Text Scale**: High-chroma, vibrant variants for readable labels. +3. **Shade Scale**: Muted, mid-tone variants for borders and status lines. + +## Components + +- **AspidBox** — The rounded-10 card. Uses `{colors.dark}` by default. +- **AspidDividingLine** — Structural rules. Always uses the `{shade}` scale or status `{shade}` variant to remain secondary to text. +- **AspidLabel** — Content blocks. Uses the `{text}` scale or status `{text}` variant for maximum contrast and "brilliance". +- **AspidInspectorHeader** — Hero strips. Pairs a 40px icon with `{typography.h1}`. Backgrounds are bound to Gemstone base colors. +- **AspidHelpBox** — Advice strips. Backgrounds use Gemstone base, borders use status `{shade-dark}`, and text uses status `{text-lightness}` for "etched" legibility. + +## Principles + +1. **Text over Lines.** Text is always 20-40% more saturated/lighter than the structural borders (Shades) surrounding it. +2. **Grounded Saturation.** We avoid pure whites and neons. Depth comes from pigment richness (Gemstone hues), not luminosity. +3. **Density over Whitespace.** Designed for 320px-wide inspectors. Row heights are 18–22px; base spacing is 5px. +4. **Status as State.** Color is only used to convey status. If an element is neutral, it must stay in the neutral grey ramp. diff --git a/README.md b/README.md index 80b36da..86f426b 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,43 @@ -![](https://img.shields.io/badge/2022.3%2B-000000?style=flat&logo=unity&logoColor=white&color=4fa35d) +# Aspid.FastTools -# Unity Fast Tools -**Unity Fast Tools** is a set of tools designed to minimize routine code writing in Unity. -## Source Code -### [[Aspid.UnityFastTools](https://github.com/VPDPersonal/Aspid.UnityFastTools)] [[Aspid.UnityFastTools.Generators](https://github.com/VPDPersonal/Aspid.UnityFastTools.Generators)] +[![Unity 2022.3+](https://img.shields.io/badge/2022.3%2B-000000?style=flat&logo=unity&logoColor=white&color=4fa35d)](https://unity.com/) +[![Releases](https://img.shields.io/github/v/release/VPDPersonal/Aspid.FastTools?label=Release&labelColor=254d2c&color=4fa35d)](https://github.com/VPDPersonal/Aspid.FastTools/releases) +[![License](https://img.shields.io/github/license/VPDPersonal/Aspid.FastTools?label=License&labelColor=254d2c&color=4fa35d)](LICENSE) + +**Aspid.FastTools** is a set of tools designed to minimize routine code writing in Unity. --- ## Integration -You can install Aspid.UnitiFastTools using one of the following methods: -* **Download .unitypackage**: Visit the [Release page on GitHub](https://github.com/VPDPersonal/Aspid.UnityFastTools/releases) and download the latest version, `Aspid.UnityFastTools.X.X.X.unitypackage`. Import it into your project. + +Install Aspid.FastTools using one of the following methods: + +- **Download .unitypackage** — Visit the [Release page on GitHub](https://github.com/VPDPersonal/Aspid.FastTools/releases) and download the latest version, `Aspid.FastTools.X.X.X.unitypackage`. Import it into your project. +- **Via UPM** (Unity Package Manager) integrate the following packages: + - `https://github.com/VPDPersonal/Aspid.Internal.Unity.git` + - `https://github.com/VPDPersonal/Aspid.FastTools.git?path=Aspid.FastTools/Assets/Plugins/Aspid/FastTools` + +--- + +## Namespaces + +| Namespace | Description | +|-----------|-------------| +| `Aspid.FastTools.Types` | `SerializableType`, `SerializableType`, `ComponentTypeSelector`, `TypeSelectorAttribute` | +| `Aspid.FastTools.Enums` | `EnumValues` | +| `Aspid.FastTools.Ids` | `IId`, `UniqueIdAttribute`, `IdRegistry` | +| `Aspid.FastTools.UIElements` | Runtime `VisualElement` fluent extensions | +| `Aspid.FastTools.Editors` | Editor helpers — `SerializedProperty` extensions, IMGUI scopes, `GetScriptName` | +| `Aspid.FastTools.Types.Editors` · `.Enums.Editors` · `.Ids.Editors` · `.UIElements.Editors` | Per-feature editor code (property drawers, registry inspector, editor-only `VisualElement` extensions) | --- ## ProfilerMarker -``` csharp + +Provides source-generated `ProfilerMarker` registration. The generator creates a static marker per call-site, identified by the calling method and line number. + +```csharp using UnityEngine; -using Aspid.UnityFastTools; public class MyBehaviour : MonoBehaviour { @@ -39,12 +60,14 @@ public class MyBehaviour : MonoBehaviour // Some code using var _ = this.Marker().WithName("Calculate"); // Some code - } + } } } ``` + ### Generated code -``` csharp + +```csharp using System; using Unity.Profiling; using System.Runtime.CompilerServices; @@ -54,13 +77,13 @@ internal static class __MyBehaviourProfilerMarkerExtensions private static readonly ProfilerMarker DoSomething1_line_13 = new("MyBehaviour.DoSomething1 (13)"); private static readonly ProfilerMarker DoSomething2_line_19 = new("MyBehaviour.DoSomething2 (19)"); private static readonly ProfilerMarker DoSomething2_line_22 = new("MyBehaviour.Calculate (22)"); - + public static ProfilerMarker.AutoScope Marker(this MyBehaviour _, [CallerLineNumberAttribute] int line = -1) { if (line is 13) return DoSomething1_line_13.Auto(); if (line is 19) return DoSomething2_line_19.Auto(); if (line is 22) return DoSomething2_line_22.Auto(); - + throw new Exception(); } } @@ -68,142 +91,434 @@ internal static class __MyBehaviourProfilerMarkerExtensions ### Result -![Aspid.UnityFastTools.ProfilerMarkers.png](Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.ProfilerMarkers.png) +![Aspid.FastTools.ProfilerMarkers.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png) -## SerializedProperty Extensions -``` csharp -SerializedProperty property = GetProperty(); - -property.ApplyModifiedProperties(); -// property.serializedObject.ApplyModifiedProperties(); - -property.SetValue(10).ApplyModifiedProperties(); -// Or -property.SetValueAndApply(10); -// Or -property.SetInt(10).ApplyModifiedProperties(); -// Or -property.SetIntAndApply(10); -// property.intValue = 10; -// property.serializedObject.ApplyModifiedProperties(); - -property.SetValue(intValue).SetInt(intValue).SetValueAndApply(intValue).SetIntAndApply(intValue); -property.SetValue(uintValue).SetUint(uintValue).SetValueAndApply(uintValue).SetUintAndApply(uintValue); -property.SetValue(longValue).SetLong(longValue).SetValueAndApply(longValue).SetLongAndApply(longValue); -property.SetValue(ulongValue).SetUlong(ulongValue).SetValueAndApply(ulongValue).SetUlongAndApply(ulongValue); -property.SetValue(floatValue).SetFloat(floatValue).SetValueAndApply(floatValue).SetFloatAndApply(floatValue); -property.SetValue(doubleValue).SetDouble(doubleValue).SetValueAndApply(doubleValue).SetDoubleAndApply(doubleValue); -property.SetValue(boolValue).SetBool(boolValue).SetValueAndApply(boolValue).SetBoolAndApply(boolValue); -property.SetValue(rectValue).SetRect(rectValue).SetValueAndApply(rectValue).SetRectAndApply(rectValue); -property.SetValue(rectIntValue).SetRectInt(rectIntValue).SetValueAndApply(rectIntValue).SetRectIntAndApply(rectIntValue); -property.SetValue(boundsValue).SetBounds(boundsValue).SetValueAndApply(boundsValue).SetBoundsAndApply(boundsValue); -property.SetValue(boundsIntValue).SetBoundsInt(boundsIntValue).SetValueAndApply(boundsIntValue).SetBoundsIntAndApply(boundsIntValue); -property.SetValue(colorValue).SetColor(colorValue).SetValueAndApply(colorValue).SetColorAndApply(colorValue); -property.SetValue(gradientValue).SetGradient(gradientValue).SetValueAndApply(gradientValue).SetGradientAndApply(gradientValue); -property.SetValue(hash128Value).SetHash128(hash128Value).SetValueAndApply(hash128Value).SetHash128AndApply(hash128Value); -property.SetValue(vactor4Value).SetVector4(vactor4Value).SetValueAndApply(vactor4Value).SetVector4AndApply(vactor4Value); -property.SetValue(vactor3Value).SetVector3(vactor3Value).SetValueAndApply(vactor3Value).SetVector3AndApply(vactor3Value); -property.SetValue(vactor3IntValue).SetVector3Int(vactor3IntValue).SetValueAndApply(vactor3IntValue).SetVector3IntAndApply(vactor3IntValue); -property.SetValue(vactor2Value).SetVector2(vactor2Value).SetValueAndApply(vactor2Value).SetVector2AndApply(vactor2Value); -property.SetValue(vactor2IntValue).SetVector2Int(vactor2IntValue).SetValueAndApply(vactor2IntValue).SetVector2IntAndApply(vactor2IntValue); -property.SetValue(quaternionValue).SetQuaternion(quaternionValue).SetValueAndApply(quaternionValue).SetQuaternionAndApply(quaternionValue); -property.SetValue(stringValue).SetString(stringValue).SetValueAndApply(stringValue).SetStringAndApply(stringValue); -property.SetValue(animationCurveValue).SetAnimationCurveValue(animationCurveValue).SetValueAndApply(animationCurveValue).SetAnimationCurveValueAndApply(animationCurveValue); - -property.SetEnumFlag(intValue).SetEnumFlagAndApply(intValue); -property.SetEnumIndex(intValue).SetEnumIndexAndApply(intValue); -property.SetArraySize(intValue).SetArraySizeAndApply(intValue); -property.SetManagedReference(objectValue).SetManagedReferenceAndApply(objectValue); -property.SetObjectReference(unityObjectValue).SetObjectReferenceAndApply(unityObjectValue); -property.SetExposedReference(unityObjectValue).SetExposedReferenceAndApply(unityObjectValue); - -// For Unity 6 -property.SetBoxed(objectValue).SetBoxedAndApply(objectValue); - -// For Unity 6.2 -property.SetValue(entityIdValue).SetEntityId(entityIdValue).SetValueAndApply(entityIdValue).SetEntityIdAndApply(entityIdValue); -``` - -## IMGUI Extensions -``` csharp -usign UnityEditor; -using Aspid.UnityFastTools.Editors; - -[CustomEditor(typeof(MyBegaviour))] -public class MyEditor : Editor -{ - public void override OnInspectorGUI() - { - // Or using (VerticalScope.Begin()); - using (AspidEdtiroGUILayout.BeginVertical()) - { - - } - - // Or using (HorizontalScope.Begin()); - using (AspidEdtiroGUILayout.BegingHorizontal()) - { - - } - - var position = Vector2.zero; - // Or using (ScrollViewScope.Begin(ref position)); - using (AspidEdtiroGUILayout.BeginScrollView(ref position)) - { - - } +--- + +## Serializable Type System + +Allows serializing a `System.Type` reference in the Unity Inspector. The selected type is stored as an assembly-qualified name and resolved lazily on first access. + +### SerializableType + +Two variants are available: + +- **`SerializableType`** — stores any type (base type is `object`) +- **`SerializableType`** — stores a type constrained to `T` or its subclasses + +Both support implicit conversion to `System.Type`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private SerializableType _anyType; + [SerializeField] private SerializableType _behaviourType; + + private void Start() + { + Type type1 = _anyType; // implicit operator + Type type2 = _behaviourType.Type; // explicit property + + var instance = (MonoBehaviour)gameObject.AddComponent(type2); + } +} +``` +![Aspid.FastTools.SerializableType.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png) +### ComponentTypeSelector + +A serializable struct that renders a type-switching dropdown in the Inspector. Add it as a field to a base class — picking a subtype rewrites `m_Script` on the `SerializedObject`, effectively changing the component or ScriptableObject to the chosen subtype. + +The dropdown is automatically constrained to subtypes of the class that declares the field. No additional configuration is required. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public abstract class BaseEnemy : MonoBehaviour +{ + [SerializeField] private ComponentTypeSelector _typeSelector; +} + +public class FastEnemy : BaseEnemy { } +public class TankEnemy : BaseEnemy { } +``` + +--- + +### TypeSelectorAttribute + +An editor-only `PropertyAttribute` that restricts the type selection popup to specific base types. Applied to `string` fields that store assembly-qualified type names. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class TypeSelectorAttribute : PropertyAttribute +{ + public TypeSelectorAttribute() // base type: object + public TypeSelectorAttribute(Type type) + public TypeSelectorAttribute(params Type[] types) + public TypeSelectorAttribute(string assemblyQualifiedName) + public TypeSelectorAttribute(params string[] assemblyQualifiedNames) + + public TypeAllow Allow { get; set; } // default: TypeAllow.None +} + +[Flags] +public enum TypeAllow +{ + None = 0, + Abstract = 1, + Interface = 2, + All = Abstract | Interface +} +``` + +| Property | Description | +|----------|-------------| +| `Allow` | Which special type categories (abstract classes, interfaces) the picker includes in addition to plain concrete classes. Default: `TypeAllow.None` | + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [TypeSelector(typeof(IMyInterface))] + [SerializeField] private string _typeName; + + // Include abstract types and interfaces in the picker + [TypeSelector(typeof(object), Allow = TypeAllow.All)] + [SerializeField] private string _anyType; +} +``` + +### Type Selector Window + +The Inspector shows a button that opens a searchable popup window with: + +- Hierarchical namespace organization +- Text search with filtering +- Keyboard navigation (Arrow keys, Enter, Escape) +- Navigation history (back button) +- Assembly disambiguation for types with identical names + +![Aspid.FastTools.TypeSelectorWindow.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png) +--- + +## Enum System + +Provides serializable enum-to-value mappings configurable from the Inspector. + +### EnumValues\ + +A serializable collection of `EnumValue` entries with a configurable default value. Implements `IEnumerable>`. + +```csharp +[Serializable] +public sealed class EnumValues : IEnumerable> +``` + +| Member | Description | +|--------|-------------| +| `TValue GetValue(Enum enumValue)` | Returns the mapped value, or `_defaultValue` if not found | +| `bool Equals(Enum, Enum)` | Equality check with proper `[Flags]` support | + +Supports `[Flags]` enums: `Equals` uses `HasFlag` and treats `0`-valued members correctly. + +```csharp +using UnityEngine; +using Aspid.FastTools.Enums; + +public enum Direction { Left, Right, Up, Down } + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private EnumValues _directionSprites; + + private void SetIcon(Direction dir) + { + var sprite = _directionSprites.GetValue(dir); + _image.sprite = sprite; + } +} +``` + +In the Inspector, select the enum type in the `EnumValues` header, then assign a value for each enum member. Right-click the property to open a context menu with **Populate Missing Enum Members** — it appends an entry for every enum member not yet in the list, seeded with the current Default Value. + +--- + +## ID System + +> **Beta:** the ID System is currently in beta. The public API, generated code layout and editor workflow may change in future releases. + +Maps an asset-assignable name to a stable integer ID. Use the resulting `int` in `switch` statements and `Dictionary` keys without paying for string lookups at runtime. + +A single `IdRegistry` ScriptableObject maps string names to stable integer IDs and provides full `int ↔ string` lookups at runtime. + +### Setup + +**1.** Declare a `partial struct` implementing `IId`. The source generator adds the required fields and property automatically: + +```csharp +using Aspid.FastTools.Ids; + +public partial struct EnemyId : IId { } +``` + +Generated code: + +```csharp +public partial struct EnemyId +{ + [SerializeField] private string __stringId; // editor-only field, stripped from player builds + [SerializeField] private int _id; + + public int Id => _id; +} +``` + +**2.** Create the registry asset and bind it to the struct type in its Inspector: +- `Assets → Create → Aspid → Id Registry` + +**3.** Use the struct as a serialized field. The Inspector shows a dropdown of registered names; the selector window also lets you create new entries on the fly: + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +[CreateAssetMenu] +public class EnemyDefinition : ScriptableObject +{ + [UniqueId] [SerializeField] private EnemyId _id; +} +``` + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +public class EnemySpawner : MonoBehaviour +{ + [SerializeField] private EnemyId _targetEnemy; + + private void Spawn() + { + int id = _targetEnemy.Id; // stable integer, safe for switch / Dictionary } } ``` +### UniqueIdAttribute + +Marks a field as requiring a unique value across all assets of the declaring type. The Inspector shows a warning if two assets share the same ID. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class UniqueIdAttribute : PropertyAttribute { } +``` + +### IdRegistry + +`ScriptableObject` in `Aspid.FastTools.Ids` that stores `(int, string)` entries and keeps the lookup tables available at runtime. Each name is assigned a stable, auto-incrementing ID that never changes when other entries are added or removed. + +| Member | Description | +|--------|-------------| +| `bool TryGetId(string name, out int id)` | Returns `true` and the ID when found; otherwise `false` | +| `bool TryGetName(int id, out string name)` | Returns `true` and the name when found; otherwise `false` and `string.Empty` | +| `bool Contains(int id)` | Whether an ID is registered | +| `bool Contains(string name)` | Whether a name is registered | +| `int Count` | Number of entries | +| `IReadOnlyList Ids` · `IReadOnlyList IdNames` | Registered IDs / names, in registration order | +| `IEnumerator> GetEnumerator()` | Iterate `(id, name)` pairs | + +The registry derives from `ScriptableObject` directly and exposes a generic counterpart `IdRegistry` (with `T : struct, IId`) that adds typed `Contains(T)` and `TryGetName(T, out string)` overloads. Edits — adding, renaming, removing entries — happen through the registry inspector and `RegistryEditorCore`, not via a public runtime API. + +--- + +## SerializedProperty Extensions + +Chainable extensions on `SerializedProperty` for synchronizing the owning `SerializedObject`, writing typed values, and reflecting on the underlying field. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +property + .Update() + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +The package covers: + +- **Update / Apply** — `Update`, `UpdateIfRequiredOrScript`, `ApplyModifiedProperties`. +- **Typed setters** — `SetValue` (generic dispatch) and `SetXxx` for `int`/`uint`/`long`/`ulong`/`float`/`double`/`bool`/`string`/`Color`/`Gradient`/`Hash128`/`Rect`/`RectInt`/`Bounds`/`BoundsInt`/`Vector2..4` (and `Vector2/3Int`)/`Quaternion`/`AnimationCurve`/`EntityId` (Unity 6.2+). Each comes with a paired `SetXxxAndApply` variant. +- **Enum setters** — `SetEnumFlag` and `SetEnumIndex` (each + `AndApply`). +- **Arrays** — `SetArraySize`, `AddArraySize`, `RemoveArraySize` (each + `AndApply`). +- **References** — `SetManagedReference`, `SetObjectReference`, `SetExposedReference`, and `SetBoxed` (Unity 6+). +- **Reflection helpers** — `GetPropertyType`, `GetMemberInfo`, `GetClassInstance` for resolving the C# member and runtime instance behind a property. + +> Full method-by-method reference: [SerializedPropertyExtensions.md](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions.md) + +--- + +## IMGUI Layout Scopes + +```csharp +using Aspid.FastTools.Editors; +``` + +Three `ref struct` scopes — `VerticalScope`, `HorizontalScope`, `ScrollViewScope` — wrap `EditorGUILayout.Begin*` / `End*`. Each exposes a `Rect` property and calls the matching `End*` method on `Dispose`: + +```csharp +using (VerticalScope.Begin()) +{ + EditorGUILayout.LabelField("Item 1"); + EditorGUILayout.LabelField("Item 2"); +} + +using (HorizontalScope.Begin()) +{ + EditorGUILayout.LabelField("Left"); + EditorGUILayout.LabelField("Right"); +} + +var scrollPos = Vector2.zero; +using (ScrollViewScope.Begin(ref scrollPos)) +{ + EditorGUILayout.LabelField("Scrollable content"); +} +``` + +Capture the group rect with the `out`-overload when needed: + +```csharp +using (VerticalScope.Begin(out var rect, GUI.skin.box)) +{ + EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.1f)); + EditorGUILayout.LabelField("Boxed content"); +} +``` + +All `Begin` overloads match the corresponding `EditorGUILayout.Begin*` signatures (optional `GUIStyle`, `GUILayoutOption[]`, scroll view options, etc.). + +--- + ## VisualElement Extensions -``` csharp + +Fluent extension methods for building UIToolkit trees in code. All methods return `T` (the element itself) for chaining. + +```csharp +using Aspid.FastTools.UIElements; // runtime extensions +using Aspid.FastTools.UIElements.Editors; // editor-only extensions (e.g. AddOpenScriptCommand) +``` + +### Quick reference + +The package covers: + +- **Core element operations** — name, visibility, tooltip, user data, picking mode, data source, and `AddChild`/`InsertChild` helpers. +- **Focus** — `SetFocus`, `SetBlur`, `SetTabIndex`, `SetFocusable`. +- **USS** — `AddClass`/`RemoveClass`/`ToggleInClass`/`EnableInClass`, `AddStyleSheets[FromResource]`. +- **Styles** — every `IStyle` property: layout, size, spacing, font, text, color, border, background, transform (incl. Unity 6.3+ aspect/filter/material), transition, overflow, slice, cursor. +- **Specialized elements** — `TextElement`, `ITextEdition`, `ITextSelection`, `BaseField`, `BaseBoolField` (Toggle), `INotifyValueChanged` (with optional `Unity.Mathematics` types), `IMixedValueSupport`, `Button`, `Slider`/`BaseSlider`, `ProgressBar`, `HelpBox`, `Foldout`, `Image`, `IMGUIContainer`, plus the full `ListView`/`TreeView`/`MultiColumn*` surface. +- **Editor-only commands** — `AddOpenScriptCommand`, `BindTo`/`BindPropertyTo`, `EnumField`/`EnumFlagsField` `Initialize`, and `PropertyField` value-change subscriptions. +- **USS custom-style helpers** — `ICustomStyle.TryGetByEnum` for parsing string USS properties as enums. + +> Full method-by-method reference: [VisualElementExtensions.md](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions.md) + +### Full example + +```csharp using UnityEditor; using UnityEngine; -using Aspid.UnityFastTools; +using Aspid.FastTools.Editors; // GetScriptName +using Aspid.FastTools.UIElements; // runtime VisualElement extensions +using Aspid.FastTools.UIElements.Editors; // AddOpenScriptCommand using UnityEngine.UIElements; -using Aspid.UnityFastTools.Editors; -[CustomEditor(typeof(VisualElementInspector))] -public class VisualElementInspectorEditor : Editor +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor { public override VisualElement CreateInspectorGUI() { - const string iconPath = "Editor/Aspid.UnityFastTools Icon"; - + const string iconPath = "Editor/MyIcon"; + var scriptName = target.GetScriptName(); - var darkColor = new Color(0.15f, 0.15f, 0.15f); - var lightColor = new Color(0.75f, 0.75f, 0.75f); - + var dark = new Color(0.15f, 0.15f, 0.15f); + var light = new Color(0.75f, 0.75f, 0.75f); + return new VisualElement() .SetName("Header") - .SetBackgroundColor(darkColor) + .SetBackgroundColor(dark) .SetFlexDirection(FlexDirection.Row) - .SetPadding(top : 5, bottom : 5, left: 10, right: 10) - .SetBorderRadius(topLeft: 10, topRight:10, bottomLeft:10, bottomRight:10) + .SetPadding(top: 5, bottom: 5, left: 10, right: 10) + .SetBorderRadius(topLeft: 10, topRight: 10, bottomLeft: 10, bottomRight: 10) .AddChild(new Image() - .SetName("HeaderIcon") + .SetName("Icon") .AddOpenScriptCommand(target) .SetImageFromResource(iconPath) .SetSize(width: 40, height: 40)) .AddChild(new Label(scriptName) - .SetName("HeaderText") + .SetName("Title") .SetFlexGrow(1) .SetFontSize(16) - .SetFlexShrink(1) .SetMargin(left: 10) - .SetColor(lightColor) + .SetColor(light) .SetAlignSelf(Align.Center) .SetOverflow(Overflow.Hidden) .SetWhiteSpace(WhiteSpace.NoWrap) .SetTextOverflow(TextOverflow.Ellipsis) - .SetUnityFontStyleAndWeight(FontStyle.Bold) - ); + .SetUnityFontStyleAndWeight(FontStyle.Bold)); } } ``` ### Result -![Aspid.UnityFastTools.VisualElement.png](Aspid.UnityFastTools/Assets/Plugins/Aspid/UnityFastTools/Documentation/Images/Aspid.UnityFastTools.VisualElement.png) +![Aspid.FastTools.VisualElement.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png) + +--- + +## Editor Helper Extensions + +Utility methods for getting display names of Unity objects in custom editors. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +public static string GetScriptName(this Object obj) +``` + +Returns the display name of a Unity object: +- If the type has `[AddComponentMenu]`, returns `ObjectNames.GetInspectorTitle(obj)` +- Otherwise returns `ObjectNames.NicifyVariableName(typeName)` + +```csharp +public static string GetScriptNameWithIndex(this Component targetComponent) +``` + +Returns the display name with a count suffix when multiple components of the same type exist on the same GameObject. For example, if two `AudioSource` components are attached, the second returns `"Audio Source (2)"`. + +```csharp +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + // "My Behaviour" — or "Custom Name" if [AddComponentMenu("Custom Name")] is present + var name = target.GetScriptName(); + + // "My Behaviour (2)" when a second component of the same type exists + var nameWithIndex = ((Component)target).GetScriptNameWithIndex(); + return new Label(name); + } +} +``` diff --git a/README_RU.md b/README_RU.md new file mode 100644 index 0000000..7b2bb6a --- /dev/null +++ b/README_RU.md @@ -0,0 +1,520 @@ +# Aspid.FastTools + +**Aspid.FastTools** — набор инструментов, предназначенных для минимизации рутинного написания кода в Unity. + +--- + +## Интеграция + +Установите Aspid.FastTools одним из следующих способов: + +- **Скачать .unitypackage** — Перейдите на [страницу релизов GitHub](https://github.com/VPDPersonal/Aspid.FastTools/releases) и скачайте последнюю версию `Aspid.FastTools.X.X.X.unitypackage`. Импортируйте его в проект. +- **Через UPM** (Unity Package Manager) подключите следующие пакеты: + - `https://github.com/VPDPersonal/Aspid.Internal.Unity.git` + - `https://github.com/VPDPersonal/Aspid.FastTools.git?path=Aspid.FastTools/Assets/Plugins/Aspid/FastTools` + +--- + +## Пространства имён + +| Пространство имён | Описание | +|-------------------|----------| +| `Aspid.FastTools.Types` | `SerializableType`, `SerializableType`, `ComponentTypeSelector`, `TypeSelectorAttribute` | +| `Aspid.FastTools.Enums` | `EnumValues` | +| `Aspid.FastTools.Ids` | `IId`, `UniqueIdAttribute`, `IdRegistry` | +| `Aspid.FastTools.UIElements` | Runtime fluent-расширения `VisualElement` | +| `Aspid.FastTools.Editors` | Редакторские утилиты — расширения `SerializedProperty`, IMGUI-области, `GetScriptName` | +| `Aspid.FastTools.Types.Editors` · `.Enums.Editors` · `.Ids.Editors` · `.UIElements.Editors` | Редакторский код по фичам (property drawers, инспектор реестров, editor-only расширения `VisualElement`) | + +--- + +## ProfilerMarker + +Предоставляет регистрацию `ProfilerMarker` через source generation. Генератор создаёт статический маркер для каждого места вызова, идентифицируемый по вызывающему методу и номеру строки. + +```csharp +using UnityEngine; + +public class MyBehaviour : MonoBehaviour +{ + private void Update() + { + DoSomething1(); + DoSomething2(); + } + + private void DoSomething1() + { + using var _ = this.Marker(); + // Некоторый код + } + + private void DoSomething2() + { + using (this.Marker()) + { + // Некоторый код + using var _ = this.Marker().WithName("Calculate"); + // Некоторый код + } + } +} +``` + +### Сгенерированный код + +```csharp +using System; +using Unity.Profiling; +using System.Runtime.CompilerServices; + +internal static class __MyBehaviourProfilerMarkerExtensions +{ + private static readonly ProfilerMarker DoSomething1_line_13 = new("MyBehaviour.DoSomething1 (13)"); + private static readonly ProfilerMarker DoSomething2_line_19 = new("MyBehaviour.DoSomething2 (19)"); + private static readonly ProfilerMarker DoSomething2_line_22 = new("MyBehaviour.Calculate (22)"); + + public static ProfilerMarker.AutoScope Marker(this MyBehaviour _, [CallerLineNumberAttribute] int line = -1) + { + if (line is 13) return DoSomething1_line_13.Auto(); + if (line is 19) return DoSomething2_line_19.Auto(); + if (line is 22) return DoSomething2_line_22.Auto(); + + throw new Exception(); + } +} +``` + +### Результат + +![Aspid.FastTools.ProfilerMarkers.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.ProfilerMarkers.png) + +--- + +## Система сериализуемых типов + +Позволяет сериализовать ссылку на `System.Type` в Unity Inspector. Выбранный тип хранится как assembly-qualified name и разрешается лениво при первом обращении. + +### SerializableType + +Доступны два варианта: + +- **`SerializableType`** — хранит любой тип (базовый тип — `object`) +- **`SerializableType`** — хранит тип, ограниченный `T` или его подклассами + +Оба поддерживают неявное преобразование в `System.Type`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private SerializableType _anyType; + [SerializeField] private SerializableType _behaviourType; + + private void Start() + { + Type type1 = _anyType; // неявный оператор + Type type2 = _behaviourType.Type; // явное свойство + + var instance = (MonoBehaviour)gameObject.AddComponent(type2); + } +} +``` +![Aspid.FastTools.SerializableType.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.SerializableType.png) +### ComponentTypeSelector + +Сериализуемая структура, добавляющая в Inspector выпадающий список для смены типа объекта. Добавьте её как поле в базовый класс — при выборе подтипа редактор перезаписывает `m_Script` на `SerializedObject`, фактически превращая компонент или ScriptableObject в выбранный подтип. + +Список автоматически ограничивается подтипами класса, в котором объявлено поле. Дополнительная настройка не требуется. + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public abstract class BaseEnemy : MonoBehaviour +{ + [SerializeField] private ComponentTypeSelector _typeSelector; +} + +public class FastEnemy : BaseEnemy { } +public class TankEnemy : BaseEnemy { } +``` + +--- + +### TypeSelectorAttribute + +Атрибут `PropertyAttribute`, доступный только в редакторе, ограничивающий всплывающее окно выбора типа конкретными базовыми типами. Применяется к полям `string`, хранящим assembly-qualified имена типов. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class TypeSelectorAttribute : PropertyAttribute +{ + public TypeSelectorAttribute() // базовый тип: object + public TypeSelectorAttribute(Type type) + public TypeSelectorAttribute(params Type[] types) + public TypeSelectorAttribute(string assemblyQualifiedName) + public TypeSelectorAttribute(params string[] assemblyQualifiedNames) + + public TypeAllow Allow { get; set; } // по умолчанию: TypeAllow.None +} + +[Flags] +public enum TypeAllow +{ + None = 0, + Abstract = 1, + Interface = 2, + All = Abstract | Interface +} +``` + +| Свойство | Описание | +|----------|----------| +| `Allow` | Какие специальные категории типов (абстрактные классы, интерфейсы) включаются в список выбора в дополнение к обычным конкретным классам. По умолчанию: `TypeAllow.None` | + +```csharp +using UnityEngine; +using Aspid.FastTools.Types; + +public class MyBehaviour : MonoBehaviour +{ + [TypeSelector(typeof(IMyInterface))] + [SerializeField] private string _typeName; + + // Включить абстрактные типы и интерфейсы в список выбора + [TypeSelector(typeof(object), Allow = TypeAllow.All)] + [SerializeField] private string _anyType; +} +``` + +### Окно выбора типа + +В Inspector отображается кнопка, открывающая всплывающее окно с поиском, которое включает: + +- Иерархическую организацию по пространствам имён +- Текстовый поиск с фильтрацией +- Навигацию с клавиатуры (стрелки, Enter, Escape) +- Историю навигации (кнопка «назад») +- Разрешение неоднозначности для типов с одинаковыми именами из разных сборок + +![Aspid.FastTools.TypeSelectorWindow.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.TypeSelectorWindow.png) +--- + +## Система перечислений + +Предоставляет сериализуемые отображения enum → значение, настраиваемые через Inspector. + +### EnumValues\ + +Сериализуемая коллекция записей `EnumValue` с настраиваемым значением по умолчанию. Реализует `IEnumerable>`. + +```csharp +[Serializable] +public sealed class EnumValues : IEnumerable> +``` + +| Член | Описание | +|------|----------| +| `TValue GetValue(Enum enumValue)` | Возвращает сопоставленное значение или `_defaultValue`, если не найдено | +| `bool Equals(Enum, Enum)` | Проверка равенства с поддержкой `[Flags]` | + +Поддерживает `[Flags]`-перечисления: `Equals` использует `HasFlag` и корректно обрабатывает члены со значением `0`. + +```csharp +using UnityEngine; +using Aspid.FastTools.Enums; + +public enum Direction { Left, Right, Up, Down } + +public class MyBehaviour : MonoBehaviour +{ + [SerializeField] private EnumValues _directionSprites; + + private void SetIcon(Direction dir) + { + var sprite = _directionSprites.GetValue(dir); + _image.sprite = sprite; + } +} +``` + +В Inspector выберите тип перечисления в заголовке `EnumValues`, затем назначьте значение для каждого члена перечисления. Нажмите правой кнопкой мыши по свойству, чтобы открыть контекстное меню с пунктом **Populate Missing Enum Members** — он добавит записи для всех отсутствующих членов перечисления, используя текущее Default Value как начальное значение. + +--- + +## Система ID + +> **Бета:** Система ID находится в бета-версии. Публичный API, структура генерируемого кода и редакторский UX могут измениться в будущих релизах. + +Сопоставляет имя, назначаемое в активе, со стабильным целочисленным ID. Получившийся `int` подходит для `switch` и ключей `Dictionary` без затрат на строковые поиски в рантайме. + +Единственный ScriptableObject `IdRegistry` сопоставляет строковые имена стабильным целочисленным ID и предоставляет полные `int ↔ string` поиски в рантайме. + +### Использование + +**1.** Объявите `partial struct`, реализующий `IId`. Генератор исходников автоматически добавит необходимые поля и свойство: + +```csharp +using Aspid.FastTools.Ids; + +public partial struct EnemyId : IId { } +``` + +Сгенерированный код: + +```csharp +public partial struct EnemyId +{ + [SerializeField] private string __stringId; // editor-only поле, вырезается из player-сборок + [SerializeField] private int _id; + + public int Id => _id; +} +``` + +**2.** Создайте ассет реестра и привяжите его к вашему типу структуры в Inspector: +- `Assets → Create → Aspid → Id Registry` + +**3.** Используйте структуру как сериализуемое поле. В Inspector отображается выпадающий список зарегистрированных имён; окно селектора также позволяет создавать новые записи на лету: + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +[CreateAssetMenu] +public class EnemyDefinition : ScriptableObject +{ + [UniqueId] [SerializeField] private EnemyId _id; +} +``` + +```csharp +using UnityEngine; +using Aspid.FastTools.Ids; + +public class EnemySpawner : MonoBehaviour +{ + [SerializeField] private EnemyId _targetEnemy; + + private void Spawn() + { + int id = _targetEnemy.Id; // стабильный integer, безопасен для switch / Dictionary + } +} +``` + +### UniqueIdAttribute + +Помечает поле как требующее уникального значения среди всех ассетов объявляющего типа. Inspector показывает предупреждение, если два ассета используют одинаковый ID. + +```csharp +[Conditional("UNITY_EDITOR")] +public sealed class UniqueIdAttribute : PropertyAttribute { } +``` + +### IdRegistry + +`ScriptableObject` из `Aspid.FastTools.Ids`, хранящий записи `(int, string)` и поддерживающий таблицы поиска доступными во рантайме. Каждому имени назначается стабильный, автоинкрементный ID, который не изменяется даже при добавлении или удалении других записей. + +| Член | Описание | +|------|----------| +| `bool TryGetId(string name, out int id)` | Возвращает `true` и найденный ID; иначе `false` | +| `bool TryGetName(int id, out string name)` | Возвращает `true` и найденное имя; иначе `false` и `string.Empty` | +| `bool Contains(int id)` | Зарегистрирован ли ID | +| `bool Contains(string name)` | Зарегистрировано ли имя | +| `int Count` | Количество записей | +| `IReadOnlyList Ids` · `IReadOnlyList IdNames` | Зарегистрированные ID / имена в порядке регистрации | +| `IEnumerator> GetEnumerator()` | Итерация по парам `(id, name)` | + +Реестр наследуется напрямую от `ScriptableObject` и предоставляет генерик-аналог `IdRegistry` (с `T : struct, IId`), добавляющий типизированные перегрузки `Contains(T)` и `TryGetName(T, out string)`. Редактирование — добавление, переименование, удаление записей — выполняется через инспектор реестра и `RegistryEditorCore`, а не через публичный runtime API. + +--- + +## Расширения SerializedProperty + +Цепочные расширения над `SerializedProperty` для синхронизации владеющего `SerializedObject`, записи типизированных значений и рефлексии над полем-источником. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +property + .Update() + .SetVector3(Vector3.up) + .SetBool(true) + .ApplyModifiedProperties(); +``` + +Пакет покрывает: + +- **Update / Apply** — `Update`, `UpdateIfRequiredOrScript`, `ApplyModifiedProperties`. +- **Типизированные сеттеры** — `SetValue` (обобщённый диспетчер) и `SetXxx` для `int`/`uint`/`long`/`ulong`/`float`/`double`/`bool`/`string`/`Color`/`Gradient`/`Hash128`/`Rect`/`RectInt`/`Bounds`/`BoundsInt`/`Vector2..4` (и `Vector2/3Int`)/`Quaternion`/`AnimationCurve`/`EntityId` (Unity 6.2+). К каждому идёт парный вариант `SetXxxAndApply`. +- **Enum-сеттеры** — `SetEnumFlag` и `SetEnumIndex` (каждый + `AndApply`). +- **Массивы** — `SetArraySize`, `AddArraySize`, `RemoveArraySize` (каждый + `AndApply`). +- **Ссылки** — `SetManagedReference`, `SetObjectReference`, `SetExposedReference`, а также `SetBoxed` (Unity 6+). +- **Рефлексионные хелперы** — `GetPropertyType`, `GetMemberInfo`, `GetClassInstance` для разрешения C#-члена и runtime-экземпляра, стоящих за property. + +> Полный справочник по методам: [SerializedPropertyExtensions_RU.md](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/SerializedPropertyExtensions_RU.md) + +--- + +## IMGUI-области разметки + +```csharp +using Aspid.FastTools.Editors; +``` + +Три `ref struct`-области — `VerticalScope`, `HorizontalScope`, `ScrollViewScope` — оборачивают `EditorGUILayout.Begin*` / `End*`. Каждая предоставляет свойство `Rect` и вызывает соответствующий метод `End*` в `Dispose`: + +```csharp +using (VerticalScope.Begin()) +{ + EditorGUILayout.LabelField("Item 1"); + EditorGUILayout.LabelField("Item 2"); +} + +using (HorizontalScope.Begin()) +{ + EditorGUILayout.LabelField("Left"); + EditorGUILayout.LabelField("Right"); +} + +var scrollPos = Vector2.zero; +using (ScrollViewScope.Begin(ref scrollPos)) +{ + EditorGUILayout.LabelField("Scrollable content"); +} +``` + +Получить rect области через перегрузку с `out`-параметром: + +```csharp +using (VerticalScope.Begin(out var rect, GUI.skin.box)) +{ + EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.1f)); + EditorGUILayout.LabelField("Boxed content"); +} +``` + +Все перегрузки `Begin` соответствуют сигнатурам `EditorGUILayout.Begin*` (опциональные `GUIStyle`, `GUILayoutOption[]`, параметры scroll view и т.д.). + +--- + +## Расширения VisualElement + +Fluent-методы расширения для построения UIToolkit-деревьев в коде. Все методы возвращают `T` (сам элемент) для цепочки вызовов. + +```csharp +using Aspid.FastTools.UIElements; // runtime-расширения +using Aspid.FastTools.UIElements.Editors; // editor-only расширения (например, AddOpenScriptCommand) +``` + +### Краткий справочник + +Пакет покрывает: + +- **Основные операции с элементом** — имя, видимость, tooltip, user data, picking mode, data source, а также хелперы `AddChild`/`InsertChild`. +- **Фокус** — `SetFocus`, `SetBlur`, `SetTabIndex`, `SetFocusable`. +- **USS** — `AddClass`/`RemoveClass`/`ToggleInClass`/`EnableInClass`, `AddStyleSheets[FromResource]`. +- **Стили** — все свойства `IStyle`: разметка, размер, отступы, шрифт, текст, цвет, рамка, фон, трансформации (вкл. aspect/filter/material с Unity 6.3+), переходы, overflow, slice, cursor. +- **Специализированные элементы** — `TextElement`, `ITextEdition`, `ITextSelection`, `BaseField`, `BaseBoolField` (Toggle), `INotifyValueChanged` (с опциональными типами `Unity.Mathematics`), `IMixedValueSupport`, `Button`, `Slider`/`BaseSlider`, `ProgressBar`, `HelpBox`, `Foldout`, `Image`, `IMGUIContainer`, а также полная поверхность `ListView`/`TreeView`/`MultiColumn*`. +- **Editor-only команды** — `AddOpenScriptCommand`, `BindTo`/`BindPropertyTo`, `Initialize` для `EnumField`/`EnumFlagsField`, подписка на изменения у `PropertyField`. +- **USS custom-style helpers** — `ICustomStyle.TryGetByEnum` для парсинга строковых USS-свойств в enum. + +> Полный справочник по методам: [VisualElementExtensions_RU.md](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/VisualElementExtensions_RU.md) + +### Полный пример + +```csharp +using UnityEditor; +using UnityEngine; +using Aspid.FastTools.Editors; // GetScriptName +using Aspid.FastTools.UIElements; // runtime-расширения VisualElement +using Aspid.FastTools.UIElements.Editors; // AddOpenScriptCommand +using UnityEngine.UIElements; + +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + const string iconPath = "Editor/MyIcon"; + + var scriptName = target.GetScriptName(); + var dark = new Color(0.15f, 0.15f, 0.15f); + var light = new Color(0.75f, 0.75f, 0.75f); + + return new VisualElement() + .SetName("Header") + .SetBackgroundColor(dark) + .SetFlexDirection(FlexDirection.Row) + .SetPadding(top: 5, bottom: 5, left: 10, right: 10) + .SetBorderRadius(topLeft: 10, topRight: 10, bottomLeft: 10, bottomRight: 10) + .AddChild(new Image() + .SetName("Icon") + .AddOpenScriptCommand(target) + .SetImageFromResource(iconPath) + .SetSize(width: 40, height: 40)) + .AddChild(new Label(scriptName) + .SetName("Title") + .SetFlexGrow(1) + .SetFontSize(16) + .SetMargin(left: 10) + .SetColor(light) + .SetAlignSelf(Align.Center) + .SetOverflow(Overflow.Hidden) + .SetWhiteSpace(WhiteSpace.NoWrap) + .SetTextOverflow(TextOverflow.Ellipsis) + .SetUnityFontStyleAndWeight(FontStyle.Bold)); + } +} +``` + +### Результат + +![Aspid.FastTools.VisualElement.png](Aspid.FastTools/Assets/Plugins/Aspid/FastTools/Documentation/Images/Aspid.FastTools.VisualElement.png) + +--- + +## Вспомогательные расширения для редактора + +Утилитарные методы для получения отображаемых имён объектов Unity в пользовательских редакторах. + +```csharp +using Aspid.FastTools.Editors; +``` + +```csharp +public static string GetScriptName(this Object obj) +``` + +Возвращает отображаемое имя объекта Unity: +- Если тип имеет `[AddComponentMenu]`, возвращает `ObjectNames.GetInspectorTitle(obj)` +- В противном случае возвращает `ObjectNames.NicifyVariableName(typeName)` + +```csharp +public static string GetScriptNameWithIndex(this Component targetComponent) +``` + +Возвращает отображаемое имя с числовым суффиксом, если на одном GameObject присутствует несколько компонентов одного типа. Например, если прикреплены два компонента `AudioSource`, второй вернёт `"Audio Source (2)"`. + +```csharp +[CustomEditor(typeof(MyBehaviour))] +public class MyBehaviourEditor : Editor +{ + public override VisualElement CreateInspectorGUI() + { + // "My Behaviour" — или "Custom Name", если присутствует [AddComponentMenu("Custom Name")] + var name = target.GetScriptName(); + + // "My Behaviour (2)" при наличии второго компонента того же типа + var nameWithIndex = ((Component)target).GetScriptNameWithIndex(); + + return new Label(name); + } +} +```