Release 2.0.0#30
Merged
CoderGamester merged 17 commits intomasterfrom Apr 26, 2026
Merged
Conversation
- Fixed 7 API inaccuracies in README code examples (TickService, DataService, CommandService, CoroutineService, MessageBroker, dependency name, version badge) - Added IDataProvider, ITimeManipulator, ICommandService<TGameLogic> to Key Components - Added CommandService section to AGENTS.md; corrected TickService/CoroutineService method names; documented IDataProvider/ITimeManipulator split; added test structure - Removed .github/workflows/openai.yml CI workflow Made-with: Cursor
AGENTS.md: - Add interface-to-concrete lookup table (Section 2.5) - Document Bind<T,T1,T2,T3> and re-binding-throws behavior - Add bulk UnsubscribeAllOnUpdate/FixedUpdate/LateUpdate overloads - Add test coverage gap map (Section 3.5) - Add error quick-reference table to Section 4 README.md: - Add StopCoroutine(triggerOnComplete) ignored-flag caveat - Add GameObjectPool<T> requires T : Behaviour constraint note - Add GetData<T> KeyNotFoundException behavior to Key Points - Add Unsubscribe(action) and StopAllCoroutines/Dispose to examples - Soften platform compatibility claims to reflect actual test coverage Tests: - Fix misleading UnsubscribeAll_BySubscriber test (was testing wrong overload) - Fix commented-out EntityDespawn_Successfully (NSubstitute mock needed Returns(true)) - Add StartDelayCall and StartDelayCall<T> tests (CoroutineService) - Add SubscribeOnFixedUpdate/LateUpdate and their unsubscribe tests (TickService) - Add SaveAllData round-trip test (DataService) - Add Clear, Dispose, SpawnWithData tests (PoolService) - Add IsSpawned, Despawn(Func), SpawnedReadOnly, SampleEntity tests (ObjectPool) - Add Bind<T,T1,T2> and Bind<T,T1,T2,T3> tests (Installer) - Add Nextfloat, Peekfloat, Range(floatP,floatP) tests (RngService) - Add SpawnWithData test (GameObjectPool) - Add GameObjectPoolTypedTest.cs -- first tests for GameObjectPool<T> Made-with: Cursor
- ObjectPool<T>: add Reset and Despawn(bool:all, Func) tests - RngService: add PeekRange(floatP,floatP) no-state-advance test - TickService: add UnsubscribeAllOnUpdate/FixedUpdate/LateUpdate (no-arg + subscriber-scoped, 6 tests) - CoroutineService: add Dispose host-GameObject teardown and double-dispose safety tests - GameObjectPool<T>: add DespawnAll, SampleEntity, SpawnedReadOnly, IsSpawned, Despawn(bool,Func), Reset, DespawnToSampleParent, Dispose(bool) tests - VersionServices: new PlayMode integration test covering LoadVersionDataAsync, VersionInternal, Branch, Commit, BuildNumber, and pre-load throw behaviour - AGENTS.md: remove section 3.5 (all gaps now covered); update test directory listing Made-with: Cursor
Documents the full test suite conventions for this package: EditMode vs PlayMode placement rules, namespace and naming patterns, mock/helper type setup, assertion style, performance test structure, and integration test ordering — so agents and contributors can write consistent tests without reverse-engineering the existing suite. Made-with: Cursor
- Extract Section 5 (Testing Conventions) from root AGENTS.md into a dedicated Tests/AGENTS.md, following the sub-folder AGENTS.md pattern. - Add MUST-read pointer to Tests/AGENTS.md in Section 3 of root AGENTS.md. - Rename "Dev Workflows" → "Package Dev Workflows" to clarify contributor scope; remove consumer-facing "Bind/resolve services" workflow (already documented in README.md). - Renumber sections 5–8 accordingly; move test-conventions update trigger to Tests/AGENTS.md update policy. Made-with: Cursor
Reorganizes Runtime/ and Editor/ into domain subfolders with matching sub-namespaces (except DependencyInjection/ which stays as a navigation-only carve-out). Absorbs all asset-loading/importing functionality previously in com.gamelovers.assetsimporter. Runtime/ - DependencyInjection/ -> ns GameLovers.Services (carve-out) - Commands/ -> ns GameLovers.Services.Commands (IGameCommand*, ICommandService) - Pooling/ -> ns GameLovers.Services.Pooling (IPoolService, IObjectPool*, GameObjectPool*, IPoolEntity*) - AssetsImporter/ -> ns GameLovers.Services.AssetsImporter (IAssetLoader, ISceneLoader, AddressablesAssetLoader, AddressableConfig, AssetConfigsScriptableObject, AssetLoaderUtils, AssetReferenceScene) - *Service.cs + VersionServices.cs + AssetResolverService.cs at root -> ns GameLovers.Services Editor/ - Versioning/ -> ns GameLovers.Services.Versioning.Editor - AssetsImporter/ -> ns GameLovers.Services.AssetsImporter.Editor - New explicit asmdef: GameLovers.Services.Editor.asmdef (refs Addressables + Addressables.Editor + ScriptableBuildPipeline.Editor) Runtime asmdef: - rootNamespace = "GameLovers.Services" - Added GUID refs: Unity.Addressables, Unity.ResourceManager, UniTask, UniTask.Addressables File splits: - CommandService.cs trimmed to concrete class; interfaces moved to Commands/ - PoolService.cs trimmed to concrete class; IPoolService moved to Pooling/ - ObjectPool.cs (10 types) split into 4 files under Pooling/ Tests: - New EditMode/Unit: AddressableConfigTest, AssetLoaderUtilsTest, AssetResolverServiceTest - New PlayMode/Integration: AddressablesAssetLoaderIntegrationTest (marked [Explicit]) - Existing pool/command tests updated with new sub-namespace usings - Tests asmdefs extended with Addressables + UniTask + ResourceManager refs Documentation: - package.json: version 2.0.0; +com.unity.addressables 1.21.20; +com.cysharp.unitask 2.5.10 - AGENTS.md: updated Interface-to-Concrete table, folder layout, namespace mapping, gotchas - Tests/AGENTS.md: added new test files under Section 9 - README.md: new "Asset Loading & Import" section; bumped version badge - CHANGELOG.md: [2.0.0] entry documenting all changes and breaking items - MIGRATION.md: new file with before/after `using` diffs for every breaking namespace change BREAKING CHANGES — see MIGRATION.md: - Pool types now in GameLovers.Services.Pooling - Command contract types now in GameLovers.Services.Commands - GameLovers.AssetsImporter.* renamed to GameLovers.Services.AssetsImporter.* - GameLovers.AssetsImporter.AssetResolverService now in GameLovers.Services - GameLovers.Services.Editor (versioning) renamed to GameLovers.Services.Versioning.Editor - Re-run AddressableIdsGenerator or manually update the emitted `using` in generated files Made-with: Cursor
… NSubstitute limitation - Qualify Object.DestroyImmediate as UnityEngine.Object.DestroyImmediate in AssetResolverServiceTest to resolve CS0104 ambiguity between System.Object and UnityEngine.Object. - Add two regression tests in ObjectPoolTest for Despawn(bool, Func<T,bool>) covering distinct-instance matches and partial matches. The existing Despawn_WithCondition_AllMatching_DespawnsAll only exercises duplicate references because the SetUp factory returns a single mock instance. - Document in Tests/AGENTS.md the NSubstitute 4.4.0 + Castle DynamicProxy proxy-generation failure on Unity's Mono runtime for self-referentially constrained generic interfaces (e.g. IObjectPool<T> where T : IPoolEntityObject<T>); prescribe real implementations or hand-written fakes as the fix. Made-with: Cursor
- Add CLAUDE.md + .meta at package root; thin @AGENTS.md import wrapper - Trim README.md to Option B shape (~700 -> 279 lines): lean Why / Install / Quick Start / Services-at-a-Glance / Related docs; dynamic version badge - Move deep per-service API reference into docs/ (11 topics + README index): main-installer, message-broker, tick-service, coroutine-service, pool-service, data-service, rng-service, time-service, command-service, version-services, asset-loading - AGENTS.md: add Companion-files blockquote; Mermaid architecture diagram in Section 2; Tests "what lives where" table; consolidate editor-only bullets in Section 3 Made-with: Cursor
…itor tooling (v2.0.0) - Added Services Explorer window (13 live-refresh tabs: Overview, Installer, MessageBroker, Tick, Coroutine, Pool, Data, Time, RNG, AssetResolver, Versioning, Assets Importer, Addressable Ids) - Added Assets > Create > GameLovers Services scaffolders (Message, Command, Service, Pool Entity templates) - Added Editor/Inspectors: AssetConfigsScriptableObjectEditor, AssetReferenceSceneDrawer - Extracted generation logic into AddressableIdsGeneratorUtils and AssetsImporterEditorUtils; replaced old AssetsImporter.cs / AssetsToolImporter.cs / AddressableIdsGenerator.cs / AddressablesIdGeneratorSettings.cs - Added AssetsImporterEditorSettings and AddressableIdsEditorSettings ScriptableSingletons under ProjectSettings/ - Added menu stubs under Tools > GameLovers: Versioning/*, Assets Importer/*, Addressable Ids/* - Moved VersionEditorUtils/GitEditorProcess to Editor/Versioning/; added VersioningEditorSettings + VersioningMenu - Added AssemblyInfo.cs to both Runtime/ and Editor/ - Condensed AGENTS.md; updated CHANGELOG.md, MIGRATION.md, README.md, docs/; added .meta files for docs/ - Replaced AddressablesAssetLoaderIntegrationTest with unit-level AddressableIdsEditorSettingsTest, AssetsImporterEditorSettingsTest, VersioningEditorSettingsTest Made-with: Cursor
Ships two importable samples under Samples~/ via Package Manager: - ServicesPlayground: zero-setup scene exercising 10 of 13 Services Explorer tabs (every foundation service except the asset pipeline). Hand-authored ServicesPlaygroundUI.prefab with 27 buttons across 10 sections + scrollable Log + scrollable LiveStatus + a programmatically- spawned bullet pool that auto-despawns off-screen entries. - AssetResolver: Addressables-backed demo of AssetResolverService end-to- end (AddConfigs / RequestAsset / UnloadAssets) using a SpriteConfigs : AssetConfigsScriptableObject<SpriteId, Sprite>. Hand-authored prefab UI; per-sample README walks through the ~2-min Addressables setup. Both drivers wire Button.onClick listeners via [SerializeField] + AddListener in Awake, swap StandaloneInputModule <-> InputSystemUIInput- Module at runtime via #if ENABLE_INPUT_SYSTEM, and use TextMeshProUGUI for cross-Active-Input-Handling and font portability. Sample-only types live under GameLovers.Services.Samples.<sample> namespaces to make the public-API boundary explicit. Also fixes a latent infinite-recursion crash in AssetConfigsScriptableObjectEditor.CreateInspectorGUI: with editor- ForChildClasses=true, calling new InspectorElement(serializedObject) re-resolved to the same custom editor and recursed ~5,300 levels deep until the OS stack guard killed the editor with EXC_BAD_ACCESS on selection of any concrete subclass. Replaced with manual SerializedProperty iteration via PropertyField. The bug had been latent since no concrete AssetConfigsScriptableObject<,> subclass existed in the repo until the new sample suite added SpriteConfigs. Documentation aligned: package.json declares samples[]; README.md gets a Samples section; AGENTS.md §3 documents Samples~/ and §4 adds the Sample Zero-Setup Invariant gotcha + the IAssetAdderService default- interface-method gotcha; CHANGELOG.md gains an [Unreleased] entry.
Runtime fix in CoroutineService.AsyncCoroutine:
- StopCoroutine(triggerOnComplete) now honors its parameter and flips
IsCompleted=true / IsRunning=false (no-op if already completed). The
previous implementation always invoked OnComplete and never updated state.
- Added internal InternalCleanup event distinct from the public _onComplete
field. Editor-only _activeAsyncCoroutines tracking subscribes via
InternalCleanup so it no longer overwrites (or is overwritten by) user
OnComplete callbacks - the v2.0.0 regression that made StartDelayCall
callbacks silently fail in editor builds and stale entries persist after
per-row Stop in the Coroutine tab.
Services Explorer lifecycle hardening:
- New ServiceTab.OnExitingPlayMode() virtual + !EditorApplication.isPlaying
short-circuit at the top of every populated-state tab's Refresh().
Decouples the Explorer's empty state from MainInstaller cleanup so tabs
visually clear the moment Stop is pressed regardless of whether the
consumer's bootstrap properly disposed services or called Clean().
Adopted by 7 tabs: Installer, MessageBroker, Data, RNG, Pool, Coroutine,
Tick. Banner is now context-sensitive ("Not in Play mode - showing last
snapshot" before first play, "Play session ended - services unbound"
after).
Services Explorer UX:
- Added .action-primary-danger USS class + MakePrimaryDangerButton helper
for destructive primary actions (Stop All Coroutines, Unsubscribe All,
Clean All). Rewrote .row-btn-danger from text-color-only to tinted-bg
+ border + bold light-pink to fix contrast in both editor skins.
- MessageBrokerTab redesign: replaced freeform "Type FQN" TextField with a
reflection-populated DropdownField over IMessage implementers, split
Test Publish from the action bar, moved per-type Unsubscribe All onto
the Foldout's Toggle header (with evt.StopPropagation() to prevent
collapse-on-click).
- RngTab UX rebuild: always-on Next-value row, tooltips, "Restore" renamed
to "Set counter" + Rewind-to-0 shortcut, cramped IntegerFields replaced
with Slider+IntegerField pairs (matches TimeTab.AddTime layout).
Sample (ServicesPlayground):
- Bullet material now self-illuminates via _EmissionColor + _EMISSION
keyword + globalIlluminationFlags=None so the pool demo is readable in
the empty playground scene without scene lights.
- Coroutine_StartAsync uses WaitForSeconds(3f) instead of WaitFrames(60)
so the handle spans multiple Coroutine-tab refresh cycles at high
editor framerates.
- Removed the "Reset spawn counts" button entirely - it only reset two
sample-internal static counters and demonstrated nothing about
IPoolService. Removal spans script field + handler + Bullet.ResetCounters
+ 10 prefab YAML documents + parent's m_Children entry + 6 stale scene
PrefabModification overrides.
Tests: added 6 PlayMode tests covering the new StopCoroutine contract,
the OnComplete-no-overwrite regression, and StopCoroutine idempotency.
Docs: AGENTS.md updated with Services Explorer Play->Edit Refresh
Lifecycle, Destructive-Action Styling, and two new sample-zero-setup
invariants (bullet emission, coroutine-timing). The IAsyncCoroutine.
StopCoroutine(triggerOnComplete) "ignored parameter" gotcha is replaced
with the new honored-contract documentation.
Made-with: Cursor
GameObjectPool.Dispose() and GameObjectPool<T>.Dispose() iterate the pool's internal Stack and call Object.Destroy on each entry. When a pooled instance had been reparented under an external GameObject (e.g. via DespawnToSampleParent) and that parent was destroyed by the owner, the pool still tracked the now-destroyed entry; Dispose then either called Destroy on a Unity fake-null (harmless) or, in the typed pool, dereferenced .gameObject on a destroyed Behaviour and threw MissingReferenceException. Both Dispose paths now use the same Unity fake-null guard (`if (obj == null) continue;`) that SpawnEntity already uses, mirroring the package's existing convention for iterating pool internals. Adds two PlayMode regression tests (one per pool variant) and an "External destruction resilience" gotcha to AGENTS.md so future code paths that iterate pool internals get the same treatment. Made-with: Cursor
Eliminates the previous ~2-minute manual setup (mark sprites Addressable + populate SpriteConfigs.asset entries) that the per-sample README documented as four user-facing steps. The sample now ships placeholder sprites (Hero/Coin/Enemy.png) and an editor automation that performs all wiring on import. What runs: - AssetResolverSampleAssetPostprocessor fires when any asset under /Asset Resolver/Sprites/ is imported, defers to delayCall (modifying assets during OnPostprocessAllAssets is unsafe). - An [InitializeOnLoadMethod] safety net handles the chicken-and-egg of first-time UPM sample import where the post-processor would miss the initial batch (sprites import before this script compiles). - Steps performed (idempotent): rename non-canonical filenames to Hero/Coin/Enemy (substring match first, alphabetical fallback), get-or-create the dedicated Addressables group GameLoversServicesSamples_AssetResolver, mark each sprite Addressable in that group with a clean lowercase address, and wire SpriteConfigs.asset rows for matching SpriteId values. Existing user mappings to a different sprite are respected. Manual escape hatches: - Menu: Tools > GameLovers > Samples > Asset Resolver > Refresh Addressables. - A sample-scoped "Refresh AssetResolver Sample Addressables" button on the SpriteConfigs.asset inspector. The button is added by the package's AssetConfigsScriptableObjectEditor only when the inspected asset's path ends with "/Asset Resolver/SpriteConfigs.asset", and is invoked through EditorApplication.ExecuteMenuItem so the inspector stays decoupled from the sample's editor assembly. If the sample's scripts are missing, the menu invocation fails with a logged warning rather than a compile error. Sample assembly: - New asmdef GameLovers.Services.Samples.AssetResolver.Editor scoped to Editor platform; lives entirely under Samples~/, so removing the sample removes the automation (no orphan InitializeOnLoad in consumer projects). Docs: - Samples~/AssetResolver/README.md rewritten around the auto-setup flow with a "swap in your own sprites" section and a manual fallback flow for users who prefer the original four-step path. - Samples~/README.md updated: file tree gains Sprites/ + Editor/, and the index summary changes from "~2 minutes of one-time setup" to "Zero per-import setup". - package.json sample description updated. Made-with: Cursor
Unity's Performance Testing Package consumes two PlayerPref keys in
EditMode:
- PT_Run (run metadata; consumed when results are emitted)
- PT_Settings (RunSettings; consumed by MethodMeasurement.SettingsOverride()
*before* the first warmup runs)
PerformanceTestSetup.InitializePerformanceTestMetadata() previously
primed only PT_Run, leaving RunSettings.Instance to lazy-load from an
empty PlayerPref string. JsonUtility throws on the empty input,
ResourcesLoader silently swallows the exception and returns null, and
SettingsOverride() then NRE's on RunSettings.Instance.MeasurementCount
at MethodMeasurement.cs:288 — before any warmup. The failure surfaced
as a generic NullReferenceException with no hint that the harness was
incomplete; every EditMode [Test, Performance] fixture in the suite
(ObjectPoolPerformanceTest, MessageBrokerPerformanceTest) was affected.
Now primes PT_Settings with `{"MeasurementCount":-1}`. -1 is the
package's "no override" sentinel: SettingsOverride() early-returns when
count < 0, preserving each fixture's per-test
.WarmupCount(...).MeasurementCount(...) configuration.
The previous misleading inline comment ("only Run metadata is required")
is replaced with a structured <remarks> XML doc that names which call
chain consumes which key, so a future contributor cannot accidentally
regress to the single-key form.
Adds PerformanceTestSetupTest.MeasureMethod_AfterInitialize_DoesNotThrow
as a regression sentinel: a no-op
Measure.Method(() => {}).WarmupCount(1).MeasurementCount(1).Run()
wrapped in Assert.DoesNotThrow. The class name targets the harness, not
a service, so a future failure points directly at PerformanceTestSetup.
Tests/AGENTS.md gains a "PerformanceTestSetup PlayerPref contract"
section in §7 documenting the two-key contract, the failure mode, and
the role of the sentinel test.
Made-with: Cursor
…Resolver full coverage - AddressableIds tab: persisted last-generation snapshot in AddressableIdsEditorSettings (sorted address/label arrays + timestamp + filename/label-filter used). New cheap-tier ComputeFreshness (file-stat only) drives a color-coded freshness banner on every Refresh; new expensive-tier Diff (GetAssetList + ProcessData) runs only on the user's "Check for stale Ids" button click and renders added/removed/warning lists in a Foldout. - Services Explorer hardening: ServiceTab gains MakeStickyFoldout (per- tab persisted collapsed state, with evt.target == foldout filter to block ChangeEvent<bool> bubbling through nested foldouts) and TryShortCircuitRefresh (digest-based early-out to avoid destroying mouse-captured VisualElements mid-click). AssetResolverTab and MessageBrokerTab adopt both; AssetResolverTab's destructive toggle invalidates the digest on change. - AssetResolver sample now exercises all three Explorer tabs the ServicesPlayground does not cover: AssetResolverExample binds IAssetResolverService through MainInstaller (populates Asset Resolver tab live); new SpriteConfigsImporter surfaces a sample row in the Assets Importer tab; post-processor applies 'services-sample-asset-resolver' label so Addressable Ids tab can demo a sample-scoped Generate. Adds a sample-runtime asmdef + an in-scene "Open Services Explorer" button that jumps to the AssetResolver tab via a sample-scoped editor menu. - Confirmed the AssetResolver "removing the dedicated group is the user's undo" design after a self-cleanup attempt was found structurally impossible (Unity recompiles before firing OnPostprocessAllAssets for deletions, dropping the post-processor class itself). Documented in AGENTS.md so the dead pattern is not re-attempted. Folds all of the above into the unreleased ## [2.0.0] CHANGELOG entry per the pre-publication versioning policy. Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New:
Tools > GameLovers > Services Explorer) with 13 live-refresh tabs: Overview, Installer, MessageBroker, Tick, Coroutine, Pool, Data, Time, RNG, AssetResolver, Versioning, Assets Importer, Addressable Ids — works in both Edit and Play modeTools > GameLovers:Versioning / Refresh Version DataandVersioning / Open in ExplorerAssets Importer / Import Assets DataandAssets Importer / Open in ExplorerAddressable Ids / Generate Addressable IdsandAddressable Ids / Open in ExplorerAssets > Create > GameLovers Services > …scaffolders: Message, Command, Service, Pool Entity (template-based,com.gamelovers.assetsimporterv0.5.2 into this packageIAssetLoader,ISceneLoader,AddressablesAssetLoadertoRuntime/AssetsImporter/(nsGameLovers.Services.AssetsImporter)AddressableConfig,AssetConfigsScriptableObject<TId,TAsset>,AssetLoaderUtils,AssetReferenceScenetoRuntime/AssetsImporter/(nsGameLovers.Services.AssetsImporter)AssetResolverService(implementsIAssetResolverService/IAssetAdderService) toRuntime/root (nsGameLovers.Services)AssetsImporter,AssetsToolImporter,AssetConfigsImporter,AddressableIdsGenerator,AddressablesIdGeneratorSettings(nsGameLovers.Services.AssetsImporter.Editor)Samples~/(importable via Unity Package Manager > GameLovers Services > Samples).MainInstallerand exercises 10 of 13 Services Explorer tabs end-to-end.AssetResolverServiceend-to-end (AddConfigs/RequestAsset/UnloadAssets) withSpriteConfigs : AssetConfigsScriptableObject<SpriteId, Sprite>. Drives the three Services Explorer tabs the Playground does not cover (Asset Resolver, Assets Importer, Addressable Ids).Changed:
Assets/*.assetScriptableObjects toProjectSettings/ScriptableSingletons (mirrorsVersioningEditorSettings).AddressableIdsGeneratorintoAddressableIdsGeneratorUtils(staticinternal); importer discovery/import logic extracted intoAssetsImporterEditorUtils.Tools/Assets Importer/*andTools/AddressableIds Generator/*menu entries removed. UseTools/GameLovers/Assets Importer/...,Tools/GameLovers/Addressable Ids/..., or the Services Explorer tabs instead.Toggle Auto Import On Refreshmenu entry removed. The toggle now lives exclusively in the Services Explorer Assets Importer tab.Assets/AssetsImporter.assetandAssets/AddressablesIdGeneratorSettings.assetare no longer used (settings moved toProjectSettings/); safe to delete from consumer projects.AssetsImporter.cs,AssetsToolImporter.cs,AddressableIdsGenerator.cs,AddressablesIdGeneratorSettings.cs.Runtime/now has domain subfoldersDependencyInjection/,Commands/,Pooling/,AssetsImporter/;Editor/now hasVersioning/andAssetsImporter/subfoldersInstaller.csandMainInstaller.csmoved toRuntime/DependencyInjection/(namespace unchanged:GameLovers.Services)CommandService.cstrimmed to concrete class only; command contract interfaces extracted toRuntime/Commands/under nsGameLovers.Services.CommandsPoolService.cstrimmed to concrete class only; pool interfaces + implementations moved toRuntime/Pooling/under nsGameLovers.Services.PoolingObjectPool.cs(578 lines, 10 types) split into 4 files underRuntime/Pooling/:IPoolEntity.cs,IObjectPool.cs,ObjectPool.cs,GameObjectPool.csVersionEditorUtils.csandGitEditorProcess.csmoved toEditor/Versioning/; re-namespaced fromGameLovers.Services.Editor→GameLovers.Services.Versioning.Editorcom.unity.addressables(1.21.20) andcom.cysharp.unitask(2.5.10)Fixed:
AddressablesAssetLoader.UnloadAssetno longer callsGC.Collect(),GC.WaitForPendingFinalizers(), orResources.UnloadUnusedAssets(). The method now only decrements the Addressables reference count. The old implementation caused PlayMode Test Runner crashes on macOS and O(total-assets-in-memory) main-thread stalls per per-asset release. Callers that need memory reclamation should invokeResources.UnloadUnusedAssets()themselves at appropriate moments (scene transitions, boot, memory-pressure events); Unity also runs an unused-assets sweep automatically onLoadSceneMode.Singlescene loads.IAssetLoader.UnloadAssetXML documentation: removed the incorrect "will also destroy GameObject instances" claim —Addressables.Release(gameObject)does not destroy the instance; callers mustObject.Destroyit separately.IAsyncCoroutine.StopCoroutine(bool triggerOnComplete)now honors itstriggerOnCompleteparameter and flipsIsCompletedtotrueandIsRunningtofalseafter stopping. The previous implementation always invokedOnCompletecallbacks regardless of the flag and left state flags unchanged, so consumers could not distinguish a stopped coroutine from a running one andtriggerOnComplete: falsewas silently ignored.GameObjectPool.Dispose()andGameObjectPool<T>.Dispose()now skip pooled entries whose underlyingGameObjecthas already been destroyed by an external owner (e.g. a parent GameObject was destroyed while pooled instances were still reparented under it viaDespawnToSampleParent).Breaking Changes — see
MIGRATION.mdfor details:GameLovers.ServicestoGameLovers.Services.Pooling(IPoolService,IObjectPool,IObjectPool<T>,ObjectPool<T>,ObjectPoolBase<T>,GameObjectPool,GameObjectPool<T>,IPoolEntitySpawn,IPoolEntitySpawn<T>,IPoolEntityDespawn,IPoolEntityObject<T>).PoolServiceconcrete class remains inGameLovers.Services.GameLovers.ServicestoGameLovers.Services.Commands(IGameCommandBase,IGameCommand<>,IGameServerCommand<>,ICommandService<>).CommandService<>concrete class remains inGameLovers.Services.GameLovers.AssetsImporter.*renamed toGameLovers.Services.AssetsImporter.*GameLovers.AssetsImporter.AssetResolverServiceis nowGameLovers.Services.AssetResolverServiceGameLovers.Services.Editor.*(versioning editor) renamed toGameLovers.Services.Versioning.Editor.*IAssetLoader.UnloadAssetAsync<T>(T, Action)→IAssetLoader.UnloadAsset<T>(T, Action): method renamed (droppedAsyncsuffix) and return type changed fromUniTasktovoidto reflect its synchronous nature. Replaceawait loader.UnloadAssetAsync(x);withloader.UnloadAsset(x);.AddressableIdsGeneratormust be re-generated (updated emittedusingstatement)