Table of Contents

Class InteractableSystem

Namespace
FishMMO.Server.Implementation.World.SceneServer.Interactable
Assembly
FishMMO.Server.dll

Server-authoritative dialogue session management. Tracks active dialogue sessions per character, validates client choices, evaluates ECA conditions/actions, and maintains per-character choice bitmasks. All dictionaries are bounded to prevent unbounded memory growth.

[CreateAssetMenu(fileName = "InteractableSystem", menuName = "FishMMO/Server/SceneServer/Interactable System", order = 1)]
[RequiresDataContainer(typeof(InteractableSystemMainThreadQueueData))]
[RequiresDataContainer(typeof(InteractableSystemRuntimeData))]
[RequiresDataContainer(typeof(AsyncWorkerData))]
public class InteractableSystem : ServerBehaviour, IServerBehaviour<INetworkManagerWrapper, ServerManager, NetworkConnection, IServerBehaviour>, IServerComponent<INetworkManagerWrapper, ServerManager, NetworkConnection, IServerBehaviour>, IInteractableSystem, IServerBehaviour, IServerComponent
Inheritance
Object
ScriptableObject
InteractableSystem
Implements
IServerBehaviour<INetworkManagerWrapper, ServerManager, NetworkConnection, IServerBehaviour>
IServerComponent<INetworkManagerWrapper, ServerManager, NetworkConnection, IServerBehaviour>
Inherited Members
ScriptableObject.SetDirty()
ScriptableObject.CreateInstance<T>()
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.ToString()
Object.name
Object.hideFlags

Remarks

Everything the dungeon group finder established carries over unchanged: the queue table, the per-server pump, the heartbeat, the leash to the board, the panel-close rule, and the single transaction that forms a match. What differs is the unit of play — a match of N teams rather than one party — and that a party may queue together. Team assignment is written into the match rows by TryFormArenaMatchAsync(long, string, int, int, int, int, DateTime, int, ArenaRatingSource, ArenaComposeOptions, CancellationToken); running the match is the coordinator's job, in InteractableSystem.ArenaMatch.cs.

Pre-made parties. The leader presses Queue as Party. Every member must be connected to this scene server, standing within the leash of the same board, free of instances and live matches, and the party must fit on one team of the format. Then every member gets a queue row carrying the party id, all or none, and each member's own entry on this server with the board as its leash. A member who walks off or closes their panel leaves alone; the rest stay queued as a smaller pre-made.

Fields

DialogueLeaveChoiceIndex

Choice index meaning "leave the conversation" rather than "take choice N".

public const int DialogueLeaveChoiceIndex = -1

Field Value

int

Remarks

A dialogue node whose choices are all filtered out — every one already taken, or every one's conditions unmet — leaves the client with no buttons at all, and the panel has no close of its own. Escaping out of it left the session open on the server, so the next interaction with anything was validated against a node the player had walked away from. This gives the client a way to say so. It reuses DialogueChoiceBroadcast rather than adding a message, because everything the leave path needs to validate — the session, the node, the range — is already carried on it.

Methods

EndDialogueSession(IPlayerCharacter)

Ends the dialogue session for the specified character without sending a broadcast.

public void EndDialogueSession(IPlayerCharacter character)

Parameters

character IPlayerCharacter

The player character whose session to end.

InitializeOnce()

Initializes the InteractableSystem: validates dependencies, registers all network broadcast handlers, subscribes to dialogue events, and clamps configuration values.

public override ServerComponentInitializationStatus InitializeOnce()

Returns

ServerComponentInitializationStatus

Initialization status indicating success or failure.

LearnAbility(IAbilityController, AbilityTemplate, List<int>)

Creates and learns a new crafted ability, then schedules asynchronous persistence.

public Ability LearnAbility(IAbilityController abilityController, AbilityTemplate abilityTemplate, List<int> abilityEvents)

Parameters

abilityController IAbilityController

Ability controller receiving the new ability.

abilityTemplate AbilityTemplate

Base ability template used for creation.

abilityEvents List<int>

Selected ability event identifiers to attach.

Returns

Ability

The created ability instance.

LearnAbilityEvent<T>(NetworkConnection, IPlayerCharacter, T)

Learns an ability event template and synchronizes the result to the client.

public MerchantPurchaseFailure LearnAbilityEvent<T>(NetworkConnection conn, IPlayerCharacter character, T template) where T : AbilityEvent

