|
| 1 | +# apiupdaterproject — agent notes |
| 2 | + |
| 3 | +Background for anyone changing this project or the relocation metadata it tests. `README.md` covers |
| 4 | +what it is and how to run it; this file covers why it is built this way and what will bite you. |
| 5 | + |
| 6 | +## Orientation |
| 7 | + |
| 8 | +* This is a standalone Unity project at the repo root. It is not part of `testproject` or |
| 9 | + `minimalproject`, and the package does not reference it. |
| 10 | +* It validates one thing end to end: that a project written against the **NGO 2.x** editor API is |
| 11 | + migrated automatically by Unity's API updater when the package is upgraded to **3.x**. |
| 12 | +* **The mechanism it tests does not live here.** The `[MovedFrom]` attributes are on the real types in |
| 13 | + `com.unity.netcode.gameobjects/Editor/**`. This project only consumes them. |
| 14 | +* **Do not "fix" the sources under `Assets/Editor`.** They are deliberately written against the 2.x |
| 15 | + API and are the input to the test. A helpful cleanup there silently guts it. |
| 16 | +* The expected-type list in `run_upgrade_test.py` is frozen: it enumerates the public editor API of |
| 17 | + `develop-2.0.0`, which is released and cannot change. It only needs extending if a public editor |
| 18 | + type is relocated again within 3.x. |
| 19 | +* CI runs it on demand only — comment `/ci apiupdater` on a PR. See `.yamato/api-updater-test.yml`. |
| 20 | +* **Opening this project locally mutates it.** Unity rewrites `ProjectVersion.txt` to whatever editor |
| 21 | + opened it, and the package manager can add builtin modules to `Packages/manifest.json` that only |
| 22 | + exist in that editor — `com.unity.modules.smartstrings` from a 6000.7 alpha broke the 6000.6 CI job |
| 23 | + exactly this way. Check `git diff` on those two files before committing, and keep the manifest to |
| 24 | + modules that exist in the editor the job downloads (`validation_editors.default`). |
| 25 | +* Verified beyond this project: a real sample project upgraded 7 of its own scripts automatically, |
| 26 | + including a `NetcodeEditorBase<T>` subclass. |
| 27 | + |
| 28 | +## Why not `[Obsolete(... (UnityUpgradable))]` skeletons |
| 29 | + |
| 30 | +That is the other mechanism for this, and it was measured first: a second assembly declaring an empty |
| 31 | +skeleton of each 2.x type under the old namespace, each carrying |
| 32 | +`[Obsolete("... (UnityUpgradable) -> [asm] ns.Type", true)]`. It works for every non-generic type, but |
| 33 | + |
| 34 | +* it **cannot** relocate a generic type — a target carrying a type argument list is treated as a |
| 35 | + same-namespace *rename*, so the namespace and assembly are dropped (see the table below), which |
| 36 | + left `NetcodeEditorBase<TT>` needing `MovedFrom` anyway; |
| 37 | +* it costs a second assembly and a hand-maintained parallel API surface that has to track the real |
| 38 | + one's `#if` guards and eventually be deleted; |
| 39 | +* it leaves the stale `using` directives and expands namespace aliases at the reference site, where |
| 40 | + `MovedFrom` removes the dead usings and rewrites aliases in place. |
| 41 | + |
| 42 | +What it buys, and `MovedFrom` does not, is a better error when the user *declines* the update: |
| 43 | +`'NetworkManagerEditor' is obsolete: ... Use Unity.Netcode.GameObjects.Editor.NetworkManagerEditor |
| 44 | +instead` rather than a bare CS0246. It is also the only route for member-level redirects (a renamed |
| 45 | +method, a changed signature) and for type *renames*, which `MovedFrom` explicitly does not support. |
| 46 | +Neither applies to this change — it is a pure relocation. |
| 47 | + |
| 48 | +## Measured behaviour |
| 49 | + |
| 50 | +Probed against 6000.7.0a5 with throwaway types, for a namespace + assembly move: |
| 51 | + |
| 52 | +| Mechanism / `(UnityUpgradable)` target form | Non-generic type | Generic type | |
| 53 | +| --- | --- | --- | |
| 54 | +| `[Asm] Ns.Type` | rewritten, fully qualified | name replaced, namespace dropped | |
| 55 | +| `[Asm] Ns.Type<TT>` | n/a | name replaced, namespace dropped (a no-op when the name is unchanged) | |
| 56 | +| ``[Asm] Ns.Type`1`` | n/a | backtick emitted into the source verbatim | |
| 57 | +| `* [Asm] Ns.Type<TT>` | n/a | not rewritten | |
| 58 | +| `[MovedFrom(true, oldNs, oldAsm, null)]` | rewritten, fully qualified | rewritten, fully qualified | |
| 59 | + |
| 60 | +Reference forms `MovedFrom` was confirmed to handle, via `Assets/Editor/DeprecatedApiUsage.cs` and |
| 61 | +`Assets/Editor/DeprecatedApiUsageQualified.cs`: `using` + simple name, fully qualified name, namespace |
| 62 | +alias, type alias, base type, `typeof`, and generic type argument. The dead |
| 63 | +`using Unity.Netcode.Editor;` directives are removed and namespace aliases are rewritten in place |
| 64 | +rather than expanded at each use. |
| 65 | + |
| 66 | +## Known gap: assembly definition references |
| 67 | + |
| 68 | +The updater rewrites C# source only; it does not touch `.asmdef` files. |
| 69 | + |
| 70 | +References made **by GUID** — the Unity default — keep working untouched. A GUID reference resolves |
| 71 | +to whichever `.asmdef` *asset* carries that GUID, independent of the `name` field inside it, and |
| 72 | +`Editor/Unity.Netcode.Editor.asmdef` kept both its path and its GUID through the rename. So a 2.x |
| 73 | +project referencing it by GUID silently ends up referencing `Unity.Netcode.GameObjects.Editor`. |
| 74 | + |
| 75 | +References made **by name** (`"Unity.Netcode.Editor"`) no longer resolve and have to be repointed at |
| 76 | +`Unity.Netcode.GameObjects.Editor` by hand. The same applies to the other renamed assemblies: |
| 77 | +`Unity.Netcode.Editor.CodeGen` and `Unity.Netcode.PackageChecker.Editor`. Nothing can be done about |
| 78 | +this from the package side — reviving the old assembly name is not an option, because |
| 79 | +`Unity.Netcode.Editor` differs from N4E's `Unity.NetCode.Editor` only by the case of one letter and |
| 80 | +the two `Library/ScriptAssemblies/*.dll` filenames collide when both packages are installed. Removing |
| 81 | +that collision is what the 3.0 rename is for. |
0 commit comments