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;
}
}