Parameters

conn NetworkConnection

Client connection to notify.

character IPlayerCharacter

Character learning the ability event.

template T

Ability event template to learn.

Returns

MerchantPurchaseFailure

Why the learn was refused, or None.

Type Parameters

T

Concrete ability event type.

LearnAbilityTemplate<T>(NetworkConnection, IPlayerCharacter, T)

Learns a base ability template and synchronizes the result to the client.

public MerchantPurchaseFailure LearnAbilityTemplate<T>(NetworkConnection conn, IPlayerCharacter character, T template) where T : BaseAbilityTemplate

Parameters

conn NetworkConnection

Client connection to notify.

character IPlayerCharacter

Character learning the ability.

template T

Ability template to learn.

Returns

MerchantPurchaseFailure

Why the learn was refused, or None.

Type Parameters

T

Concrete base ability template type.

OnDeinitialize()

Deinitializes the InteractableSystem: drains queued actions, clears ingress guards, unregisters network broadcast handlers, unsubscribes from dialogue events, and clears dialogue session state.

public override void OnDeinitialize()

OnInteractNPC(IPlayerCharacter, IInteractable)

Updates an NPC to face the interacting character and enter idle state.

public void OnInteractNPC(IPlayerCharacter character, IInteractable interactable)

Parameters

character IPlayerCharacter

Interacting player character.

interactable IInteractable

Interacted NPC object.

OnServerAbilityCraftBroadcastReceived(NetworkConnection, AbilityCraftBroadcast, Channel)

Handles an incoming ability crafting request and validates cost, ownership, and selected events.

public void OnServerAbilityCraftBroadcastReceived(NetworkConnection conn, AbilityCraftBroadcast msg, Channel channel)

Parameters

conn NetworkConnection

Requesting client connection.

msg AbilityCraftBroadcast

Ability crafting request payload.

channel Channel

Transport channel used by FishNet.

OnServerArenaHistoryRequestReceived(NetworkConnection, ArenaHistoryRequestBroadcast, Channel)

The player's recent matches, for the board.

