GameAttr 0.2.0
dotnet add package GameAttr --version 0.2.0
NuGet\Install-Package GameAttr -Version 0.2.0
<PackageReference Include="GameAttr" Version="0.2.0" />
<PackageVersion Include="GameAttr" Version="0.2.0" />
<PackageReference Include="GameAttr" />
paket add GameAttr --version 0.2.0
#r "nuget: GameAttr, 0.2.0"
#:package GameAttr@0.2.0
#addin nuget:?package=GameAttr&version=0.2.0
#tool nuget:?package=GameAttr&version=0.2.0
GameAttr
A generic, decoupled game attribute library — computes attribute values using the formula
FinalValue = BaseValue × (1 + PercentBonus) + FlatBonus, a modifier model rooted in classic RPGs like Dungeons & Dragons and Diablo II. Thread-safe, fully tested, and designed for easy integration into any C# game project.
Features
- Generic by design —
Attr<TKey, TModId, TValue>supports any key type, modifier ID type, and numeric value type (INumber<T>). - Three modifier types —
BaseValue,PercentBonus,FlatBonuscover the full stack of base, percentage, and flat modifiers. - Thread-safe — per-key locking for concurrent modifier reads/writes, plus a global lock for batch operations.
- Cached reads —
GetValuecaches its result with a generation counter that auto-invalidates on writes; repeated reads of unchanged attributes cost near-zero contention. - Rich modifier removal — remove by
(key, type, modId),(key, modId)across all types, or(modId)globally. - Zero coupling — pure logic library with no dependency on any game engine or framework. Run tests in isolation.
- Fully documented — XML doc comments on all public APIs.
- 100% test coverage — MSTest suite covering base values, percent/flat bonuses, removal semantics, enum keys, overwrites, and edge cases.
Formula
FinalValue = BaseValue × (1 + PercentBonus) + FlatBonus
Where:
| Modifier | Meaning | Example |
|---|---|---|
BaseValue |
Sum of all base value modifiers | Initial ATK 1000 |
PercentBonus |
Sum of all percentage modifiers, applied additively | 0.3 → +30% |
FlatBonus |
Sum of all flat modifiers, added after percentage | +50 |
Example: if BaseValue = 1000, PercentBonus = 0.3, FlatBonus = 50:
FinalValue = 1000 × (1 + 0.3) + 50 = 1350
Quick Start
<PackageReference Include="GameAttr" Version="0.2.0" />
using GameAttr;
// Create an attribute container: string keys, string modifier IDs, float values
Attr<string, string, float> attr = new();
// Set base value
attr.SetModifier("atk", ModifierType.BaseValue, "base", 1000);
// Apply bonuses
attr.SetModifier("atk", ModifierType.PercentBonus, "buff1", 0.2); // +20%
attr.SetModifier("atk", ModifierType.PercentBonus, "buff2", 0.1); // +10%
attr.SetModifier("atk", ModifierType.FlatBonus, "flat", 50); // +50
// Get computed value
float final = attr.GetValue("atk"); // 1000 * (1 + 0.3) + 50 = 1350
// Remove a modifier
attr.RemoveModifier("atk", ModifierType.PercentBonus, "buff1");
API Overview
Attr<TKey, TModId, TValue>
| Method | Description |
|---|---|
SetModifier(key, type, modId, value) |
Set or overwrite a modifier |
GetValue(key) |
Get the computed attribute value (cached — re-reads only when modifiers change) |
RemoveModifier(key, type, modId) |
Remove a specific modifier |
RemoveModifier(key, modId) |
Remove a modifier by ID across all types for a key |
RemoveModifier(modId) |
Remove a modifier by ID globally across all keys |
RemoveAllModifiers(key) |
Remove all modifiers for a key |
Clear() |
Remove all modifiers |
ToString() |
JSON snapshot of all modifiers |
ModifierType
BaseValue— foundation of the attribute; all bonuses are applied on top of the sum of base values.PercentBonus— percentage of the base value (e.g.,0.1= +10%). Multiple percent bonuses stack additively.FlatBonus— flat value added after percentage calculation.
Thread Safety
- Per-key locking for
SetModifier,GetValue,RemoveModifier,RemoveAllModifiers— concurrent operations on different keys never block each other. - Global lock for
Clear()andRemoveModifier(modId)— ensures atomic cross-key operations. - GetValue caching — each read result is cached alongside a generation counter that increments on every write to the same key. Subsequent
GetValuecalls check the generation first; if unchanged, the cached value is returned without acquiring the write lock, minimizing contention in read-heavy scenarios. - Backed by
ConcurrentDictionaryfor lock-free reads where possible.
Running Tests & Coverage
Prerequisites:
dotnet add package coverlet.collector
dotnet tool install --global dotnet-reportgenerator-globaltool
On Windows, run the convenience script:
cd GameAttr.Tests
.\run-coverage.cmd
This runs tests with coverage collection, generates an HTML report via ReportGenerator, and opens it in your browser.
Or manually:
dotnet test GameAttr.Tests/GameAttr.Tests.csproj --collect:"XPlat Code Coverage"
License
Mozilla Public License 2.0 © Suntion
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.