A Unity-friendly, game-agnostic buff & stat calculation library designed to support a wide range of gameplay systems.
BuffLibrary.Net provides a flexible and deterministic system for handling stat modifications (“buffs”) in games. It is built around a reactive core while still supporting on-demand evaluation, making it suitable for both client and server environments.
- Unified architecture supporting both reactive (event-based) and on-demand calculations
- Fully game-agnostic (no hardcoded stats, entities, or conditions)
- Scriptable condition system
e.g.self.stats.attack > 40 AND self.stats.defense >= 30 - Clean separation of features into logical components
- Compatible with:
- Unity (IL2CPP)
pythonnet- Deterministic frameworks (via 32-bit fixed-point math)
- Fully stateless calculations (external context-driven)
- Extensible and modular design
- Cross-platform support:
.NET Standard 2.1(Unity).NET Core(backend)
A Buffable is any entity that can receive buffs.
It consists of:
- A set of stats
- A set of modifiers applied to those stats
All stat calculations follow this formula:
sum(additives) * (1 + sum(multiplicatives)) + sum(finalAdditives)
- Additives: Flat increases (e.g.
+100 Attack) - Multiplicatives: Percentage-based modifiers (e.g.
+50% Attack) - Final Additives: Post-multiplication adjustments (used for “bracketing”)
+100 Attack
+50% Attack
+50% Attack
Result: 200 Attack
Derivation allows transforming one stat into another.
+100 Attack
+50% Attack → Defense
Result:
Attack: 100
Defense: 50
Propagation allows buffs applied to one entity to affect connected entities.
Source Entity:
+50 Attack to Target
Target A:
+100 Attack
Target B:
+200 Attack
Result:
Target A: 150 Attack
Target B: 250 Attack
Buffs can have a lifetime and automatically expire after a duration.
Example: Buff lasts 10 seconds
Triggers are the backbone of the system.
They represent events (e.g. “damage dealt”, “buff applied”) and provide contextual data.
A buff with a trigger remains inactive until the trigger condition is met.
+100% Attack
On Trigger: Entity mined resources
Buffs can be deactivated via:
- Conditions
- Other triggers
Conditions determine whether buffs activate or deactivate.
They can read from:
- Entity stats
- Entity contextual state
- Connected entities
- Trigger context
Stat-based condition
self.stats.attack > 50 AND self.stats.defense > 30
Context-based condition
self.isMining = true OR self.isDocked = true
Connected entity condition
connected.Base.hasShield = true
Conditions are expressed using a lightweight script-like language.
When combining propagation and derivation, designers can choose the source of values:
self→ the origin entitytarget→ the affected entityconnected→ related entities
Entity A:
HP: 100
ATK: 20
Entity B:
ATK: 10
Using self:
+50% self.ATK → HP (propagated)
Result: HP = 105
Using target:
+50% target.ATK → HP (propagated)
Result: HP = 110
Using connected entity:
Base:
BonusResources: 500
+50% connected.Base.BonusResources → HP
Result: HP = 350
- Ensures triggers and conditions only reference valid properties
- Defined by designers, enforced by the system
- Condition parser reports invalid or missing properties
- Stateless design enables easy comparison between client/server states
- Merge test-only methods (currently marked as TODO/Obsolete)
- Support partial stack removal (instead of removing entire buff)
- Full condition validation across specs
- Schema validation (allowed/required properties per entity/trigger)
- Cross-system deterministic serialization
(investigating MsgPack, Protobuf, FlatBuffers)
- Replace string identifiers with
ushortIDs:- Attributes
- Propagation types
- Trigger types
- Precompile condition handlers (server-side IL generation)
- Optimize propagation lookups using indexed entity types
This library intentionally avoids domain-specific concepts like “Ship” or “Starbase”.
Instead, it operates on generic entities and relationships, allowing it to be reused across different game genres and systems.