Skip to content

SunYanbox/GameAttr

Repository files navigation

GameAttr

License: MPL-2.0 .NET Commit Convention Tests Coverage

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 designAttr<TKey, TModId, TValue> supports any key type, modifier ID type, and numeric value type (INumber<T>).
  • Three modifier typesBaseValue, PercentBonus, FlatBonus cover 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 readsGetValue caches 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

<!-- Add from NuGet or reference the project directly -->
<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() and RemoveModifier(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 GetValue calls check the generation first; if unchanged, the cached value is returned without acquiring the write lock, minimizing contention in read-heavy scenarios.
  • Backed by ConcurrentDictionary for 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

About

GameAttr is a generic, decoupled C# game attribute library that computes final values using a classic RPG formula (`FinalValue = BaseValue × (1 + PercentBonus) + FlatBonus`) and is thread-safe, fully tested, and designed for easy integration into any C# game project.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors