Commit graph

198 commits

Author SHA1 Message Date
Erik
bd8ad863d1 fix(v2): pack capacity from enhanced_properties.ItemSlots_Decal
The inventory service doesn't return items_capacity directly — it's
in enhanced_properties.ItemSlots_Decal. Updated normalizer to read
from there. Also defaults to 24 (standard AC pack size) with ||
instead of ?? to catch 0/undefined/null. Removed debug console.logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:29:46 +02:00
Erik
8e77274316 fix(v2): pack fill — count children directly from items array
Instead of relying on the packItems Map (which may have key matching
issues), count pack children directly by filtering the normalized
items array for items whose container_id matches the pack's item_id.
Also removed debug console.log spam from WindowRenderer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:26:57 +02:00
Erik
f9ae3d6b96 debug(v2): log WindowRenderer to check if windows mount
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:23:38 +02:00
Erik
a2f77e1061 debug(v2): add earlier console.log to trace inventory fetch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:22:15 +02:00
Erik
87598e0952 debug(v2): add console.log to trace pack item mapping
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:19:36 +02:00
Erik
b68502989e fix(v2): more visible pack capacity bars — wider, brighter border, tooltip
Increased bar width to 7px with #222 background and #666 border for
better contrast. Added tooltip showing "X% full" on hover. Minimum
2px fill height when non-empty so even nearly-empty packs show a sliver.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:15:50 +02:00
Erik
8c8409eac6 fix(v2): pack capacity fill bars now show actual fill level
The pack fill bars were always empty because items weren't mapping
to container key 0 (main backpack). The bodyContainerId detection
failed when the inventory service doesn't include container_id on
wielded items. Now falls back to using the largest non-container
item group as the main backpack if key 0 is empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:09:08 +02:00
Erik
e6adb5cb68 fix(v2): pack capacity bars visible + mana item icons
1. Pack capacity bars: gave the fill bar div explicit height (30px)
   instead of relying on alignItems:stretch which produced 0 height.
   Bar now visibly fills green/orange/red beside each pack icon.

2. Mana panel: added 20px item icons back to each mana row, between
   the status dot and item name. Uses the same ItemIcon component
   with 3-layer compositing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:06:10 +02:00
Erik
bc247aa9b3 fix(v2): cleaner mana panel — flexbox rows, readable fonts, no overflow
Replaced the cramped 3-column CSS Grid mana layout with simple
flexbox rows matching the player sidebar style:
- Status dot (green/red) + item name + mana current/max + time remaining
- Font sizes use rem units (0.65-0.72rem) matching sidebar buttons/stats
- tabular-nums for aligned numbers
- Time column has min-width so it doesn't get clipped
- No more horizontal scrolling or cut-off text
- Empty state message when no mana items equipped

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:47:02 +02:00
Erik
a8078c51ec fix(v2): inventory — full item normalization + all visual fixes
1. Item normalization: normalizeItem() handles ALL formats:
   - Inventory service (snake_case): current_wielded_location, object_class
   - Plugin raw (PascalCase): CurrentWieldedLocation, ObjectClass
   - Plugin IntValues: IntValues['10'] for wielded, ['5'] for burden
   - Sentinel filtering: -1 values properly excluded

2. Equipment slots: armor (object_class=2) fills ALL matching slots.
   Non-armor uses exact mask match first, then first bit overlap.
   Body container ID detected to separate worn from pack items.

