import type { SanitizedConfig } from "payload"; import { getPayload } from "payload"; import type { GameStructure, GameVehicle, Shipment, Vehicle } from "@/payload-types"; import { processShipmentTick } from "./processShipmentTick"; import { processConstructionTick } from "@/lib/map/construction"; import { createBinLogger, errorMessage } from "./lib/binFileLogger"; import { emitGameEvent } from "@/utils/event-log/emit"; import { EventTypes } from "@/utils/event-log/eventTypes"; export const script = async (config: SanitizedConfig) => { const payload = await getPayload({ config }); const log = createBinLogger("game-tick", payload.logger); try { log.info("[Game Tick] Starting game tick..."); const activeShipments = await payload.find({ collection: "shipments", where: { status: { in: ["dispatched", "in_transit"] }, }, limit: 100, depth: 2, }); let processedCount = 0; for (const shipment of activeShipments.docs) { try { await processShipmentTick( payload, shipment as unknown as Shipment & { transportVehicle: GameVehicle & { type: Vehicle }; origin: GameStructure; destination: GameStructure; }, log, ); processedCount++; } catch (error) { log.error(`[Game Tick] Error processing shipment ${shipment.id}: ${errorMessage(error)}`); } } const construction = await processConstructionTick(payload, log); await emitGameEvent(payload, { type: EventTypes.GameTick, message: `Game tick processed ${processedCount} of ${activeShipments.docs.length} active shipments`, data: { processedCount, totalActive: activeShipments.docs.length, construction, }, }); const notifyUrl = (process.env.APP_URL ?? "http://localhost:3000").replace(/\/$/, ""); const notifySecret = process.env.GAME_TICK_NOTIFY_SECRET; if (notifySecret) { await fetch(`${notifyUrl}/api/game-tick/notify`, { method: "POST", headers: { "content-type": "application/json", "x-game-tick-secret": notifySecret, }, body: JSON.stringify({ processedAt: new Date().toISOString() }), }).catch((error: unknown) => { log.error(`[Game Tick] Failed to notify app clients: ${errorMessage(error)}`); }); } else { log.warn("[Game Tick] GAME_TICK_NOTIFY_SECRET not set; skipping client notification"); } log.info(`[Game Tick] Complete. Processed ${processedCount} shipments.`); process.exit(0); } catch (error) { log.error( `[Game Tick] Fatal: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`, ); process.exit(1); } };