import sys, os import argparse from datetime import datetime import math from helper import floatToFixed248 from inputParser import parseInputFile from mapParser import parseMap from chunkParser import chunkGetLocalTileX, chunkGetLocalTileY, chunkGetTileIndex, chunkGetOutputTileIndex, parseChunk from constants import CHUNK_WIDTH, CHUNK_HEIGHT, TILE_WIDTH_HEIGHT, ENTITY_TYPE_MAP, CHUNK_TILE_COUNT # Check if the script is run with the correct arguments parser = argparse.ArgumentParser(description="Generate chunk header files") parser.add_argument('--output', required=True, help='Dir to output headers') parser.add_argument('--input', required=True, help='Input JSON file from tiled') args = parser.parse_args() # Ensure outdir exists outputDir = args.output os.makedirs(outputDir, exist_ok=True) # Create world directory if it does not exist worldDir = os.path.join(outputDir, "world") os.makedirs(worldDir, exist_ok=True) # Create chunks directory if it does not exist chunksDir = os.path.join(worldDir, "chunk") os.makedirs(chunksDir, exist_ok=True) # Some vars used during printing now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Read the input JSON file data = parseInputFile(args.input) mapData = parseMap(data) # For each output chunk. worldWidth = 0 worldHeight = 0 chunksDone = set() for chunkY in range(mapData['mapHeightInRealChunks']): for chunkX in range(mapData['mapWidthInRealChunks']): chunkData = parseChunk(chunkX, chunkY, mapData) if chunkData is None: continue # This is a valid chunk. worldWidth = max(worldWidth, chunkX + 1) worldHeight = max(worldHeight, chunkY + 1) chunksDone.add((chunkX, chunkY)) chunkHeaderPath = os.path.join(chunksDir, f"chunk_{chunkX}_{chunkY}.h") with open(chunkHeaderPath, 'w') as f: f.write(f"// Generated chunk header for chunk at position ({chunkX}, {chunkY})\n") f.write(f"// Generated at {now}\n") f.write("#pragma once\n") f.write("#include \"world/chunkdata.h\"\n\n") f.write(f"static const chunkdata_t CHUNK_{chunkX}_{chunkY} = {{\n") f.write(f" .layerBase = {{\n") for y in range(CHUNK_HEIGHT): f.write(f" ") for x in range(CHUNK_WIDTH): i = y * CHUNK_WIDTH + x byte = chunkData['layerBaseData'][i] f.write(f"0x{byte:02x}, ") f.write(f"\n") f.write(" },\n\n") f.write(" .layerBaseOverlay = {\n") if chunkData['layerBaseOverlay'] is not None: for y in range(CHUNK_HEIGHT): f.write(f" ") for x in range(CHUNK_WIDTH): i = y * CHUNK_WIDTH + x byte = chunkData['layerBaseOverlayData'][i] f.write(f"0x{byte:02x}, ") f.write(f"\n") f.write(" },\n\n") f.write(f" .entities = {{\n") for entity in chunkData['entities']: # Entities are center aligned in tiled. localX = round(entity['x'] - (chunkData['topLeftTileX'] * TILE_WIDTH_HEIGHT)) localY = round(entity['y'] - (chunkData['topLeftTileY'] * TILE_WIDTH_HEIGHT)) if 'type' in entity and entity['type'] not in ENTITY_TYPE_MAP: continue f.write(" {\n") f.write(f" .id = {entity['id']},\n") f.write(f" .type = ENTITY_TYPE_NPC,\n") f.write(f" .x = {localX},\n") f.write(f" .y = {localY},\n") f.write(f" .dir = ENTITY_DIR_SOUTH,\n") f.write(" },\n") f.write(f" }},\n") f.write("};\n\n") # Output header file. headerPath = os.path.join(worldDir, "world.h") with open(headerPath, 'w') as f: f.write(f"// Generated chunks file. Generated at {now}\n\n") f.write("#pragma once\n") f.write("#include \"dusk.h\"\n") # Now, for each chunk, include its header file for (x, y) in chunksDone: chunk_header = f"world/chunk/chunk_{x}_{y}.h" f.write(f"#include \"{chunk_header}\"\n") f.write("\n") f.write(f"#define WORLD_WIDTH {worldWidth}\n") f.write(f"#define WORLD_HEIGHT {worldHeight}\n\n") f.write(f"static const chunkdata_t* WORLD_CHUNKS[] = {{\n") for i in range(worldHeight): f.write(" ") for j in range(worldWidth): if(j, i) in chunksDone: f.write(f"&CHUNK_{j}_{i}, ") else: f.write("NULL, ") f.write("\n") f.write("};\n\n") f.write(f"#define WORLD_PLAYER_SPAWN_X ((fixed248_t){floatToFixed248(mapData['playerSpawnX'])})\n") f.write(f"#define WORLD_PLAYER_SPAWN_Y ((fixed248_t){floatToFixed248(mapData['playerSpawnY'])})\n") print(f"chunks.h generated at: {headerPath}")