diff --git a/packages/client/src/renderer/client/client.ts b/packages/client/src/renderer/client/client.ts index ff54ad4..2508575 100644 --- a/packages/client/src/renderer/client/client.ts +++ b/packages/client/src/renderer/client/client.ts @@ -263,11 +263,19 @@ async function obtainGameClient() { const settleTimer = setInterval(() => { const modules = (window as any).__eqSourceModules; const count = Array.isArray(modules) ? modules.length : 0; + // Readiness signal: the GameManager bundle is present in the captured source. + // We used to gate on window.gm, but EvilQuest's bundle update STOPPED assigning + // window.gm (it's no longer a global), so that gate never opened -> the Reflector + // never parsed -> zero hooks -> dead client. GameManager's source still ships its + // distinctive method, so detect that instead (window.gm-independent). Keep the + // window.gm OR as a fast-path in case it ever comes back. + const gmReady = (window as any).gm + || (Array.isArray(modules) && modules.some((m: string) => typeof m === 'string' && m.includes('waitForCurrentLocalPlayerReady'))); if (count === lastCount && count > 0) { stableTicks++; - if (stableTicks >= 3 && !(window as any).__eqHooksBound && (window as any).gm && count > lastParsedCount) { + if (stableTicks >= 3 && !(window as any).__eqHooksBound && gmReady && count > lastParsedCount) { lastParsedCount = count; - console.log('[EvilLite] Parsing at', count, 'modules (game core ready)...'); + console.log('[EvilLite] Parsing at', count, 'modules (GameManager source present)...'); runReflectorParse(); } } else { diff --git a/packages/client/src/renderer/client/plugins/CollectionLogPlugin.ts b/packages/client/src/renderer/client/plugins/CollectionLogPlugin.ts index e00b48d..4c2869a 100644 --- a/packages/client/src/renderer/client/plugins/CollectionLogPlugin.ts +++ b/packages/client/src/renderer/client/plugins/CollectionLogPlugin.ts @@ -257,12 +257,14 @@ export default class CollectionLogPlugin extends Plugin { private itemDef(itemId: number): any { return this.em?.itemDefsCache?.get(itemId) ?? null; } private itemName(itemId: number): string { return (this.itemDef(itemId)?.name ?? `Item #${itemId}`) + ''; } /** The item's icon, matching what the inventory shows: its 2D icon if it ships one, otherwise - * the data-URL the game rendered from the item's 3D model (harvested from the live inventory — - * there is no static URL for those; `items/3d/.png` 404s). '' if we've never seen it. */ + * EvilQuest's server-rendered 3D icon at `items/3d/.png`. The game now serves these for + * every item (the inventory renders model-only items from exactly this URL) — they used to + * 404, which is why we previously had to harvest the inventory data-URL. A harvested data-URL, + * if we cached one, takes precedence (it's the exact inventory render). '' only if no id. */ private itemIcon(itemId: number): string { const ic = this.itemDef(itemId)?.icon; if (ic) return ICON_BASE + encodeURIComponent(ic); - return this.data.itemIcons?.[itemId] || ''; + return this.data.itemIcons?.[itemId] || (itemId ? `${ICON_BASE}3d/${itemId}.png` : ''); } // ── source identity / icons ───────────────────────────────────────────────