Table of Contents

Class Interactable

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Abstract base class for interactable objects in the game world. Handles interaction logic, network payloads, and UI display. Implements IInteractable and ISpawnable for scene registration and spawning.

public abstract class Interactable : NetworkBehaviour, IInteractable, ISceneObject, ISpawnable
Inheritance
Object
Component
Behaviour
MonoBehaviour
NetworkBehaviour
Interactable
Implements
Derived
Inherited Members
NetworkBehaviour.IsSpawned
NetworkBehaviour.ComponentIndex
NetworkBehaviour.NetworkObject
NetworkBehaviour.MAXIMUM_NETWORKBEHAVIOURS
NetworkBehaviour.UNSET_NETWORKBEHAVIOUR_ID
NetworkBehaviour.ToString()
NetworkBehaviour.Reset()
NetworkBehaviour.OnValidate()
NetworkBehaviour.IsBehaviourReconciling
NetworkBehaviour.ClearReplicateCache()
NetworkBehaviour.CreateReconcile()
NetworkBehaviour.Reconcile_Reader<T>(PooledReader, ref T)
NetworkBehaviour.OnStartServerCalled
NetworkBehaviour.OnStartClientCalled
NetworkBehaviour.OnStartNetwork()
NetworkBehaviour.OnStopNetwork()
NetworkBehaviour.OnStopServer()
NetworkBehaviour.OnOwnershipServer(NetworkConnection)
NetworkBehaviour.OnSpawnServer(NetworkConnection)
NetworkBehaviour.OnDespawnServer(NetworkConnection)
NetworkBehaviour.OnStartClient()
NetworkBehaviour.OnStopClient()
NetworkBehaviour.OnOwnershipClient(NetworkConnection)
NetworkBehaviour.ClearBuffedRpcs()
NetworkBehaviour.ExcludeOwnerFromUnbufferedObserversRpcs
NetworkBehaviour.IsClientOnly
NetworkBehaviour.IsServerOnly
NetworkBehaviour.IsHost
NetworkBehaviour.IsClient
NetworkBehaviour.IsServer
NetworkBehaviour.IsDeinitializing
NetworkBehaviour.NetworkManager
NetworkBehaviour.ServerManager
NetworkBehaviour.ClientManager
NetworkBehaviour.ObserverManager
NetworkBehaviour.TransportManager
NetworkBehaviour.TimeManager
NetworkBehaviour.SceneManager
NetworkBehaviour.PredictionManager
NetworkBehaviour.RollbackManager
NetworkBehaviour.NetworkObserver
NetworkBehaviour.IsClientInitialized
NetworkBehaviour.IsClientStarted
NetworkBehaviour.IsClientOnlyInitialized
NetworkBehaviour.IsClientOnlyStarted
NetworkBehaviour.IsServerInitialized
NetworkBehaviour.IsServerStarted
NetworkBehaviour.IsServerOnlyInitialized
NetworkBehaviour.IsServerOnlyStarted
NetworkBehaviour.IsHostInitialized
NetworkBehaviour.IsHostStarted
NetworkBehaviour.IsOffline
NetworkBehaviour.IsNetworked
NetworkBehaviour.GetIsNetworked()
NetworkBehaviour.IsManagerReconciling
NetworkBehaviour.Observers
NetworkBehaviour.IsOwner
NetworkBehaviour.IsController
NetworkBehaviour.HasAuthority
NetworkBehaviour.Owner
NetworkBehaviour.OwnerId
NetworkBehaviour.ObjectId
NetworkBehaviour.LocalConnection
NetworkBehaviour.OwnerMatches(NetworkConnection)
NetworkBehaviour.Despawn(GameObject, DespawnType?)
NetworkBehaviour.Despawn(NetworkObject, DespawnType?)
NetworkBehaviour.Despawn(DespawnType?)
NetworkBehaviour.Spawn(GameObject, NetworkConnection, Scene)
NetworkBehaviour.Spawn(NetworkObject, NetworkConnection, Scene)
NetworkBehaviour.RemoveOwnership()
NetworkBehaviour.GiveOwnership(NetworkConnection)
NetworkBehaviour.GetInstance<T>()
NetworkBehaviour.TryRegisterInstance<T>(T)
NetworkBehaviour.UnregisterInstance<T>()
NetworkBehaviour.CanLog(LoggingType)
MonoBehaviour.IsInvoking()
MonoBehaviour.CancelInvoke()
MonoBehaviour.StopCoroutine(Coroutine)
MonoBehaviour.StopAllCoroutines()
MonoBehaviour.destroyCancellationToken
MonoBehaviour.useGUILayout
MonoBehaviour.didStart
MonoBehaviour.didAwake
MonoBehaviour.runInEditMode
Behaviour.enabled
Behaviour.isActiveAndEnabled
Component.GetComponent<T>()
Component.TryGetComponent<T>(out T)
Component.GetComponentInChildren<T>()
Component.GetComponentsInChildren<T>()
Component.GetComponentInParent<T>()
Component.GetComponentsInParent<T>()
Component.GetComponents<T>()
Component.GetComponentIndex()
Component.CompareTag(TagHandle)
Component.transform
Component.transformHandle
Component.gameObject
Component.tag
Object.GetEntityId()
Object.GetInstanceID()
Object.GetHashCode()
Object.InstantiateAsync<T>(T)
Object.InstantiateAsync<T>(T, Transform)
Object.InstantiateAsync<T>(T, Vector3, Quaternion)
Object.InstantiateAsync<T>(T, Transform, Vector3, Quaternion)
Object.Instantiate(Object, Vector3, Quaternion)
Object.Instantiate(Object, Vector3, Quaternion, Transform)
Object.Instantiate(Object)
Object.Instantiate(Object, Scene)
Object.Instantiate<T>(T, InstantiateParameters)
Object.Instantiate<T>(T, Vector3, Quaternion, InstantiateParameters)
Object.Instantiate(Object, Transform)
Object.Instantiate<T>(T)
Object.Instantiate<T>(T, Vector3, Quaternion)
Object.Instantiate<T>(T, Vector3, Quaternion, Transform)
Object.Instantiate<T>(T, Transform)
Object.Destroy(Object)
Object.DestroyImmediate(Object)
Object.DontDestroyOnLoad(Object)
Object.DestroyObject(Object)
Object.FindObjectsOfType<T>()
Object.FindObjectsByType<T>(FindObjectsSortMode)
Object.FindObjectsByType<T>(FindObjectsInactive, FindObjectsSortMode)
Object.FindObjectOfType<T>()
Object.FindFirstObjectByType<T>()
Object.FindAnyObjectByType<T>()
Object.FindFirstObjectByType<T>(FindObjectsInactive)
Object.FindAnyObjectByType<T>(FindObjectsInactive)
Object.FindObjectsByType<T>()
Object.FindObjectsByType<T>(FindObjectsInactive)
Object.name
Object.hideFlags

