import type { JsonObject } from "./editorCore"; export const WORLD_INDEX_SCHEMA_VERSION = 1; export const WORLD_SCHEMA_VERSION = 1; export const WORLD_CHUNK_SCHEMA_VERSION = 1; export const WORLD_BOOKMARKS_SCHEMA_VERSION = 1; export const DEFAULT_WORLD_CHUNK_SIZE = 32; export const DEFAULT_WORLD_TILE_SIZE = 32; export type WorldIndexEntry = { id: string; name: string; worldDir: string; }; export type WorldIndexPayload = { schemaVersion: number; worlds: WorldIndexEntry[]; }; export type WorldBookmark = { id: string; label: string; x: number; y: number; }; export type WorldBookmarksPayload = { schemaVersion: number; worldId: string; bookmarks: WorldBookmark[]; }; export type WorldDefinition = { schemaVersion: number; id: string; name: string; chunkWidth: number; chunkHeight: number; tileSize: number; defaultBackgroundTileId: string; spawn: { x: number; y: number }; editor?: { defaultZoom?: number; gridVisible?: boolean; }; }; export type WorldChunkLayer = { layer: number; name?: string; rows: string[]; instanceIds: string[]; }; export type WorldHeightPatch = { id: string; name?: string; z: number; x: number; y: number; rows: string[]; }; export type WorldChunkInstance = { id: string; templateId?: string; layer: number; x: number; y: number; record: JsonObject; }; export type WorldChunk = { schemaVersion: number; worldId: string; chunkX: number; chunkY: number; width: number; height: number; backgroundTileId: string; roomLayers: WorldChunkLayer[]; heightLayers: WorldHeightPatch[]; instances: WorldChunkInstance[]; }; export function normalizeChunkDimension(value: unknown, fallback = DEFAULT_WORLD_CHUNK_SIZE): number { return Math.max(1, Math.floor(Number(value) || fallback)); } export function buildChunkKey(chunkX: number, chunkY: number): string { return `${Math.floor(chunkX)}:${Math.floor(chunkY)}`; } export function buildChunkFileName(chunkX: number, chunkY: number): string { return `${Math.floor(chunkX)}_${Math.floor(chunkY)}.json`; } export function worldToChunkCoord(worldCoord: number, chunkSize: number): number { const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE)); return Math.floor(Number(worldCoord) / safeChunkSize); } export function worldToLocalCoord(worldCoord: number, chunkSize: number): number { const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE)); const chunkCoord = worldToChunkCoord(worldCoord, safeChunkSize); return Math.floor(Number(worldCoord) - (chunkCoord * safeChunkSize)); } export function localToWorldCoord(chunkCoord: number, localCoord: number, chunkSize: number): number { const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE)); return (Math.floor(Number(chunkCoord) || 0) * safeChunkSize) + Math.floor(Number(localCoord) || 0); } export function resolveWorldChunkAddress(worldX: number, worldY: number, chunkWidth: number, chunkHeight: number) { const safeChunkWidth = normalizeChunkDimension(chunkWidth); const safeChunkHeight = normalizeChunkDimension(chunkHeight); const chunkX = worldToChunkCoord(worldX, safeChunkWidth); const chunkY = worldToChunkCoord(worldY, safeChunkHeight); const localX = worldToLocalCoord(worldX, safeChunkWidth); const localY = worldToLocalCoord(worldY, safeChunkHeight); return { chunkX, chunkY, localX, localY, chunkKey: buildChunkKey(chunkX, chunkY), fileName: buildChunkFileName(chunkX, chunkY), }; } export function createEmptyChunk(worldId: string, chunkX: number, chunkY: number, backgroundTileId = "", chunkWidth = DEFAULT_WORLD_CHUNK_SIZE, chunkHeight = DEFAULT_WORLD_CHUNK_SIZE): WorldChunk { const width = normalizeChunkDimension(chunkWidth); const height = normalizeChunkDimension(chunkHeight); return { schemaVersion: WORLD_CHUNK_SCHEMA_VERSION, worldId: String(worldId || "").trim(), chunkX: Math.floor(Number(chunkX) || 0), chunkY: Math.floor(Number(chunkY) || 0), width, height, backgroundTileId: String(backgroundTileId || "").trim(), roomLayers: [ { layer: 0, rows: Array.from({ length: height }, () => ".".repeat(width)), instanceIds: [], }, { layer: 1, rows: Array.from({ length: height }, () => " ".repeat(width)), instanceIds: [], }, ], heightLayers: [], instances: [], }; }