Skip to content

dlqw/numerickit-wf-unity

Repository files navigation

Numeric System

HuaYe Studio rdququ

Static Badge Static Badge Static Badge Static Badge

Introduction

The Numeric System is a powerful and flexible toolset designed to address the numerical needs of gameplay, aiming to provide a simple and efficient solution for handling combat system calculations.

  • Event Store-based Numeric Change Tracking: Ensures traceability, easy self-verification, and security of original data.
  • Fixed-point Arithmetic: Guarantees numerical consistency across platforms and devices, enhancing network synchronization reliability.
  • Simple Syntax: Supports the addition of integers, floating points, fractions, or percentages to numerical values using addition, multiplication, or custom modifiers.
  • Extensible Architecture: Support for custom modifiers, conditional modifiers, and modifier priorities.
  • Thread-Safe Operations: Optional thread-safe wrapper for multi-threaded scenarios.
  • Serialization Support: Built-in support for modifier serialization/deserialization.

Changelog

Version 1.2.0 - Advanced Features and Performance (2025-02-03)

This major release adds advanced features while maintaining 100% backward compatibility:

New Features:

  • Modifier Priority System - Control modifier application order with fine-grained priorities
  • Conditional Modifiers - Apply modifiers based on dynamic conditions using predicate conditions
  • Serialization Support - Serialize and deserialize modifiers for save/load functionality
  • Thread-Safe Wrapper - Thread-safe Numeric operations for multi-threaded environments
  • Performance Benchmarks - Comprehensive benchmark suite using BenchmarkDotNet
  • Diagnostic Tools - Enhanced debugging and diagnostic capabilities
  • Fluent API - Rich extension methods and builder patterns for better developer experience

Improvements:

  • 🚀 Increased test coverage from 117 to 129 tests (100% pass rate)
  • 🚀 Enhanced error messages and validation
  • 🚀 Improved caching mechanism
  • 🚀 Better performance for modifier queries

Documentation:

  • 📚 Complete XML documentation coverage
  • 📚 Performance benchmark documentation
  • 📚 Architecture refactoring plan

For detailed information, see changelogs/1.2.0.md

Version 1.1.0 - Logic Fixes and Security Enhancements (2025-02-03)

  • Fixed Division by Zero: Added validation in FractionNumericModifier constructor
  • Fixed Multi-Fraction Modifier Bug: Redesigned the Apply method
  • Added Overflow Protection: Prevented silent value corruption
  • Improved CustomNumericModifier Safety: Enhanced null checking

For detailed information, see changelogs/1.1.0_CN.md

Table of Contents

Download and Deployment

Get from GitHub

git clone git@github.com:dlqw/NumericSystem.git

Get from npm

npm i numericsystem

Getting Started

Creating the First Numeric

To use the tool, you need to reference WFramework.CoreGameDevKit.NumericSystem;

using WFramework.CoreGameDevKit.NumericSystem;

You can manually create a Numeric object and pass an integer or floating point number to its constructor.

Numeric health = new Numeric(100);

This value (100 in the example above) acts as the base value of the Numeric object and is read-only. You can retrieve its value using GetOriginValue(). To change this base value, create a new Numeric object.

// Get original/base value
var healthBasicValue = health.GetOriginValue();

// Change the base value => Create a new Numeric object
health = new Numeric(200);

Alternatively, you can assign an integer or floating-point number to a Numeric object to create a new one.

Numeric health = 100;
Debug.Log(health.GetHashCode()); // 402183648

health = 100.67f;
Debug.Log(health.GetHashCode()); // 1146914344

Attaching Modifiers

Addition Modifiers

You can use operators or explicit methods:

// Using operators (recommended)
health += 20;
health -= 10;

// Using explicit methods
health.AddModifier(new AdditionNumericModifier(20));
health.RemoveModifier(new AdditionNumericModifier(10));

Multiplication Modifiers

// Percentage increase
health *= (150, FractionType.Increase);  // +50%

// Percentage override
health *= (200, FractionType.Override);  // ×2.0

// Remove modifiers
health /= (150, FractionType.Increase);

Getting the Final Value

Numeric health = 100;
health += 20.3f;

Debug.Log(health.FinalValue);   // 120 (int)
Debug.Log(health.FinalValueF); // 120.3f (float)

Using Modifiers with Tags and Names

// Create named modifier with tags
health += (20, new[] { "Equipment" }, "Armor", 1);
health *= (120, FractionType.Override, new[] { "Equipment" }, "ArmorUpgrade", 1);
health *= (50, FractionType.Increase, new[] { "Buff" }, "StrengthBoost", 1);

Using Custom Modifiers

Custom modifiers are invoked at the end of the calculation pipeline and can enforce specific constraints.

Numeric health = 100;

// Clamp health between 0 and 150
health.ClampMax(150, "MaxHealthCap");
health.ClampMin(0, "MinHealthCap");

// Or use custom function
Func<int, int> healthLimit = value => Mathf.Clamp(value, 0, 150);
health.AddModifier(new CustomNumericModifier(healthLimit));

Advanced Features

Modifier Priority System

Control the order in which modifiers are applied using priorities:

var health = new Numeric(100);

