Files
dusk/tools/mapcompile/layerParser.py

144 lines
5.0 KiB
Python

import sys
from constants import TILE_WIDTH_HEIGHT, CHUNK_WIDTH, CHUNK_HEIGHT
import math
def parseLayers(data):
parsed = {}
# Extract layers
parsed['layers'] = data['layers']
# Object layer
for layer in parsed['layers']:
if layer.get('type') == 'objectgroup':
parsed['objectLayer'] = layer
break
if parsed['objectLayer'] is None:
print(f"Error: Data does not contain an object layer.")
sys.exit(1)
if 'objects' not in parsed['objectLayer'] or not isinstance(parsed['objectLayer']['objects'], list):
print(f"Error: Object layer does not contain 'objects' key or it is not a list.")
sys.exit(1)
# Tile Layers
parsed['tileLayers'] = []
for layer in parsed['layers']:
if layer.get('type') == 'tilelayer':
parsed['tileLayers'].append(layer)
if len(parsed['tileLayers']) == 0:
print(f"Error: Data does not contain any tile layers.")
sys.exit(1)
# First layer
parsed['firstLayer'] = parsed['tileLayers'][0]
if 'width' not in parsed['firstLayer'] or 'height' not in parsed['firstLayer']:
print(f"Error: First layer does not contain 'width' or 'height' key.")
sys.exit(1)
if 'chunks' not in parsed['firstLayer'] or not isinstance(parsed['firstLayer']['chunks'], list):
print(f"Error: First layer does not contain 'chunks' key.")
sys.exit(1)
if len(parsed['firstLayer']['chunks']) == 0:
print(f"Error: First layer does not contain any chunks.")
sys.exit(1)
parsed['firstLayerFirstChunk'] = parsed['firstLayer']['chunks'][0]
# Now determine the input map bounds.
isMinXFound = False
isMaxXFound = False
isMinYFound = False
isMaxYFound = False
parsed['inputMapLowestX'] = 0
parsed['inputMapHighestX'] = 0
parsed['inputMapLowestY'] = 0
parsed['inputMapHighestY'] = 0
parsed['inputLayerWidthInTiles'] = parsed['firstLayerFirstChunk']['width']
parsed['inputLayerHeightInTiles'] = parsed['firstLayerFirstChunk']['height']
for chunk in parsed['firstLayer']['chunks']:
if 'x' not in chunk or 'y' not in chunk:
print(f"Error: Chunk in first layer does not contain 'x' or 'y' key.")
sys.exit(1)
# Check chunk is not empty
if 'data' not in chunk or not isinstance(chunk['data'], list):
print(f"Error: Chunk in first layer does not contain 'data' key or it is not a list.")
sys.exit(1)
if len(chunk['data']) != parsed['inputLayerWidthInTiles'] * parsed['inputLayerHeightInTiles']:
print(f"Error: Chunk in first layer does not contain the expected number of tiles.")
sys.exit(1)
chunkEmpty = True
for tile in chunk['data']:
if tile == 0:
continue
chunkEmpty = False
break
if chunkEmpty:
print(f"Warning: Chunk at ({chunk['x']}, {chunk['y']}) is empty, skipping.")
continue
chunkX = chunk['x']
chunkY = chunk['y']
if parsed['inputMapLowestX'] > chunkX or not isMinXFound:
parsed['inputMapLowestX'] = chunkX
isMinXFound = True
if parsed['inputMapHighestX'] < chunkX or not isMaxXFound:
parsed['inputMapHighestX'] = chunkX
isMaxXFound = True
if parsed['inputMapLowestY'] > chunkY or not isMinYFound:
parsed['inputMapLowestY'] = chunkY
isMinYFound = True
if parsed['inputMapHighestY'] < chunkY or not isMaxYFound:
parsed['inputMapHighestY'] = chunkY
isMaxYFound = True
parsed['inputMapHighestX'] += parsed['inputLayerWidthInTiles']
parsed['inputMapHighestY'] += parsed['inputLayerHeightInTiles']
# We now offset all chunks by the lowest X/Y values to make them start at (0, 0).
for layerIndex, layer in enumerate(parsed['tileLayers']):
for chunkIndex, chunk in enumerate(layer['chunks']):
chunk['x'] -= parsed['inputMapLowestX']
chunk['y'] -= parsed['inputMapLowestY']
layer['chunks'][chunkIndex] = chunk
parsed['layers'][layerIndex] = layer
# Same for object layers
for obIndex, ob in enumerate(parsed['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)
ob['x'] -= parsed['inputMapLowestX'] * TILE_WIDTH_HEIGHT
ob['y'] -= parsed['inputMapLowestY'] * TILE_WIDTH_HEIGHT
# Objects are bottom aligned in tiled, so we need to adjust the Y coordinate.
ob['y'] -= TILE_WIDTH_HEIGHT
# Round off the coordinates
ob['x'] = round(ob['x'])
ob['y'] = round(ob['y'])
parsed['objectLayer']['objects'][obIndex] = ob
parsed['mapWidthInTiles'] = parsed['inputMapHighestX'] - parsed['inputMapLowestX']
parsed['mapHeightInTiles'] = parsed['inputMapHighestY'] - parsed['inputMapLowestY']
parsed['mapWidthInRealChunks'] = math.ceil(float(parsed['mapWidthInTiles']) / float(CHUNK_WIDTH))
parsed['mapHeightInRealChunks'] = math.ceil(float(parsed['mapHeightInTiles']) / float(CHUNK_HEIGHT))
if parsed['inputLayerWidthInTiles'] < CHUNK_WIDTH or parsed['inputLayerHeightInTiles'] < CHUNK_HEIGHT:
print(f"Error: Input layer size is smaller than chunk size.")
sys.exit(1)
return parsed