Table of Contents

Class Buff

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Represents a single instance of a buff applied to a character, tracking time, stacks, and template. All state is deterministic — timing is tick-based (ExpiryTick, NextTickTick) rather than float-second accumulators, eliminating floating-point drift across prediction ticks.

public class Buff
Inheritance
Buff
Inherited Members

Constructors

Buff(int, uint, float, int, int)

Creates a new buff instance from a fresh application. ExpiryTick and NextTickTick are computed from the template's duration and tick-rate via ceil(seconds / tickDelta), matching CooldownInstance's convention.

public Buff(int templateID, uint currentTick, float tickDelta, int stacks = 0, int tickCount = 0)

Parameters

templateID int

The template ID for the buff.

currentTick uint

The network tick at the moment of application.

tickDelta float

Fixed seconds-per-tick for the active session.

stacks int

The initial stack count.

tickCount int

The number of ticks that have already fired (for restoration).

Buff(int, uint, uint, float, int, int)

Restores a buff from serialized absolute-tick values (reconcile / payload restore). Does not recompute tick values from the template — uses the provided values directly.

public Buff(int templateID, uint expiryTick, uint nextTickTick, float tickDelta, int stacks, int tickCount)

Parameters

templateID int

The template ID for the buff.

expiryTick uint

Absolute tick at which the buff expires.

nextTickTick uint

Absolute tick at which the next OnTick fires.

tickDelta float

Fixed seconds-per-tick (for RemainingSeconds(uint) UI conversion).

stacks int

The current stack count.

tickCount int

The number of ticks that have already fired.

Fields

CumulativeTickMultiplier

Running sum of (1 + Stacks) for every tick that has fired on this buff instance. Tracks the exact cumulative multiplier applied by templates such as AttributeTickBuffTemplate so that OnRemove can reverse the precise total modifier regardless of how many times Stacks changed between tick firings. Reconciled via CumulativeTickMultiplier so rollback replay and post-reconcile removal both produce correct reversal.

public int CumulativeTickMultiplier

Field Value

int

ExpiryTick

The absolute network tick at which this buff expires. A buff has expired when (int)(currentTick - ExpiryTick) >= 0. Permanent buffs use FishNet.Managing.Timing.TimeManager.UNSET_TICK.

public uint ExpiryTick

Field Value

uint

NextTickTick

The absolute network tick at which the next OnTick(Buff, ICharacter) should fire. Advances by one tick-rate interval after each fire so missed intervals catch up without drifting the cadence to the late current tick.

public uint NextTickTick

Field Value

uint

Stacks

The current number of stacks of this buff.

public int Stacks

Field Value

int

TickCount

The number of ticks that have fired for this buff instance. Used by cumulative tick templates to track total applied modifiers for clean reversal. Serialized in payload for deterministic restoration.

public int TickCount

Field Value

int

Version

Version number for this buff instance, used for database state-driven safety on updates. Incremented whenever the buff's state changes in a way that requires persistence (e.g., stacks added/removed, remaining time checkpointed).

public long Version

Field Value

long

Properties

Caster

The character to credit for this buff's periodic effects, or null when there is nobody left to credit.

public ICharacter Caster { get; }

Property Value

ICharacter

Remarks

Returns null once the caster has been destroyed — a player who disconnected, an NPC that despawned. That is deliberately not treated as a reason to stop ticking: a lingering poison is part of the simulation whether or not the person who applied it is still in the scene, so the effect lands with a null attacker and simply generates no threat and no kill credit.

The null check goes through UnityEngine.Object on purpose. A destroyed component compared through an interface reference uses reference equality and reports itself as non-null, so the plain test would hand out a dead object.

IsAuthoritative

True while the tick currently executing on this buff runs on the authoritative simulation (the server). False on every client, replayed or not.

public bool IsAuthoritative { get; }

Property Value

bool

Remarks

With state forwarding off, only the owning client (prediction) and the server tick a buff. The owner's tick keeps predicted health responsive, but everything that is not a pure resource mutation — ECA tick triggers, threat, kill credit, achievements — must happen exactly once, on the server. IsReplaying alone cannot express that: the owner's first, non-replayed pass is still not authoritative. Set by TryTick(ICharacter, uint, float, bool, bool) from the value the controller passes.

