albion/server/src/gamedata/download.ts
Заид Омар Медхат 7ba275dd77 Phase 1: scaffold + game data ingestion
npm workspaces (Fastify+TS server, Vite+React web), SQLite schema,
ao-bin-dumps downloader and parser (items, recipes, enchant upgrades,
EN localization), item browser UI and debug API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 02:53:19 +05:00

51 lines
1.8 KiB
TypeScript

import fs from 'node:fs';
import path from 'node:path';
import { pipeline } from 'node:stream/promises';
import { Readable } from 'node:stream';
import { AO_BIN_DUMPS_BASE, GAMEDATA_DIR } from '../config.js';
/** Files pulled from ao-data/ao-bin-dumps. Add zone/world files in the travel phase. */
export const GAMEDATA_FILES = [
{ remote: 'items.json', local: 'items.json' },
{ remote: 'formatted/items.json', local: 'items_localized.json' },
] as const;
export function gamedataFilePath(local: string): string {
return path.join(GAMEDATA_DIR, local);
}
async function downloadFile(remote: string, dest: string): Promise<void> {
const url = `${AO_BIN_DUMPS_BASE}/${remote}`;
const res = await fetch(url);
if (!res.ok || !res.body) {
throw new Error(`Download failed for ${url}: HTTP ${res.status}`);
}
fs.mkdirSync(path.dirname(dest), { recursive: true });
const tmp = `${dest}.download`;
await pipeline(Readable.fromWeb(res.body as import('node:stream/web').ReadableStream), fs.createWriteStream(tmp));
fs.renameSync(tmp, dest);
}
export interface DownloadResult {
file: string;
status: 'downloaded' | 'cached';
bytes: number;
}
/**
* Ensure all game data files exist locally. With force=true, re-download everything
* (used by the "refresh game data" action after a game patch).
*/
export async function downloadGameData(force = false): Promise<DownloadResult[]> {
const results: DownloadResult[] = [];
for (const f of GAMEDATA_FILES) {
const dest = gamedataFilePath(f.local);
if (!force && fs.existsSync(dest)) {
results.push({ file: f.local, status: 'cached', bytes: fs.statSync(dest).size });
continue;
}
await downloadFile(f.remote, dest);
results.push({ file: f.local, status: 'downloaded', bytes: fs.statSync(dest).size });
}
return results;
}