- Create IPluginLogger interface, PluginCore implements it
- CharacterStats.cs and WebSocket.cs now use IPluginLogger instead of PluginCore.WriteToChat
- Extract KillTracker.cs: owns kill detection (all 36 regex patterns), death tracking,
rate calculation, and the 1-sec stats update timer
- Bridge properties on PluginCore maintain backward compat for WebSocket telemetry
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract magic numbers (timer intervals, message type IDs, property keys) into Constants.cs
- Replace ~600-line HandleMmCommand switch with dictionary-based CommandRouter
- All /mm commands preserved with same behavior, now registered via lambdas
- PluginCore.cs and CharacterStats.cs updated to use named constants
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move Init() and ServerDispatch hook from LoginComplete to Startup so
event 0x0013 (character properties) is caught during login sequence
- Add handler for message 0x02CF (PrivateUpdatePropertyInt64) to capture
runtime luminance changes when player earns/spends luminance in-game
- Uses RawData byte parsing for 0x02CF since Decal messages.xml may not
define this message type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ServerDispatch was hooked in Startup() but Init() was called later in
LoginComplete(), clearing the luminance/title data already captured from
the 0x0013 network event. Now hook ServerDispatch after Init() so
captured data is not reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add missing DLLs to lib/: Decal.Interop.Filters, Decal.FileService,
Decal.Interop.D3DService, Decal.Interop.Input, Decal, DecalNet, VCS5
- Convert all Windows-absolute HintPaths to relative lib\ paths
- Convert COM references (Decal, DecalNet) to regular assembly references
- Add Microsoft.NETFramework.ReferenceAssemblies for cross-platform builds
- Add AllowUnsafeBlocks and PlatformTarget to Release configuration
- Update Release DLL with character stats streaming feature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
• Guard Start() so only one connection loop can run per client.
• Capture the socket inside each receive loop, so reconnects can’t
leave old loops fighting over the same ClientWebSocket.