Class PredictedCombatEvents
Tracks combat numbers a client has drawn from its OWN predicted hits, and reconciles them against the server's combat report.
public static class PredictedCombatEvents
- Inheritance
-
PredictedCombatEvents
- Inherited Members
Remarks
Why the client draws first. Damage numbers used to come only from
CombatEventBroadcast, so a player's own hit showed nothing until the report came back
— half a round trip of nothing happening, on the one action combat is built around. The
caster predicted the cast and owns the input that produced it, so it can draw the number the
moment its predicted projectile connects.
Why the amounts agree. Damage variance is drawn from the ability object's
DeterministicRNG (RandomRangeValue reads EventData.RNG), whose state is
carried in the reconcile and corrected every tick. Client and server draw the same number
from the same state. A hit-count divergence advances the two generators differently until
the next reconcile realigns them, so a mismatch is possible, bounded, and self-healing —
which is why TryConfirm(ICharacter, ICharacter, Kind, int) matches on source, target and kind rather than on the
amount.
Why there is no server-sent rejection. The server cannot tell a client "that hit did not land", because it never knew the client predicted one — it simply resolves its own simulation and reports what happened. Absence is the only signal available, so a prediction that goes unconfirmed for ConfirmationWindowSeconds is treated as rejected. That costs no bandwidth and needs no new message.
Pure bookkeeping with no Unity or rendering dependency, so the policy is unit tested. The client's display layer subscribes to the events below; nothing here draws anything.
Properties
ConfirmationWindowSeconds
How long a predicted number waits for the server to confirm it before being treated as rejected.
public static float ConfirmationWindowSeconds { get; set; }
Property Value
Remarks
Must comfortably exceed a round trip plus the server's report cadence (combat events flush every tick, so the cadence term is one tick). Too short invalidates good hits on a laggy connection — far worse than the occasional wrong number lingering, because it makes a working hit look broken.
PendingCount
Predicted entries still waiting on the server.
public static int PendingCount { get; }
Property Value
Methods
Clear()
Drops every pending prediction without raising rejections.
public static void Clear()
Remarks
For a scene change or disconnect, where the numbers and the characters they were drawn over are both gone. Raising rejections here would ask the display to grey out labels that no longer exist.
Predict(ICharacter, ICharacter, int, Kind, DamageAttributeTemplate, float)
Records and announces a number this client predicted.
public static void Predict(ICharacter source, ICharacter target, int amount, PredictedCombatEvents.Kind kind, DamageAttributeTemplate damageAttribute, float now)
Parameters
sourceICharacterThe character that dealt it — this client's own, since only an owner predicts.
targetICharacterThe character the number belongs to.
amountintThe predicted amount.
kindPredictedCombatEvents.KindDamage or heal.
damageAttributeDamageAttributeTemplateDamage type, for colouring. Null for heals and typeless damage.
nowfloatCurrent unscaled time, in seconds.
Sweep(float)
Rejects predictions the server never confirmed. Call once per frame or tick.
public static void Sweep(float now)
Parameters
nowfloatCurrent unscaled time, in seconds.
TryConfirm(ICharacter, ICharacter, Kind, int)
Consumes a pending prediction matching an arriving server report.
public static bool TryConfirm(ICharacter source, ICharacter target, PredictedCombatEvents.Kind kind, int occurrences = 1)
Parameters
sourceICharacterThe attacker named by the report. A report with none matches nothing.
targetICharacterThe character named by the report.
kindPredictedCombatEvents.KindDamage or heal.
occurrencesintHow many separate hits the report's amount was merged from —
CombatEventBroadcast.Occurrences. That many pending predictions are settled, because the caster drew one label per hit while the server sent one message for all of them. Values below one are treated as one.
Returns
- bool
True when this report was already drawn as a prediction.
Remarks
Matched on SOURCE, target and kind, oldest first. The source is what makes this a pairing rather than a guess: a combat report is broadcast to everyone observing the victim, so with source ignored any other player's hit on the same target consumed this client's pending entry. Two players on one mob was enough — the other player's real number was swallowed (the caller draws nothing on a match) and this client's own report, arriving to find no pending entry left, was then drawn a second time.
Deliberately NOT matched on the amount. The two numbers agree whenever the RNG states agree, but a transient divergence would otherwise leave the prediction unmatched and produce the worst outcome available: the predicted number greyed out AND the server's number drawn beside it, for a hit that landed. Trusting the pairing and letting the amount differ is the lesser error.
The caller draws the server's number only when this returns false — that is, only when the report settled NOTHING. A report that settles some but not all of what it claims does not produce a second label: the numbers already on screen are the caster's own predictions of the same hits, and drawing the server's merged total beside them would show the damage twice.
Events
OnPredicted
Raised when this client predicts a combat number. The display draws it immediately.
public static event Action<long, ICharacter, int, PredictedCombatEvents.Kind, DamageAttributeTemplate> OnPredicted
Event Type
Remarks
The long is a handle the display keeps, so a later
OnPredictionRejected can name the number to grey out.
OnPredictionConfirmed
Raised when the server's report confirmed a predicted number. Nothing needs redrawing — the number on screen was already right — but the display holds a handle per prediction so it can grey one out later, and without this it would only ever release the handles for predictions that turned out WRONG. A session's worth of correct hits leaked one entry each.
public static event Action<long> OnPredictionConfirmed
Event Type
OnPredictionRejected
Raised when a predicted number went unconfirmed past the window. The display should mark it invalid rather than deleting it — a number that vanishes reads as a rendering glitch, one that greys out reads as "that did not land".
public static event Action<long> OnPredictionRejected