Aetheria/docs/addressables-cut.md
Meta Vens 78fd617cdd Restore the escaped dot in the corrected grep
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 19:33:24 +02:00

33 KiB

|.AssetPathb"# Engine Asset References Through Addressables: Cut Map |.AssetPathb" |.AssetPathb"Date: 2026-09-17 |.AssetPathb" |.AssetPathb"Status: Imagination pass, cut map. Nothing here has landed. Anchors are against |.AssetPathb"codex/item-provenance HEAD f8396313 (settings Cut 0 in progress; none of its commits |.AssetPathb"touch a file named here, checked with git diff --name-only f13a3356 f8396313). Ends are |.AssetPathb"owned by the ruling in docs/settings-globals-cut.md (header); this document owns the means. |.AssetPathb" |.AssetPathb"Claims marked (probe) were run, not read off names: |.AssetPathb"- a scratch console over Aetheria.Shared (sparse scratch worktree of f13a3356, CultLib |.AssetPathb" a0813c6 as a detached scratch worktree, both removed afterwards; the catalog was a copy) |.AssetPathb" that opened GameData/Aetheria.cc through AetheriaStores.Open read-only and walked every |.AssetPathb" stored document for string members carrying [CultInspectorAssetPath]; |.AssetPathb"- a Python pass resolving each stored path against the main tree and its .meta guid, and a |.AssetPathb" guid closure over the referenced prefabs' YAML; |.AssetPathb"- reads of Library/PackageCache/com.unity.addressables@8460f1c9c927 (2.9.1) source and its |.AssetPathb" Documentation~. |.AssetPathb" |.AssetPathb"Operator ruling (2026-09-17): engine asset references from CultCache data are Unity |.AssetPathb"Addressables, stored as the asset's .meta GUID and loaded through Addressables by GUID. |.AssetPathb"One rule for every engine asset reference from data. No dual Resources/Addressables path. |.AssetPathb" |.AssetPathb"Rulings: Q1 (A), one Assets/Content folder entry (operator, 2026-09-17: "I take your recommendation"). Open: none. |.AssetPathb"Ruling S (A), sub-assets (operator, 2026-09-17: "A"): a stored reference is the Addressables key, |.AssetPathb"the bare GUID for a main asset and guid[subAssetName] when a sub-asset (e.g. one sprite of a |.AssetPathb"sheet) is picked. It is what AssetReference keeps (GUID plus sub-object name), and |.AssetPathb"Addressables loads both forms. The drawer writes and reads both; EngineAssets.Load<T> passes the |.AssetPathb"key through. Found by Soul on CultLib 0155ba8, before release. |.AssetPathb"Correction: Cut 0's negative grep AssetPath also matches Unity's GUIDToAssetPath/ |.AssetPathb"AssetPathToGUID; the check is git grep -n "CultInspectorAssetPath\|.AssetPath\b". |.AssetPathb" |.AssetPathb"## 0. Target |.AssetPathb" |.AssetPathb"Ends: |.AssetPathb"- A CultCache field that names an engine asset stores that asset's GUID. No stored path. |.AssetPathb"- One Unity-side loader turns a GUID into an asset. No runtime code calls Resources.Load |.AssetPathb" for data-named assets, and nothing strips an Assets/Resources/ prefix. |.AssetPathb"- Every stored GUID resolves to an addressable asset of the type its consumer loads, and a |.AssetPathb" check proves it. |.AssetPathb" |.AssetPathb"Invariants kept: |.AssetPathb"- ServerShared stays engine-free (Aetheria.Shared.csproj builds it without Unity), so the |.AssetPathb" data carries a string, never a Unity type. |.AssetPathb"- Catalog globals are authored, never invented; the migration rewrites values in existing |.AssetPathb" records only. |.AssetPathb"- One home store per type, one-store commits. |.AssetPathb" |.AssetPathb"## 1. Census |.AssetPathb" |.AssetPathb"### 1.1 Stored references (probe) |.AssetPathb" |.AssetPathb"8 attributed members exist (git grep CultInspectorAssetPath). No other engine asset string |.AssetPathb"exists in ServerShared: the only other *Path strings are InputLayout.cs:68,92 (input |.AssetPathb"control paths) and WwiseMetadata.cs:37,91 (Wwise object paths), neither a Unity asset. |.AssetPathb" |.AssetPathb"| Member (file:line) | Stored | Non-empty | Resolves | Dangling | Runtime reader | |.AssetPathb"|---|---|---|---|---|---| |.AssetPathb"| ConsumableItemData.Icon (ItemData.cs:352) | 0 | 0 | 0 | 0 | ActionBarSlot.cs:114 | |.AssetPathb"| EquippableItemData.Schematic (ItemData.cs:362) | 51 | 1 | 1 | 0 | editor only, Editor/CultCacheDrawers.cs:104 | |.AssetPathb"| EquippableItemData.ActionBarIcon (ItemData.cs:392) | 51 | 0 | 0 | 0 | ActionBarSlot.cs:153 | |.AssetPathb"| HullData.Prefab (ItemData.cs:499) | 3 | 3 | 3 | 0 | ZoneRenderer.cs:295,304 | |.AssetPathb"| WeaponData.EffectPrefab (Behaviors/Weapon.cs:43) | 18 | 18 | 18 | 0 | EntityInstance.cs:195,224 | |.AssetPathb"| ThrusterData.ParticlesPrefab (Behaviors/Thruster.cs:26) | 2 | 2 | 2 | 0 | ShipInstance.cs:67 | |.AssetPathb"| AetherDriveData.Particles (Behaviors/AetherDrive.cs:50) | 1 | 1 | 1 | 0 | ShipInstance.cs:53 | |.AssetPathb"| Faction.Logo (Corporations.cs:25) | 12 | 5 | 5 | 0 | none | |.AssetPathb" |.AssetPathb"Totals: 138 stored values in 180 documents, 30 non-empty, 27 distinct paths, all 30 resolve |.AssetPathb"to an existing file with a .meta guid, 0 dangling. Every one of the 27 distinct paths is |.AssetPathb"under Assets/Resources/: 21 prefabs under Prefabs/, 1 png under Schematics/, 5 pngs under |.AssetPathb"Sprites/Icons/{Logos,Tech} (3 paths are shared by two records each). |.AssetPathb"The value-by-value list (record, member, path, guid) is the migration's expected report; |.AssetPathb"Cut 2 regenerates it rather than trusting this copy. |.AssetPathb" |.AssetPathb"### 1.2 Load sites (all synchronous, all on the main thread) |.AssetPathb" |.AssetPathb"| Site | Loads | Context | |.AssetPathb"|---|---|---| |.AssetPathb"| Gameplay/ActionBarSlot.cs:114 | Resources.Load<Texture2D> with inline prefix strip | binding ctor | |.AssetPathb"| Gameplay/ActionBarSlot.cs:153 | same | binding ctor | |.AssetPathb"| Gameplay/EntityInstance.cs:195 | UnityHelpers.LoadAsset<InstantWeaponEffectManager> | SetEntity, then Instantiate | |.AssetPathb"| Gameplay/EntityInstance.cs:224 | UnityHelpers.LoadAsset<ConstantWeaponEffectManager> | same | |.AssetPathb"| Gameplay/ShipInstance.cs:53 | UnityHelpers.LoadAsset<ParticleSystem> | same, Instantiate | |.AssetPathb"| Gameplay/ShipInstance.cs:67 | same | LINQ select, Instantiate | |.AssetPathb"| Zone Display/ZoneRenderer.cs:295,304 | UnityHelpers.LoadAsset<GameObject> | LoadEntity, Instantiate | |.AssetPathb"| Editor/CultCacheDrawers.cs:104 | AssetDatabase.LoadAssetAtPath<Texture2D> | Studio drawer | |.AssetPathb" |.AssetPathb"UnityHelpers.cs:7-10 is the only helper and has no other caller. Four sites load a |.AssetPathb"component type. Addressables cannot do that: "You can't load a component of a GameObject |.AssetPathb"directly through Addressables" (Documentation~/load-assets.md:60). The loader must load the |.AssetPathb"GameObject and take the component. |.AssetPathb" |.AssetPathb"### 1.3 Resources.Load not tied to data |.AssetPathb" |.AssetPathb"One: Gameplay/ActionGameManager.cs:420 (:425 before Cut 0) loads |.AssetPathb"Sprites/Input/{controlName} by naming convention. No data names it; it is outside the ruling. |.AssetPathb"Default: out of scope, and Assets/Resources/Sprites/Input/ stays in Resources. It goes to |.AssetPathb"follow-ups: if Resources is ever emptied, this becomes a player-store or catalog map of control |.AssetPathb"name to GUID. |.AssetPathb" |.AssetPathb"### 1.4 Resources dependencies of the referenced assets (probe) |.AssetPathb" |.AssetPathb"The guid closure of the 27 referenced assets is 145 assets; 40 sit in Assets/Resources: the |.AssetPathb"27 seeds, plus 13 dependencies. 8 of those are inside the subtrees Cut 2 moves (Prefabs/ |.AssetPathb"top-level Influence, Lightning, PingEffect, Shield, Tractor Beam; Sprites/Icons/Stroked/ |.AssetPathb"Satellite, Ship, orbital). 5 stay behind: Gradients/Ironbow.png (written there by |.AssetPathb"GradientMapper.cs:94-96), Sprites/Mote.png, Sprites/ringThick.png, |.AssetPathb"Sun Albedo/sunsurface1map 1.png, Sun Flow/sunsurface1offset 1.png. Nothing loads them by |.AssetPathb"name; left in Resources they ship twice (Resources data and the bundle). That is size, not |.AssetPathb"correctness. Default: follow-up, reported by the Addressables Analyze rule "Check Resources |.AssetPathb"to Addressable Duplicate Dependencies" (Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs). |.AssetPathb" |.AssetPathb"## 2. Ownership decisions |.AssetPathb" |.AssetPathb"### 2.1 The picker and the attribute belong to CultLib |.AssetPathb" |.AssetPathb"[CultInspectorAssetPath] is CultLib's (src/GameCult.Caching/CultInspectorAttributes.cs:65-77), |.AssetPathb"read into CultInspectorMetadata.AssetPath (CultInspectorModel.cs:44,56) and drawn by CultLib's |.AssetPathb"Studio, not by Aetheria: src/GameCult.Unity/Assets/Caching/Editor/CultCacheStudioDrawers.cs:168-176 |.AssetPathb"turns an ObjectField into AssetDatabase.GetAssetPath. Aetheria's |.AssetPathb"Assets/Scripts/Editor/CultCacheDrawers.cs claims only its own attributes. No CultLib path |.AssetPathb"under src/GameCult.Caching, src/GameCult.Unity or unity/ changed between a0813c6 and |.AssetPathb"CultLib main 244154e. Aetheria is the only consumer in F:\Projects (git grep over every |.AssetPathb"repo; the other hits are CultLib's README and voidbot memory dumps). |.AssetPathb" |.AssetPathb"Decision: the owner fills the gap. CultLib replaces the path attribute with |.AssetPathb"CultInspectorAssetGuidAttribute(Type? assetType = null), "a string member holding an engine |.AssetPathb"asset's stable identity; in Unity, the .meta GUID", and its Studio drawer stores |.AssetPathb"AssetDatabase.AssetPathToGUID and reads back through GUIDToAssetPath. Reusing the name |.AssetPathb"AssetPath for GUIDs would make the attribute lie, and keeping both leaves a dead path form |.AssetPathb"for the next field to pick up. Addressables stays out of CultLib: whether an asset is |.AssetPathb"addressable is Aetheria's content rule (2.3), so the Studio package gains no Addressables |.AssetPathb"dependency. AssetType stays optional; Aetheria cannot pass it (ServerShared is engine-free, |.AssetPathb"recorded in docs/cultcache-migration-cut.md:2003), so the Studio falls back to Object. |.AssetPathb" |.AssetPathb"Cost: a CultLib release (plugins rebuilt with scripts/build-unity-package.ps1), tags |.AssetPathb"cultlib-unity-v1.0.60 and caching-unity-v1.4.0 (removing a public attribute is breaking), |.AssetPathb"and an Aetheria bump of Packages/manifest.json (both URLs), Packages/packages-lock.json |.AssetPathb"and Directory.Build.props CultLibRevision. Coordination: CultLib codex/studio-grouping |.AssetPathb"(mapped, blocked on the Aetheria lot schema) also edits CultInspectorModel.cs and the Studio |.AssetPathb"drawers; whichever releases second rebases onto the first release. The older CultLib worktree branches |.AssetPathb"(CultLib-aetheria-authority, CultLib-delvehold-isosurface, CultLib-document-variants) carry |.AssetPathb"the attribute in its pre-move location (Runtime/CultCacheInspectorAttributes.cs); they are |.AssetPathb"CultLib branches, not consumers, and meet the rename only if rebased. |.AssetPathb" |.AssetPathb"### 2.2 Addressables package (probe) |.AssetPathb" |.AssetPathb"- com.unity.addressables 2.9.1 is already resolved and compiled, at depth 1, pulled by |.AssetPathb" com.unity.localization 1.5.8 (Packages/packages-lock.json:18-33,117-126). Its |.AssetPathb" package.json needs Unity 2023.1+; the project is 6000.3.24f1. Library/ScriptAssemblies |.AssetPathb" holds Unity.Addressables.dll, Unity.Addressables.Editor.dll, Unity.ResourceManager.dll. |.AssetPathb" No script uses Localization and no Localization settings exist (grep of Assets, |.AssetPathb" ProjectSettings); that is a follow-up, not this cut. |.AssetPathb"- No settings exist yet: no Assets/AddressableAssetsData, no com.unity.addressableassets |.AssetPathb" in ProjectSettings/EditorBuildSettings.asset m_configObjects. |.AssetPathb"- Creating settings (AddressableAssetSettings.Create, :2023-2056, and Validate, |.AssetPathb" :1946-1976) writes: Assets/AddressableAssetsData/AddressableAssetSettings.asset, |.AssetPathb" DefaultObject.asset, AssetGroups/Default Local Group.asset with |.AssetPathb" AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset and |.AssetPathb" _ContentUpdateGroupSchema.asset, AssetGroupTemplates/Packed Assets.asset, |.AssetPathb" DataBuilders/BuildScriptFastMode.asset, BuildScriptPackedPlayMode.asset, |.AssetPathb" BuildScriptPackedMode.asset, each with a .meta, plus the config object entry in |.AssetPathb" EditorBuildSettings.asset. It sets BuildAddressablesWithPlayerBuild = PreferencesValue, |.AssetPathb" a per-user preference. |.AssetPathb"- GUID keys. BundledAssetGroupSchema.IncludeGUIDInCatalog defaults to true |.AssetPathb" (BundledAssetGroupSchema.cs:155); the player catalog then adds each entry's guid as a key |.AssetPathb" (AddressableAssetEntry.CreateKeyList, :254-261). Folder entries expand into sub-entries |.AssetPathb" carrying their own guid (AddressableAssetEntry.cs:554). In editor play mode ("Use Asset |.AssetPathb" Database"), AddressableAssetSettingsLocator keys direct entries by guid (:155) and resolves |.AssetPathb" a guid under an addressable folder entry by walking parent folders (:262-283). A guid that is |.AssetPathb" not addressable yields no location and the load fails. So LoadAssetAsync<T>(guid) works in |.AssetPathb" editor and player for direct and folder entries, and fails for non-addressable assets. |.AssetPathb"- Resources. An asset under a Resources folder cannot be an entry: the Inspector and Groups |.AssetPathb" window move it to Resources_moved (AddressableAssetUtility.SafeMoveResourcesToGroup, |.AssetPathb" :309-339), and moving an entry into Resources unmarks it (AddressableAssetSettings.cs:2900-2906). |.AssetPathb" The programmatic CreateOrMoveEntry (:2541) does not check, so a script could create an |.AssetPathb" entry the GUI would refuse; the cut must move assets out of Resources rather than rely on that. |.AssetPathb" Moving a file together with its .meta keeps the guid, so stored GUIDs survive the move. |.AssetPathb"- Sync. AsyncOperationHandle.WaitForCompletion (AsyncOperationHandle.cs:178) completes a |.AssetPathb" local load in place; SynchronousAddressables.md:21 puts the cost near Resources.Load for |.AssetPathb" local bundles and warns that it completes every pending load. |.AssetPathb"- Player build. Bundles build with the player only when BuildAddressablesWithPlayerBuild |.AssetPathb" resolves to build (build-player-builds.md:5). Cut 1 sets BuildWithPlayer in the project |.AssetPathb" settings so the rule is committed, not a preference. |.AssetPathb" |.AssetPathb"### 2.3 How an asset becomes addressable (Q1) |.AssetPathb" |.AssetPathb"Recommended (Q1 A): one folder entry, Assets/Content, in Default Local Group. Addressable |.AssetPathb"means "lives under Assets/Content". Cut 2 moves Assets/Resources/Prefabs/, |.AssetPathb"Assets/Resources/Schematics/ and Assets/Resources/Sprites/Icons/ there with their .meta |.AssetPathb"files, keeping relative paths. Sprites/Icons/ includes the 33 settings icons settings Cut 1 |.AssetPathb"will reference, so that cut only stores GUIDs. The 7 CelestialBodySettings presets under |.AssetPathb"Assets/Plugins/Celestial Body/Solar System/ move into Assets/Content/Celestial Bodies/ in |.AssetPathb"settings Cut 1 (that map's old fork B(a) move, retargeted). |.AssetPathb" |.AssetPathb"### 2.4 Loading owner |.AssetPathb" |.AssetPathb"Assets/Scripts/EngineAssets.cs (Assembly-CSharp, replaces UnityHelpers.cs), about 30 lines: |.AssetPathb"- public static T Load<T>(string guid) where T : Object. Empty GUID returns null. A |.AssetPathb" Component type loads the GameObject and returns GetComponent<T>(). |.AssetPathb"- Loads with Addressables.LoadAssetAsync<T>(guid).WaitForCompletion(). All call sites are |.AssetPathb" synchronous construction paths that Instantiate at once. Making them async would reorder |.AssetPathb" entity construction for 30 local assets. Default: sync. |.AssetPathb"- Caches one handle per (guid, type) for the process lifetime and never releases, which is |.AssetPathb" the lifetime Resources.Load has today. It owns every handle; no caller holds or releases one. |.AssetPathb" A failed handle logs the GUID and returns null; callers keep their existing null handling. |.AssetPathb" |.AssetPathb"### 2.5 Validation owner |.AssetPathb" |.AssetPathb"Assets/Scripts/Editor/EngineAssetCheck.cs (Assembly-CSharp-Editor). It needs AssetDatabase, |.AssetPathb"the Addressables editor settings and the consumer component types, so it cannot be a headless |.AssetPathb"AetherDb command or a Tests.asmdef test (that assembly cannot reference Assembly-CSharp). |.AssetPathb"It has a menu item and a batchmode entry (-executeMethod EngineAssetCheck.Run, exit 1 on |.AssetPathb"failure). It opens the catalog read-only through AetheriaStores.Open, walks every stored |.AssetPathb"document for [CultInspectorAssetGuid] string members, and for each non-empty value checks: |.AssetPathb"1. it is 32 lowercase hex characters; |.AssetPathb"2. AssetDatabase.GUIDToAssetPath names an existing file; |.AssetPathb"3. AddressableAssetSettingsDefaultObject.Settings.FindAssetEntry(guid, includeImplicit: true) is non-null; |.AssetPathb"4. the asset satisfies its member's consumer contract, from one table with one row per member: |.AssetPathb" Icon, ActionBarIcon, Schematic, Logo are Texture2D; HullData.Prefab is a |.AssetPathb" GameObject with EntityInstance; WeaponData.EffectPrefab has InstantWeaponEffectManager |.AssetPathb" on InstantWeaponData records and ConstantWeaponEffectManager on ConstantWeaponData |.AssetPathb" records; ThrusterData.ParticlesPrefab and AetherDriveData.Particles have ParticleSystem. |.AssetPathb" An attributed member missing from the table fails the check, so a new field cannot skip it. |.AssetPathb" |.AssetPathb"It reports record name, member, GUID and path per failure. The check does not write, and no |.AssetPathb"repair path exists. |.AssetPathb" |.AssetPathb"## 3. Data migration (Cut 2, First) |.AssetPathb" |.AssetPathb"- Scratch-only program over Aetheria.Shared at the pre-Cut-2 commit (the fork K (a) |.AssetPathb" precedent: no landed bypass, no one-shot command left behind). It opens a copy of the |.AssetPathb" catalog writable, walks every stored document for [CultInspectorAssetPath] string members, |.AssetPathb" and maps each non-empty path to the guid: of <repo>/<path>.meta. It writes through the |.AssetPathb" catalog's own types and commits once. |.AssetPathb"- Report, one line per value: record type, record name, member, old path, GUID. Unresolved |.AssetPathb" paths are listed and fail the run with nothing written; none are expected (1.1). Empty |.AssetPathb" values stay empty. |.AssetPathb"- No record is added or removed, and no global is touched. Member names, keys and JsonProperty |.AssetPathb" names are unchanged: the member still names the asset, and the attribute says the form. |.AssetPathb"- The rewritten GameData/Aetheria.cc (LFS) lands in the same commit as the code. A commit |.AssetPathb" that holds GUIDs with path-loading code, or paths with GUID-loading code, loads nothing. |.AssetPathb"- Before/after: AetherDb census and dangling outputs are byte-identical (same capture |.AssetPathb" method both sides); the report has 30 lines; a scratch re-read finds 30 GUIDs, 108 empty |.AssetPathb" strings and no string starting with Assets/. |.AssetPathb" |.AssetPathb"## 4. Cuts |.AssetPathb" |.AssetPathb"### Cut 0. CultLib: asset GUID attribute and Studio picker |.AssetPathb" |.AssetPathb"- Repo/branch: CultLib, a codex/ branch from main 244154e. Releases before Cut 2. |.AssetPathb"- Deletes first: CultInspectorAssetPathAttribute (src/GameCult.Caching/CultInspectorAttributes.cs:65-77); |.AssetPathb" CultInspectorMetadata.AssetPath (CultInspectorModel.cs:44,56); the path branch in |.AssetPathb" CultCacheStudioDrawers.cs:170-176. |.AssetPathb"- Adds: CultInspectorAssetGuidAttribute(Type? assetType = null) with the identity comment; |.AssetPathb" CultInspectorMetadata.AssetGuid; the drawer branch: GUIDToAssetPath then |.AssetPathb" LoadAssetAtPath(path, assetType), then ObjectField, storing AssetPathToGUID(next) or |.AssetPathb" string.Empty. README src/GameCult.Unity/Assets/Caching/README.md:153,164. |.AssetPathb"- Release: rebuild plugins, bump unity/org.gamecult.cultlib/package.json to 1.0.60 and |.AssetPathb" src/GameCult.Unity/Assets/Caching/package.json to 1.4.0 (depending on cultlib 1.0.60), tag both. |.AssetPathb"- Verification: |.AssetPathb" - builds: GameCult.Caching, the CultLib test project that covers CultInspectorModel, the |.AssetPathb" Unity package build script. |.AssetPathb" - tests: a model test pins that a member carrying the GUID attribute exposes AssetGuid and |.AssetPathb" its AssetType. |.AssetPathb" - negative: git grep -n "AssetPath" -- src unity finds nothing (checked: today the only hits |.AssetPathb" are the three files above and the README). |.AssetPathb" - operator (Unity, after Cut 2's bump): pick a prefab in Studio, the stored value is its GUID, |.AssetPathb" and reopening shows the same asset. |.AssetPathb" |.AssetPathb"### Cut 1. Aetheria: Addressables settings |.AssetPathb" |.AssetPathb"- Repo/branch: Aetheria codex/item-provenance, after settings Cut 0 lands. Independent of Cut 0. |.AssetPathb"- First: Unity closed (operator), because batchmode refuses an open project. |.AssetPathb"- Adds: "com.unity.addressables": "2.9.1" as a direct dependency in Packages/manifest.json, |.AssetPathb" since Aetheria code now uses it; the lock entry goes from depth 1 to 0. Settings created by a |.AssetPathb" scratch-only batchmode -executeMethod script, which is not landed: Create, then set |.AssetPathb" BuildAddressablesWithPlayerBuild = BuildWithPlayer, create Assets/Content/ (+.meta) and |.AssetPathb" CreateOrMoveEntry(guid of Assets/Content, DefaultGroup). Operator alternative: Window > |.AssetPathb" Asset Management > Addressables > Groups > Create Addressables Settings, then the same three |.AssetPathb" edits by hand. |.AssetPathb"- Intentional Unity churn (the whole list): Packages/manifest.json, |.AssetPathb" Packages/packages-lock.json, ProjectSettings/EditorBuildSettings.asset (one |.AssetPathb" com.unity.addressableassets config object), Assets/Content.meta, and under |.AssetPathb" Assets/AddressableAssetsData/: AddressableAssetSettings.asset, DefaultObject.asset, |.AssetPathb" AssetGroups/Default Local Group.asset, AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset, |.AssetPathb" AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset, |.AssetPathb" AssetGroupTemplates/Packed Assets.asset, DataBuilders/BuildScriptFastMode.asset, |.AssetPathb" DataBuilders/BuildScriptPackedPlayMode.asset, DataBuilders/BuildScriptPackedMode.asset, |.AssetPathb" and every folder and file .meta. Nothing else: the modified materials and render textures |.AssetPathb" in the worktree today are pre-existing Unity churn and stay unstaged. |.AssetPathb"- Harmless alone: no code loads through Addressables yet, and Assets/Content is empty. |.AssetPathb"- Verification: |.AssetPathb" - operator: Unity opens without Addressables errors; the Groups window shows Assets/Content |.AssetPathb" under Default Local Group; the ARPG play smoke is unchanged. |.AssetPathb" - negative: git show --stat lists only the files above. |.AssetPathb" |.AssetPathb"### Cut 2. Aetheria: switch every data asset reference to GUIDs |.AssetPathb" |.AssetPathb"One commit, or a series whose intermediate commits Soul accepts as unplayable. See section 3 |.AssetPathb"for why it is atomic. |.AssetPathb" |.AssetPathb"- Depends on: Cuts 0 and 1, and Q1. |.AssetPathb"- First: the migration report (section 3) against the pre-cut catalog; AetherDb census and |.AssetPathb" dangling captures; git grep -n "Assets/Resources/" -- Assets/Scripts capture. |.AssetPathb"- Deletes first: |.AssetPathb" - Assets/Scripts/UnityHelpers.cs (+.meta), 11 lines. |.AssetPathb" - Gameplay/ActionBarSlot.cs:114, :153: the inline Substring("Assets/Resources/".Length).Split('.').First() |.AssetPathb" loads (and using System.Linq if nothing else uses it). |.AssetPathb" - All 8 CultInspectorAssetPath usages (ItemData.cs:352,362,392,499, Weapon.cs:43, |.AssetPathb" Thruster.cs:26, AetherDrive.cs:50, Corporations.cs:25) become CultInspectorAssetGuid. |.AssetPathb"- Moves (git mv, file and .meta together, guids unchanged): Assets/Resources/Prefabs/ to |.AssetPathb" Assets/Content/Prefabs/, Assets/Resources/Schematics/ to Assets/Content/Schematics/, |.AssetPathb" Assets/Resources/Sprites/Icons/ to Assets/Content/Sprites/Icons/, plus their folder .meta files. |.AssetPathb"- Adds: Assets/Scripts/EngineAssets.cs (2.4); Assets/Scripts/Editor/EngineAssetCheck.cs (2.5); |.AssetPathb" the migrated GameData/Aetheria.cc; the CultLib bump (manifest URLs #cultlib-unity-v1.0.60 |.AssetPathb" and #caching-unity-v1.4.0, lock, Directory.Build.props:5 CultLibRevision). |.AssetPathb"- Per-file changes (against f8396313): |.AssetPathb" - ActionBarSlot.cs:114, :153: EngineAssets.Load<Texture2D>(...). |.AssetPathb" - EntityInstance.cs:195, :224: EngineAssets.Load<InstantWeaponEffectManager> / |.AssetPathb" <ConstantWeaponEffectManager>(data.EffectPrefab); the error text at :200, :229 says GUID, not path. |.AssetPathb" - ShipInstance.cs:53, :67: EngineAssets.Load<ParticleSystem>. |.AssetPathb" - ZoneRenderer.cs:295, :304: EngineAssets.Load<GameObject>. |.AssetPathb" - Editor/CultCacheDrawers.cs:104: LoadAssetAtPath<Texture2D>(AssetDatabase.GUIDToAssetPath(item.Schematic)). |.AssetPathb"- Authority map: |.AssetPathb" - Owner: the catalog field holds the GUID. EngineAssets owns turning a GUID into a loaded |.AssetPathb" asset and holding its handle. The Assets/Content folder entry owns addressability. |.AssetPathb" - Inputs: GUID strings from catalog records; the Addressables catalog (editor locator or player catalog). |.AssetPathb" - Outputs: loaded Objects or components, or null with a logged GUID. |.AssetPathb" - Derived state: asset paths are display-only (Studio, check reports). Group entries are |.AssetPathb" derived from folder location. |.AssetPathb" - Forbidden writers: Resources.Load for data-named assets; any path-prefix stripping; any |.AssetPathb" runtime or editor code that writes a path into an asset member; per-asset entries created by |.AssetPathb" scripts outside Assets/Content. |.AssetPathb" - Shared paths: game runtime, editor play mode and player builds all load through |.AssetPathb" EngineAssets and the same GUID keys. Studio authoring and the migration both store GUIDs. |.AssetPathb" The check reads through the same AetheriaStores.Open. |.AssetPathb" - Deletion line: UnityHelpers.cs, the two inline strips, and the path attribute are gone |.AssetPathb" before EngineAssets exists. |.AssetPathb"- Verification: |.AssetPathb" - builds: Aetheria.Shared headless with -p:CultLibRoot=<CultLib 1.0.60 scratch worktree>; |.AssetPathb" tests/Aetheria.Shared.Tests; Unity batchmode compile. |.AssetPathb" - tests: EngineAssetCheck.Run in batchmode exits 0 on the migrated catalog. Mutation: on a |.AssetPathb" scratch catalog copy, set one HullData.Prefab to a Texture2D GUID, one to a GUID outside |.AssetPathb" Assets/Content, one to a random 32-hex, and one to an old path. Each must fail with its |.AssetPathb" record named. Also add a scratch attributed member missing from the table; it must fail. |.AssetPathb" - data: section 3 before/after checks. |.AssetPathb" - negative (checked against f8396313 for collisions; each has hits only at the sites above today): |.AssetPathb" - git grep -n "Resources.Load" -- Assets/Scripts gives exactly ActionGameManager.cs:420. |.AssetPathb" - git grep -n "Assets/Resources/" -- '*.cs' gives only the generated comments at |.AssetPathb" AetheriaInput.cs:5,19, GradientMapper.cs:94,96, and tools/AetherDb/AuthoredSettings.cs:13 |.AssetPathb" until settings Cut 1 deletes that file. |.AssetPathb" - git grep -n "UnityHelpers\|CultInspectorAssetPath" gives nothing outside docs/. |.AssetPathb" - git ls-files Assets/Resources/Prefabs Assets/Resources/Schematics Assets/Resources/Sprites/Icons is empty. |.AssetPathb" - operator (Unity): |.AssetPathb" 1. Addressables Play Mode Script "Use Asset Database": ARPG play smoke. Ships, turret and |.AssetPathb" Zenith station spawn; thruster and aether drive particles show; fire an instant weapon |.AssetPathb" (e.g. Autocannon) and a charged one (ChargeBlast SG); the action bar shows icons where |.AssetPathb" the settings fallback applies. |.AssetPathb" 2. Play Mode Script "Use Existing Build" after Build > New Build > Default Build Script: |.AssetPathb" the same smoke. This proves the player catalog carries GUID keys. |.AssetPathb" 3. Addressables Analyze: run "Check Resources to Addressable Duplicate Dependencies" and |.AssetPathb" record the result. The 5 known leftovers (1.4) are expected. |.AssetPathb" 4. Studio: LonginusX schematic still underlays the shape drawer. |.AssetPathb" |.AssetPathb"## 5. Subtraction ledger (estimate) |.AssetPathb" |.AssetPathb"| Cut | Removed | Added | Dependencies, formats, targets | |.AssetPathb"|---|---|---|---| |.AssetPathb"| 0 | path attribute ~12, metadata 2, drawer branch 6 | GUID attribute ~12, metadata 2, drawer branch ~7, test ~15 | CultLib release; no targets | |.AssetPathb"| 1 | none | Addressables settings assets (Unity YAML, ~12 files) | com.unity.addressables becomes direct (already installed); Addressables build step joins player builds | |.AssetPathb"| 2 | UnityHelpers.cs 11, 2 inline strips, 283 assets (584 files with .meta) leave Assets/Resources (moved, not deleted) | EngineAssets.cs ~30, EngineAssetCheck.cs 80, 30 catalog values rewritten | removes the Resources path convention for data; no targets | |.AssetPathb" |.AssetPathb"Net code is positive (+110). It buys the ruled capability (GUID identity that survives moves, |.AssetPathb"and one loader) and a check that did not exist: today a mistyped path fails only at spawn. |.AssetPathb" |.AssetPathb"## 6. Operator forks |.AssetPathb" |.AssetPathb"Q1. How assets become addressable. Blocks Cut 1. |.AssetPathb"- (A) One folder entry Assets/Content. Addressable means under that folder. Cut 2 moves |.AssetPathb" Prefabs/, Schematics/ and Sprites/Icons/ out of Resources into it, and settings Cut 1 |.AssetPathb" moves the 7 body presets there. New content is addressable by placement, and the group file |.AssetPathb" does not change per asset. Unreferenced assets in those folders ship too, as they do from |.AssetPathb" Resources today. |.AssetPathb"- (B) One entry per referenced asset, assets kept in place, except that the 27 in Resources must |.AssetPathb" still move (2.2). Only referenced assets ship. Each new pick needs a manual Addressable tick |.AssetPathb" (the check catches a miss), and the group asset changes with every new reference. |.AssetPathb"- (C) Per-asset entries generated from the catalog by an editor step before play and build. The |.AssetPathb" group becomes derived state, but a sync step runs at play and build boundaries, and a stale |.AssetPathb" group between steps fails loads in play mode. |.AssetPathb"- Recommend (A). It makes the invariant structural (location) with no per-asset bookkeeping |.AssetPathb" and no sync step, and it matches how Resources behaves today. |.AssetPathb" |.AssetPathb"## Follow-ups outside this migration |.AssetPathb" |.AssetPathb"- ActionGameManager.cs:420 loads input prompt sprites from Resources/Sprites/Input by control |.AssetPathb" name (1.3). |.AssetPathb"- 5 Resources textures referenced by moved prefabs stay in Resources and ship twice (1.4). |.AssetPathb"- com.unity.localization 1.5.8 is a direct dependency with no script use and no settings; it |.AssetPathb" was the only reason Addressables was installed. |.AssetPathb"- Faction.Logo (5 values) has no reader; EquippableItemData.ActionBarIcon and |.AssetPathb" ConsumableItemData.Icon hold no values (1.1). |.AssetPathb"- Doc sweep for Self: docs/settings-globals-cut.md still carries path-based text in 2.1 |.AssetPathb" (:238, "Engine asset paths (forks I and B...)"), 3.2 (:328), Cut 1, and forks I and B |.AssetPathb" (:522-541). Those become history once this map is ruled. Settings Cut 1's icon and preset |.AssetPathb" fields use [CultInspectorAssetGuid] and EngineAssets.