Skip to content

Commit 109e036

Browse files
Merge pull request #25 from CoderGamester/develop
Release 1.1.0
2 parents 7a173a9 + afd1e41 commit 109e036

File tree

325 files changed

+41011
-3400
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

325 files changed

+41011
-3400
lines changed

AGENTS.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# GameLovers.UiService - AI Agent Guide
2+
3+
## 1. Package Overview
4+
- **Package**: `com.gamelovers.uiservice`
5+
- **Unity**: 6000.0+
6+
- **Dependencies** (see `package.json`)
7+
- `com.unity.addressables` (2.6.0)
8+
- `com.cysharp.unitask` (2.5.10)
9+
10+
This package provides a centralized UI management service that coordinates presenter **load/open/close/unload**, supports **layering**, **UI sets**, and **multi-instance** presenters, and integrates with **Addressables** + **UniTask**.
11+
12+
For user-facing docs, treat `docs/README.md` (and linked pages) as the primary documentation set. This file is for contributors/agents working on the package itself.
13+
14+
## 2. Runtime Architecture (high level)
15+
- **Service core**: `Runtime/UiService.cs` (`UiService : IUiServiceInit`)
16+
- Owns configs, loaded presenter instances, visible list, and UI set configs.
17+
- Creates a `DontDestroyOnLoad` parent GameObject named `"Ui"` and attaches `UiServiceMonoComponent` for resolution/orientation tracking.
18+
- Tracks presenters as **instances**: `Dictionary<Type, IList<UiInstance>>` where each `UiInstance` stores `(Type, Address, UiPresenter)`.
19+
- **Public API surface**: `Runtime/IUiService.cs`
20+
- Exposes lifecycle operations (load/open/close/unload) and readonly views:
21+
- `VisiblePresenters : IReadOnlyList<UiInstanceId>`
22+
- `UiSets : IReadOnlyDictionary<int, UiSetConfig>`
23+
- `GetLoadedPresenters() : List<UiInstance>`
24+
- Note: **multi-instance overloads** (explicit `instanceAddress`) exist on `UiService` (concrete type), not on `IUiService`.
25+
- **Configuration**: `Runtime/UiConfigs.cs` (`ScriptableObject`)
26+
- Stores UI configs as `UiConfigs.UiConfigSerializable` (address + layer + type name) and UI sets as `UiSetConfigSerializable` containing `UiSetEntry` items.
27+
- Use the specialized subclasses (each has `CreateAssetMenu`): `AddressablesUiConfigs` (default), `ResourcesUiConfigs`, `PrefabRegistryUiConfigs` (embedded prefab registry).
28+
- Note: `UiConfigs` is `abstract` to prevent accidental direct usage—always use one of the specialized subclasses.
29+
- **UI Sets**: `Runtime/UiSetConfig.cs`
30+
- `UiSetEntry` stores:
31+
- presenter type as `AssemblyQualifiedName` string
32+
- optional `InstanceAddress` (empty string means default instance)
33+
- `UiSetConfig` is the runtime shape: `SetId` + `UiInstanceId[]`.
34+
- **Presenter pattern**: `Runtime/UiPresenter.cs`
35+
- Lifecycle hooks: `OnInitialized`, `OnOpened`, `OnClosed`, `OnOpenTransitionCompleted`, `OnCloseTransitionCompleted`.
36+
- Typed presenters: `UiPresenter<T>` with a `Data` property that triggers `OnSetData()` on assignment (works during `OpenUiAsync(..., initialData, ...)` or later updates).
37+
- Presenter features are discovered via `GetComponents(_features)` at init time and are notified in the open/close lifecycle.
38+
- **Transition tasks**: `OpenTransitionTask` and `CloseTransitionTask` are public `UniTask` properties that complete when all transition features finish.
39+
- **Visibility control**: `UiPresenter` is the single point of responsibility for `SetActive(false)` on close; it waits for all `ITransitionFeature` tasks before hiding.
40+
- **Composable features**: `Runtime/Features/*`
41+
- `PresenterFeatureBase` allows attaching components to a presenter prefab to hook lifecycle.
42+
- `ITransitionFeature` interface for features that provide open/close transition delays (presenter awaits these).
43+
- Built-in transition features: `TimeDelayFeature`, `AnimationDelayFeature`.
44+
- UI Toolkit support: `UiToolkitPresenterFeature` (via `UIDocument`) provides `AddVisualTreeAttachedListener(callback)` for safe element queries. Callback is invoked on each open because UI Toolkit recreates elements when the presenter is deactivated/reactivated.
45+
- **Helper views**: `Runtime/Views/*` (`GameLovers.UiService.Views`)
46+
- `SafeAreaHelperView`: adjusts anchors/size based on safe area (notches).
47+
- `NonDrawingView`: raycast target without rendering (extends `Graphic`).
48+
- `AdjustScreenSizeFitterView`: layout fitter that clamps between min/flexible size.
49+
- `InteractableTextView`: TMP link click handling.
50+
- **Asset loading**: `Runtime/Loaders/IUiAssetLoader.cs`
51+
- `IUiAssetLoader` abstraction with multiple implementations under `Runtime/Loaders/`:
52+
- `AddressablesUiAssetLoader` (default): uses `Addressables.InstantiateAsync` and `Addressables.ReleaseInstance`.
53+
- `PrefabRegistryUiAssetLoader`: uses direct prefab references (useful for samples/testing). Can be initialized with a `PrefabRegistryUiConfigs` in its constructor.
54+
- `ResourcesUiAssetLoader`: uses `Resources.Load`.
55+
- Supports optional synchronous instantiation via `UiConfig.LoadSynchronously` (in Addressables loader).
56+
- **Analytics (optional)**: `Runtime/UiAnalytics.cs`
57+
- `IUiAnalytics`/`UiAnalytics` track lifecycle events + basic timings; defaults to `NullAnalytics`.
58+
- `UiService.CurrentAnalytics` is an **internal** static reference used by editor windows.
59+
60+
## 3. Key Directories / Files
61+
- **Docs (user-facing)**: `docs/`
62+
- `docs/README.md` — documentation entry point.
63+
- **Runtime**: `Runtime/`
64+
- Entry points: `IUiService.cs`, `UiService.cs`, `UiPresenter.cs`, `UiConfigs.cs`, `UiSetConfig.cs`, `UiInstanceId.cs`.
65+
- Integrations / extension points (start here when behavior differs from expectations):
66+
- `Loaders/*`**how presenter prefabs are instantiated / released**.
67+
- If UI fails to load/unload, start at `Loaders/IUiAssetLoader.cs` and the active loader (`AddressablesUiAssetLoader`, `ResourcesUiAssetLoader`, `PrefabRegistryUiAssetLoader`).
68+
- Loader choice is typically driven by which `UiConfigs` subclass you use (`AddressablesUiConfigs` / `ResourcesUiConfigs` / `PrefabRegistryUiConfigs`).
69+
- `Features/*`**presenter composition** (components attached to presenter prefabs).
70+
- Lifecycle hooks live in `PresenterFeatureBase`; features are discovered during presenter initialization.
71+
- Transition timing issues (UI not showing/hiding when expected) usually involve `ITransitionFeature` implementations (eg `TimeDelayFeature`, `AnimationDelayFeature`).
72+
- UI Toolkit presenters rely on `UiToolkitPresenterFeature`; avoid querying `UIDocument.rootVisualElement` during `OnInitialized()`—use `AddVisualTreeAttachedListener(...)`.
73+
- `Views/*`**optional helper components** used by presenter prefabs (safe area, raycasts, layout fitters, TMP link clicks).
74+
- If interaction/layout is off but service bookkeeping looks correct, look here before changing `UiService`.
75+
- **Editor**: `Editor/` (assembly: `Editor/GameLovers.UiService.Editor.asmdef`)
76+
- Config editors: `UiConfigsEditorBase.cs`, `*UiConfigsEditor.cs`, `DefaultUiConfigsEditor.cs`.
77+
- Debugging: `UiAnalyticsWindow.cs`, `UiServiceHierarchyWindow.cs`, `UiPresenterEditor.cs`.
78+
- **Samples**: `Samples~/`
79+
- Demonstrates basic flows, data presenters, delay features, UI Toolkit integration, analytics.
80+
- **Tests**: `Tests/`
81+
- `Tests/EditMode/*` — unit tests (configs, sets, analytics, loaders, core service behavior)
82+
- `Tests/PlayMode/*` — integration/performance/smoke tests
83+
84+
## 4. Important Behaviors / Gotchas
85+
- **Instance address normalization**
86+
- `UiInstanceId` normalizes `null/""` to `string.Empty`.
87+
- Prefer **`string.Empty`** as the default/singleton instance identifier.
88+
- **Ambiguous “default instance” calls**
89+
- `UiService` uses an internal `ResolveInstanceAddress(type)` when an API is called without an explicit `instanceAddress`.
90+
- If **multiple instances** exist, it logs a warning and selects the **first** instance. For multi-instance usage, prefer calling `UiService` overloads that include `instanceAddress`.
91+
- **Presenter self-close + destroy with multi-instance**
92+
- `UiPresenter.Close(destroy: true)` now correctly uses the presenter's stored `InstanceAddress` to unload the correct instance.
93+
- This works seamlessly for both singleton and multi-instance presenters.
94+
- **Layering**
95+
- `UiService` enforces sorting by setting `Canvas.sortingOrder` or `UIDocument.sortingOrder` to the config layer when adding/loading.
96+
- Loaded presenters are instantiated under the `"Ui"` root directly (no per-layer container GameObjects).
97+
- **UI Sets store types, not addresses**
98+
- UI sets are serialized as `UiSetEntry` (type name + instance address). The default editor populates `InstanceAddress` with the **addressable address** for uniqueness.
99+
- **`LoadSynchronously` persistence**
100+
- `UiConfig.LoadSynchronously` exists and is respected by `AddressablesUiAssetLoader`.
101+
- **However**: `UiConfigs.UiConfigSerializable` currently does **not** serialize `LoadSynchronously`, so configs loaded from a `UiConfigs` asset will produce `LoadSynchronously = false` in `UiConfigs.Configs`.
102+
- **Static events**
103+
- `UiService.OnResolutionChanged` / `UiService.OnOrientationChanged` are static `UnityEvent`s raised by `UiServiceMonoComponent`.
104+
- The service does not clear listeners; consumers must unsubscribe appropriately.
105+
- **Disposal**
106+
- `UiService.Dispose()` closes all visible UI, attempts to unload all loaded instances, clears collections, and destroys the `"Ui"` root GameObject.
107+
- **Editor debugging tools**
108+
- Some editor windows toggle `presenter.gameObject.SetActive(...)` directly for convenience; this may not reflect in `IUiService.VisiblePresenters` since it bypasses `UiService` bookkeeping.
109+
- **UI Toolkit visual tree timing and element recreation**
110+
- `UIDocument.rootVisualElement` may not be ready when `OnInitialized()` is called on a presenter.
111+
- UI Toolkit **recreates visual elements** when the presenter GameObject is deactivated/reactivated (close/reopen cycle), `AddVisualTreeAttachedListener(callback)` invokes on **each open** to handle element recreation.
112+
113+
## 5. Coding Standards (Unity 6 / C# 9.0)
114+
- **C#**: C# 9.0 syntax; no global `using`s; keep **explicit namespaces**.
115+
- **Assemblies**
116+
- Runtime code should avoid `UnityEditor` references; editor-only tooling belongs under `Editor/` and `GameLovers.UiService.Editor.asmdef`.
117+
- If you must add editor-only code near runtime types, guard it with `#if UNITY_EDITOR` and keep it minimal.
118+
- **Async**
119+
- Use `UniTask`; thread `CancellationToken` through async APIs where available.
120+
- **Memory / allocations**
121+
- Avoid per-frame allocations; keep API properties allocation-free (see `UiService` read-only wrappers for `VisiblePresenters` and `UiSets`).
122+
123+
## 6. External Package Sources (for API lookups)
124+
When you need third-party source/docs, prefer the locally-cached UPM packages:
125+
- Addressables: `Library/PackageCache/com.unity.addressables@*/`
126+
- UniTask: `Library/PackageCache/com.cysharp.unitask@*/`
127+
128+
## 7. Dev Workflows (common changes)
129+
- **Add a new presenter**
130+
- Create a prefab with a component deriving `UiPresenter` (or `UiPresenter<T>`).
131+
- Ensure it has a `Canvas` or `UIDocument` if you want layer sorting to apply.
132+
- Mark the prefab Addressable and set its address.
133+
- Add/update the entry in `UiConfigs` (menu: `Tools/UI Service/Select UiConfigs`).
134+
- **Add / update UI sets**
135+
- The default `UiConfigs` inspector uses `DefaultUiSetId` (out-of-the-box).
136+
- To customize set ids, create your own enum and your own `[CustomEditor(typeof(UiConfigs))] : UiConfigsEditor<TEnum>`.
137+
- **Add multi-instance flows**
138+
- Use `UiInstanceId` (default = `string.Empty`) when you need to track instances externally.
139+
- Presenters know their own instance address via the internal `InstanceAddress` property; `Close(destroy: true)` unloads the correct instance.
140+
- **Add a presenter feature**
141+
- Extend `PresenterFeatureBase` and attach it to the presenter prefab.
142+
- Features are discovered via `GetComponents` at init time and notified during open/close.
143+
- For features with transitions (animations, delays): implement `ITransitionFeature` so the presenter can await your `OpenTransitionTask` / `CloseTransitionTask`.
144+
- **Change loading strategy**
145+
- Prefer using one of the built-in loaders (`AddressablesUiAssetLoader`, `PrefabRegistryUiAssetLoader`, `ResourcesUiAssetLoader`) or extending `IUiAssetLoader` for custom needs.
146+
- **Update docs/samples**
147+
- User-facing docs live in `docs/` and should be updated when behavior/API changes.
148+
- If you add a new core capability, consider adding/adjusting a sample under `Samples~/`.
149+
150+
## 8. Update Policy
151+
Update this file when:
152+
- Public API changes (`IUiService`, `IUiServiceInit`, presenter lifecycle, config formats)
153+
- Core runtime systems/features are introduced/removed (features, views, analytics, multi-instance)
154+
- Editor tooling changes how configs or sets are generated/serialized

