diff --git a/assets/chunks/-1_0_0.dcf b/assets/maps/overworld/chunks/-1_0_0.dcf similarity index 90% rename from assets/chunks/-1_0_0.dcf rename to assets/maps/overworld/chunks/-1_0_0.dcf index 268ee8d5..51344b70 100644 Binary files a/assets/chunks/-1_0_0.dcf and b/assets/maps/overworld/chunks/-1_0_0.dcf differ diff --git a/assets/chunks/0_0_0.dcf b/assets/maps/overworld/chunks/0_0_0.dcf similarity index 93% rename from assets/chunks/0_0_0.dcf rename to assets/maps/overworld/chunks/0_0_0.dcf index 79abf599..adbc2840 100644 Binary files a/assets/chunks/0_0_0.dcf and b/assets/maps/overworld/chunks/0_0_0.dcf differ diff --git a/assets/chunks/0_1_0.dcf b/assets/maps/overworld/chunks/0_1_0.dcf similarity index 90% rename from assets/chunks/0_1_0.dcf rename to assets/maps/overworld/chunks/0_1_0.dcf index 7742f4e8..5048d3e4 100644 Binary files a/assets/chunks/0_1_0.dcf and b/assets/maps/overworld/chunks/0_1_0.dcf differ diff --git a/assets/chunks/1_0_0.dcf b/assets/maps/overworld/chunks/1_0_0.dcf similarity index 87% rename from assets/chunks/1_0_0.dcf rename to assets/maps/overworld/chunks/1_0_0.dcf index f86048fe..ed0d0ba7 100644 Binary files a/assets/chunks/1_0_0.dcf and b/assets/maps/overworld/chunks/1_0_0.dcf differ diff --git a/assets/chunks/1_1_0.dcf b/assets/maps/overworld/chunks/1_1_0.dcf similarity index 90% rename from assets/chunks/1_1_0.dcf rename to assets/maps/overworld/chunks/1_1_0.dcf index 1c99c441..aca3ec24 100644 Binary files a/assets/chunks/1_1_0.dcf and b/assets/maps/overworld/chunks/1_1_0.dcf differ diff --git a/assets/chunks/2_0_0.dcf b/assets/maps/overworld/chunks/2_0_0.dcf similarity index 96% rename from assets/chunks/2_0_0.dcf rename to assets/maps/overworld/chunks/2_0_0.dcf index 3f0a7a65..61c16946 100644 Binary files a/assets/chunks/2_0_0.dcf and b/assets/maps/overworld/chunks/2_0_0.dcf differ diff --git a/assets/meshes/chunks/chunk_-1_0_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_-1_0_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_-1_0_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_-1_0_0_0.dmf diff --git a/assets/meshes/chunks/chunk_0_0_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_0_0_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_0_0_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_0_0_0_0.dmf diff --git a/assets/meshes/chunks/chunk_0_1_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_0_1_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_0_1_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_0_1_0_0.dmf diff --git a/assets/meshes/chunks/chunk_1_0_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_1_0_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_1_0_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_1_0_0_0.dmf diff --git a/assets/meshes/chunks/chunk_1_1_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_1_1_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_1_1_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_1_1_0_0.dmf diff --git a/assets/meshes/chunks/chunk_2_0_0_0.dmf b/assets/maps/overworld/meshes/chunks/chunk_2_0_0_0.dmf similarity index 100% rename from assets/meshes/chunks/chunk_2_0_0_0.dmf rename to assets/maps/overworld/meshes/chunks/chunk_2_0_0_0.dmf diff --git a/assets/models/chunks/chunk_-1_0_0_0.json b/assets/maps/overworld/models/chunks/chunk_-1_0_0_0.json similarity index 57% rename from assets/models/chunks/chunk_-1_0_0_0.json rename to assets/maps/overworld/models/chunks/chunk_-1_0_0_0.json index e2757646..7862dbc9 100644 --- a/assets/models/chunks/chunk_-1_0_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_-1_0_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_-1_0_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_-1_0_0_0.dmf", "color": [ 255, 255, diff --git a/assets/models/chunks/chunk_0_0_0_0.json b/assets/maps/overworld/models/chunks/chunk_0_0_0_0.json similarity index 57% rename from assets/models/chunks/chunk_0_0_0_0.json rename to assets/maps/overworld/models/chunks/chunk_0_0_0_0.json index 7715800a..6630678c 100644 --- a/assets/models/chunks/chunk_0_0_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_0_0_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_0_0_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_0_0_0_0.dmf", "color": [ 255, 255, diff --git a/assets/models/chunks/chunk_0_1_0_0.json b/assets/maps/overworld/models/chunks/chunk_0_1_0_0.json similarity index 57% rename from assets/models/chunks/chunk_0_1_0_0.json rename to assets/maps/overworld/models/chunks/chunk_0_1_0_0.json index e2da8643..bb3f33f7 100644 --- a/assets/models/chunks/chunk_0_1_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_0_1_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_0_1_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_0_1_0_0.dmf", "color": [ 255, 255, diff --git a/assets/models/chunks/chunk_1_0_0_0.json b/assets/maps/overworld/models/chunks/chunk_1_0_0_0.json similarity index 57% rename from assets/models/chunks/chunk_1_0_0_0.json rename to assets/maps/overworld/models/chunks/chunk_1_0_0_0.json index 1c5947f8..1e309aee 100644 --- a/assets/models/chunks/chunk_1_0_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_1_0_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_1_0_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_1_0_0_0.dmf", "color": [ 255, 255, diff --git a/assets/models/chunks/chunk_1_1_0_0.json b/assets/maps/overworld/models/chunks/chunk_1_1_0_0.json similarity index 57% rename from assets/models/chunks/chunk_1_1_0_0.json rename to assets/maps/overworld/models/chunks/chunk_1_1_0_0.json index b68b098c..1996649d 100644 --- a/assets/models/chunks/chunk_1_1_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_1_1_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_1_1_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_1_1_0_0.dmf", "color": [ 255, 255, diff --git a/assets/models/chunks/chunk_2_0_0_0.json b/assets/maps/overworld/models/chunks/chunk_2_0_0_0.json similarity index 57% rename from assets/models/chunks/chunk_2_0_0_0.json rename to assets/maps/overworld/models/chunks/chunk_2_0_0_0.json index 8b720701..0658252b 100644 --- a/assets/models/chunks/chunk_2_0_0_0.json +++ b/assets/maps/overworld/models/chunks/chunk_2_0_0_0.json @@ -1,5 +1,5 @@ { - "mesh": "meshes/chunks/chunk_2_0_0_0.dmf", + "mesh": "maps/overworld/meshes/chunks/chunk_2_0_0_0.dmf", "color": [ 255, 255, diff --git a/assetsraw/chunks/chunk_-1_0_0.json b/assetsraw/maps/overworld/chunks/chunk_-1_0_0.json similarity index 100% rename from assetsraw/chunks/chunk_-1_0_0.json rename to assetsraw/maps/overworld/chunks/chunk_-1_0_0.json diff --git a/assetsraw/chunks/chunk_0_0_0.json b/assetsraw/maps/overworld/chunks/chunk_0_0_0.json similarity index 100% rename from assetsraw/chunks/chunk_0_0_0.json rename to assetsraw/maps/overworld/chunks/chunk_0_0_0.json diff --git a/assetsraw/chunks/chunk_0_1_0.json b/assetsraw/maps/overworld/chunks/chunk_0_1_0.json similarity index 100% rename from assetsraw/chunks/chunk_0_1_0.json rename to assetsraw/maps/overworld/chunks/chunk_0_1_0.json diff --git a/assetsraw/chunks/chunk_1_0_0.json b/assetsraw/maps/overworld/chunks/chunk_1_0_0.json similarity index 100% rename from assetsraw/chunks/chunk_1_0_0.json rename to assetsraw/maps/overworld/chunks/chunk_1_0_0.json diff --git a/assetsraw/chunks/chunk_1_1_0.json b/assetsraw/maps/overworld/chunks/chunk_1_1_0.json similarity index 100% rename from assetsraw/chunks/chunk_1_1_0.json rename to assetsraw/maps/overworld/chunks/chunk_1_1_0.json diff --git a/assetsraw/chunks/chunk_2_0_0.json b/assetsraw/maps/overworld/chunks/chunk_2_0_0.json similarity index 100% rename from assetsraw/chunks/chunk_2_0_0.json rename to assetsraw/maps/overworld/chunks/chunk_2_0_0.json diff --git a/assetsraw/maps/overworld/map.json b/assetsraw/maps/overworld/map.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/assetsraw/maps/overworld/map.json @@ -0,0 +1 @@ +{} diff --git a/editor/client/public/map/map.js b/editor/client/public/map/map.js index 0693663c..0d883c12 100644 --- a/editor/client/public/map/map.js +++ b/editor/client/public/map/map.js @@ -345,12 +345,14 @@ return promise; } + const MAP_NAME = "overworld"; + function chunkPaths(x, y, z) { return { - raw: `assetsraw/chunks/chunk_${x}_${y}_${z}.json`, - dcf: `assets/chunks/${x}_${y}_${z}.dcf`, - terrainDmf: `assets/meshes/chunks/chunk_${x}_${y}_${z}_0.dmf`, - terrainModel: `assets/models/chunks/chunk_${x}_${y}_${z}_0.json`, + raw: `assetsraw/maps/${MAP_NAME}/chunks/chunk_${x}_${y}_${z}.json`, + dcf: `assets/maps/${MAP_NAME}/chunks/${x}_${y}_${z}.dcf`, + terrainDmf: `assets/maps/${MAP_NAME}/meshes/chunks/chunk_${x}_${y}_${z}_0.dmf`, + terrainModel: `assets/maps/${MAP_NAME}/models/chunks/chunk_${x}_${y}_${z}_0.json`, }; } @@ -767,7 +769,7 @@ async function buildChunkBrowseList() { const list = document.getElementById("chunkBrowseList"); list.innerHTML = ""; - const res = await apiLs("assetsraw/chunks"); + const res = await apiLs(`assetsraw/maps/${MAP_NAME}/chunks`); for(const entry of res.entries || []) { const m = entry.name.match(/^chunk_(-?\d+)_(-?\d+)_(-?\d+)\.json$/); if(!m) continue; diff --git a/editor/server/server.py b/editor/server/server.py index fe6d68db..8985ce34 100644 --- a/editor/server/server.py +++ b/editor/server/server.py @@ -209,7 +209,10 @@ class Handler(BaseHTTPRequestHandler): self.send_json({"error": "invalid chunk coordinates"}, 400) return - json_path = PROJECT_ROOT / "assetsraw" / "chunks" / f"chunk_{x}_{y}_{z}.json" + json_path = ( + PROJECT_ROOT / "assetsraw" / "maps" / "overworld" / "chunks" + / f"chunk_{x}_{y}_{z}.json" + ) if not json_path.is_file(): self.send_json({"error": "chunk json not found"}, 404) return diff --git a/src/dusk/rpg/overworld/map.c b/src/dusk/rpg/overworld/map.c index 01aa8944..baaffe16 100644 --- a/src/dusk/rpg/overworld/map.c +++ b/src/dusk/rpg/overworld/map.c @@ -28,7 +28,25 @@ void mapChunkLoadingSlotClear(chunk_t *chunk) { errorret_t mapInit() { memoryZero(&MAP, sizeof(map_t)); - MAP.loaded = true; + errorOk(); +} + +bool_t mapIsLoaded() { + return MAP.name[0] != '\0'; +} + +errorret_t mapSetMap(const char_t *map) { + assertNotNull(map, "mapSetMap: map name cannot be NULL"); + assertStrLenMax(map, MAP_NAME_MAX, "Map name too long"); + + if(mapIsLoaded()) { + for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { + mapChunkUnload(&MAP.chunks[i]); + } + } + + memoryZero(&MAP, sizeof(map_t)); + stringCopy(MAP.name, map, MAP_NAME_MAX); chunkindex_t i = 0; for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) { @@ -47,10 +65,6 @@ errorret_t mapInit() { errorOk(); } -bool_t mapIsLoaded() { - return MAP.loaded; -} - errorret_t mapPositionSet(const chunkpos_t newPos) { if(!mapIsLoaded()) errorThrow("No map loaded"); if(chunkPositionIsEqual(newPos, MAP.chunkPosition)) errorOk(); @@ -132,6 +146,7 @@ errorret_t mapDispose() { for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { mapChunkUnload(&MAP.chunks[i]); } + MAP.name[0] = '\0'; errorOk(); } @@ -203,10 +218,11 @@ errorret_t mapChunkLoad(chunk_t *chunk) { chunk->meshCount = 0; - char_t name[64]; + char_t name[MAP_FILE_PATH_MAX]; stringFormat( name, sizeof(name), - "chunks/%d_%d_%d.dcf", + "maps/%s/chunks/%d_%d_%d.dcf", + MAP.name, (int32_t)chunk->position.x, (int32_t)chunk->position.y, (int32_t)chunk->position.z @@ -241,10 +257,11 @@ void mapChunkLoadNext() { MAP.loadQueueCount--; MAP.loadingChunks[slot] = chunk; - char_t name[64]; + char_t name[MAP_FILE_PATH_MAX]; stringFormat( name, sizeof(name), - "chunks/%d_%d_%d.dcf", + "maps/%s/chunks/%d_%d_%d.dcf", + MAP.name, (int32_t)chunk->position.x, (int32_t)chunk->position.y, (int32_t)chunk->position.z diff --git a/src/dusk/rpg/overworld/map.h b/src/dusk/rpg/overworld/map.h index b9c48ae7..2a907ff0 100644 --- a/src/dusk/rpg/overworld/map.h +++ b/src/dusk/rpg/overworld/map.h @@ -12,12 +12,18 @@ #define MAP_FILE_PATH_MAX 128 +// Buffer size for a map's name, including the null terminator - so map +// names are at most 9 characters. +#define MAP_NAME_MAX 10 + // Number of chunks that may be mid-load (asset locked & awaiting onLoaded/ // onError) at the same time - everything past this waits in loadQueue. #define MAP_CHUNK_LOAD_CONCURRENCY 2 typedef struct map_s { - bool_t loaded; + // Name of the currently loaded map, or an empty string if none is + // loaded (see mapIsLoaded). + char_t name[MAP_NAME_MAX]; chunk_t chunks[MAP_CHUNK_COUNT]; chunk_t *chunkOrder[MAP_CHUNK_COUNT]; @@ -31,19 +37,30 @@ typedef struct map_s { extern map_t MAP; /** - * Initializes the map. - * + * Initializes the map subsystem. No map is loaded until mapSetMap is + * called. + * * @return An error code. */ errorret_t mapInit(); /** * Checks if a map is loaded. - * + * * @return true if a map is loaded, false otherwise. */ bool_t mapIsLoaded(); +/** + * Sets the active map by name, unloading the previously loaded map (if + * any) first, then starts loading the new map's chunks around chunk + * position (0, 0, 0). + * + * @param map The map's name, at most MAP_NAME_MAX - 1 characters. + * @return An error code. + */ +errorret_t mapSetMap(const char_t *map); + /** * Updates the map. * diff --git a/src/dusk/rpg/rpg.c b/src/dusk/rpg/rpg.c index 2a8fef40..59ae98ad 100644 --- a/src/dusk/rpg/rpg.c +++ b/src/dusk/rpg/rpg.c @@ -31,10 +31,9 @@ errorret_t rpgInit(void) { cutsceneSystemInit(); errorChain(mapInit()); rpgCameraInit(); - // Init test world - errorChain(mapPositionSet((chunkpos_t){ 0, 0, 0 })); + errorChain(mapSetMap("overworld")); // The player is the one entity that isn't sourced from map/chunk data - // every other entity (NPCs, items) and map area comes from the loaded diff --git a/test/rpg/entity/entitytestfixture.c b/test/rpg/entity/entitytestfixture.c index acbbe5f7..bbc9d447 100644 --- a/test/rpg/entity/entitytestfixture.c +++ b/test/rpg/entity/entitytestfixture.c @@ -9,12 +9,13 @@ #include "rpg/overworld/map.h" #include "rpg/overworld/tile.h" #include "util/memory.h" +#include "util/string.h" void entityTestFixtureReset(void) { memoryZero(ENTITIES, sizeof(ENTITIES)); memoryZero(&MAP, sizeof(map_t)); - MAP.loaded = true; + stringCopy(MAP.name, "test", MAP_NAME_MAX); MAP.chunkPosition = (chunkpos_t){ 0, 0, 0 }; chunk_t *chunk = &MAP.chunks[0]; diff --git a/tools/asset/chunk/__main__.py b/tools/asset/chunk/__main__.py index e7d28bdc..7f488a23 100644 --- a/tools/asset/chunk/__main__.py +++ b/tools/asset/chunk/__main__.py @@ -7,7 +7,7 @@ Generates DCF + companion DMF files from raw chunk JSON files, or upgrades legacy DCF files (version 1 or 2) to the current version. -JSON input (assetsraw/chunks/chunk_X_Y_Z.json): +JSON input (assetsraw/maps//chunks/chunk_X_Y_Z.json): { "tiles": [ { "pos": [x, y, z], "type": , "tile": } @@ -35,6 +35,9 @@ JSON input (assetsraw/chunks/chunk_X_Y_Z.json): Mesh files are located by searching under assets/meshes/ and referenced by path from the assets root in the DCF. + is the map's name, up to 9 characters (MAP_NAME_MAX in + src/dusk/rpg/overworld/map.h reserves 1 byte for the null terminator). + "entities" spawns things into the world when this chunk loads. A "global" entity is spawned via mapSpawnEntity() - globalId indexes ENTITY_GLOBAL_LIST (src/dusk/rpg/entity/global/entitygloballist.h) and is @@ -53,7 +56,8 @@ JSON input (assetsraw/chunks/chunk_X_Y_Z.json): trigger is bitwise MAP_TRIGGER_STEP(1)|ENTER(2)|EXIT(4). Output DCF is derived automatically: - assetsraw/chunks/chunk_X_Y_Z.json -> assets/chunks/X_Y_Z.dcf + assetsraw/maps//chunks/chunk_X_Y_Z.json + -> assets/maps//chunks/X_Y_Z.dcf Version 5 DCF format (after 8-byte header): tile_t tiles[CHUNK_WIDTH * CHUNK_HEIGHT] (one per x/y column) @@ -85,7 +89,7 @@ DMF format: Each vertex: uv[2] + pos[3] = 5 x float32 LE = 20 bytes Usage: - python3 -m tools.asset.chunk # process all assetsraw/chunks/*.json + python3 -m tools.asset.chunk # process all assetsraw/maps/*/chunks/*.json python3 -m tools.asset.chunk # process one JSON file python3 -m tools.asset.chunk # upgrade legacy (v1/v2) DCF in-place """ @@ -118,6 +122,10 @@ CHUNK_MESH_NAME_MAX = 64 CHUNK_ENTITY_SPAWN_COUNT_MAX = 8 CHUNK_AREA_COUNT_MAX = 4 +# Matches MAP_NAME_MAX in src/dusk/rpg/overworld/map.h (buffer size, +# including the null terminator - so map names are at most 9 characters). +MAP_NAME_MAX = 10 + ENTITY_SPAWN_KIND_GLOBAL = 0 ENTITY_SPAWN_KIND_ITEM = 1 @@ -188,8 +196,29 @@ def write_model_json(path, mesh_rel, texture_rel, color): print(f' Wrote model JSON {path}') +def chunk_map_name(json_path): + """assetsraw/maps//chunks/chunk_X_Y_Z.json -> + + Raises ValueError if json_path isn't under that structure, or if + is longer than MAP_NAME_MAX - 1 characters.""" + rel = os.path.relpath(os.path.abspath(json_path), ASSETSRAW_DIR) + parts = rel.split(os.sep) + if len(parts) != 4 or parts[0] != 'maps' or parts[2] != 'chunks': + raise ValueError( + f"Chunk JSON must live at assetsraw/maps//chunks/*.json, got: " + f"{json_path}" + ) + map_name = parts[1] + if len(map_name) > MAP_NAME_MAX - 1: + raise ValueError( + f"Map name too long (> {MAP_NAME_MAX - 1} characters): {map_name}" + ) + return map_name + + def derive_dcf_path(json_path): - """assetsraw/chunks/chunk_X_Y_Z.json -> assets/chunks/X_Y_Z.dcf""" + """assetsraw/maps//chunks/chunk_X_Y_Z.json + -> assets/maps//chunks/X_Y_Z.dcf""" base = os.path.splitext(os.path.basename(json_path))[0] if base.startswith('chunk_'): base = base[len('chunk_'):] @@ -351,6 +380,8 @@ def build_terrain_verts(tiles_bytes): def from_json(json_path, dcf_path): + map_name = chunk_map_name(json_path) + with open(json_path) as f: data = json.load(f) @@ -377,15 +408,17 @@ def from_json(json_path, dcf_path): dcf_base = os.path.splitext(os.path.basename(dcf_path))[0] - # Terrain mesh + model (only written if non-empty) - terrain_dir = os.path.join(ASSETS_DIR, 'meshes', 'chunks') - models_dir = os.path.join(ASSETS_DIR, 'models', 'chunks') + # Terrain mesh + model (only written if non-empty). Namespaced under the + # owning map so two maps can each have a chunk at the same (x, y, z) + # without their generated terrain assets colliding. + terrain_dir = os.path.join(ASSETS_DIR, 'maps', map_name, 'meshes', 'chunks') + models_dir = os.path.join(ASSETS_DIR, 'maps', map_name, 'models', 'chunks') os.makedirs(terrain_dir, exist_ok=True) os.makedirs(models_dir, exist_ok=True) if terrain_verts: dmf_name = f'chunk_{dcf_base}_0.dmf' write_dmf(os.path.join(terrain_dir, dmf_name), terrain_verts) - mesh_rel = f'meshes/chunks/{dmf_name}' + mesh_rel = f'maps/{map_name}/meshes/chunks/{dmf_name}' json_name = f'chunk_{dcf_base}_0.json' write_model_json( os.path.join(models_dir, json_name), @@ -393,7 +426,7 @@ def from_json(json_path, dcf_path): 'tiles.png', [255, 255, 255, 255] ) - model_names.append(f'models/chunks/{json_name}') + model_names.append(f'maps/{map_name}/models/chunks/{json_name}') mesh_offsets.append((0.0, 0.0, 0.0)) # External mesh references -> look up matching model JSON @@ -555,22 +588,27 @@ def main(): parser.add_argument( 'path', nargs='?', help='Chunk JSON file to process, or legacy DCF file to upgrade. ' - 'If omitted, processes all assetsraw/chunks/*.json' + 'If omitted, processes all assetsraw/maps/*/chunks/*.json' ) args = parser.parse_args() if args.path is None: - chunks_dir = os.path.join(ASSETSRAW_DIR, 'chunks') - if not os.path.isdir(chunks_dir): - print(f"No directory found: {chunks_dir}") + maps_dir = os.path.join(ASSETSRAW_DIR, 'maps') + if not os.path.isdir(maps_dir): + print(f"No directory found: {maps_dir}") sys.exit(1) - json_files = sorted( - os.path.join(chunks_dir, f) - for f in os.listdir(chunks_dir) - if f.endswith('.json') - ) + json_files = [] + for map_name in sorted(os.listdir(maps_dir)): + chunks_dir = os.path.join(maps_dir, map_name, 'chunks') + if not os.path.isdir(chunks_dir): + continue + json_files.extend(sorted( + os.path.join(chunks_dir, f) + for f in os.listdir(chunks_dir) + if f.endswith('.json') + )) if not json_files: - print(f"No JSON files found in {chunks_dir}") + print(f"No JSON files found under {maps_dir}") sys.exit(0) for p in json_files: process_json(p)