"My interface scan returns nothing at runtime"
▸ SYMPTOM
Scene.GetAllComponents<Component>().OfType<IInteractable>()compiles, runs, and returns nothing, even though interactable components are clearly in the scene. Prompts never appear; nearest-target logic always finds null.
▸ CAUSE
Interface-based scene scans are unreliable in this engine. GetAllComponents<Component>().OfType<I…>() has been observed to return an empty sequence at runtime even when concrete implementors exist.
Mechanism (confirmed on engine 26.07.22): Scene.GetAllComponents<T>() answers off a component index keyed by concrete type: it does not walk every component in the scene doing an is T runtime check. Asking for the base Component type and filtering the result with .OfType<ISomeInterface>() compiles cleanly and always returns an empty sequence, with no compiler error and no runtime exception. That silence is what lets it ship unnoticed: two call sites reading the identical fact can disagree for a whole session before anyone compares them against a live check.
The gap is specific to interfaces, not to any non-exact-type query. An abstract base class works fine as T: GetAllComponents<SomeAbstractBase>() correctly returns every concrete subclass instance when every candidate shares that one base class. Only the interface-then-OfType pattern comes back empty.
▸ FIX
Keep an explicit union of concrete types:
public interface IInteractable
{
string GetPrompt(/* player */);
void Interact(/* player */);
}
static IEnumerable<IInteractable> AllInteractables(Scene scene)
{
foreach (var c in scene.GetAllComponents<Door>()) yield return c;
foreach (var c in scene.GetAllComponents<Chest>()) yield return c;
foreach (var c in scene.GetAllComponents<Workbench>()) yield return c;
// one GetAllComponents<T> per concrete implementor
}If every implementor happens to share one abstract base class, a single GetAllComponents<SomeAbstractBase>() call replaces the whole union. Either way, centralize the enumeration in one shared function so a future implementer of the interface is a single added line rather than a rediscovery of this gotcha at another call site.
Cache the list on a short timer (e.g. 0.25 s) if you scan every frame.
Pick nearest whose prompt is non-null: components can decline (healthy panel → no prompt; damaged → "re-anchor").
UX that works: floating marker over the target (bounds-top + bob) + a [F] prompt line in the HUD.
▸ WHY IT WORKS
GetAllComponents<T> is typed against concrete Component subclasses the scene graph knows how to enumerate. Filtering a broad Component query by interface does not reliably surface those instances at runtime, so you pay the boring explicit list and get correct results.
- Added the mechanism (concrete-type index, not a runtime is-T walk) and the abstract-base-class exception; re-verified on engine 26.07.22
- Published