Table of Contents

Class EquipmentController

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Controls the character's equipment slots, handling equip/unequip logic and network synchronization.

Implements IPredictableController at Order 93 so equipment participates in the prediction pipeline: an owner's equip or unequip is INPUT, carried by EquipmentRequest, applied by both the owner and the server inside the replicate body for that tick, and confirmed by the reconcile. Equipment-driven attribute changes therefore land on the same tick on both peers, and the attribute reconcile (Order 95) never has a socket to correct that the replay would not also have re-applied.

Three network paths feed this container and they must agree with one another:

public class EquipmentController : ItemContainer, IEquipmentController, ICharacterBehaviour, IItemContainer, IPredictableController
Inheritance
Object
Component
Behaviour
MonoBehaviour
NetworkBehaviour
EquipmentController
Implements
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.OnStopNetwork()
NetworkBehaviour.OnStartServer()
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

ServerRequestValidator

Server-side gate consulted before a replicated request is applied: is this character allowed to act at all, and may it reach the named container right now?

public static Func<ICharacter, InventoryType, bool> ServerRequestValidator

Field Value

Func<ICharacter, InventoryType, bool>

Remarks

Installed by the server's inventory system. It answers the two questions this shared class cannot — "can the character act" is a server-side validation rule set, and "is a banker in range" needs the scene object registry. Null on every other peer, and null on the server means no gate, which is the permissive default a test harness expects.

Properties

OnEquipTriggers

Triggers invoked when this character equips an item. EventData: EquipItemEventData.

public List<Trigger> OnEquipTriggers { get; }

Property Value

List<Trigger>

OnUnequipTriggers

Triggers invoked when this character unequips an item. EventData: EquipItemEventData.

public List<Trigger> OnUnequipTriggers { get; }

Property Value

List<Trigger>

Order

Execution order in the unified prediction pipeline. Runs after CooldownController (90) and before CharacterAttributeController (95) so equipment attribute modifiers are settled before the attribute reconcile snapshot.

public int Order { get; }

Property Value

int

Remarks

Must stay below Order (95). Restoring an item restates its own ledger entry through ItemGenerator.ApplyAttributes → CharacterAttribute.SetSource; the attribute reconcile then installs the server's total as the residual over whatever those entries sum to. Raising this above 95 would have that residual computed before this tick's equipment is settled, so an item equipped on the reconciled tick counts twice. See the remarks on Order.

Methods

Activate(int)

Activates the item in the specified equipment slot, typically triggering its use effect.

public void Activate(int index)

Parameters

index int

The equipment slot index to activate.

ApplyUnequipDestination(long, InventoryType, int)

Moves an unequipped item to the slot the server put it in, if this peer has it anywhere else. Owner only; a no-op when the item is already there.

public void ApplyUnequipDestination(long itemID, InventoryType container, int slot)

Parameters

itemID long

Identity of the item that was unequipped.

container InventoryType

The container the server placed it in.

slot int

The slot within that container.

Equip(Item, int, IItemContainer, ItemSlot)

Equips the specified item into the given equipment slot, handling swaps and unequips as needed.

public bool Equip(Item item, int inventoryIndex, IItemContainer container, ItemSlot toSlot)

Parameters

item Item

The item to equip.

inventoryIndex int

The index in the source inventory.

container IItemContainer

The source item container (e.g., inventory or bank).

toSlot ItemSlot

The equipment slot to equip the item into.

Returns

bool

True if the item was successfully equipped, false otherwise.

Remarks

Applies immediately on whichever peer calls it. Server-side paths that are not the owner's predicted request — ECA actions, for instance — call this directly; the owner learns of the change through the reconcile. The owner's own requests must go through RequestEquip(Item, int, InventoryType, ItemSlot) instead, so they run inside the replicate tick.

OnAwake()

Called before InitializeOnce, character will not be set yet. Override for early setup.

public override void OnAwake()

OnCreateReconcile(ref CharacterReconcileData)

Writes this controller's authoritative state into the reconcile data (server only). Called once per tick after OnReplicate(ref CharacterReplicateData, ReplicateState, Channel).

public void OnCreateReconcile(ref CharacterReconcileData data)

Parameters

data CharacterReconcileData

OnReconcile(CharacterReconcileData, Channel)

Restores this controller's state from the server's authoritative reconcile data.

public void OnReconcile(CharacterReconcileData data, Channel channel)

Parameters

data CharacterReconcileData
channel Channel

OnReplicate(ref CharacterReplicateData, ReplicateState, Channel)

Executes this controller's simulation for the current tick. May modify input for observer prediction.

public void OnReplicate(ref CharacterReplicateData input, ReplicateState state, Channel channel)

Parameters

input CharacterReplicateData
state ReplicateState
channel Channel

OnStartCharacter()

Called after Character.OnStartClient. Use this for local client initialization.

public override void OnStartCharacter()

OnStartNetwork()

Called when the network has initialized this object. May be called for server or client but will only be called once. When as host or server this method will run before OnStartServer. When as client only the method will run before OnStartClient.

public override void OnStartNetwork()

OnStopCharacter()

