ModernUO/dev-docs/claude-skills/modernuo-events.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

184 lines
5.5 KiB
Markdown

---
name: modernuo-events
description: >
Trigger when subscribing to or creating game events, working with EventSink or generated events. When hooking into player login, death, speech, or other game events.
---
# ModernUO Events System
## When This Activates
- Subscribing to game events (login, logout, death, speech)
- Creating new events
- Working with `EventSink` static events
- Using `[GeneratedEvent]` / `[OnEvent]` attributes
## Key Rules
1. **Subscribe to events in `Configure()`** static method
2. **EventSink events are `static event Action<T>`** -- subscribe with `+=`
3. **Event handlers must match the delegate signature**
4. **Unsubscribe if your system can be disabled** (prevent leaks)
## EventSink Events
Subscribe in `Configure()`:
```csharp
public static void Configure()
{
EventSink.Connected += OnPlayerConnected;
EventSink.Disconnected += OnPlayerDisconnected;
EventSink.Logout += OnLogout;
EventSink.ServerStarted += OnServerStarted;
}
```
### Available Events
#### Core Lifecycle
```csharp
EventSink.ServerStarted // Action -- Server fully started
EventSink.Shutdown // Action -- Server shutting down
EventSink.WorldLoad // Action -- World loaded from saves
EventSink.WorldSave // Action -- World save triggered
EventSink.WorldSavePostSnapshot // Action<WorldSavePostSnapshotEventArgs>
```
#### Player Connection
```csharp
EventSink.Connected // Action<Mobile> -- Player connected
EventSink.BeforeDisconnected // Action<Mobile> -- About to disconnect
EventSink.Disconnected // Action<Mobile> -- Player disconnected
EventSink.Logout // Action<Mobile> -- Player logged out
```
#### Account
```csharp
EventSink.AccountLogin // Action<AccountLoginEventArgs>
// AccountLoginEventArgs: .State (NetState), .Username, .Password, .Accepted (set), .RejectReason (set)
```
#### Communication
```csharp
EventSink.Speech // Action<SpeechEventArgs>
// SpeechEventArgs: .Mobile, .Speech, .Type, .Hue, .Keywords, .Handled (set), .Blocked (set)
```
#### Combat
```csharp
EventSink.AggressiveAction // Action<AggressiveActionEventArgs>
// AggressiveActionEventArgs: .Aggressed, .Aggressor, .Criminal
```
#### Movement
```csharp
EventSink.Movement // Action<MovementEventArgs>
// MovementEventArgs: .Mobile, .Direction, .Blocked (set)
```
#### Network
```csharp
EventSink.SocketConnect // Action<SocketConnectEventArgs>
// SocketConnectEventArgs: .Address, .AllowConnection (set)
EventSink.ServerCrashed // Action<ServerCrashedEventArgs>
// ServerCrashedEventArgs: .Exception, .Close (set)
```
#### UI
```csharp
EventSink.PaperdollRequest // Action<Mobile, Mobile> -- (beholder, beheld)
```
## Event Handler Pattern
```csharp
public static class MyEventSystem
{
public static void Configure()
{
EventSink.Connected += OnConnected;
EventSink.Speech += OnSpeech;
}
private static void OnConnected(Mobile m)
{
if (m is PlayerMobile pm)
{
pm.SendMessage("Welcome back!");
}
}
private static void OnSpeech(SpeechEventArgs e)
{
if (e.Speech.InsensitiveContains("help"))
{
e.Mobile.SendMessage("How can I help you?");
e.Handled = true; // Prevent further processing
}
}
}
```
## Generated Events (Code-Generated)
For custom events on game entities, use the CodeGeneratedEvents package:
### Defining Events
```csharp
// On the class that fires the event:
[GeneratedEvent(nameof(PlayerLoginEvent))]
public static partial void PlayerLoginEvent(PlayerMobile player);
```
### Subscribing to Events
```csharp
// On the handler class:
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
public static void HandleLogin(PlayerMobile player)
{
// Handle the event
}
```
### Known Generated Events
- `PlayerMobile.PlayerLoginEvent`
- `PlayerMobile.PlayerDeathEvent`
- `BaseCreature.CreatureDeathEvent`
External reference: https://github.com/modernuo/CodeGeneratedEvents
## EventArgs Pool Pattern
Some EventArgs use object pooling to avoid allocation:
```csharp
// Movement uses pooling:
var args = MovementEventArgs.Create(mobile, dir);
EventSink.InvokeMovement(args);
args.Free(); // Return to pool
// AggressiveAction uses pooling:
var args = AggressiveActionEventArgs.Create(aggressed, aggressor, criminal);
EventSink.InvokeAggressiveAction(args);
args.Free();
```
## Anti-Patterns
- **Subscribing outside `Configure()`**: Won't be called during startup
- **Not checking player type**: `EventSink.Connected` fires for all mobiles, cast to `PlayerMobile` if needed
- **Blocking in event handlers**: Event handlers run on the game loop -- keep them fast
- **Not unsubscribing**: If system can be disabled, unsubscribe to prevent leaks
## Real Examples
- EventSink core: `Projects/Server/Events/EventSink.cs`
- Speech events: `Projects/Server/Events/SpeechEvent.cs`
- Movement events: `Projects/Server/Events/MovementEvent.cs`
- Account events: `Projects/Server/Events/AccountLoginEvent.cs`
- World events: `Projects/Server/Events/EventSink.cs` (WorldLoad, WorldSave, ServerStarted, Shutdown)
- Connection events: `Projects/Server/Events/SocketConnectionEvent.cs`
- GumpSystem subscription: `Projects/UOContent/Gumps/Base/GumpSystem.cs`
## See Also
- `dev-docs/events.md` - Complete events documentation
- `dev-docs/claude-skills/modernuo-content-patterns.md` - Content hooks
- `dev-docs/claude-skills/modernuo-configuration.md` - Configure() pattern