// Add modifiers with different priorities
health += (50, new[] { "Base" }, "RaceBonus", 1, ModifierPriority.Base);      // 100
health += (30, new[] { "Base" }, "ClassBonus", 1, ModifierPriority.Base);     // 100
health += (50, new[] { "Equipment" }, "Armor", 1, ModifierPriority.Equipment); // 200
health += (30, new[] { "Buff" }, "Strength", 1, ModifierPriority.Buff);       // 300
health *= (50, FractionType.Increase, Array.Empty<string>(), "Multiplier", 1, ModifierPriority.Multiplier); // 500

// Application order: Base → Equipment → Buff → Multiplier

Priority Levels:

  • Critical (0) - Highest priority
  • Base (100) - Base attributes
  • Equipment (200) - Equipment modifiers
  • Buff (300) - Buff/Debuff effects
  • Skill (400) - Skill bonuses
  • Default (400) - Default priority
  • Multiplier (500) - Percentage modifiers
  • Clamp (600) - Constraint modifiers

Conditional Modifiers

Apply modifiers based on dynamic conditions:

var health = new Numeric(100);

// Condition: Health below 30%
var lowHpCondition = ConditionBuilder.Where(h => h.FinalValue < 30);
var emergencyShield = ConditionalNumericModifier.ConditionalAdd(
    lowHpCondition,
    50,
    "EmergencyShield"
);
health.AddModifier(emergencyShield);

// Complex conditions with AND/OR/NOT
var complexCondition = ConditionBuilder
    .Where(h => h.FinalValue < 50)
    .And(h => h.GetAddModifierValueByTag(new[] { "Buff" }) < 1000000)
    .Build();

health.AddConditionalModifier(
    complexCondition,
    new AdditionNumericModifier(30, Array.Empty<string>(), "ComplexBonus")
);

Serialization

Save and load modifier states:

var health = new Numeric(100);
health += 50;
health *= (150, FractionType.Increase);

// Serialize
var data = health.Serialize();

// Deserialize
var restored = data.Deserialize();
Assert.Equal(health.FinalValue, restored.FinalValue);

Supported Modifiers:

  • AdditionNumericModifier
  • FractionNumericModifier
  • ⚠️ CustomNumericModifier (contains delegates)
  • ⚠️ ConditionalNumericModifier (contains delegates)

Thread-Safe Operations

For multi-threaded scenarios, use ThreadSafeNumeric:

var safeHealth = new ThreadSafeNumeric(100);

// Thread-safe operations
safeHealth += 50;
safeHealth.AddModifier(new FractionNumericModifier(150, FractionType.Increase));

// Thread-safe read
var value = safeHealth.FinalValue;

// Thread-safe operations with callbacks
safeHealth.Read(numeric =>
{
    Debug.Log($"Health: {numeric.FinalValue}");
    Debug.Log($"Modifiers: {numeric.GetAllModifiers().Count}");
});

safeHealth.Write(numeric =>
{
    numeric += 20;
});

Performance Benchmarks

Run benchmarks to measure performance:

cd src
dotnet run -c Release --project NumericSystem.Tests -- --filter *NumericBenchmarks*

Benchmark categories:

  • Basic - Creation, modification, calculation
  • Scalability - Large modifier counts (10, 100, 1000)
  • Complex - Real-world scenarios
  • Fraction - Fraction modifier performance
  • Query - Lookup operations

See src/NumericSystem.Tests/Benchmarks/README.md for details.

API Reference

Fluent API

// Builder pattern
var health = Numeric.Build(100, builder =>
{
    builder.AddEquipment(50, "Armor");
    builder.AddBuff(30, "Strength");
    builder.BoostBase(150, "BaseBoost");
    builder.WithMaxLimit(500, "MaxHP");
});

// Extension methods
health.AddEquipment(20, "Helmet");
health.AddBuff(10, "Potion");
health.ClampMax(300);

// Conditional extensions
health.AddIf(h => h.FinalValue < 100, 50, "EmergencyHeal");
health.MultiplyIf(
    ConditionBuilder.Where(h => h.FinalValue > 200).Build(),
    150,
    FractionType.Increase
);

Diagnostic Tools

var health = new Numeric(100);
health += 50;
health *= (150, FractionType.Increase);

// Get modifier statistics
var stats = health.GetModifierStats();
foreach (var stat in stats)
{
    Debug.Log($"{stat.Key}: {stat.Value}");
}

// Dump detailed information
health.Dump("Player Health");

// Check cache status
Debug.Log(health.GetCacheStatus());

File Path Description

NumericSystem
├── .gitignore
├── README.md
├── README_CN.md
├── CHANGELOG.md
├── ARCHITECTURE_REFACTORING_PLAN.md
├── package.json
├── src
│   └── NumericSystem
│       ├── Core/                          # Core abstractions
│       ├── Chain/                         # Responsibility chain pattern
│       ├── Serialization/                 # Serialization support
│       ├── FixedPoint.cs
│       ├── Numeric.cs
│       ├── NumericModifier*.cs            # Modifier implementations
│       ├── NumericExtensions.cs           # Extension methods
│       ├── ThreadSafeNumeric.cs           # Thread-safe wrapper
│       └── DiagnosticHelper.cs            # Diagnostic tools
│   └── NumericSystem.Tests
│       ├── Benchmarks/                    # Performance benchmarks
│       ├── *Tests.cs                      # Unit tests
└── LICENSE

Testing

The project includes comprehensive unit tests:

cd src
dotnet test

Test Coverage:

  • 129 tests (100% pass rate)
  • All major features covered
  • Edge cases and error handling

License

This project is released under the MIT License

About

A flexible, generalized numerical system for computing game values.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages