Saltar al contenido principal

InstanceModule

Tsvrc.Editor.InstanceModule is what finds, creates, and heals a project's single Instance subclass, the type you'd otherwise need to hand-wire onto the generated root yourself. There's no manual configuration for this one: the module scans every loaded assembly for a non-abstract Instance subclass and fully owns a child object named "Instance" under the scaffold root, self-recovering without any user action needed.

Detecting the one real subclass

DetectInstanceType reflects across every loaded assembly, filters out anything marked [TsCodegenIgnore] (test doubles, most commonly), and deduplicates by full type name. Unity's AppDomain can carry stale duplicate copies of the same assembly across successive recompiles, which would otherwise make one real subclass look ambiguous just because it was seen twice. Zero candidates or exactly one are both unambiguous outcomes; more than one logs an error and makes Wire() leave whatever's currently wired untouched entirely, since destroying a working setup because a second, possibly-transient subclass momentarily appeared would be worse than doing nothing.

Surviving a broken compile

The generated field and property (_instance / public override Instance Instance => _instance;) are always declared as the plain Instance base type. GenerateCode()'s output never depends on which concrete subclass was detected, so a broken compile can't corrupt the generated code. What a broken compile can corrupt is Wire()'s live-reflection detection: if the AppDomain scan finds zero candidates, but ScriptIndex's independent, source-text-based scan confirms exactly one real Instance subclass genuinely exists in project source, that almost always means the subclass itself just failed to compile along with everything else. In that case (_knownViaScriptIndexOnly), Wire() deliberately does nothing rather than destroying the real, working "Instance" child object and nulling the scene field. There's no live type to re-wire it with anyway, so leaving the existing scene state alone is the only safe option.

Self-healing the scene object

On a clean detection, Wire() creates the "Instance" child if it doesn't exist, or recreates its component if the existing one is the wrong type (renamed/retyped) or its UdonSharp program asset was deleted. UdonSharpUndo.DestroyImmediate is required for that teardown rather than a plain destroy, since an UdonSharp component carries a hidden backing UdonBehaviour a plain destroy would orphan. This destruction is narrowly scoped: it only ever removes a component that's either exactly the currently-detected type or some other stale Instance subclass, never every UdonSharpBehaviour on that child indiscriminately, so a developer's own unrelated script hand-attached to the same GameObject survives an Instance retype untouched.

Reserved name

Instance is reported via ExposedFieldNames() at ReservedFieldNamePrecedence unconditionally, so a Global entry that happens to auto-derive the exact name "Instance" (for example, referencing a plain GameObject literally named that) is caught by collision detection and excluded, rather than silently producing a duplicate-member compile error.