public void OnServerArenaHistoryRequestReceived(NetworkConnection conn, ArenaHistoryRequestBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg ArenaHistoryRequestBroadcast
channel Channel

OnServerArenaLeaderboardRequestReceived(NetworkConnection, ArenaLeaderboardRequestBroadcast, Channel)

The season leaderboard, for the board.

public void OnServerArenaLeaderboardRequestReceived(NetworkConnection conn, ArenaLeaderboardRequestBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg ArenaLeaderboardRequestBroadcast
channel Channel

OnServerArenaProfileRequestReceived(NetworkConnection, ArenaProfileRequestBroadcast, Channel)

The player's season standing and queue lock, for the board.

public void OnServerArenaProfileRequestReceived(NetworkConnection conn, ArenaProfileRequestBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg ArenaProfileRequestBroadcast
channel Channel

OnServerArenaQueueBroadcastReceived(NetworkConnection, ArenaQueueBroadcast, Channel)

Handles a request to queue for an arena, alone or as a party.

public void OnServerArenaQueueBroadcastReceived(NetworkConnection conn, ArenaQueueBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg ArenaQueueBroadcast
channel Channel

OnServerDungeonFinderCreateBroadcastReceived(NetworkConnection, DungeonFinderCreateBroadcast, Channel)

Handles a request to open a new instance of a dungeon.

public void OnServerDungeonFinderCreateBroadcastReceived(NetworkConnection conn, DungeonFinderCreateBroadcast msg, Channel channel)

Parameters

conn NetworkConnection

Requesting client connection.

msg DungeonFinderCreateBroadcast

Which entrance, which difficulty, and whether to list it.

channel Channel

Transport channel used by FishNet.

OnServerDungeonFinderJoinBroadcastReceived(NetworkConnection, DungeonFinderJoinBroadcast, Channel)

Handles a request to join an instance somebody else has opened.

public void OnServerDungeonFinderJoinBroadcastReceived(NetworkConnection conn, DungeonFinderJoinBroadcast msg, Channel channel)

Parameters

conn NetworkConnection

Requesting client connection.

msg DungeonFinderJoinBroadcast

Which entrance and which instance.

channel Channel

Transport channel used by FishNet.

OnServerDungeonFinderListBroadcastReceived(NetworkConnection, DungeonFinderListBroadcast, Channel)

Answers a client browsing the instances joinable at one difficulty.

public void OnServerDungeonFinderListBroadcastReceived(NetworkConnection conn, DungeonFinderListBroadcast msg, Channel channel)

Parameters

conn NetworkConnection

Requesting client connection.

msg DungeonFinderListBroadcast

Which entrance and which difficulty.

channel Channel

Transport channel used by FishNet.

Remarks

Every exit sends a DungeonFinderListResultBroadcast, including the refusals and the empty lists. The panel disables its list and its Refresh button while a request is outstanding — the guard that stops the button being held down — so a handler that returned silently would leave the panel inert for the rest of its life.

Not gated on character state. Reading a list is not a move, and a player in combat who cannot see the list can see it by walking ten metres away; refusing would hide information rather than prevent an action.

OnServerGroupFinderLeaveBroadcastReceived(NetworkConnection, GroupFinderLeaveBroadcast, Channel)

Handles a request to leave the queue.

public void OnServerGroupFinderLeaveBroadcastReceived(NetworkConnection conn, GroupFinderLeaveBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg GroupFinderLeaveBroadcast
channel Channel

Remarks

Refused once matched. The group has formed and this character is already in its party; backing out now would leave a party with a member who never arrives. The client hides its Leave control at that point, so reaching this is a race with the pump, not a click.

OnServerGroupFinderQueueBroadcastReceived(NetworkConnection, GroupFinderQueueBroadcast, Channel)

Handles a request to be found a group for one dungeon at one difficulty.

public void OnServerGroupFinderQueueBroadcastReceived(NetworkConnection conn, GroupFinderQueueBroadcast msg, Channel channel)

Parameters

conn NetworkConnection
msg GroupFinderQueueBroadcast
channel Channel

Remarks

Validated like the finder's other requests — the player must be standing at the entrance — but not gated on character state, because joining a queue is not a move. The move comes later, from the pump, and is gated then.

OnUpdate(float)

Called every frame. Drains a bounded number of queued main-thread actions and sweeps stale debounce entries.

protected override void OnUpdate(float deltaTime)

Parameters

deltaTime float

Time elapsed since the last frame.

SendNewItemBroadcast<T>(T, ICharacter, IInventoryController, Item)

Grants an item to a character's inventory through the inventory system's grant funnel: placed, broadcast to the owner, persisted, identity assigned.

public bool SendNewItemBroadcast<T>(T conn, ICharacter character, IInventoryController inventoryController, Item newItem)

Parameters

conn T
character ICharacter
inventoryController IInventoryController
newItem Item

Returns

bool

Type Parameters

T

Remarks

The body that used to live here — place, broadcast, persist — is now CharacterInventorySystem.TryGrantItem, because it was one of three copies (the quest and achievement systems had their own) and only this one handed the item its database identity. A server without an inventory system refuses the grant rather than persisting without a write-back: an item that never learns its id is an item that cannot be equipped, used or moved, and the caller's own fallback (put it back on the corpse, refund the purchase) is the better outcome.

StartDialogueSession(IPlayerCharacter, ISceneObject, IDialogueInteractable)

Starts a new dialogue session for the character from an interactable interaction. Evaluates the start node's conditions and sends DialogueStartBroadcast to the client.

public void StartDialogueSession(IPlayerCharacter character, ISceneObject sceneObject, IDialogueInteractable dialogue)

Parameters

character IPlayerCharacter

The player character starting the dialogue.

sceneObject ISceneObject

The scene object hosting the interactable.

dialogue IDialogueInteractable

The dialogue interactable.

StartECADialogueSession(IPlayerCharacter, DialogueTemplate, IInteractable)

Starts a new dialogue session triggered by an ECA action.

public void StartECADialogueSession(IPlayerCharacter character, DialogueTemplate template, IInteractable interactable = null)

Parameters

character IPlayerCharacter

The player character starting the dialogue.

template DialogueTemplate

The dialogue template to use.

interactable IInteractable

The interactable the dialogue is anchored to, or null.

Remarks

interactable is what anchors the conversation to a place in the world. Every dialogue in the game reaches the server through this method — the interactable-typed StartDialogueSession(IPlayerCharacter, ISceneObject, IDialogueInteractable) overload has no callers — so when this passed a hard-coded 0 for the scene object ID, every session was unanchored and the choice handler's range check was dead code for all of them. A player could open a conversation, walk to the far side of the zone, and keep taking choices — including any that hand out items or currency.