Fields

GizmoColor

public Color GizmoColor

Field Value

Color

InteractionRange

The maximum distance (in units) at which a player can interact with this object.

public float InteractionRange

Field Value

float

Properties

GameObject

The GameObject associated with this interactable.

public GameObject GameObject { get; }

Property Value

GameObject

ID

Unique ID for this interactable object (used for network sync).

public long ID { get; set; }

Property Value

long

InteractRateLimit

The rate limit (in milliseconds) between allowed interactions for this object.

public virtual double InteractRateLimit { get; }

Property Value

double

Name

The name of this interactable object (defaults to GameObject name).

public virtual string Name { get; }

Property Value

string

ObjectSpawner

Reference to the object spawner responsible for spawning/despawning this object.

public ObjectSpawner ObjectSpawner { get; set; }

Property Value

ObjectSpawner

OnInteractTriggers

ECA triggers invoked server-side when a player successfully interacts with this object. Configure these in the Inspector to define per-object interaction behaviour without code.

public List<Trigger> OnInteractTriggers { get; }

Property Value

List<Trigger>

SpawnableSettings

Settings for spawning this object (e.g., prefab, spawn rules).

public SpawnableSettings SpawnableSettings { get; set; }

Property Value

SpawnableSettings

Title

The display title for this interactable, shown in the UI.

public virtual string Title { get; }

Property Value

string

TitleColor

The color of the title displayed for this interactable in the UI.

public virtual Color TitleColor { get; }

Property Value

Color

Transform

The transform of this object in the scene.

public Transform Transform { get; }

Property Value

Transform

Methods

CanInteract(IPlayerCharacter)

Returns true if the specified player character may interact with this object.

public virtual bool CanInteract(IPlayerCharacter character)

Parameters

character IPlayerCharacter

The player character attempting to interact.

Returns

bool

True if interaction is allowed, false otherwise.

Remarks

