Files
dusk/tools/mapcompile/chunkParser.py
2025-06-23 16:30:56 -05:00

127 lines
4.3 KiB
Python

import sys
from constants import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_TILE_COUNT, TILE_WIDTH_HEIGHT
from entityParser import parseEntity
import math
def parseChunkLayerData(layer, mapData, chunkData):
layerData = []
for y in range(CHUNK_HEIGHT):
for x in range(CHUNK_WIDTH):
inputTileIndex = chunkGetTileIndex(x, y, mapData, chunkData)
outputTileIndex = chunkGetOutputTileIndex(x, y)
layerData.append(layer['data'][inputTileIndex])
if len(layerData) != CHUNK_TILE_COUNT:
print(f"Error: Layer data length {len(layerData)} does not match expected chunk tile count {CHUNK_TILE_COUNT}.")
sys.exit(1)
return layerData
def parseChunk(chunkX, chunkY, mapData):
chunkData = { }
chunkData['topLeftTileX'] = chunkX * CHUNK_WIDTH
chunkData['topLeftTileY'] = chunkY * CHUNK_HEIGHT
chunkData['inputTopLeftTileX'] = math.floor(
float(chunkData['topLeftTileX']) / float(mapData['inputLayerWidthInTiles'])
) * mapData['inputLayerWidthInTiles']
chunkData['inputTopLeftTileY'] = math.floor(
float(chunkData['topLeftTileY']) / float(mapData['inputLayerHeightInTiles'])
) * mapData['inputLayerHeightInTiles']
# Get the data for this chunk out of the map data.
chunkData['layers'] = []
for layer in mapData['tileLayers']:
foundChunk = None
if 'chunks' not in layer or not isinstance(layer['chunks'], list):
print(f"Error: Layer '{layer['name']}' does not contain 'chunks' key or it is not a list.")
sys.exit(1)
for chunk in layer['chunks']:
if 'x' not in chunk or 'y' not in chunk:
print(f"Error: Chunk in layer '{layer['name']}' does not contain 'x' or 'y' key.")
sys.exit(1)
# Check if this chunk is within the bounds of the top left tile.
if chunk['x'] != chunkData['inputTopLeftTileX'] or chunk['y'] != chunkData['inputTopLeftTileY']:
continue
foundChunk = chunk
break
if foundChunk is None:
chunkData['layers'].append(None)
continue
# Is layer empty?
layerEmpty = True
for tile in foundChunk['data']:
if tile == 0:
continue
layerEmpty = False
break
if layerEmpty:
chunkData['layers'].append(None)
else:
chunkData['layers'].append(foundChunk)
# Any layers for this chunk?
if all(chunk is None for chunk in chunkData['layers']):
return None
if len(chunkData['layers']) == 0:
return None
# Parse Layer Data
chunkData['layerBase'] = chunkData['layers'][0]
chunkData['layerBaseOverlay'] = None
if len(chunkData['layers']) > 1:
chunkData['layerBaseOverlay'] = chunkData['layers'][1]
chunkData['layerBaseData'] = parseChunkLayerData(chunkData['layerBase'], mapData, chunkData)
if chunkData['layerBaseOverlay'] is not None:
chunkData['layerBaseOverlayData'] = parseChunkLayerData(chunkData['layerBaseOverlay'], mapData, chunkData)
else:
chunkData['layerBaseOverlayData'] = []
# Parse chunk entities.
chunkData['entities'] = []
for ob in mapData['objectLayer']['objects']:
if 'x' not in ob or 'y' not in ob:
print(f"Error: Object in object layer does not contain 'x' or 'y' key.")
sys.exit(1)
# Is this object within the chunk?
if ob['x'] < chunkData['topLeftTileX'] * TILE_WIDTH_HEIGHT:
continue
if ob['x'] >= (chunkData['topLeftTileX'] + CHUNK_WIDTH) * TILE_WIDTH_HEIGHT:
continue
if ob['y'] < chunkData['topLeftTileY'] * TILE_WIDTH_HEIGHT:
continue
if ob['y'] >= (chunkData['topLeftTileY'] + CHUNK_HEIGHT) * TILE_WIDTH_HEIGHT:
continue
ent = parseEntity(ob, chunkData)
if ent is None:
continue
chunkData['entities'].append(ent)
return chunkData
def chunkGetLocalTileX(absoluteTileX, mapData):
return absoluteTileX % mapData['inputLayerWidthInTiles']
def chunkGetLocalTileY(absoluteTileY, mapData):
return absoluteTileY % mapData['inputLayerHeightInTiles']
def chunkGetTileIndex(localX, localY, mapData, chunkData):
absoluteTileX = chunkData['topLeftTileX'] + localX
absoluteTileY = chunkData['topLeftTileY'] + localY
inputLocalTileX = chunkGetLocalTileX(absoluteTileX, mapData)
inputLocalTileY = chunkGetLocalTileY(absoluteTileY, mapData)
return inputLocalTileY * mapData['inputLayerWidthInTiles'] + inputLocalTileX
def chunkGetOutputTileIndex(localX, localY):
return localY * CHUNK_WIDTH + localX