finished up grid detection.

This commit is contained in:
Boki 2026-02-10 17:29:37 -05:00
parent 41d174195e
commit 1246884be9
11 changed files with 1037 additions and 19 deletions

157
src/game/GridReader.ts Normal file
View file

@ -0,0 +1,157 @@
import { logger } from '../util/logger.js';
import type { OcrDaemon } from './OcrDaemon.js';
import type { Region } from '../types.js';
// ── Grid type definitions ───────────────────────────────────────────────────
export interface GridLayout {
region: Region;
cols: number;
rows: number;
}
export interface CellCoord {
row: number;
col: number;
x: number;
y: number;
}
export interface ScanResult {
layout: GridLayout;
occupied: CellCoord[];
}
// ── Calibrated grid layouts (2560×1440) ─────────────────────────────────────
export const GRID_LAYOUTS: Record<string, GridLayout> = {
/** Player inventory — always 12×5, right side (below equipment slots) */
inventory: {
region: { x: 1696, y: 788, width: 840, height: 350 },
cols: 12,
rows: 5,
},
/** Personal stash 12×12 — left side, tab not in folder */
stash12: {
region: { x: 23, y: 169, width: 840, height: 840 },
cols: 12,
rows: 12,
},
/** Personal stash 12×12 — left side, tab in folder */
stash12_folder: {
region: { x: 23, y: 216, width: 840, height: 840 },
cols: 12,
rows: 12,
},
/** Personal stash 24×24 (quad tab) — left side, tab not in folder */
stash24: {
region: { x: 23, y: 169, width: 840, height: 840 },
cols: 24,
rows: 24,
},
/** Personal stash 24×24 (quad tab) — left side, tab in folder */
stash24_folder: {
region: { x: 23, y: 216, width: 840, height: 840 },
cols: 24,
rows: 24,
},
/** Seller's public stash — always 12×12 */
seller: {
region: { x: 416, y: 299, width: 840, height: 840 },
cols: 12,
rows: 12,
},
/** NPC shop — 12×12 */
shop: {
region: { x: 23, y: 216, width: 840, height: 840 },
cols: 12,
rows: 12,
},
/** NPC vendor inventory — 12×12 */
vendor: {
region: { x: 416, y: 369, width: 840, height: 840 },
cols: 12,
rows: 12,
},
};
// Backward-compat exports
export const INVENTORY = GRID_LAYOUTS.inventory;
export const STASH_12x12 = GRID_LAYOUTS.stash12;
export const STASH_24x24 = GRID_LAYOUTS.stash24;
export const SELLER_12x12 = GRID_LAYOUTS.seller;
// ── GridReader ──────────────────────────────────────────────────────────────
export class GridReader {
constructor(private daemon: OcrDaemon) {}
/**
* Scan a named grid layout for occupied cells.
*/
async scan(layoutName: string, threshold?: number): Promise<ScanResult> {
const layout = GRID_LAYOUTS[layoutName];
if (!layout) throw new Error(`Unknown grid layout: ${layoutName}`);
const t = performance.now();
const occupied = await this.getOccupiedCells(layout, threshold);
const ms = (performance.now() - t).toFixed(0);
logger.info(
{ layoutName, cols: layout.cols, rows: layout.rows, occupied: occupied.length, ms },
'Grid scan complete',
);
return { layout, occupied };
}
/** Get the screen-space center of a grid cell */
getCellCenter(layout: GridLayout, row: number, col: number): { x: number; y: number } {
const cellW = layout.region.width / layout.cols;
const cellH = layout.region.height / layout.rows;
return {
x: Math.round(layout.region.x + col * cellW + cellW / 2),
y: Math.round(layout.region.y + row * cellH + cellH / 2),
};
}
/** Scan the grid and return which cells are occupied */
async getOccupiedCells(layout: GridLayout, threshold?: number): Promise<CellCoord[]> {
const t = performance.now();
const cells = await this.daemon.gridScan(
layout.region,
layout.cols,
layout.rows,
threshold,
);
const occupied: CellCoord[] = [];
for (let row = 0; row < cells.length; row++) {
for (let col = 0; col < cells[row].length; col++) {
if (cells[row][col]) {
const center = this.getCellCenter(layout, row, col);
occupied.push({ row, col, x: center.x, y: center.y });
}
}
}
const ms = (performance.now() - t).toFixed(0);
logger.info(
{ layout: `${layout.cols}x${layout.rows}`, occupied: occupied.length, ms },
'Grid scan complete',
);
return occupied;
}
/** Get all cell centers in the grid */
getAllCells(layout: GridLayout): CellCoord[] {
const cells: CellCoord[] = [];
for (let row = 0; row < layout.rows; row++) {
for (let col = 0; col < layout.cols; col++) {
const center = this.getCellCenter(layout, row, col);
cells.push({ row, col, x: center.x, y: center.y });
}
}
return cells;
}
}