using UnityEngine; namespace NightclubArcadia.Core { /// /// Finds objects that live in a different loaded scene. /// /// Unity cannot serialize a reference across a scene boundary — the Inspector /// refuses it and any existing reference is nulled when the scenes are split. So a /// level object that needs the dialogue runner, or the player, has to resolve it at /// runtime. This is a lookup helper, not a service container: there is no /// registration step and nothing to keep in sync. /// /// It is deliberately thin. FindFirstObjectByType is not cheap, so callers cache /// what they get in Awake rather than calling per frame, and an Inspector-assigned /// reference always wins — this only fills in what the split left null. /// public static class SceneServices { /// /// Inspector value if set, otherwise the first one in any loaded scene. Silent: /// returns null when nothing is found. /// /// Use this when the answer may legitimately not exist yet — during Awake, for /// instance, when the scene holding it may not have loaded. /// public static T TryResolve(T assigned) where T : Object { if (assigned != null) { return assigned; } // Include inactive: a system parked inactive at startup is still the object // we mean, and excluding it produces a confusing "not found" for something // sitting right there in the hierarchy. return Object.FindFirstObjectByType(FindObjectsInactive.Include); } /// /// As TryResolve, but logs an error when nothing is found. Only call this at the /// point the dependency is actually needed — calling it during Awake reports a /// failure that may simply be a scene that has not finished loading. /// public static T Resolve(T assigned, Object context, string field) where T : Object { var found = TryResolve(assigned); if (found == null) { Debug.LogError( $"[SceneServices] {context?.name}: could not resolve {field} ({typeof(T).Name}). " + "Is the Systems scene loaded?", context); } return found; } static Transform player; /// /// The player transform, by tag, cached. Null between scene loads if the /// systems scene has not come up yet, so callers must handle null. /// public static Transform Player { get { if (player == null) { var go = GameObject.FindGameObjectWithTag("Player"); player = go != null ? go.transform : null; } return player; } } /// Drop the cache. Call when unloading a scene that held the player. public static void Forget() => player = null; } }