diff --git a/.gitignore b/.gitignore index 587bbcb..e958ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ node_modules/ !/src/libs/sqljsfork/dist/ .vscode/ /cache*/ -/extract/ +/extract*/ *.code-workspace .* *.sqlite3 diff --git a/generated/maprenderconfig.schema.json b/generated/maprenderconfig.schema.json new file mode 100644 index 0000000..f8da683 --- /dev/null +++ b/generated/maprenderconfig.schema.json @@ -0,0 +1,100 @@ +{ + "properties": { + "layers": { + "items": { + "properties": { + "mode": { + "type": "string", + "enum": [ + "3d", + "map", + "height", + "collision", + "locs", + "maplabels", + "rendermeta", + "minimap" + ] + }, + "name": { + "type": "string" + }, + "pxpersquare": { + "type": "number" + }, + "level": { + "type": "number" + }, + "format": { + "type": "string", + "enum": [ + "png", + "webp" + ] + }, + "usegzip": { + "type": "boolean" + }, + "subtractlayers": { + "items": { + "type": "string" + } + }, + "dxdy": { + "type": "number" + }, + "dzdy": { + "type": "number" + }, + "wallsonly": { + "type": "boolean" + } + }, + "required": [ + "mode", + "name", + "level", + "pxpersquare" + ] + } + }, + "tileimgsize": { + "type": "number" + }, + "mapsizex": { + "type": "number" + }, + "mapsizez": { + "type": "number" + }, + "area": { + "default": "full", + "description": "A string representing the the map area to render. Either one of the named presets (main, full, test ...), or one or more chunk ranges. eg: 50.50,20.20-70.70", + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+\\.\\d+(-\\d+\\.\\d+)?(,\\d+\\.\\d+(-\\d+\\.\\d+)?)*$" + }, + { + "type": "string", + "enum": [ + "main", + "full", + "test" + ] + }, + { + "type": "string", + "pattern": "^\\w+$" + } + ] + } + }, + "required": [ + "layers", + "tileimgsize", + "mapsizex", + "mapsizez", + "area" + ] +} \ No newline at end of file diff --git a/src/buildfiletypes.ts b/src/buildfiletypes.ts index 5f725e0..c9f24eb 100644 --- a/src/buildfiletypes.ts +++ b/src/buildfiletypes.ts @@ -2,11 +2,13 @@ import * as fs from "fs"; import * as path from "path"; import * as opcode_reader from "./opcode_reader"; import * as commentjson from "comment-json"; - +import { maprenderConfigSchema } from "./jsonschemas"; async function buildFileTypes() { let basedir = path.resolve("./src/opcodes"); let outdir = path.resolve("./generated"); + + //generate config file metas let files = fs.readdirSync(basedir); if (files.some(f => !path.basename(f).match(/\.jsonc?$/))) { console.error("non-json files matched, is path wrong?"); @@ -35,6 +37,8 @@ async function buildFileTypes() { fs.writeFileSync(outfile, typesfile); } + //other one off files + fs.writeFileSync(path.resolve(outdir, "maprenderconfig.schema.json"), JSON.stringify(maprenderConfigSchema, undefined, "\t")); } buildFileTypes(); \ No newline at end of file diff --git a/src/jsonschemas.ts b/src/jsonschemas.ts index 9efa95e..3d8e113 100644 --- a/src/jsonschemas.ts +++ b/src/jsonschemas.ts @@ -173,7 +173,15 @@ export const maprenderConfigSchema: JSONSchema6 = { tileimgsize: number, mapsizex: number, mapsizez: number, - area: string + area: { + default: "full", + description: "A string representing the the map area to render. Either one of the named presets (main, full, test ...), or one or more chunk ranges. eg: 50.50,20.20-70.70", + anyOf: [ + { type: "string", pattern: /^\d+\.\d+(-\d+\.\d+)?(,\d+\.\d+(-\d+\.\d+)?)*$/.source }, + { type: "string", enum: ["main", "full", "test"] }, + { type: "string", pattern: /^\w+$/.source }, + ] + } }, required: ["layers", "tileimgsize", "mapsizex", "mapsizez", "area"] } \ No newline at end of file diff --git a/src/scripts/dependencies.ts b/src/scripts/dependencies.ts index a299aaf..f8c304b 100644 --- a/src/scripts/dependencies.ts +++ b/src/scripts/dependencies.ts @@ -9,6 +9,8 @@ import { crc32, crc32addInt } from "../libs/crc32util"; import { arrayEnum, trickleTasksTwoStep, trickleTasks } from "../utils"; import { EngineCache, iterateConfigFiles } from "../3d/modeltothree"; import { legacyMajors, legacyGroups } from "../cache/legacycache"; +import { mapsquare_overlays } from "../../generated/mapsquare_overlays"; +import { mapsquare_underlays } from "../../generated/mapsquare_underlays"; const depids = arrayEnum(["material", "model", "item", "loc", "mapsquare", "sequence", "skeleton", "frameset", "animgroup", "npc", "framebase", "texture", "enum", "overlay", "underlay"]); const depidmap = Object.fromEntries(depids.map((q, i) => [q, i])); @@ -51,7 +53,7 @@ function chunkDeps(data: ChunkData, addDep: DepCallback, addHash: HashCallback) } //set iterators are same as insertion order according to the spec overlays.forEach(id => addDep("overlay", id, "mapsquare", squareindex)); - underlays.forEach(id => addDep("overlay", id, "mapsquare", squareindex)); + underlays.forEach(id => addDep("underlay", id, "mapsquare", squareindex)); } const mapsquareDeps2: DepCollector = async (cache, addDep, addHash, args) => { @@ -68,27 +70,41 @@ const mapsquareDeps2: DepCollector = async (cache, addDep, addHash, args) => { }); } +function coltoint(col: number[] | undefined | null) { + if (!col) { return 0xff00ff; } + return col[0] << 16 | col[1] << 8 | col[2]; +} + +function hashFloorType(lay: mapsquare_overlays & mapsquare_underlays, hash: number) { + hash = crc32addInt(+!!lay.bleedToUnderlay, hash); + hash = crc32addInt(lay.bleedpriority ?? -1, hash); + hash = crc32addInt(lay.materialbyte ?? lay.material ?? -1, hash); + hash = crc32addInt(coltoint(lay.color), hash); + hash = crc32addInt(coltoint(lay.secondary_colour), hash); + hash = crc32addInt(coltoint(lay.tertiary_colour), hash); + hash = crc32addInt(lay.material_tiling ?? -1, hash); + return hash; +} + const mapUnderlayDeps: DepCollector = async (cache, addDep, addHash) => { for (let [id, underlay] of cache.mapUnderlays.entries()) { if (!underlay) { continue; } - //the original underlay file may not even exist in some versions, just rebuild one for the hash - //its actually an overlay config in legacy caches - let rebuiltfile = (cache.legacyData ? parse.mapsquareOverlays : parse.mapsquareUnderlays).write(underlay); - let crc = crc32(rebuiltfile); + + let crc = hashFloorType(underlay, 0); addHash("underlay", id, crc, 0); if (underlay.material) { addDep("material", underlay.material, "underlay", id); } } } + const mapOverlayDeps: DepCollector = async (cache, addDep, addHash) => { for (let [id, overlay] of cache.mapOverlays.entries()) { if (!overlay) { continue; } //the original overlay file may not even exist in some versions, just rebuild one for the hash - let rebuiltfile = parse.mapsquareOverlays.write(overlay); - let crc = crc32(rebuiltfile); + let crc = hashFloorType(overlay, 0); if (overlay.material) { - addDep("material", overlay.material, "underlay", id); + addDep("material", overlay.material, "overlay", id); } addHash("overlay", id, crc, 0); }