Class AbilityObject
Represents a spawned ability object in the world, handling its lifetime, collision, and event triggers.
public class AbilityObject : MonoBehaviour
- Inheritance
-
ObjectComponentBehaviourMonoBehaviourAbilityObject
- Inherited Members
-
MonoBehaviour.IsInvoking()MonoBehaviour.CancelInvoke()MonoBehaviour.StopCoroutine(Coroutine)MonoBehaviour.StopAllCoroutines()MonoBehaviour.destroyCancellationTokenMonoBehaviour.useGUILayoutMonoBehaviour.didStartMonoBehaviour.didAwakeMonoBehaviour.runInEditModeBehaviour.enabledBehaviour.isActiveAndEnabledComponent.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.transformComponent.transformHandleComponent.gameObjectComponent.tagObject.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.nameObject.hideFlags
Fields
Ability
The ability instance this object represents.
public Ability Ability
Field Value
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
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
HitCount
Number of hits this object can perform before being destroyed.
public int HitCount
Field Value
OnPetSummon
Event invoked when a pet ability is summoned.
public static Action<PetAbilityTemplate, IPlayerCharacter> OnPetSummon
Field Value
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
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
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
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
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
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
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
Speed
Movement speed. Prefers the live Ability, falls back to the Snapshot.
public float Speed { get; }
Property Value
TotalLifeTime
Total configured lifetime. Prefers the live Ability, falls back to the Snapshot.
public float TotalLifeTime { get; }
Property Value
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
ticksuintLifetime 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
ticksuintTicks 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
casterICharacterThe character casting the ability.
abilityAbilityThe ability being spawned.
abilitySpawnerTransformThe transform acting as the spawn origin.
targetInfoTargetInfoThe targeting information.
aimOriginVector3Aim origin replicated for the tick being simulated.
aimDirectionVector3Aim direction replicated for the tick being simulated.
Returns
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
casterICharacterabilityAbilityabilitySpawnerTransformtargetInfoTargetInfoaimOriginVector3aimDirectionVector3abilityTransformTransform
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
abilityAbilityThe ability to spawn.
casterICharacterThe character casting the ability.
abilitySpawnerTransformThe transform used as the spawn origin.
targetInfoTargetInfoThe targeting information for the ability.
aimOriginVector3aimDirectionVector3seedintThe deterministic RNG seed.
spawnTickPredictionTickThe replicate-input tick at which this object is being spawned, used for rollback. Must be sourced from GetPredictionTick() to preserve type-safe tick sourcing.
poseAbilitySpawnPose?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
templateAbilityTemplate
Returns
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
eventDataEventDataThe event the action was invoked with. Null yields false.
abilityObjectAbilityObjectThe 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.