Table of Contents

Class AbilityObject

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Represents a spawned ability object in the world, handling its lifetime, collision, and event triggers.

public class AbilityObject : MonoBehaviour
Inheritance
Object
Component
Behaviour
MonoBehaviour
AbilityObject
Inherited Members
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.ToString()
Object.name
Object.hideFlags

Fields

Ability

The ability instance this object represents.

public Ability Ability

Field Value

Ability

CachedRigidBody

Cached reference to the object's Rigidbody, if present.

public Rigidbody CachedRigidBody

Field Value

Rigidbody

Caster

The character who cast or owns this ability object. May be a live IPlayerCharacter during normal play, or a SnapshotCharacter phantom after the caster disconnects.

public ICharacter Caster

Field Value

ICharacter

ElapsedTicks

Ticks this object has simulated since spawn. Advanced in FishMMO.Shared.AbilityObject.OnTick() before tick events dispatch, so the first tick's events see a value of 1.

public uint ElapsedTicks

Field Value

uint

HitCount

Number of hits this object can perform before being destroyed.

public int HitCount

Field Value

int

OnPetSummon

Event invoked when a pet ability is summoned.

public static Action<PetAbilityTemplate, IPlayerCharacter> OnPetSummon

Field Value

Action<PetAbilityTemplate, IPlayerCharacter>

PreRedirectElapsedTicks

Ticks this object simulated on legs BEFORE the current one. Zero until a FishMMO.Shared.AbilityObject.Redirect(UnityEngine.Quaternion) resets ElapsedTicks for a new leg.

public uint PreRedirectElapsedTicks

Field Value

uint

Remarks

Lifetime and trajectory age at different clocks once an object has been redirected: the closed-form pose reads the CURRENT leg's ElapsedTicks, but RemainingLifeTime has been running since the original spawn. The spawn payload's in-flight block anchors its fast-forward to the current leg (that is what reproduces the pose), so without this counter a late joiner rebuilt a redirected object with its FULL lifetime less only the current leg — the copy outlived the server's by however long the object flew before the turn, then played its authored OnDestroy effects at a place and time where nothing happened. The payload sends this so the receiver can charge the earlier legs against lifetime too; see ConsumeLifetime(uint).

RNG

Random number generator for ability effects.

public DeterministicRNG RNG

Field Value

DeterministicRNG

Remarks

Shared by every action in this object's event chains, and advanced by side effect — so a draw that happens on one peer and not another desynchronises everything drawn after it. The generator is threaded onto the OnSpawn, OnTick, OnHit and OnDestroy payloads, and RandomRangeValue / RandomRangeFloatValue consume it through EventData.RNG. Its state is carried in the reconcile, which keeps the server and the caster's owner aligned; an observer has no reconcile and stays aligned only by making the same draws in the same order.

The rule that follows: a value provider is evaluated BEFORE any peer gate, never after. An action that draws behind EcaAuthority.MayPredict, an IsServer test or FishMMO.Shared.AbilityObject.ResolvesHitsLocally advances this generator only on the peers that pass — and an ungated action later in the same chain (AbilityForkHitAction) then reads a different number. That put an observer's copy of a forking projectile on a heading the server never took, permanently, from its first hit. Evaluate the provider, then gate on what to DO with it. This is the same rule ResolveTargetAndSpawn already follows when it advances the seed during a replay whose spawn it deliberately skips.

RemainingLifeTime

Remaining lifetime in seconds before the object is destroyed.

public float RemainingLifeTime

Field Value

float

Snapshot

Immutable snapshot of the ability data captured at spawn time. Used as a fallback when the live Ability reference becomes null (e.g., after the owning character disconnects and the ability is detached).

public AbilityObjectSnapshot Snapshot

Field Value

AbilityObjectSnapshot

SpawnPosition

World position this object was spawned at.

public Vector3 SpawnPosition

Field Value

Vector3

Remarks

Recorded so trajectories can be evaluated as a closed form — SpawnPosition + SpawnRotation * direction * speed * elapsed — instead of accumulating position += per tick. Accumulation is exactly reproducible only while every peer takes the identical number of steps; the closed form is reproducible from the spawn tuple alone, which is what an observer that reconstructs the object from a broadcast actually holds. See AbilityMoveTransformAction.

