ModernUO/dev-docs/claude-skills/modernuo-configuration.md
Kamron Batman 1391c563fe
chore: Adds AI instructions and SKILLs for ModernUO codebase (#2347)
Summary

  - Adds CLAUDE.md at repo root with 14 terse code audit rules (always loaded, low token cost)
  - Adds pointer files for other AI tools: AGENTS.md (Codex), GEMINI.md, .github/COPILOT-INSTRUCTIONS.md (Copilot), .cursorrules (Cursor) — all redirect to CLAUDE.md as single source of truth
  - Gitignores /.claude so personal AI config isn't distributed
  - Moves Claude skills to dev-docs/claude-skills/ (opt-in, not auto-loaded)
  - Adds 14 dev-docs covering codebase conventions

  Code Audit Rules (in CLAUDE.md)

  1. LINQ tiered rules (Tier 1 free, Tier 2 warm, Tier 3 forbidden)
  2. No Console.WriteLine — use LogFactory.GetLogger()
  3. No concurrency primitives in game code
  4. No World.Mobiles/World.Items iteration
  5. Clean up refs in OnDelete()/OnAfterDelete()
  6. Cancel timers in OnDelete()/OnAfterDelete()
  7. STArrayPool<T>.Shared not ArrayPool<T>.Shared
  8. PooledRefList<T> not new List<T>() on hot paths
  9. Serialization: partial class, [Constructible], no serialized TimerExecutionToken
  10. No Task.Run/new Thread() in game code
  11. Never assume era — ask which expansion
  12. _camelCase fields, PascalCase properties/methods
  13. No empty gumps — use DisplayTo() pattern
  14. PropertyList string literals must be {} holes, cliloc-as-argument uses :#
2026-03-01 11:42:19 -08:00

177 lines
5.5 KiB
Markdown

---
name: modernuo-configuration
description: >
Trigger when adding server settings, reading config values, or working with modernuo.json or JsonConfig.
---
# ModernUO Configuration System
## When This Activates
- Adding new server settings
- Reading config values with `ServerConfiguration`
- Using `JsonConfig.Serialize/Deserialize<T>`
- Working with `modernuo.json` or custom config files
## Key Rules
1. **Read settings in `Configure()`** static method
2. **Use `GetOrUpdateSetting()`** when you want the setting created with a default if missing
3. **Use `GetSetting()`** for read-only access (won't write default to file)
4. **Custom config files use `JsonConfig.Serialize/Deserialize<T>()`**
5. **Config path base**: `Distribution/Configuration/`
## ServerConfiguration
### GetOrUpdateSetting (Creates Default If Missing)
```csharp
// In Configure() method:
var maxAccounts = ServerConfiguration.GetOrUpdateSetting("accountHandler.maxAccountsPerIP", 1);
var saveDelay = ServerConfiguration.GetOrUpdateSetting("autosave.saveDelay", TimeSpan.FromMinutes(5));
var enabled = ServerConfiguration.GetOrUpdateSetting("mySystem.enabled", true);
```
If the key doesn't exist in `modernuo.json`, it writes the default value and returns it.
### GetSetting (Read-Only)
```csharp
var statMax = ServerConfiguration.GetSetting("stats.statMax", 100);
var usePub45 = ServerConfiguration.GetSetting("stats.usePub45StatGain", false);
```
Returns the default if key is missing but does NOT write to the config file.
### Supported Types
```csharp
ServerConfiguration.GetSetting(string key, int defaultValue)
ServerConfiguration.GetSetting(string key, bool defaultValue)
ServerConfiguration.GetSetting(string key, double defaultValue)
ServerConfiguration.GetSetting(string key, TimeSpan defaultValue)
ServerConfiguration.GetSetting<T>(string key, T defaultValue) where T : struct, Enum
```
### SetSetting
```csharp
ServerConfiguration.SetSetting("mySystem.customValue", "42");
// Immediately persisted to modernuo.json
```
## Configuration Pattern
```csharp
namespace Server.Custom;
public static class MySystem
{
private static bool _enabled;
private static int _maxItems;
private static TimeSpan _cooldown;
public static void Configure()
{
_enabled = ServerConfiguration.GetOrUpdateSetting("mySystem.enabled", true);
_maxItems = ServerConfiguration.GetOrUpdateSetting("mySystem.maxItems", 100);
_cooldown = ServerConfiguration.GetOrUpdateSetting("mySystem.cooldown", TimeSpan.FromMinutes(5));
}
// System logic uses _enabled, _maxItems, _cooldown...
}
```
## Custom Config Files with JsonConfig
For complex configuration that doesn't fit in `modernuo.json`:
```csharp
using Server.Json;
public static class MyComplexSystem
{
private static MyConfig _config;
private static readonly string ConfigPath =
Path.Combine(Core.BaseDirectory, "Configuration/MySystem/config.json");
public static void Configure()
{
_config = JsonConfig.Deserialize<MyConfig>(ConfigPath)
?? new MyConfig();
}
public static void SaveConfig()
{
JsonConfig.Serialize(ConfigPath, _config);
}
}
public class MyConfig
{
public bool Enabled { get; set; } = true;
public int MaxItems { get; set; } = 100;
public List<string> BlockedNames { get; set; } = new();
public Dictionary<string, int> Scores { get; set; } = new();
}
```
### JsonConfig Options
- Pretty-printed (WriteIndented = true)
- Comments allowed (ReadCommentHandling = Skip)
- Trailing commas allowed
- Null values omitted (WhenWritingNull)
- Enums serialized as strings (JsonStringEnumConverter)
- Built-in converters for: `ClientVersion`, `Guid`, `Map`, `Point3D`, `Rectangle3D`, `TimeSpan`, `IPEndPoint`, `Type`, `WorldLocation`, `TextDefinition`
## modernuo.json Structure
Location: `Distribution/Configuration/modernuo.json`
```json
{
"assemblyDirectories": ["./Assemblies"],
"dataDirectories": ["C:\\Ultima Online Classic"],
"listeners": ["0.0.0.0:2593"],
"settings": {
"accountHandler.enableAutoAccountCreation": "True",
"accountHandler.maxAccountsPerIP": "1",
"autosave.enabled": "True",
"autosave.saveDelay": "00:05:00",
"world.savePath": "Saves",
"stats.statMax": "100",
"timer.initialPoolCapacity": "1024",
"mySystem.enabled": "True"
}
}
```
All settings are stored as strings in the `settings` dictionary.
## Naming Convention for Keys
Use dot-separated hierarchical keys:
```
systemName.settingName
systemName.subSystem.settingName
```
Examples:
- `accountHandler.maxAccountsPerIP`
- `stats.statMax`
- `movement.delay.walkFoot`
- `autosave.saveDelay`
## Anti-Patterns
- **Reading config in constructors**: Use `Configure()` static method instead
- **Hardcoding values**: Use `ServerConfiguration.GetOrUpdateSetting()` for tunable values
- **Complex objects in modernuo.json**: Use `JsonConfig` with separate files instead
- **Not providing defaults**: Always pass a sensible default value
## Real Examples
- ServerConfiguration: `Projects/Server/Configuration/ServerConfiguration.cs`
- JsonConfig: `Projects/Server/Json/JsonConfig.cs`
- Config usage: `Projects/UOContent/Skills/SkillCheck.cs` (Configure method)
- Timer pool config: `Projects/Server/Timer/Timer.Pool.cs`
- Main config: `Distribution/Configuration/modernuo.json`
## See Also
- `dev-docs/configuration.md` - Complete configuration documentation
- `dev-docs/claude-skills/modernuo-era-expansion.md` - Expansion configuration
- `dev-docs/claude-skills/modernuo-events.md` - Configure() pattern