Called right before Character.OnStopClient. Use this for local client cleanup.

public override void OnStopCharacter()

PopulateInput(ref CharacterReplicateData)

Populates this controller's portion of the unified input data (owner only). Called once per tick before OnReplicate(ref CharacterReplicateData, ReplicateState, Channel).

public void PopulateInput(ref CharacterReplicateData input)

Parameters

input CharacterReplicateData

ReadPayload(NetworkConnection, Reader)

Called before network start callbacks, but after the object is initialized with network values. This may be used to read information from predicted spawning, or simply have values set before initialization without depending on SyncTypes.

public override void ReadPayload(NetworkConnection conn, Reader reader)

Parameters

conn NetworkConnection
reader Reader

RequestEquip(Item, int, InventoryType, ItemSlot)

Queues an equip to be applied on the owner's next replicate tick.

public bool RequestEquip(Item item, int sourceIndex, InventoryType fromContainer, ItemSlot socket)

Parameters

item Item

The item to equip, as the caller currently sees it.

sourceIndex int

Its index in fromContainer.

fromContainer InventoryType

The container it is in.

socket ItemSlot

The equipment socket it is going to.

Returns

bool

True when the request was queued.

Remarks

Owner only. Validates what can be validated locally — the item is where the request says, it fits the socket, it has a database identity, neither slot is locked — and refuses without queueing when it cannot. One request is held at a time; a second call before the first has ridden a replicate replaces it, and the displaced request is reported through OnRequestResolved as not applied.

RequestUnequip(ItemSlot, InventoryType)

Queues an unequip to be applied on the owner's next replicate tick.

public bool RequestUnequip(ItemSlot socket, InventoryType toContainer)

Parameters

socket ItemSlot

The equipment socket being emptied.

toContainer InventoryType

The container the item should land in.

Returns

bool

True when the request was queued.

Remarks

ResetState(bool)

Drops the per-spawn container state before the object returns to the pool.

public override void ResetState(bool asServer)

Parameters

asServer bool

True if called on the server.

Remarks

The locks are the reason this exists. A slot is locked for the duration of an operation — a consumable activation, an equip round trip — and unlocked when that operation resolves. A despawn mid-flight resolves nothing, so the lock was still set when the object went into the pool, and OnDestroying was the only thing that cleared it: a path a pooled object never takes. The next character to occupy the slot inherited a permanently locked inventory slot, which IsSlotLocked(int) makes unswappable, unremovable and untransferable for the rest of that character's session, with nothing in the UI to explain it.

The subscriber lists go with them. Both events are held by client panels bound to the character that is being torn down; leaving them attached to a recycled container would drive the previous occupant's UI from the next occupant's slot writes.

Items are deliberately NOT cleared here. Each concrete container clears its own in its ResetState, and EquipmentController has to run work either side of that call — see its override for why the order there cannot be inverted.

Unequip(IItemContainer, byte, out List<Item>)

Unequips the item from the specified slot and adds it to the given container (e.g., inventory or bank).

public bool Unequip(IItemContainer container, byte slot, out List<Item> modifiedItems)

Parameters

container IItemContainer

The destination item container.

slot byte

The equipment slot to unequip from.

modifiedItems List<Item>

The list of items modified during the operation.

Returns

bool

True if the item was successfully unequipped and added, false otherwise.

Remarks

See Equip(Item, int, IItemContainer, ItemSlot) for when to call this directly.

WritePayload(NetworkConnection, Writer)

Called when writing a spawn. This may be used to deliver information for predicted spawning, or simply have values set before initialization without depending on SyncTypes.

public override void WritePayload(NetworkConnection conn, Writer writer)

Parameters

conn NetworkConnection
writer Writer

Events

OnItemEquipped

Fired after an item is successfully equipped. Subscribers receive the item and the slot.

public event Action<Item, ItemSlot> OnItemEquipped

Event Type

Action<Item, ItemSlot>

OnItemUnequipped

Fired after an item is successfully unequipped. Subscribers receive the item and the slot.

public event Action<Item, ItemSlot> OnItemUnequipped

Event Type

Action<Item, ItemSlot>

OnRequestResolved

Fired on the owner when a queued request has run in the replicate body, whether or not it was applied. Arguments: the kind, the socket, the container the request named, the container index (or -1 for an unequip), and whether the move happened.

public event Action<EquipmentRequestKind, ItemSlot, InventoryType, int, bool> OnRequestResolved

Event Type

Action<EquipmentRequestKind, ItemSlot, InventoryType, int, bool>

Remarks

This is how a panel that marked two slots as waiting learns that nothing will change them. A refusal here is LOCAL — the item was no longer where the request said, or the socket did not fit it. A refusal by the SERVER is not reported through this event at all: it arrives as a reconcile that puts the item back, which updates the slots directly.

OnServerEquipmentChanged

Fired on the server after any equip or unequip has been applied to this controller, from whichever path applied it. The persistence layer is the intended subscriber.

public event Action<IEquipmentController, EquipmentChange> OnServerEquipmentChanged

Event Type

Action<IEquipmentController, EquipmentChange>