import sys from constants import TILE_WIDTH_HEIGHT, CHUNK_WIDTH, CHUNK_HEIGHT import math def parseMap(data): mapData = { 'layers': data['layers'], 'playerSpawnX': 0, 'playerSpawnY': 0, } # Object layer for layer in mapData['layers']: if layer.get('type') == 'objectgroup': mapData['objectLayer'] = layer break if mapData['objectLayer'] is None: print(f"Error: Data does not contain an object layer.") sys.exit(1) if 'objects' not in mapData['objectLayer'] or not isinstance(mapData['objectLayer']['objects'], list): print(f"Error: Object layer does not contain 'objects' key or it is not a list.") sys.exit(1) # Tile Layers mapData['tileLayers'] = [] for layer in mapData['layers']: if layer.get('type') == 'tilelayer': mapData['tileLayers'].append(layer) if len(mapData['tileLayers']) == 0: print(f"Error: Data does not contain any tile layers.") sys.exit(1) # First layer mapData['firstLayer'] = mapData['tileLayers'][0] if 'width' not in mapData['firstLayer'] or 'height' not in mapData['firstLayer']: print(f"Error: First layer does not contain 'width' or 'height' key.") sys.exit(1) if 'chunks' not in mapData['firstLayer'] or not isinstance(mapData['firstLayer']['chunks'], list): print(f"Error: First layer does not contain 'chunks' key.") sys.exit(1) if len(mapData['firstLayer']['chunks']) == 0: print(f"Error: First layer does not contain any chunks.") sys.exit(1) mapData['firstLayerFirstChunk'] = mapData['firstLayer']['chunks'][0] # Now determine the input map bounds. isMinXFound = False isMaxXFound = False isMinYFound = False isMaxYFound = False mapData['inputMapLowestX'] = 0 mapData['inputMapHighestX'] = 0 mapData['inputMapLowestY'] = 0 mapData['inputMapHighestY'] = 0 mapData['inputLayerWidthInTiles'] = mapData['firstLayerFirstChunk']['width'] mapData['inputLayerHeightInTiles'] = mapData['firstLayerFirstChunk']['height'] for chunk in mapData['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']) != mapData['inputLayerWidthInTiles'] * mapData['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 mapData['inputMapLowestX'] > chunkX or not isMinXFound: mapData['inputMapLowestX'] = chunkX isMinXFound = True if mapData['inputMapHighestX'] < chunkX or not isMaxXFound: mapData['inputMapHighestX'] = chunkX isMaxXFound = True if mapData['inputMapLowestY'] > chunkY or not isMinYFound: mapData['inputMapLowestY'] = chunkY isMinYFound = True if mapData['inputMapHighestY'] < chunkY or not isMaxYFound: mapData['inputMapHighestY'] = chunkY isMaxYFound = True mapData['inputMapHighestX'] += mapData['inputLayerWidthInTiles'] mapData['inputMapHighestY'] += mapData['inputLayerHeightInTiles'] # We now offset all chunks by the lowest X/Y values to make them start at (0, 0). for layerIndex, layer in enumerate(mapData['tileLayers']): for chunkIndex, chunk in enumerate(layer['chunks']): chunk['x'] -= mapData['inputMapLowestX'] chunk['y'] -= mapData['inputMapLowestY'] layer['chunks'][chunkIndex] = chunk mapData['layers'][layerIndex] = layer # Same for object layers for obIndex, ob in enumerate(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) ob['x'] -= mapData['inputMapLowestX'] * TILE_WIDTH_HEIGHT ob['y'] -= mapData['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']) mapData['objectLayer']['objects'][obIndex] = ob mapData['mapWidthInTiles'] = mapData['inputMapHighestX'] - mapData['inputMapLowestX'] mapData['mapHeightInTiles'] = mapData['inputMapHighestY'] - mapData['inputMapLowestY'] mapData['mapWidthInRealChunks'] = math.ceil(float(mapData['mapWidthInTiles']) / float(CHUNK_WIDTH)) mapData['mapHeightInRealChunks'] = math.ceil(float(mapData['mapHeightInTiles']) / float(CHUNK_HEIGHT)) if mapData['inputLayerWidthInTiles'] < CHUNK_WIDTH or mapData['inputLayerHeightInTiles'] < CHUNK_HEIGHT: print(f"Error: Input layer size is smaller than chunk size.") sys.exit(1) # Extract player spawn point for ob in mapData['objectLayer']['objects']: if 'type' not in ob or ob['type'] != 'player_spawn': continue if 'x' not in ob or 'y' not in ob: print(f"Error: Player spawn object does not contain 'x' or 'y' key.") sys.exit(1) mapData['playerSpawnX'] = ob['x'] mapData['playerSpawnY'] = ob['y'] return mapData