AGENTS.md.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,50 @@ All notable changes to this package will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
66

7+
## [1.1.0] - 2026-01-06
8+
9+
**New**:
10+
- Added `OpenUiSetAsync(int setId, CancellationToken)` method to `IUiService` for opening all UI presenters in a set with proper address handling, ensuring compatibility with `CloseAllUiSet` and `UnloadUiSet`
11+
- Added `OnOpenTransitionCompleted()` and `OnCloseTransitionCompleted()` lifecycle hooks to `UiPresenter` for reacting after all transition animations/delays complete
12+
- Added comprehensive test suite:
13+
- Unit tests for `UiAnalytics`, `UiConfig`, `UiInstanceId`, `UiServiceCore`, `UiSetConfig`
14+
- PlayMode integration tests for multi-instance, loading, open/close, and UI set management
15+
- Performance and smoke tests
16+
- Feature-specific tests for `AnimationDelayFeature`, `TimeDelayFeature`, and `PresenterFeatureBase`
17+
- Added `ITransitionFeature` interface for features that provide open/close transition delays
18+
- Added `OpenTransitionTask` and `CloseTransitionTask` public properties on `UiPresenter` for awaiting transition completion externally
19+
- Added `AGENTS.md` documentation for AI coding agents
20+
- Added structured documentation under `docs/` folder with separate pages for getting started, core concepts, API reference, advanced topics, and troubleshooting
21+
- Added multiple new samples to the package library
22+
- Added multiple `IUiAssetLoader` implementations to support different asset loading scenarios:
23+
- `AddressablesUiAssetLoader` (default): Integration with Unity Addressables.
24+
- `PrefabRegistryUiAssetLoader`: Simple loader for direct prefab references (useful for testing and samples).
25+
- `ResourcesUiAssetLoader`: Support for loading from Unity's `Resources` folder.
26+
- Added `AddressablesUiConfigs`, `ResourcesUiConfigs`, `PrefabRegistryUiConfigs`, `ResourcesUiConfigsEditor`, `AddressablesUiConfigsEditor` and `PrefabRegistryUiConfigsEditor` for managing UI configurations.
27+
28+
**Changed**:
29+
- **BREAKING**: Made `UiConfigs` class `abstract` to enforce usage of specialized subclasses (`AddressablesUiConfigs`, `ResourcesUiConfigs`, `PrefabRegistryUiConfigs`) and prevent runtime errors from misconfiguration
30+
- **BREAKING**: Removed `IPresenterFeature` interface; features now extend `PresenterFeatureBase` directly
31+
- **BREAKING**: Renamed `UiAssetLoader` to `AddressablesUiAssetLoader` to reflect its specific loading mechanism.
32+
- **BREAKING**: Renamed `UiConfig.AddressableAddress` to `UiConfig.Address` for loader-agnosticism
33+
- Changed `UiPresenter<T>.Data` property to have a public setter that automatically triggers `OnSetData()` when assigned
34+
- Refactored `TimeDelayFeature` and `AnimationDelayFeature` to no longer call `gameObject.SetActive(false)` directly; visibility is now controlled solely by `UiPresenter`
35+
- Refactored `UiPresenter.InternalOpen()` and `InternalClose()` to use internal async processes that await `ITransitionFeature` tasks
36+
- Refactored `AnimationDelayFeature` and `TimeDelayFeature` to use `Presenter.NotifyOpenTransitionCompleted()` and `Presenter.NotifyCloseTransitionCompleted()` instead of internal events
37+
- Removed `OnOpenCompletedEvent` and `OnCloseCompletedEvent` internal events from delay features
38+
- Updated all samples to use UI buttons instead of input system dependencies for better project compatibility
39+
40+
**Fixed**:
41+
- Fixed `AnimationDelayFeature` animation playback logic - was incorrectly checking `!_introAnimationClip` instead of `_introAnimationClip != null`
42+
- Fixed `UiPresenterEditor` play-mode buttons to properly call `InternalOpen()` and `InternalClose()` instead of just toggling `gameObject.SetActive()`
43+
- Fixed delay features to work correctly when tests run together (UniTaskCompletionSource lifecycle)
44+
- Fixed null checks in delay features using explicit null comparisons instead of null-conditional operators for Unity object compatibility
45+
- Fixed inconsistent lifecycle where `OnOpenTransitionCompleted`/`OnCloseTransitionCompleted` were only called when features existed
46+
- Fixed split responsibility for visibility control where both `UiPresenter` and features could call `SetActive(false)`, allowing now to properly close the presenters in all scenarios
47+
- Fixed `LoadUiAsync` visibility state inconsistency where calling it on an already-visible presenter with `openAfter=false` would disable the GameObject but not update `VisiblePresenters`, causing subsequent `OpenUiAsync` calls to fail silently
48+
- Fixed multi-instance ambiguity when calling `Close(destroy: true)` from within a presenter and now correctly unloads the specific instance instead of potentially unloading the wrong one
49+
- Fixed UI Toolkit timing issue where element queries in `OnInitialized()` would fail because the visual tree was not yet attached to a panel
50+
751
## [1.0.0] - 2025-11-04
852

953
**New**:

0 commit comments

Comments
 (0)