Reintroduce multiple maps: per-map chunk directories + map_t name/mapSetMap
Move chunk assets from a single flat assetsraw/chunks (and assets/chunks) into per-map assetsraw/maps/<map>/chunks (assets/maps/<map>/chunks), so terrain mesh/model output no longer collides across maps sharing chunk coordinates. map_t gains a name[MAP_NAME_MAX] field plus mapSetMap()/ mapIsLoaded() (checks name[0] == '\0') in place of the old bool loaded flag; mapInit() now just resets state and mapSetMap() does the chunk grid load. Updated the chunk asset tool and the map editor's dev server/client to match.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
+1
-1
@@ -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": [
|
"color": [
|
||||||
255,
|
255,
|
||||||
255,
|
255,
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -345,12 +345,14 @@
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAP_NAME = "overworld";
|
||||||
|
|
||||||
function chunkPaths(x, y, z) {
|
function chunkPaths(x, y, z) {
|
||||||
return {
|
return {
|
||||||
raw: `assetsraw/chunks/chunk_${x}_${y}_${z}.json`,
|
raw: `assetsraw/maps/${MAP_NAME}/chunks/chunk_${x}_${y}_${z}.json`,
|
||||||
dcf: `assets/chunks/${x}_${y}_${z}.dcf`,
|
dcf: `assets/maps/${MAP_NAME}/chunks/${x}_${y}_${z}.dcf`,
|
||||||
terrainDmf: `assets/meshes/chunks/chunk_${x}_${y}_${z}_0.dmf`,
|
terrainDmf: `assets/maps/${MAP_NAME}/meshes/chunks/chunk_${x}_${y}_${z}_0.dmf`,
|
||||||
terrainModel: `assets/models/chunks/chunk_${x}_${y}_${z}_0.json`,
|
terrainModel: `assets/maps/${MAP_NAME}/models/chunks/chunk_${x}_${y}_${z}_0.json`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,7 +769,7 @@
|
|||||||
async function buildChunkBrowseList() {
|
async function buildChunkBrowseList() {
|
||||||
const list = document.getElementById("chunkBrowseList");
|
const list = document.getElementById("chunkBrowseList");
|
||||||
list.innerHTML = "";
|
list.innerHTML = "";
|
||||||
const res = await apiLs("assetsraw/chunks");
|
const res = await apiLs(`assetsraw/maps/${MAP_NAME}/chunks`);
|
||||||
for(const entry of res.entries || []) {
|
for(const entry of res.entries || []) {
|
||||||
const m = entry.name.match(/^chunk_(-?\d+)_(-?\d+)_(-?\d+)\.json$/);
|
const m = entry.name.match(/^chunk_(-?\d+)_(-?\d+)_(-?\d+)\.json$/);
|
||||||
if(!m) continue;
|
if(!m) continue;
|
||||||
|
|||||||
@@ -209,7 +209,10 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
self.send_json({"error": "invalid chunk coordinates"}, 400)
|
self.send_json({"error": "invalid chunk coordinates"}, 400)
|
||||||
return
|
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():
|
if not json_path.is_file():
|
||||||
self.send_json({"error": "chunk json not found"}, 404)
|
self.send_json({"error": "chunk json not found"}, 404)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -28,7 +28,25 @@ void mapChunkLoadingSlotClear(chunk_t *chunk) {
|
|||||||
|
|
||||||
errorret_t mapInit() {
|
errorret_t mapInit() {
|
||||||
memoryZero(&MAP, sizeof(map_t));
|
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;
|
chunkindex_t i = 0;
|
||||||
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||||
@@ -47,10 +65,6 @@ errorret_t mapInit() {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t mapIsLoaded() {
|
|
||||||
return MAP.loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
||||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||||
if(chunkPositionIsEqual(newPos, MAP.chunkPosition)) errorOk();
|
if(chunkPositionIsEqual(newPos, MAP.chunkPosition)) errorOk();
|
||||||
@@ -132,6 +146,7 @@ errorret_t mapDispose() {
|
|||||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||||
mapChunkUnload(&MAP.chunks[i]);
|
mapChunkUnload(&MAP.chunks[i]);
|
||||||
}
|
}
|
||||||
|
MAP.name[0] = '\0';
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,10 +218,11 @@ errorret_t mapChunkLoad(chunk_t *chunk) {
|
|||||||
|
|
||||||
chunk->meshCount = 0;
|
chunk->meshCount = 0;
|
||||||
|
|
||||||
char_t name[64];
|
char_t name[MAP_FILE_PATH_MAX];
|
||||||
stringFormat(
|
stringFormat(
|
||||||
name, sizeof(name),
|
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.x,
|
||||||
(int32_t)chunk->position.y,
|
(int32_t)chunk->position.y,
|
||||||
(int32_t)chunk->position.z
|
(int32_t)chunk->position.z
|
||||||
@@ -241,10 +257,11 @@ void mapChunkLoadNext() {
|
|||||||
MAP.loadQueueCount--;
|
MAP.loadQueueCount--;
|
||||||
MAP.loadingChunks[slot] = chunk;
|
MAP.loadingChunks[slot] = chunk;
|
||||||
|
|
||||||
char_t name[64];
|
char_t name[MAP_FILE_PATH_MAX];
|
||||||
stringFormat(
|
stringFormat(
|
||||||
name, sizeof(name),
|
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.x,
|
||||||
(int32_t)chunk->position.y,
|
(int32_t)chunk->position.y,
|
||||||
(int32_t)chunk->position.z
|
(int32_t)chunk->position.z
|
||||||
|
|||||||
@@ -12,12 +12,18 @@
|
|||||||
|
|
||||||
#define MAP_FILE_PATH_MAX 128
|
#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/
|
// Number of chunks that may be mid-load (asset locked & awaiting onLoaded/
|
||||||
// onError) at the same time - everything past this waits in loadQueue.
|
// onError) at the same time - everything past this waits in loadQueue.
|
||||||
#define MAP_CHUNK_LOAD_CONCURRENCY 2
|
#define MAP_CHUNK_LOAD_CONCURRENCY 2
|
||||||
|
|
||||||
typedef struct map_s {
|
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 chunks[MAP_CHUNK_COUNT];
|
||||||
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||||
@@ -31,19 +37,30 @@ typedef struct map_s {
|
|||||||
extern map_t MAP;
|
extern map_t MAP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the map.
|
* Initializes the map subsystem. No map is loaded until mapSetMap is
|
||||||
*
|
* called.
|
||||||
|
*
|
||||||
* @return An error code.
|
* @return An error code.
|
||||||
*/
|
*/
|
||||||
errorret_t mapInit();
|
errorret_t mapInit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a map is loaded.
|
* Checks if a map is loaded.
|
||||||
*
|
*
|
||||||
* @return true if a map is loaded, false otherwise.
|
* @return true if a map is loaded, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool_t mapIsLoaded();
|
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.
|
* Updates the map.
|
||||||
*
|
*
|
||||||
|
|||||||
+1
-2
@@ -31,10 +31,9 @@ errorret_t rpgInit(void) {
|
|||||||
cutsceneSystemInit();
|
cutsceneSystemInit();
|
||||||
errorChain(mapInit());
|
errorChain(mapInit());
|
||||||
rpgCameraInit();
|
rpgCameraInit();
|
||||||
|
|
||||||
|
|
||||||
// Init test world
|
// 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 -
|
// 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
|
// every other entity (NPCs, items) and map area comes from the loaded
|
||||||
|
|||||||
@@ -9,12 +9,13 @@
|
|||||||
#include "rpg/overworld/map.h"
|
#include "rpg/overworld/map.h"
|
||||||
#include "rpg/overworld/tile.h"
|
#include "rpg/overworld/tile.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
void entityTestFixtureReset(void) {
|
void entityTestFixtureReset(void) {
|
||||||
memoryZero(ENTITIES, sizeof(ENTITIES));
|
memoryZero(ENTITIES, sizeof(ENTITIES));
|
||||||
|
|
||||||
memoryZero(&MAP, sizeof(map_t));
|
memoryZero(&MAP, sizeof(map_t));
|
||||||
MAP.loaded = true;
|
stringCopy(MAP.name, "test", MAP_NAME_MAX);
|
||||||
MAP.chunkPosition = (chunkpos_t){ 0, 0, 0 };
|
MAP.chunkPosition = (chunkpos_t){ 0, 0, 0 };
|
||||||
|
|
||||||
chunk_t *chunk = &MAP.chunks[0];
|
chunk_t *chunk = &MAP.chunks[0];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Generates DCF + companion DMF files from raw chunk JSON files, or upgrades
|
Generates DCF + companion DMF files from raw chunk JSON files, or upgrades
|
||||||
legacy DCF files (version 1 or 2) to the current version.
|
legacy DCF files (version 1 or 2) to the current version.
|
||||||
|
|
||||||
JSON input (assetsraw/chunks/chunk_X_Y_Z.json):
|
JSON input (assetsraw/maps/<map>/chunks/chunk_X_Y_Z.json):
|
||||||
{
|
{
|
||||||
"tiles": [
|
"tiles": [
|
||||||
{ "pos": [x, y, z], "type": <tile_shape_int>, "tile": <uv_tile_int> }
|
{ "pos": [x, y, z], "type": <tile_shape_int>, "tile": <uv_tile_int> }
|
||||||
@@ -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
|
Mesh files are located by searching under assets/meshes/ and referenced by
|
||||||
path from the assets root in the DCF.
|
path from the assets root in the DCF.
|
||||||
|
|
||||||
|
<map> 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"
|
"entities" spawns things into the world when this chunk loads. A "global"
|
||||||
entity is spawned via mapSpawnEntity() - globalId indexes
|
entity is spawned via mapSpawnEntity() - globalId indexes
|
||||||
ENTITY_GLOBAL_LIST (src/dusk/rpg/entity/global/entitygloballist.h) and is
|
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).
|
trigger is bitwise MAP_TRIGGER_STEP(1)|ENTER(2)|EXIT(4).
|
||||||
|
|
||||||
Output DCF is derived automatically:
|
Output DCF is derived automatically:
|
||||||
assetsraw/chunks/chunk_X_Y_Z.json -> assets/chunks/X_Y_Z.dcf
|
assetsraw/maps/<map>/chunks/chunk_X_Y_Z.json
|
||||||
|
-> assets/maps/<map>/chunks/X_Y_Z.dcf
|
||||||
|
|
||||||
Version 5 DCF format (after 8-byte header):
|
Version 5 DCF format (after 8-byte header):
|
||||||
tile_t tiles[CHUNK_WIDTH * CHUNK_HEIGHT] (one per x/y column)
|
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
|
Each vertex: uv[2] + pos[3] = 5 x float32 LE = 20 bytes
|
||||||
|
|
||||||
Usage:
|
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 <file.json> # process one JSON file
|
python3 -m tools.asset.chunk <file.json> # process one JSON file
|
||||||
python3 -m tools.asset.chunk <file.dcf> # upgrade legacy (v1/v2) DCF in-place
|
python3 -m tools.asset.chunk <file.dcf> # upgrade legacy (v1/v2) DCF in-place
|
||||||
"""
|
"""
|
||||||
@@ -118,6 +122,10 @@ CHUNK_MESH_NAME_MAX = 64
|
|||||||
CHUNK_ENTITY_SPAWN_COUNT_MAX = 8
|
CHUNK_ENTITY_SPAWN_COUNT_MAX = 8
|
||||||
CHUNK_AREA_COUNT_MAX = 4
|
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_GLOBAL = 0
|
||||||
ENTITY_SPAWN_KIND_ITEM = 1
|
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}')
|
print(f' Wrote model JSON {path}')
|
||||||
|
|
||||||
|
|
||||||
|
def chunk_map_name(json_path):
|
||||||
|
"""assetsraw/maps/<map>/chunks/chunk_X_Y_Z.json -> <map>
|
||||||
|
|
||||||
|
Raises ValueError if json_path isn't under that structure, or if <map>
|
||||||
|
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/<map>/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):
|
def derive_dcf_path(json_path):
|
||||||
"""assetsraw/chunks/chunk_X_Y_Z.json -> assets/chunks/X_Y_Z.dcf"""
|
"""assetsraw/maps/<map>/chunks/chunk_X_Y_Z.json
|
||||||
|
-> assets/maps/<map>/chunks/X_Y_Z.dcf"""
|
||||||
base = os.path.splitext(os.path.basename(json_path))[0]
|
base = os.path.splitext(os.path.basename(json_path))[0]
|
||||||
if base.startswith('chunk_'):
|
if base.startswith('chunk_'):
|
||||||
base = base[len('chunk_'):]
|
base = base[len('chunk_'):]
|
||||||
@@ -351,6 +380,8 @@ def build_terrain_verts(tiles_bytes):
|
|||||||
|
|
||||||
|
|
||||||
def from_json(json_path, dcf_path):
|
def from_json(json_path, dcf_path):
|
||||||
|
map_name = chunk_map_name(json_path)
|
||||||
|
|
||||||
with open(json_path) as f:
|
with open(json_path) as f:
|
||||||
data = json.load(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]
|
dcf_base = os.path.splitext(os.path.basename(dcf_path))[0]
|
||||||
|
|
||||||
# Terrain mesh + model (only written if non-empty)
|
# Terrain mesh + model (only written if non-empty). Namespaced under the
|
||||||
terrain_dir = os.path.join(ASSETS_DIR, 'meshes', 'chunks')
|
# owning map so two maps can each have a chunk at the same (x, y, z)
|
||||||
models_dir = os.path.join(ASSETS_DIR, 'models', 'chunks')
|
# 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(terrain_dir, exist_ok=True)
|
||||||
os.makedirs(models_dir, exist_ok=True)
|
os.makedirs(models_dir, exist_ok=True)
|
||||||
if terrain_verts:
|
if terrain_verts:
|
||||||
dmf_name = f'chunk_{dcf_base}_0.dmf'
|
dmf_name = f'chunk_{dcf_base}_0.dmf'
|
||||||
write_dmf(os.path.join(terrain_dir, dmf_name), terrain_verts)
|
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'
|
json_name = f'chunk_{dcf_base}_0.json'
|
||||||
write_model_json(
|
write_model_json(
|
||||||
os.path.join(models_dir, json_name),
|
os.path.join(models_dir, json_name),
|
||||||
@@ -393,7 +426,7 @@ def from_json(json_path, dcf_path):
|
|||||||
'tiles.png',
|
'tiles.png',
|
||||||
[255, 255, 255, 255]
|
[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))
|
mesh_offsets.append((0.0, 0.0, 0.0))
|
||||||
|
|
||||||
# External mesh references -> look up matching model JSON
|
# External mesh references -> look up matching model JSON
|
||||||
@@ -555,22 +588,27 @@ def main():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'path', nargs='?',
|
'path', nargs='?',
|
||||||
help='Chunk JSON file to process, or legacy DCF file to upgrade. '
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.path is None:
|
if args.path is None:
|
||||||
chunks_dir = os.path.join(ASSETSRAW_DIR, 'chunks')
|
maps_dir = os.path.join(ASSETSRAW_DIR, 'maps')
|
||||||
if not os.path.isdir(chunks_dir):
|
if not os.path.isdir(maps_dir):
|
||||||
print(f"No directory found: {chunks_dir}")
|
print(f"No directory found: {maps_dir}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
json_files = sorted(
|
json_files = []
|
||||||
os.path.join(chunks_dir, f)
|
for map_name in sorted(os.listdir(maps_dir)):
|
||||||
for f in os.listdir(chunks_dir)
|
chunks_dir = os.path.join(maps_dir, map_name, 'chunks')
|
||||||
if f.endswith('.json')
|
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:
|
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)
|
sys.exit(0)
|
||||||
for p in json_files:
|
for p in json_files:
|
||||||
process_json(p)
|
process_json(p)
|
||||||
|
|||||||
Reference in New Issue
Block a user