SpawnRotation

World rotation this object was spawned with. See SpawnPosition.

public Quaternion SpawnRotation

Field Value

Quaternion

SpawnTick

The network tick at which this ability object was spawned, expressed as a PredictionTick sourced from the replicate input. Used by the rollback system to identify predicted objects that need to be destroyed on reconcile mismatch.

public PredictionTick SpawnTick

Field Value

PredictionTick

Properties

GameObject

Cached reference to the object's GameObject.

public GameObject GameObject { get; }

Property Value

GameObject

IsServer

True when this ability object is simulating on the server. Gameplay effects (damage, healing, buffs, area queries) are only applied where this is true.

public bool IsServer { get; }

Property Value

bool

OnHitEvents

OnHit events for collision dispatching. Prefers the live Ability, falls back to the Snapshot. Returns IReadOnlyDictionary<TKey, TValue> to prevent mutation through consumer code.

public IReadOnlyDictionary<int, AbilityOnHitEvent> OnHitEvents { get; }

Property Value

IReadOnlyDictionary<int, AbilityOnHitEvent>

Speed

Movement speed. Prefers the live Ability, falls back to the Snapshot.

public float Speed { get; }

Property Value

float

TotalLifeTime

Total configured lifetime. Prefers the live Ability, falls back to the Snapshot.

public float TotalLifeTime { get; }

Property Value

float

Transform

Cached reference to the object's Transform.

public Transform Transform { get; }

Property Value

Transform

Methods

ConsumeLifetime(uint)

Charges ticks against this object's lifetime WITHOUT advancing its trajectory clock.

public void ConsumeLifetime(uint ticks)

Parameters

ticks uint

Lifetime ticks consumed on legs this client is not reproducing.

Remarks

For a streamed object that was redirected before this client saw it: the in-flight payload anchors FastForward(uint) to the current leg so the pose lands where the server holds it, and this separately charges the legs flown before the turn — see PreRedirectElapsedTicks. Expiry here destroys quietly for the same reason FastForward's does: an object this far through its life may already be gone on the server, and its destroy effects have played there.

FastForward(uint)

Advances this object's simulation clock without running per-tick events, so an observer that learns about a spawn late can place the object where the server has it.

public void FastForward(uint ticks)

Parameters

ticks uint

Ticks the server has already simulated for this object.

Remarks

The closed-form trajectory (AbilityMoveTransformAction) reads ElapsedTicks, so bumping the counter is enough to move the object on its next tick; the lifetime is advanced by the same amount so the object still expires on the server's schedule. An object fast-forwarded past its lifetime is destroyed quietly — it no longer exists on the server, so its destroy effects have already played.

Per-tick ECA events are deliberately NOT replayed for the skipped ticks. Catching up a second of a channelled flame would fire a second of its OnTick chain in one frame: a stack of particle systems at every position the object passed through, and, for any authored tick action with a peer-visible effect, that effect repeated as many times as the message was late. What the observer owes is the object's POSE — where the server holds it now — and advancing the counter is the whole of that debt. The ticks it did not run are ticks whose visuals happened before this peer was watching.

ResolveSpawnPose(ICharacter, Ability, Transform, TargetInfo, Vector3, Vector3)

Resolves the world pose an ability object spawns with, from the spawn target type. Resolves motor position from KCC for PCs or transform for NPCs.

public static AbilitySpawnPose ResolveSpawnPose(ICharacter caster, Ability ability, Transform abilitySpawner, TargetInfo targetInfo, Vector3 aimOrigin, Vector3 aimDirection)

Parameters

caster ICharacter

The character casting the ability.

ability Ability

The ability being spawned.

abilitySpawner Transform

The transform acting as the spawn origin.

targetInfo TargetInfo

The targeting information.

aimOrigin Vector3

Aim origin replicated for the tick being simulated.

aimDirection Vector3

Aim direction replicated for the tick being simulated.

Returns

AbilitySpawnPose

Remarks

Run only where the caster's pose is authoritative or predicted — server and owner. Observers receive the result in AbilityActivatedBroadcast; see AbilitySpawnPose for why they must not call this themselves.