3. Slot colors: per-slot-type backgrounds matching v1:
   purple (#3a2555) for jewelry, blue (#1e2e55) for armor,
   teal (#1e3e3e) for clothing, dark blue (#142040) for weapons

4. Burden: fetches /character-stats/{name} for burden_units and
   encumbrance_capacity. Shows percentage when available, raw burden
   otherwise. Bar fills 0-200% mapped to 0-100% height with
   green/orange/red thresholds.

5. Mana panel: shows equipped items with current/max mana + estimated
   time remaining. State dot green/red. Sorted by mana ascending.

6. Fonts: switched to system font stack (-apple-system etc.) instead
   of Palatino for crisp rendering.

7. Tooltip: proper system font, larger text (13px), structured sections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:40:32 +02:00
Erik
2b1c06a5e0 fix(v2): inventory — multi-slot armor + vertical fill bars + burden fix
1. Equipment slots: armor (object_class=2) now renders in ALL matching
   slots via bitmask, not just the first. E.g. a chest piece covering
   upper arm + chest + abdomen appears in all 3 slots. Non-armor items
   still use first-match. Matches v1's exact logic.

2. Pack fill bars: changed from horizontal-below to vertical-right of
   each pack icon. 4px wide bar with fill from bottom, color-coded:
   green <70%, orange 70-90%, red >90%.

3. Burden: removed garbled percentage (was dividing by 10). Now shows
   "Burden" label with total burden in tooltip. Bar shows 50% as
   placeholder until character_stats provides encumbrance_capacity.

4. PackIcon component: reusable for main backpack + sub-packs, shows
   game icon + vertical fill bar + green active glow + gold ▶ arrow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:31:58 +02:00
Erik
a38c7f3e69 fix(v2): v1-faithful inventory window — full 3-panel layout
Rebuilt inventory window to match v1 pixel-for-pixel:

Left column (316px):
- Equipment grid: 6×7 slots at 44px spacing, beveled 3D borders,
  cyan glow (#00ffff) when equipped, faded ghost icon when empty
- Item grid: 6-column CSS Grid with purple gradient cells,
  minimum 24 empty cells to fill grid

Center sidebar (38px):
- Burden bar: 14×40px vertical bar, green/orange/red thresholds,
  percentage label, tooltip with burden units
- Pack icons: 32×32px with actual game icon images (not emoji)
- Active pack: green border + glow + gold ▶ arrow indicator
- Fill indicator: 4px green bar below each pack showing capacity %
- Main backpack (icon 0600127E) + sub-packs with actual container icons

Right panel (flex):
- Mana panel: header + equipped items with mana tracking
- Per-item: 16px icon, name, mana state dot (green/red),
  current/max mana values in v1's grid layout

Hover tooltip:
- Follows mouse cursor (fixed position)
- Shows: name (gold), value, burden, material (green), armor level,
  max damage, damage range/type, attack/defense bonuses as %,
  skill requirements (orange), imbue, set, tinks, workmanship,
  ratings, spellcraft, mana, spell list (blue)
- Black semi-transparent background matching v1's inventory-tooltip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:17:20 +02:00
Erik
3cb8768dc1 fix(v2): v1-faithful character window + improved inventory/radar
Character Window — now matches v1 exactly:
- Navy blue background (#000022) with gold/bronze borders (#af7a30)
- Two side-by-side 320px tab containers
- Left tabs: Attributes (vital bars with gold borders + attribute
  table with green/blue cell backgrounds + vitals base + skill
  credits) | Skills (specialized=purple gradient, trained=teal
  gradient, grouped and sorted) | Titles
- Right tabs: Augmentations (with auras section) | Ratings | Other
  (allegiance with followers)
- Active tab: green tint background with gold top/side borders
- Header: large name + level (gold, right-floated) + race/gender
- XP grid: total, unassigned, luminance earned/total, deaths
- Live vital bars from WebSocket vitals data
- Augmentation/aura/rating property ID maps from v1

Radar — passes full radarData message (not just objects array)
so canvas can render map background + entity positions properly

WindowRenderer — passes live vitals to CharacterWindow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:10:15 +02:00
Erik
cf078b7765 fix(v2): full v1-style radar canvas + inventory icon composites
Radar — now pixel-accurate reproduction of v1:
- 300×300 canvas with dark circular background
- Semi-transparent dereth.png map overlay (heading-rotated)
- 4 range rings + crosshair lines
- Compass labels (N=red, E/S/W=gray) rotating with heading
- Facing direction indicator line
- Entity dots color-coded by type (Monster=red, Player=blue,
  NPC=green, Portal=purple, Corpse=orange, Container=yellow)
- Player dot: gold center with white border
- Heading-up rotation for all entity positions
- Click to select entity (white selection ring)
- Scroll to zoom (0.02-5.0 AC units range)
- Entity list with color dot, name, type, distance, compass direction
- Selected entity highlighted with blue left border

Inventory — v1-style icon composites + slot styling:
- 3-layer icon composite: underlay → base → overlay images
  using portal.dat offset formula + icon_overlay_id/IntValues
- Equipment slots: 3D beveled border + cyan glow when equipped
  (matching v1's outset border + #00ffff shadow)
- Pack item cells: purple gradient background (v1's #3d007a)
- Proper 36×36px icon rendering with pixelated scaling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:16:21 +02:00
Erik
e5c982d6f5 fix(v2): radar data flow + inventory icons
Radar:
- nearby_objects WebSocket messages now tracked in useLiveData state
- Passed through MapLayout → WindowRenderer → RadarWindow
- Objects list updates live as radar data streams in

Inventory:
- Items now render actual game icons via /icons/{hexId}.png
  using the portal.dat offset formula (iconRaw + 0x06000000)
- Hover tooltip shows: name, material, AL, damage, workmanship,
  tinks, set, imbue (multi-line)
- Equipment grid slots show item icons instead of text names
- Pack item grid shows item icons with proper tooltips
- Fallback icon (06000133.png) on load error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:06:14 +02:00
Erik
863adb0c3c fix(v2): inventory window — v1-style equipment grid + pack sidebar
Rebuilt InventoryWindow to match v1's three-panel layout:

Left column:
- Equipment grid: 6×7 slot grid (44px per slot) with color-coded
  backgrounds matching v1's EQUIP_SLOTS map (purple=jewelry,
  blue=armor, teal=clothing, dark blue=weapons). Items placed in
  correct slots using wielded_location bitmask matching.
- Pack contents: 40px item tiles in a wrapping grid, hover for
  full item tooltip (name, material, AL, damage, workmanship)

Right sidebar:
- Pack browser: main backpack + sub-packs (containers). Click to
  switch which pack's contents are shown. Item counts per pack.

Equipment slot layout matches v1 exactly: Row 1 (Neck, Head, Sigils),
Row 2 (Trinket, Upper Arm, Chest, Cloak), Row 3 (Bracelets, Lower
Arm, Abdomen, Upper Leg, Shirt), Row 4 (Rings, Hands, Lower Leg,
Pants), Row 5 (Feet), Row 6 (Shield, Weapon, Ammo).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:52:48 +02:00
Erik
52e1bcd6b8 fix(v2): all reported issues — missing windows, broken features, layouts
Missing features (now added):
1. Vital Sharing window — polls /vital-sharing/peers, shows peer vitals
   with HP/STA/MANA bars, connection status, position, tags
2. Combat Stats window — full Mag-Tools style with monster list (left),
   damage breakdown grid (right), session/lifetime toggle, element matrix
3. Issues Board window — CRUD with categories, resolve/reopen, comments
4. Quest Status — links to /quest-status.html (separate page like v1)
5. Sidebar: added Issues + Vitals buttons, Quest link, Combat button
   per player row (6 buttons now: Chat/Stats/Inv/Char/Combat/Radar)

Fixed functionality:
6. Radar — fixed command to "start_radar"/"stop_radar" (was wrong path)
7. Character window — redesigned with v1-style tabbed layout:
   Left tabs: Attributes (vitals bars + attribute grid) | Skills
   (specialized/trained grouped) | Titles
   Right tabs: Augs | Ratings | Other (allegiance)
   Header: level, race, gender, XP, luminance, deaths, skill credits
8. Stats window — proper Grafana iframe grid (4 panels 2x2) with
   time range selector (1H/6H/24H/7D)

Color palette: expanded to 60 distinct colors (was 30)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:49:16 +02:00
Erik
b77450b6eb fix(v2): comprehensive bug fix round — all reported issues
1. Server stats: now shows player count, latency (rounded), uptime hours
2. Rares/Kills counters: fixed API response fields (all_time/total)
3. Chat send: wired socket.send with v1 envelope { player_name, command }
4. Stats button: opens Grafana iframe grid (4 panels, time range selector)
5. Char button: opens character window with attributes/skills/vitals from
   /character-stats/{name} API, structured display with sections
6. Inventory button: full inventory window with equipment table (material,
   set, imbue, AL, dmg, work, tink) + pack contents pill grid + filter
7. Radar button: opens radar window, sends start/stop commands via socket
8. Sidebar links: added Inventory Search, Suitbuilder, Player Debug
9. Color palette: expanded from 30 to 60 distinct colors matching v1
10. Window types properly routed: stats- prefix → Grafana, char- → character
    data, inv- → inventory, radar- → radar with socket commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:31:06 +02:00
Erik
de7b547349 feat(v2): Phases 2-6 — trails, heatmap, portals, windows, effects
Phase 2 — Map overlays:
- TrailsSVG: SVG polylines per character from /trails, polled 2s
- HeatmapCanvas: canvas radial gradients from /spawns/heatmap
- PortalMarkers: emoji markers from /portals
- Sidebar toggles for heatmap and portals

Phase 3 — Draggable windows:
- WindowManagerContext: z-index stack for open windows
- DraggableWindow: generic shell with drag-header, close btn, z-stack
- ChatWindow: color-coded messages + input form (1000 msg buffer)
- CharacterWindow: combat stats with monster damage table
- InventoryWindow: item table with material/set/AL/dmg/workmanship
- WindowRenderer: reads context, renders all open windows
- Action buttons (Chat/Stats/Inv/Char/Radar) now open windows

Phase 4 — Window types share same DraggableWindow shell with
character-specific content. Combat stats and inventory via API.

Phase 5 — Effects:
- RareNotification: slide-in/slide-out banner with gold border
- Fireworks: 30-particle explosion with CSS custom property animation
- Notification queue with 6s display + 0.5s exit animation

Phase 6 — Polish:
- Window header uses modern blue gradient (not solid purple)
- Chat uses monospace font
- All overlay layers properly stacked (heatmap → trails → dots → portals)
- Mobile: sidebar stacks above map at 768px breakpoint
- Chat messages tracked per-character in useLiveData

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:58:58 +02:00
Erik
183d662bb9 style(v2): modern button styling — subtle translucent instead of solid purple
Primary buttons: soft blue translucent background with blue text,
glows slightly on hover. Secondary buttons: dark subtle with gray
text. Cleaner, more modern feel vs the old solid #88f blocks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:50:48 +02:00
Erik
53bb1ba9cf fix(v2): aligned stat grid + correct icons + action buttons
- Stats now use a 3-column CSS Grid so values align across rows
- Fixed icons: ☠️ for deaths (was 💀), prismatic-taper-icon.png
  for tapers (was wrong emoji 🔮), 🕐 for time (was 🕑)
- Added action buttons row (Chat, Stats, Inv, Char, Radar) matching
  v1's button bar — accent-colored for primary actions
- Buttons are present but not wired to windows yet (Phase 3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:46:47 +02:00
Erik
7890ab477f fix(v2): add emoji icons + labels to player row stats
Stats were bare numbers with no visual hint what they represent.
Now each stat has the same emoji prefix as v1:
  ⚔️ session kills, 🏆 total kills, KPH suffix
  💎 rares (session/total), 📊 KPR suffix
  🕑 online time, 💀 deaths, 🔮 prismatic tapers

Meta state pill still color-coded (green=active, gray=idle).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:42:39 +02:00
Erik
2c4b8d3afb feat(v2): Phase 1 — map-first layout matching v1
Rebuilds the v1 map-centric experience in React:

Layout:
- 400px sidebar on left, interactive map on right (flex, 100vh)
- Exact same proportions and dark theme as v1

Sidebar (top→bottom):
- Header with active player count + Dashboard toggle button
- Server status dot (Coldeve online/offline with pulse)
- Aggregate counters: Rares (gold), Server KPH (blue glow), Kills (red)
- 6 sort buttons (Name, KPH, S.Kills, S.Rares, T.Kills, KPR)
- Player name filter
- Scrollable player list with per-row:
  - Name + coordinates
  - HP/Stamina/Mana vital bars (red/orange/blue gradients)
  - Session kills, total kills, KPH
  - Session rares, total rares, VTank meta state pill
  - Online time, deaths, prismatic tapers
  - Color-coded left border per player

Map:
- dereth.png with CSS transform pan (drag) + zoom (wheel, 1.1x factor, max 20x)
- Player dots (6px circles, color-matched to sidebar)
- Hover tooltip (name, coords, kph, kills)
- World coordinate display at cursor position
- Fit-to-window on first load

View toggle: Map View ↔ Dashboard with localStorage persistence.
All v1 CSS ported under ml-* prefix, scoped via map-layout.css.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:38:14 +02:00
Erik
3791c01bf3 feat(v2): Phase 2 — analytics tabs (Combat, Rares, Map, Inventory)
Below the character cards grid, adds four tabbed analytics sections:

Combat Tab (Recharts):
- Kills per hour horizontal bar chart (all characters, sorted)
- Total damage session bar chart
- Damage by element pie chart (aggregated across all characters)

Rares Tab:
- Summary cards: total rares, total kills, drop rate (1 in N)
- Recent rare drops timeline (from WebSocket events)
- Rares per character lifetime bar chart

Map Tab:
- Dereth map (dereth_highres.png) with SVG overlay
- Character position dots (green=hunting, yellow=other)
- Hover to see character name + coordinates
- Responsive, maintains aspect ratio

Inventory Tab:
- Cross-character item search with debounced input
- Results table: character, item, type, material, set, workmanship
- Powered by existing /search/items API

All tabs lazy-rendered (only active tab mounts). Horizontal scroll
tab bar on mobile. Dark theme consistent with cards.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:14:50 +02:00
Erik
69ead07051 fix(v2): recognize Hunt/Default VTank states + show unknown states
vt_state values from plugins include "Hunt", "combat", "Default",
"turn_in_quests" etc. Previously only "combat" showed as green badge,
everything else was "Idle". Now Hunt shows green, unknown states show
their actual name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:10:35 +02:00
Erik
e58c05c895 feat: v2 dashboard — React + Vite parallel implementation
New modern dashboard at /v2 running alongside the existing UI at /.
Same backend, same APIs, same WebSocket — zero backend changes.

Stack: React 19 + Vite + TypeScript + Recharts
Source: frontend/ — build output: static/v2/

Phase 1 delivers:
- Character overview cards in a responsive CSS Grid
  - Live HP/Stamina/Mana bars via WebSocket vitals
  - Kills/hr, total kills, deaths, session uptime
  - VTank state badge (Combat/Nav/Idle)
  - Location coordinates
  - Click to expand: combat stats, prismatic count, CPU/RAM
- Global stats header: active chars, total kills, total rares, server health
- WebSocket hook with auto-reconnect
- HTTP poll fallback for initial load + server health
- Mobile responsive (single column on narrow screens)
- Dark theme matching the MosswartOverlord palette

Build: cd frontend && npm run build
Access: /v2 (served by existing NoCacheStaticFiles mount)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:07:11 +02:00
Erik
ee30ad2636 fix(combat): show offense + defense damage by element in grid
The element breakdown grid previously only showed damage RECEIVED
(defense) in the Mel/Msl and Magic columns, which was mostly empty
for characters who evade/resist everything. Now shows both:

- Given M/M + Given Mag: damage dealt by element (offense)
- Recv M/M + Recv Mag: damage taken by element (defense)

This makes the element breakdown immediately useful — you can see
that you're dealing Slash damage via melee, for example.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:13:47 +02:00
Erik
c03b1c19f2 feat: combat stats backend + frontend (Mag-Tools style)
Backend:
- db_async.py: new combat_stats + combat_stats_sessions tables
- main.py: combat_stats message handler with DB upsert (lifetime +
  session snapshots), in-memory live_combat_stats dict, broadcast
  to browser clients.
- REST: GET /combat-stats and GET /combat-stats/{character_name}

Frontend:
- index.html: new "Combat Stats" sidebar link
- script.js: full Combat Stats window with two panels:
  - Top: monster list (name, kills, dmg recv, dmg given) with
    clickable rows and "All" aggregate, matching CombatTrackerGUI.cs
  - Bottom: damage breakdown grid matching CombatTrackerGUIInfo.cs
    layout — element × attack type matrix (Mel/Msl + Magic columns),
    Attacks (hit%), Evades (%), Resists (%), A.Surges (%), C.Surges (%),
    normal Avg/Max, Crits (%), Crit Avg/Max, Total Damage.
  - Session / Lifetime toggle button
- style.css: combat-stats-toggle styles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:42:11 +02:00
Erik
da4e840581 fix(vitalsharing): clear stopped peers from the NetworkUI window
Peers who unsubscribed or disconnected from vital sharing were lingering
forever in the Vital Sharing browser window because nothing ever deleted
them from the server-side state or told the browser to drop them.

Backend:
- share_unsubscribe now pops the character from _vital_sharing_peer_state
  (not just flips connected=false) and broadcasts a share_peer_removed
  envelope to browser clients.
- On real plugin disconnect, do the same: pop the state entry and
  broadcast share_peer_removed so the NetworkUI updates immediately.

Frontend:
- New removeVitalSharingPeer(name) deletes from the local
  vitalSharingPeers dict and re-renders.
- socket.onmessage now routes share_peer_removed to it.
- refreshVitalSharingPeers() reconciles against the server's list and
  prunes any local entries the server no longer knows about, catching
  any race where the broadcast was missed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 15:25:08 +02:00
Erik
7a31469d69 fix(vitalsharing): don't evict subscribers on transient send failures
_broadcast_share_to_plugin_clients was discarding a character from
_vital_sharing_subscribers whenever a single send_json hit the 1-second
timeout or raised any exception. Under heavy load this permanently
dropped clients from the subscriber set even though their WebSocket was
still fully connected — the user had to toggle vital sharing off and on
to get peer updates flowing again.

Now we log the send failure but leave the subscriber intact. Actual
eviction still happens on real WebSocket disconnect via the finally
block in the plugin receive loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 15:14:37 +02:00
Erik
2b521d1df5 fix(vitalsharing): match sidebar colors for HP/STA/MANA bars
Previously the NetworkUI window used #c44/#4c4/#46c which rendered
stamina as green. Updated to the gradients used in .vital-fill.* in
style.css (#ff4444, #ffaa00, #4488ff) so the network UI matches the
player sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 14:33:23 +02:00
Erik
1973aa1547 feat: relay cross-machine vital/debuff sharing for MosswartMassacre
Accepts new share_subscribe / share_unsubscribe / share_* WebSocket
messages from MM plugin clients and fans them out to other opted-in
plugin clients (excluding origin) and to browser clients for the
NetworkUI window.

- main.py: _vital_sharing_subscribers set, _vital_sharing_peer_state
  snapshot, _broadcast_share_to_plugin_clients relay, disconnect
  cleanup, GET /vital-sharing/peers endpoint.
- static/index.html: new sidebar link for Vital Sharing window.
- static/script.js: showVitalSharingWindow with live HP/STA/MANA bars,
  per-peer status dot/tags/position, 5s /vital-sharing/peers poll, and
  share_* routing through the existing browser WebSocket handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 14:19:41 +02:00
Erik
52d57c9121 Security hardening: HTML sanitization, WS auth, rate limiting, constant-time login 2026-04-10 20:40:09 +02:00
Erik
8f681398ee Fix login page: allow /icons/ through auth middleware, match color scheme to AC logo 2026-04-10 20:07:06 +02:00
Erik
9f49038107 Redesign login page: AC logo, side-by-side fields, fading Alex time quotes 2026-04-10 20:04:17 +02:00
Erik
6e090eb4dc Fix bcrypt incompatibility: replace passlib with direct bcrypt 5.x API 2026-04-10 19:55:55 +02:00
Erik
b09169ade2 feat: add app-level authentication with login, session cookies, and admin panel
Replace Nginx basic auth with proper user accounts:
- Session cookies via itsdangerous (30-day expiry, httponly, secure)
- Password hashing with bcrypt via passlib
- Login page with AC-themed UI
- Admin page for user management (CRUD)
- AuthMiddleware exempts plugin WS and browser WS endpoints
- Issues/comments author auto-populated from session
- Sidebar shows logged-in username, admin link, and logout
- Seed users: erik (admin), alex, lundberg
- SECRET_KEY env var for cookie signing
2026-04-10 19:45:08 +02:00
Erik
fac5063878 feat: show issue comments inline without toggle 2026-04-10 17:44:52 +02:00
Erik
f96171a345 feat: issues board - add submitter name, comments, and edit support 2026-04-10 17:36:08 +02:00
Erik
21e72b438f fix: use content-type instead of path for no-cache detection
Root "/" path doesn't match .html ending. Checking the response's
content-type header catches index.html served via html=True and is
more robust for any URL that returns HTML/JS/CSS/JSON.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:59:03 +02:00
Erik
4fe0977b71 fix: also apply no-cache to root path serving index.html
The StaticFiles path is empty for root "/" which served index.html via
html=True. Include root/directory paths in the no-cache match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:58:13 +02:00
Erik
994bc618db fix: force browser revalidation for JS/CSS/HTML static files
FastAPI StaticFiles sets Last-Modified/ETag but no Cache-Control, so
browsers use heuristic caching and can serve stale code after git pull.

Subclass StaticFiles to add 'Cache-Control: no-cache, must-revalidate'
on .html/.js/.css/.json files. ETag/Last-Modified still work, so
revalidation returns efficient 304 Not Modified when unchanged.

Other assets (images, fonts, tile textures) are unaffected and cache
normally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:57:00 +02:00
Erik
604d4376b4 feat: two-step issue resolution (resolve then delete)
- New PATCH /issues/{id} endpoint to toggle resolved flag
- Add resolved:false to new issues
- Frontend: click "✓ Resolve" marks issue green with strikethrough
- Resolved issues show "↺ Reopen" and "🗑 Delete" buttons
- Delete requires confirmation
- Sort: unresolved first, then resolved
- Issues persist until explicitly deleted

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:48:20 +02:00
Erik
f2b43fce0b fix: store openissues.json in bind-mounted static/ dir
Was stored at /app/openissues.json (ephemeral container filesystem).
Moved to /app/static/openissues.json which is bind-mounted to the
host at ./static/, persisting across container rebuilds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:32:28 +02:00
Erik
80cfbfdfca fix: compact player sidebar layout for 5 buttons
- Add buttons as 6th grid row instead of extra element below grid
- Reduce stat pill padding and font size (4px→2px, 0.75rem→0.7rem)
- Reduce grid gap (6px→4px row, 12px→8px col) and item padding
- Unify all 5 button styles (Chat/Stats/Inventory/Char/Radar) with
  shared compact sizing, individual colors preserved
- flex-wrap on buttons container as safety for narrow sidebars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:52:46 +02:00
Erik
ee775a7e71 style: move version to top-left corner, white text
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 13:07:47 +02:00
Erik
38ca6ead12 feat: version display + issues board
Version: CalVer + git hash shown in top-right corner of main page.
Built via Docker ARG BUILD_VERSION at build time. Served via /api-version.

Issues Board: shared notepad window for tracking issues with plugin,
overlord, nav files, macros. Stored in openissues.json on server.
- GET/POST/DELETE /issues endpoints
- Draggable window matching Chat/Radar pattern
- Category tags (plugin, overlord, nav, macro, other) with colors
- Add/resolve issues through the UI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:53:06 +02:00
Erik
c4856dc701 feat: compute base item values by reversing active spell buffs
Extract spell effect mappings from Dictionaries.cs into spell_effects.json.
During item ingestion, compute_base_values() reverses active enchantment
effects to get true base stats:
- base_armor_level: armor without Impenetrability buffs
- base_max_damage: damage without Blood Drinker buffs
- base_attack_bonus: attack without Heart Seeker buffs
- base_melee_defense_bonus: defense without Defender buffs
- base_elemental_damage_vs_monsters: elemental without Spirit Drinker
- base_mana_conversion_bonus: mana conv without Hermetic Link

New columns in ItemCombatStats, exposed in search CTEs.
Frontend: Base Armor and Base Dmg columns (hidden by default, toggle on).
Requires ALTER TABLE migration before deploy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:31:39 +02:00
Erik
77e5a544d1 fix: restore sort click to full th area, not just label span
Sort listener was on .th-label span only, making clickable area too
small. Moved back to full .sortable th element. The × hide button
already uses stopPropagation so it won't trigger sort.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:28:28 +02:00
Erik
84d651ac44 fix: filter garbage weapon_time values (67108882 is flag data, not speed)
Some unidentified items have IntValues[218103835] = 67108882 which is
a bitmask/flags value, not weapon speed. Cap at 100 in extraction and
filter >100 in frontend display. AC weapon speed is typically 0-50.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:18:00 +02:00