Dice Roller Pro is a comprehensive Unity-based dice rolling library that provides powerful parsing capabilities for standard dice notation and supports both runtime parsing and Unity Editor asset creation workflows. The library excels at parsing complex dice expressions like “3d6+2”, “4d8!”, and “{2d6,1d8}kh2” while offering advanced mechanics including exploding dice, modifier systems, and mathematical operations.
Key Features:
- Comprehensive Dice Notation Parser – Supports standard and extended dice notation with full mathematical expressions
- ScriptableObject Integration – Create dice configurations as Unity assets with full Inspector support
- Advanced Dice Mechanics – Exploding, compound, and penetrating dice with keep/drop modifiers
- High Performance – Thread-safe design with memory pooling, caching, and optimized algorithms
- Validation Framework – Built-in validation for dice expressions and configurations
- Unity Editor Tools – Asset creation menus and Inspector validation support
- Extensible Architecture – Easy to extend with new dice types and mechanics
Core Architecture
ScriptableObject-Based Design
All dice types inherit from BaseRoll (ScriptableObject), enabling:
- Unity Asset Integration: Create dice configurations as
.assetfiles - Inspector Support: Visual configuration and assignment to GameObjects
- Persistent Storage: Save and load dice configurations across sessions
- Modular Design: Mix and match different dice types in complex expressions
Dice Types:
NormalDice– Standard polyhedral dice (d4, d6, d8, d10, d12, d20, etc.)PercentileDice– Percentile dice (d100/d%) rolling 1-100 with specialized mechanicsFateDice– Fate/Fudge dice (-1, 0, +1 results)CustomDice– Custom dice with user-defined face values (e.g., [2,4,6,8])Group– Collections of dice with shared modifiersSequence– Mathematical combinations of dice rollsNumber– Static values for modifiers and mathematical operations
Dice Notation Support
The parser supports comprehensive dice notation with mathematical expressions:
Basic Dice Notation
1d6 - Single six-sided die
3d8 - Three eight-sided dice
2d20+5 - Two d20 plus 5
1d4*2 - One d4 multiplied by 2
(1d6+2)*3 - Parenthesized expressions
Custom Dice
1d[1,3,5] - Custom die with face values 1, 3, 5
3d[2,4,6,8,10,12] - Three custom dice with even values
2d[-1,0,1] - Two dice with negative values (Fate-style)
1d[0,0,1,1,2,3] - Weighted custom die (more 0s and 1s)
4d[1,1,2,3]kh3! - Custom dice with modifiers and exploding
Exploding Dice
3d6! - Exploding dice (roll again on max)
4d8!! - Compound exploding (add to same die)
2d10!p - Penetrating exploding (reroll with -1)
Modifiers (Keep/Drop)
4d6kh3 - Keep highest 3 of 4d6
5d8kl2 - Keep lowest 2 of 5d8
6d6dh1 - Drop highest 1 of 6d6
4d6dl1 - Drop lowest 1 of 4d6
Groups and Advanced Expressions
{2d6, 1d8}kh2 - Roll 2d6 and 1d8, keep highest 2 results
{3d6!, 2d8} - Mix exploding and normal dice
1d20 + {4d6}kh3 - Combine groups with other rolls
Fate Dice
4dF - Four Fate dice (-1, 0, +1 each)
3dF+2 - Three Fate dice plus 2
Percentile Dice
1d% - Single percentile die (1-100)
1d100 - Single percentile die (equivalent to d%)
2d%+10 - Two percentile dice plus 10
3d100kh2 - Three percentile dice, keep highest 2
1d%! - Exploding percentile die
Mathematical Operations
1d8 + 1d6 + 3 - Addition sequence
2d6 * 1d4 - Multiplication
1d20 - 1d4 - Subtraction
(2d6 + 3) / 2 - Division with parentheses
Usage Patterns
1. Runtime Parsing
using DiceRollerPro;
using DiceRollerPro.Parser;
public class GameDiceRoller : MonoBehaviour
{
private readonly Parser parser = new Parser();
private readonly System.Random random = new System.Random();
public void RollDice(string diceExpression)
{
try
{
// Parse the dice expression
var roll = parser.Parse(diceExpression);
// Generate the result
var result = roll.GenerateValue(random);
// Display result and explanation
Debug.Log($"Result: {result.Value}");
Debug.Log($"Breakdown: {RollExplainer.Explain(result)}");
}
catch (SyntaxException ex)
{
Debug.LogError($"Invalid dice expression: {ex.Message}");
}
}
}
2. ScriptableObject Assets
Create dice configurations in the Unity Editor:
- Assets → Create → Dice Roller Pro → Normal Dice
- Configure properties in Inspector
- Use in scripts:
public class CharacterSheet : MonoBehaviour
{
[SerializeField] private BaseRoll attackRoll; // Assign in Inspector
[SerializeField] private BaseRoll damageRoll; // e.g., 2d6+3 asset
private readonly System.Random random = new System.Random();
public void Attack()
{
var attackResult = attackRoll.GenerateValue(random);
var damageResult = damageRoll.GenerateValue(random);
Debug.Log($"Attack: {attackResult.Value} ({RollExplainer.Explain(attackResult)})");
Debug.Log($"Damage: {damageResult.Value} ({RollExplainer.Explain(damageResult)})");
}
}
3. Programmatic Creation
using DiceRollerPro;
using DiceRollerPro.Models;
public class DynamicDiceCreator : MonoBehaviour
{
public void CreateComplexRoll()
{
// Create dice with modifiers
var modifiers = new Modifiers(keepHighest: 3, explode: true);
var dice = DiceRollFactory.CreateNormalDice(count: 4, size: 6, modifiers);
// Create a group
var rolls = new BaseRoll[] { dice, DiceRollFactory.CreateNumber(2) };
var group = DiceRollFactory.CreateGroup(rolls, null);
// Roll and display
var result = group.GenerateValue(new System.Random());
Debug.Log($"Complex roll result: {RollExplainer.Explain(result)}");
}
}
Dice Types and Mechanics
Normal Dice
Standard polyhedral dice with full modifier support:
// Create 4d6 with keep highest 3 and exploding
var modifiers = new Modifiers(keepHighest: 3, explode: true);
var dice = new NormalDice(count: 4, size: 6, modifiers);
// Roll and get results
var result = dice.GenerateValue(random);
Debug.Log(RollExplainer.Explain(result)); // e.g., "(6!K + 5K + 4K + 1D)"
Exploding Mechanics:
- Basic Exploding (
!): Roll additional dice when rolling maximum value - Compound Exploding (
!!): Add explosion results to the same die - Penetrating Exploding (
!p): Reroll with -1 modifier to prevent infinite loops
Fate Dice
Fate/Fudge system dice with three equally likely outcomes:
var fateDice = new FateDice(count: 4, size: 3, modifiers: null);
var result = fateDice.GenerateValue(random);
// Result.Value will be between -4 and +4 (sum of four dice each rolling -1, 0, or +1)
Percentile Dice
Percentile dice for percentage-based rolls with values from 1 to 100:
var percentileDice = new PercentileDice(count: 1, size: 100, modifiers: null);
var result = percentileDice.GenerateValue(random);
// Result.Value will be between 1 and 100 (inclusive)
// With exploding mechanics
var explodingModifiers = new Modifiers { Explode = true };
var explodingPercentile = new PercentileDice(count: 1, size: 100, explodingModifiers);
// Explodes on rolling 100, just like other dice types
Custom Dice
Custom dice with user-defined face values instead of sequential numbers:
// Create custom dice with specific face values
var faceValues = new int[] { 2, 4, 6, 8, 10, 12 }; // Even numbers only
var customDice = DiceRollFactory.CreateCustomDice(count: 3, faceValues, modifiers: null);
var result = customDice.GenerateValue(random);
// Each die will roll one of: 2, 4, 6, 8, 10, or 12
// Weighted custom dice (values can repeat)
var weightedFaces = new int[] { 1, 1, 2, 2, 3, 6 }; // 1s and 2s are twice as likely
var weightedDice = DiceRollFactory.CreateCustomDice(count: 2, weightedFaces, null);
// Story dice with success counting
var storyFaces = new int[] { 0, 0, 1, 1, 2, 3 }; // More failures than successes
var storyDice = DiceRollFactory.CreateCustomDice(count: 4, storyFaces, null);
// Custom dice with exploding (explodes on highest face value)
var explodingModifiers = new Modifiers { Explode = true };
var explodingCustom = DiceRollFactory.CreateCustomDice(1, new int[] { 1, 3, 5, 7, 9 }, explodingModifiers);
// Will explode when rolling a 9
Parser Syntax:
1d[1,3,5] - Single die with face values 1, 3, 5
3d[2,4,6,8,10,12] - Three dice with even values
2d[-1,0,1] - Two dice with negative values
4d[1,1,2,3]kh3! - Custom dice with modifiers and exploding
Key Features:
- Create via
Assets/Create/Dice Roller Pro/Custom Dicemenu - Configure
FaceValuesarray directly in the Inspector - Array length automatically determines number of sides
- Supports all standard modifiers (keep/drop, exploding, etc.)
Groups
Combine multiple dice types with shared modifiers:
var normalDice = DiceRollFactory.CreateNormalDice(2, 6, null);
var percentileDice = DiceRollFactory.CreatePercentileDice(1, 100, null);
var fateDice = DiceRollFactory.CreateFateDice(2, 3, null);
var number = DiceRollFactory.CreateNumber(3);
var rolls = new BaseRoll[] { normalDice, percentileDice, fateDice, number };
var modifiers = new Modifiers(keepHighest: 2); // Keep best 2 results from all rolls
var group = new Group(rolls, modifiers);
Sequences
Mathematical combinations of multiple rolls:
var roll1 = DiceRollFactory.CreateNormalDice(1, 20, null);
var roll2 = DiceRollFactory.CreateNumber(5);
var sequence = new Sequence(new[] { roll1, roll2 }, Operator.Addition);
// Equivalent to "1d20+5"
Supported Operators:
Addition(+): Sum all resultsSubtraction(-): Subtract subsequent results from firstMultiplication(*): Multiply all resultsDivision(/): Divide by subsequent results
Modifier System
The Modifiers class provides comprehensive dice modification options:
Keep/Drop Mechanics
var modifiers = new Modifiers
{
KeepHighest = 3, // Keep 3 highest results
KeepLowest = 0, // Keep 0 lowest (disabled)
DropHighest = 0, // Drop 0 highest (disabled)
DropLowest = 1 // Drop 1 lowest result
};
Important Notes:
- Keep and Drop modifiers work on the final results after all dice are rolled
- Modifiers can be combined (e.g., drop lowest then keep highest)
- Results are marked as “Taken” (kept) or not taken (dropped)
- The
RollExplainershows kept results with “K” and dropped with “D”
Exploding Dice Configuration
var modifiers = new Modifiers
{
Explode = true, // Enable exploding on maximum rolls
CompoundExplode = false, // Don't compound (create separate dice)
PenetratingExplode = true // Use penetrating mode (-1 on rerolls)
};
Result System
IResult Interface
All dice operations return objects implementing IResult:
public interface IResult
{
int Value { get; } // Final calculated value
int Index { get; set; } // Position in result set
bool Taken { get; set; } // Whether included in final calculation
}
Result Types
Result – Single die result:
var result = new Result(value: 6, index: 0, taken: true);
CompositeResult – Collection of results:
var results = new IResult[] { new Result(4, 0, true), new Result(6, 1, false) };
var composite = new CompositeResult(results);
// composite.Value equals sum of taken results (4 in this case)
Roll Explanations
The RollExplainer provides human-readable breakdowns:
var result = roll.GenerateValue(random);
var explanation = RollExplainer.Explain(result);
// Example outputs:
// "(4K + 3K + 1D)" - 3d6 with 1 dropped
// "6 + 3" - 1d6+3
// "(2K + 1D) * (4K)" - Complex expression with operations
Legend:
K= Kept (taken) resultD= Dropped (not taken) result- Operators show mathematical operations between components
Unity Editor Integration
Asset Creation Menu
Access dice creation tools via Assets → Create → Dice Roller Pro:
- Normal Dice – Standard polyhedral dice
- Percentile Dice – Percentile dice (d100/d%)
- Fate Dice – Fate/Fudge dice
- Group – Collection of dice with modifiers
- Sequence – Mathematical combination of rolls
- Number – Static value for modifiers
Inspector Configuration
All dice types provide full Inspector support:
[SerializeField] private NormalDice characterStats; // Configure in Inspector
[SerializeField] private Group complexRoll; // Drag dice assets here
[SerializeField] private BaseRoll[] dicePresets; // Array of dice assets
Inspector Features:
- Drag-and-drop dice asset assignment
- Real-time validation warnings
- Tooltip documentation for all fields
- Visual modifier configuration
Editor Tools Menu
Unity Editor integration focuses on asset creation via Assets → Create → Dice Roller Pro menus. The validation framework provides runtime validation that can be integrated into custom editor tools as needed.
Dice Validation Framework
The Dice Validation Framework provides comprehensive validation for dice expressions and configurations in DiceRollerPro.
Basic Usage
using DiceRollerPro.Validation;
// Validate a dice expression
var result = DiceValidator.ValidateExpression("3d6+2");
if (!result.IsValid)
{
Debug.LogError($"Invalid dice expression: {result.GetSummary()}");
}
// Detailed validation with all issues
var detailedResult = DiceValidator.ValidateExpression("1000d6");
Debug.Log(detailedResult.GetSummary()); // "⚠ 1 Warning - High dice count: 1000"
// Check individual issues
foreach (var issue in detailedResult.Issues)
{
Debug.LogWarning($"{issue.Severity} [{issue.Category}]: {issue.Message}");
if (!string.IsNullOrEmpty(issue.Suggestion))
{
Debug.Log($"Suggestion: {issue.Suggestion}");
}
}
// Validate with performance checking disabled
var quickResult = DiceValidator.ValidateExpression("4d6", validatePerformance: false);
Validating Roll Configurations
using DiceRollerPro.Validation;
using DiceRollerPro.Models;
// Validate a BaseRoll asset
public BaseRoll myDiceAsset;
void Start()
{
var result = DiceValidator.ValidateRoll(myDiceAsset);
if (!result.IsValid)
{
Debug.LogError($"Dice configuration issues: {result.GetSummary()}");
}
}
// Validate dice parameters before creating
int count = 100;
int size = 6;
var paramResult = DiceValidator.ValidateDiceParameters(count, size);
if (paramResult.GetIssueCount(ValidationSeverity.Warning) > 0)
{
Debug.LogWarning("High dice count may impact performance");
}
// Validate modifiers separately
var modifiers = new Modifiers
{
KeepHighest = 3,
DropLowest = 1, // This will generate a warning
Explode = true
};
var modifierResult = DiceValidator.ValidateModifiers(modifiers);
foreach (var issue in modifierResult.GetIssuesBySeverity(ValidationSeverity.Warning))
{
Debug.LogWarning(issue.Message);
}
Runtime Validation Integration
using DiceRollerPro.Validation;
using DiceRollerPro.Parser;
public class PlayerDiceRoller : MonoBehaviour
{
public void RollUserExpression(string userInput)
{
// Validate user input before processing
var validationResult = DiceValidator.ValidateExpression(userInput);
if (!validationResult.IsValid)
{
ShowErrorMessage($"Invalid dice expression: {validationResult.GetSummary()}");
// Show detailed error information
foreach (var issue in validationResult.Issues)
{
if (issue.Severity == ValidationSeverity.Critical || issue.Severity == ValidationSeverity.Error)
{
Debug.LogError($"{issue.Category}: {issue.Message}");
if (!string.IsNullOrEmpty(issue.Suggestion))
Debug.Log($"Suggestion: {issue.Suggestion}");
}
}
return;
}
// Safe to parse and roll
var parser = new Parser();
var roll = parser.Parse(userInput);
var result = roll.GenerateValue(new System.Random());
ShowResult(result.Value);
}
}
Unity Editor Integration
The validation framework is a runtime system that can be integrated into custom editor tools. The framework provides static methods that can be called from editor scripts to validate dice configurations during development.
Validation Categories
The framework checks for issues in several categories:
Syntax Issues
- Invalid dice notation syntax
- Parse errors in expressions
- Malformed dice expressions
- Empty or null expressions
Parameters Issues
- Negative or zero dice counts
- Negative or zero dice sizes
- Extremely large dice sizes
- Non-standard dice sizes (informational)
Logic Issues
- Conflicting modifiers (keep and drop together)
- Multiple exploding dice types
- Keep/drop counts exceeding dice count
- Invalid modifier combinations
Performance Issues
- High dice counts (>100 warning, >1000 critical)
- Complex expressions with high complexity scores
- Very long expression strings
- Deep nesting in roll structures
Configuration Issues
- Null references in roll structures
- Empty groups or sequences
- Missing required components
Convention Issues
- Single-sided dice (d1)
- Non-standard dice sizes
- Optimization opportunities (single-item sequences)
Validation Severity Levels
- Critical: Blocking issues that prevent operation (syntax errors, null references)
- Error: Significant issues that should be fixed (invalid parameters, logic conflicts)
- Warning: Potential problems or performance concerns (high dice counts, unusual configurations)
- Info: Informational messages and suggestions (conventions, optimizations)
ValidationResult API
The ValidationResult class provides comprehensive information about validation outcomes:
// Access basic properties
bool isValid = result.IsValid;
DateTime when = result.ValidationTime;
string objectName = result.ValidatedObjectName;
List<ValidationIssue> allIssues = result.Issues;
// Filter issues by severity
var criticalIssues = result.GetIssuesBySeverity(ValidationSeverity.Critical);
int warningCount = result.GetIssueCount(ValidationSeverity.Warning);
ValidationSeverity highest = result.HighestSeverity;
// Generate summaries
string summary = result.GetSummary();
// Merge multiple validation results
result.Merge(anotherValidationResult);
ValidationIssue Details
Each validation issue contains detailed information:
ValidationIssue issue = result.Issues[0];
// Core properties
ValidationSeverity severity = issue.Severity;
string category = issue.Category; // e.g., "Syntax", "Performance"
string message = issue.Message; // Brief description
string details = issue.Details; // Detailed explanation
string suggestion = issue.Suggestion; // How to fix it
Supported Validation Methods
DiceValidator.ValidateExpression(string, bool)
Validates a complete dice expression string with optional performance checking.
DiceValidator.ValidateDiceParameters(int, int)
Validates dice count and size parameters independently.
DiceValidator.ValidateRoll(BaseRoll)
Validates any BaseRoll configuration including recursive validation.
DiceValidator.ValidateModifiers(Modifiers)
Validates modifier configurations for conflicts and logic issues.
Configuration Limits
The validation framework enforces the following limits to prevent excessive memory usage:
- Maximum Dice Count: 1,000 dice per roll
- Maximum Dice Size: 1,000,000 sides
- Maximum Expression Length: 1,000 characters
- Maximum Recursion Depth: 10 levels (for nested groups/sequences)
These limits generate warnings or errors when exceeded and help maintain reasonable performance.
Performance Complexity Scoring
The validator calculates a complexity score for dice configurations to identify potentially slow operations:
- BaseDice: Count × 1 (×2 if exploding dice enabled)
- Groups/Sequences: Sum of contained roll complexities
- Numbers: 1 point each
Complexity Thresholds:
- > 10,000: Warning for high complexity
- > 1,000: Info for moderate complexity
- ≤ 1,000: No performance concerns
Example complexities:
1d6= 1 (low)10d6!= 20 (exploding dice penalty){4d6, 3d8, 2d10}= 9 (sum of group contents)100d20= 100 (moderate)
Standard Dice Sizes
The validator recognizes these standard tabletop gaming dice sizes and provides informational messages for non-standard sizes:
Standard Sizes: d4, d6, d8, d10, d12, d20, d100
Examples of non-standard sizes that generate info messages: d3, d5, d7, d13, d30, etc.
Best Practices
- Always validate user input before parsing dice expressions using
ValidateExpression() - Check validation results when creating dice configurations programmatically
- Use performance validation for complex dice configurations in production
- Handle Critical and Error issues before allowing dice rolls to proceed
- Log Warning and Info issues for debugging and optimization opportunities
- Validate after modifying dice parameters or modifiers at runtime
Example Validation Results
✓ No issues found - Configuration is valid
⚠ 1 Warning - High dice count: 100
✗ 2 Errors, 1 Warning - Invalid parameters, conflicting modifiers
⚠ 1 Info - Non-standard dice size: d7
✗ 1 Critical - Parse error: Expected number after 'd'
The validation framework helps ensure reliable dice rolling by catching common configuration errors and performance issues before they impact your game.
Performance & Optimization
Dice Roller Pro is designed for high performance with several optimization features:
Memory Management
StringBuilder Pooling: The RollExplainer uses thread-local StringBuilder instances to minimize garbage collection:
// Automatic memory reuse - no manual management needed
var explanation = RollExplainer.Explain(result);
Thread-Safe Arrays: Group and Sequence classes use thread-local arrays for temporary storage:
// Each thread gets its own result array - no allocation overhead
var groupResult = group.GenerateValue(random);
Caching System
Expression Caching: Common dice expressions are cached for instant retrieval:
// First parse is slow, subsequent ones are cached
var roll1 = parser.Parse("3d6+2"); // Parses and caches
var roll2 = parser.Parse("3d6+2"); // Retrieved from cache
Optimized Algorithms
Sorting Optimization: Keep/drop operations use optimized sorting algorithms:
// Efficient keep/drop without full sorting when possible
OptimizedSorting.ApplyModifiersOptimized(results, modifiers);
Span-Based Parsing: Zero-allocation string processing using ReadOnlySpan<char>:
// No string allocations during parsing
private BaseRoll ParseWithSpan(ReadOnlySpan<char> input) { /* ... */ }
Thread Safety
All core operations are thread-safe:
// Safe to use from multiple threads
private static readonly Parser parser = new Parser();
// Each thread should have its own Random instance
[ThreadStatic]
private static System.Random threadRandom;
Performance Guidelines
- Reuse Parser instances across multiple parse operations
- Use dedicated Random instances per thread for consistency
- Cache frequently used expressions in your own application layer
- Monitor dice counts – validation framework warns about performance issues
- Profile complex expressions using Unity Profiler when needed
Advanced Features
Custom Dice Factory
The DiceRollFactory provides convenient creation methods:
// Factory methods for all dice types
var normalDice = DiceRollFactory.CreateNormalDice(4, 6, modifiers);
var percentileDice = DiceRollFactory.CreatePercentileDice(1, null);
var fateDice = DiceRollFactory.CreateFateDice(4, 3, null);
var customDice = DiceRollFactory.CreateCustomDice(2, new int[] { 2, 4, 6, 8 }, null);
var group = DiceRollFactory.CreateGroup(rolls, modifiers);
var sequence = DiceRollFactory.CreateSequence(rolls, Operator.Addition);
var number = DiceRollFactory.CreateNumber(42);
Exception Handling
Comprehensive error handling with detailed context:
try
{
var roll = parser.Parse("invalid expression");
}
catch (SyntaxException ex)
{
// Detailed error with position information
Debug.LogError(ex.Message);
// Example: "Invalid dice notation at position 8\nInput: invalid expression\nError: ^"
}
Extensibility Points
The architecture supports extension:
// Create custom dice types
public class CustomDice : BaseDice
{
public CustomDice(int count, int size, Modifiers modifiers)
: base(count, size, modifiers) { }
public override bool GetValue(Random random, out int value)
{
// Custom rolling logic
value = /* your implementation */;
return false; // or true if should continue rolling
}
}
Sample Implementation
The included RollScript sample demonstrates complete integration:
public class RollScript : MonoBehaviour
{
[SerializeField] private InputField inputField; // User input
[SerializeField] private Text resultText; // Numeric result
[SerializeField] private Text explanationText; // Roll breakdown
[SerializeField] private BaseRoll presetDice; // Optional preset
private readonly Parser.Parser parser = new Parser.Parser();
private readonly System.Random random = new System.Random();
public void Generate()
{
BaseRoll roll = presetDice ?? parser.Parse(inputField.text);
var result = roll.GenerateValue(random);
resultText.text = result.Value.ToString();
explanationText.text = RollExplainer.Explain(result);
}
}
This sample showcases:
- UI integration with InputField and Text components
- Both preset dice assets and runtime parsing
- Result display with detailed explanations
- Error-safe implementation patterns
Integration Checklist
When integrating Dice Roller Pro into your project:
- [ ] Import the package and verify Unity 2022.3.16f1 compatibility
- [ ] Create dice assets using Assets → Create → Dice Roller Pro menus
- [ ] Set up UI with InputField, result Text, and explanation Text components
- [ ] Implement validation for user input using
DiceValidator.ValidateExpression() - [ ] Use consistent Random instances for predictable results
- [ ] Test complex expressions using the validation framework in your code
- [ ] Profile performance with high dice counts in your specific use case
- [ ] Consider thread safety if using dice rolling from multiple threads
Troubleshooting
Common Issues
Parse Errors: Use the Expression Validator tool to test dice notation syntax
Performance Issues: Enable validation warnings to identify high dice counts
Thread Safety: Ensure each thread uses its own Random instance
Memory Usage: The system automatically pools memory – no manual management needed
Validation Failures: Check the validation framework documentation for specific issue categories