SetAbilitySpawnPosition(ICharacter, Ability, Transform, TargetInfo, Vector3, Vector3, Transform)

Positions and rotates the ability object transform based on the spawn target type. See ResolveSpawnPose(ICharacter, Ability, Transform, TargetInfo, Vector3, Vector3).

public static void SetAbilitySpawnPosition(ICharacter caster, Ability ability, Transform abilitySpawner, TargetInfo targetInfo, Vector3 aimOrigin, Vector3 aimDirection, Transform abilityTransform)

Parameters

caster ICharacter
ability Ability
abilitySpawner Transform
targetInfo TargetInfo
aimOrigin Vector3
aimDirection Vector3
abilityTransform Transform

Spawn(Ability, ICharacter, Transform, TargetInfo, Vector3, Vector3, int, PredictionTick, AbilitySpawnPose?)

Spawns an ability object for any character type (PC or NPC). Handles pet summons, self-targets, and projectile/area spawning. Pet abilities are only supported for player characters; NPCs silently ignore them.

public static AbilityObject Spawn(Ability ability, ICharacter caster, Transform abilitySpawner, TargetInfo targetInfo, Vector3 aimOrigin, Vector3 aimDirection, int seed, PredictionTick spawnTick, AbilitySpawnPose? pose = null)

Parameters

ability Ability

The ability to spawn.

caster ICharacter

The character casting the ability.

abilitySpawner Transform

The transform used as the spawn origin.

targetInfo TargetInfo

The targeting information for the ability.

aimOrigin Vector3
aimDirection Vector3
seed int

The deterministic RNG seed.

spawnTick PredictionTick

The replicate-input tick at which this object is being spawned, used for rollback. Must be sourced from GetPredictionTick() to preserve type-safe tick sourcing.

pose AbilitySpawnPose?

Pose to spawn at, when the caller already holds the authoritative one (an observer reproducing a broadcast). Null resolves it locally via ResolveSpawnPose(ICharacter, Ability, Transform, TargetInfo, Vector3, Vector3).

Returns

AbilityObject

The root object representing this spawn, or null when the ability spawns nothing (pet, self, no prefab, missing required target). When an identical spawn (same seed and tick) is already simulating, that existing object is returned and the new instance is discarded — see FishMMO.Shared.AbilityContainerAllocator.

SpawnsWorldObject(AbilityTemplate)

True when Spawn(Ability, ICharacter, Transform, TargetInfo, Vector3, Vector3, int, PredictionTick, AbilitySpawnPose?) would create a world object for this template — i.e. there is something for an observer to reproduce.

public static bool SpawnsWorldObject(AbilityTemplate template)

Parameters

template AbilityTemplate

Returns

bool

Remarks

Pet and self-target abilities create nothing for an observer to reproduce, so an activation broadcast for them would be received, decoded and discarded for nothing. Their effects reach an observer through the ordinary state paths instead (buff and resource broadcasts, pet spawns). Note this is about what an OBSERVER must be told; the caster's own client does dispatch a self-target ability's effects locally, for feedback.

TryResolveFrom(EventData, out AbilityObject)

Pulls the ability object out of whichever event shape an action was wired to.

public static bool TryResolveFrom(EventData eventData, out AbilityObject abilityObject)

Parameters

eventData EventData

The event the action was invoked with. Null yields false.

abilityObject AbilityObject

The resolved object, or null.

Returns

bool

True when an ability object was found on any of the three payloads.

Remarks

The three ability event payloads carry the object on three different fields, and an action that resolves hits is meaningful on all of them: OnSpawn for a blast that goes off where it appears, OnTick for a lingering field, OnHit for a second effect fired from wherever the first one landed.

Shared because the actions disagreed. AbilityApplyHitscanAction resolved all three; AbilityApplyAreaAction tested only AbilityCollisionEventData and so silently did nothing on OnSpawn or OnTick — which is exactly the failure a previous fix to that action believed it had removed, having corrected the peer gate while leaving the payload gate in place. One implementation is what stops the two drifting apart again.

The collision payload is tried first: an action wired to OnHit is asking about the object that produced THAT hit, and a fork or a chain can carry a spawn payload alongside it describing a different object.