A pure question with no side effects. It used to stamp the character's interact rate-limit as part of answering, which made it unusable as a check: the scene server, the quest system and the client's input handler all call it, and each call silently consumed a limiter meant for one of the others. A quest accepted within the limiter's window of the interaction that opened the dialogue was refused by a debounce nobody intended to spend, and the refusal path sends nothing back — so the player saw a dead keypress. Spend the limiter explicitly with TryConsumeInteractRateLimit(IPlayerCharacter).

Despawn()

Despawns this interactable, returning it to the object pool.

public void Despawn()

Remarks

Routes through the owning ObjectSpawner when there is one, so the spawner can schedule a respawn. Falls back to despawning directly otherwise.

The fallback is the important half. An interactable with no spawner — ground loot dropped by a kill, a container placed by script — used to hit a null-conditional and do nothing at all, so picking it up left the object spawned in the world forever: an invisible, already-looted pickup that every client kept observing. Pooled despawn is also what keeps world items inside the map's fixed memory budget rather than being destroyed and re-instantiated on every drop.

ExecuteOnInteract(EventData)

Fires all OnInteractTriggers with the provided event data. Called by FishMMO.Server.Implementation.World.SceneServer.Interactable.InteractableSystem after server-side validation succeeds.

public bool ExecuteOnInteract(EventData eventData)

Parameters

eventData EventData

Context for this interaction (initiator, interactable reference, etc.).

Returns

bool

True when at least one trigger was fired.

Remarks

Every entry is null-checked. A list element left empty in the inspector is an easy authoring slip and used to take the whole interaction down with a NullReferenceException, losing the triggers after it as well as the one that was blank.

An interactable with no triggers at all is warned about once per interaction rather than passing silently. There is no default behaviour left in these classes — the ECA list is the entire implementation — so an empty list means the object does nothing when used, and that is indistinguishable from a broken object unless it says so.

InRange(Transform)

Returns true if the specified transform is within interaction range of this object. Uses squared distance for efficiency.

public bool InRange(Transform transform)

Parameters

transform Transform

The transform to check range against.

Returns

bool

True if in range, false otherwise.

OnAwake()

Called when the object is awakened. Override to implement custom initialization logic.

public virtual void OnAwake()

OnStartServer()

Registers this interactable in the scene object registry and assigns its ID.

public override void OnStartServer()

Remarks

Deliberately not in Awake under #if UNITY_SERVER, which is where it used to live. UNITY_SERVER is a build-target define, and the scene server also runs from the editor — where it is undefined. Every interactable therefore skipped registration there, kept ID 0, and sent 0 to every client in WritePayload(NetworkConnection, Writer); the server's own registry stayed empty, so ValidateSceneObject refused every interaction in the world. Nothing could be talked to, looted, or bound to outside a dedicated server build. This is the same gate that had already been found and removed from NPC.OnStartServer, for the same reason.

OnStartServer() is the correct home: FishNet invokes it only on a peer that is actually running a server, and it runs before the spawn message — and therefore before WritePayload(NetworkConnection, Writer) — is built, so the ID a client receives is the one assigned here. Re-registration on pool reuse is a no-op that preserves the existing ID.

ReadPayload(NetworkConnection, Reader)

Reads network payload data for this interactable, setting its ID and registering it in the scene.

public override void ReadPayload(NetworkConnection connection, Reader reader)

Parameters

connection NetworkConnection

The network connection.

reader Reader

The network reader.

ResetState(bool)

Resets the state of this interactable, clearing event handlers and spawn settings.

public override void ResetState(bool asServer)

Parameters

asServer bool

True if called on the server.

TryConsumeInteractRateLimit(IPlayerCharacter)

Spends the character's interact rate-limit, returning false when it is still cooling.

public bool TryConsumeInteractRateLimit(IPlayerCharacter character)

Parameters

character IPlayerCharacter

The interacting character.

Returns

bool

True when the limiter was free and has now been spent.

Remarks

Separate from CanInteract(IPlayerCharacter) so a caller that only needs to validate — the quest system, which already holds its own ingress guard — does not consume a budget belonging to the interaction path.

WritePayload(NetworkConnection, Writer)

Writes network payload data for this interactable, sending its ID to the writer.

public override void WritePayload(NetworkConnection connection, Writer writer)

Parameters

connection NetworkConnection

The network connection.

writer Writer

The network writer.

Events

OnDespawn

Event invoked when this object is despawned.

public event Action<ISpawnable> OnDespawn

Event Type

Action<ISpawnable>