Add a Metas tab that lists remote .met/.nav files, checks update status, and downloads with .bak backups on overwrite. Add an Auto Install Updates setting (default on) and guard settings usage during early startup to avoid initialization errors.
RequestId() is called for armor, weapons, jewelry, and other items that need full ID data when picked up via OnCreateObject or OnChangeObject. Adds ObjectClassNeedsIdent helper matching MossyInventory's logic.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Replace hardcoded AssemblyVersion/AssemblyFileVersion with a CalVer
scheme (YYYY.M.D.HHmm) generated at build time via an MSBuild target
that writes a CalVer.cs file into obj/ before compilation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unsubscribe all event handlers and stop/dispose timers at the start of
Startup() before re-creating objects. On first load the -= calls are
no-ops; on hot reload they remove stale handlers that would otherwise
compound with each reload. Also adds LoginComplete unsubscription to
Shutdown() for completeness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
InitializeForHotReload was missing window position restore (settings
loaded after ViewInit, but position never re-applied) and character
stats streaming timer (10-min interval + initial send).
Added VVSTabbedMainView.RestorePosition() static wrapper and wired
it into the hot reload path after settings load. Added character
stats timer initialization as step 10.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
InitializeForHotReload() was called at the top of Startup() before
_killTracker, _chatEventRouter, and _inventoryMonitor were created,
causing NullReferenceException. Move the hot reload block to after
all core objects are initialized.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
InitializeForHotReload() never created a RareTracker — it only ran
if one already existed. When the new DLL is loaded on an already-
logged-in character, LoginComplete doesn't fire, so _rareTracker
stayed null and the null-check in ChatEventRouter.OnChatText silently
skipped all rare detection.
Now InitializeForHotReload creates and wires the RareTracker if it
hasn't been set yet, matching what LoginComplete does.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse augmentation, rating, mastery, society, and general DWORD properties
from the 0x0013 login message. Capture the full titles list from 0x0029.
Both are included in the character_stats WebSocket payload for the new
TreeStats-style character window in the frontend.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove dead no-op commands (harmonyraw, debugtaper)
- Remove duplicate command (initgui, same as gui)
- Hide debug/test commands from help output (vtanktest, decalstatus,
decaldebug, testprismatic, testdeath, testtaper, debugupdate)
- Clean up descriptions for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add debug logging to all empty catch blocks in DecalHarmonyClean.cs setup methods
(prefix method catches intentionally stay silent to never break other plugins)
- Add error logging to VtankControl.VtSetSetting catch
- Add logging to DecalPatchMethods.ProcessInterceptedMessage catch
- Remove unused usings from PluginCore.cs (System.Diagnostics, System.Drawing,
System.Text, System.Text.RegularExpressions)
- Flatten redundant nested try/catch in PatchPluginHost
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>