IsReplaying

True while this buff is ticking inside a prediction replay rather than for the first time.

public bool IsReplaying { get; }

Property Value

bool

Remarks

Reconcile replays every input since the last authoritative state, so a DoT's tick fires again on each pass. The resource mutation must repeat — that is what keeps the client's predicted health in step — but the ECA triggers hanging off it must not, or a single tick of poison counts a dozen times toward an achievement.

Template

The template that defines this buff's behavior and properties.

public BaseBuffTemplate Template { get; }

Property Value

BaseBuffTemplate

Methods

AddStack(ICharacter)

Adds a stack to the buff and applies stack effects to the target.

public void AddStack(ICharacter target)

Parameters

target ICharacter

The character receiving the stack.

Apply(ICharacter)

Applies the buff's effects to the target character.

public void Apply(ICharacter target)

Parameters

target ICharacter

The character receiving the buff.

HasExpired(uint)

Returns true when this buff has expired at the given tick. Uses a signed cast for overflow-safe wrap-around comparison; safe for any duration < 2^31 ticks (~828 days at 30 tps).

public bool HasExpired(uint currentTick)

Parameters

currentTick uint

Returns

bool

RemainingSeconds(uint)

Computes the remaining buff duration in seconds for the given tick. Returns zero if the buff has already expired. Used by the UI duration slider.

public float RemainingSeconds(uint currentTick)

Parameters

currentTick uint

Returns

float

Remove(ICharacter)

Removes the buff's effects from the target character.

public void Remove(ICharacter target)

Parameters

target ICharacter

The character losing the buff.

RemoveStack(ICharacter)

Removes a stack from the buff and removes stack effects from the target.

public void RemoveStack(ICharacter target)

Parameters

target ICharacter

The character losing the stack.

ResetDuration(uint, float)

Resets the expiry to currentTick + durationTicks, refreshing the buff's lifetime.

public void ResetDuration(uint currentTick, float tickDelta)

Parameters

currentTick uint
tickDelta float

ResetTickTime(uint, float)

Resets NextTickTick to currentTick + tickRateTicks.

public void ResetTickTime(uint currentTick, float tickDelta)

Parameters

currentTick uint
tickDelta float

SetCaster(ICharacter)

Snapshots the character responsible for this buff.

public void SetCaster(ICharacter caster)

Parameters

caster ICharacter

The character applying the buff, or null if unknown.

Remarks

Called again when an existing buff is re-applied or stacked, so a fresh application re-points attribution at whoever cast it most recently. A null is ignored rather than clearing an existing caster: a re-application from a source that does not know its initiator (a region trigger, a database restore) should not strip credit from one that did.

SetTickDelta(float)

Updates the cached tick-delta used by RemainingSeconds(uint). Called by Tick(uint) every tick so UI duration bars never get stuck reporting 0 when a buff was constructed before TimeManager became available. Ignores non-positive values to preserve the last good delta.

public void SetTickDelta(float tickDelta)

Parameters

tickDelta float

TryTick(ICharacter, uint, float, bool, bool)

Tries to trigger a tick for the buff if NextTickTick has been reached, then advances NextTickTick by the template tick-rate in ticks.

public bool TryTick(ICharacter target, uint currentTick, float tickDelta, bool isReplaying = false, bool isAuthoritative = true)

Parameters

target ICharacter

The character affected by the buff.

currentTick uint

The current network tick.

tickDelta float

Fixed seconds-per-tick of the active session.

isReplaying bool

True when this tick is part of a prediction replay. Exposed to templates via IsReplaying so effects that raise events can suppress them.

isAuthoritative bool

True when the caller is the server. Exposed to templates via IsAuthoritative so ECA triggers and other non-idempotent side effects run on the server only. Defaults to true for direct callers; Tick(uint) always passes its own server state explicitly.

Returns

bool

True if tick state changed (snapshot must be marked dirty).