Last active
November 20, 2020 23:59
-
-
Save doriancransac/15f0ae1ea0ebc74a84c99988f121664a to your computer and use it in GitHub Desktop.
A hijacked TileMap loader for libgdx which works in headless context (i.e without ANY Gdx context)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.assets.AssetDescriptor; | |
import com.badlogic.gdx.assets.AssetLoaderParameters; | |
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader; | |
import com.badlogic.gdx.assets.loaders.FileHandleResolver; | |
import com.badlogic.gdx.assets.loaders.TextureLoader; | |
import com.badlogic.gdx.files.FileHandle; | |
import com.badlogic.gdx.graphics.Color; | |
import com.badlogic.gdx.graphics.Texture.TextureFilter; | |
import com.badlogic.gdx.graphics.g2d.TextureRegion; | |
import com.badlogic.gdx.maps.*; | |
import com.badlogic.gdx.maps.objects.EllipseMapObject; | |
import com.badlogic.gdx.maps.objects.PolygonMapObject; | |
import com.badlogic.gdx.maps.objects.PolylineMapObject; | |
import com.badlogic.gdx.maps.objects.RectangleMapObject; | |
import com.badlogic.gdx.maps.tiled.*; | |
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell; | |
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject; | |
import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile; | |
import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile; | |
import com.badlogic.gdx.math.Polygon; | |
import com.badlogic.gdx.math.Polyline; | |
import com.badlogic.gdx.utils.*; | |
import java.io.BufferedInputStream; | |
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.StringTokenizer; | |
import java.util.zip.GZIPInputStream; | |
import java.util.zip.InflaterInputStream; | |
public abstract class HijackedBaseTmxMapLoader<P extends com.badlogic.gdx.maps.tiled.BaseTmxMapLoader.Parameters> extends AsynchronousAssetLoader<TiledMap, P> { | |
public static class Parameters extends AssetLoaderParameters<TiledMap> { | |
/** generate mipmaps? **/ | |
public boolean generateMipMaps = false; | |
/** The TextureFilter to use for minification **/ | |
public TextureFilter textureMinFilter = TextureFilter.Nearest; | |
/** The TextureFilter to use for magnification **/ | |
public TextureFilter textureMagFilter = TextureFilter.Nearest; | |
/** Whether to convert the objects' pixel position and size to the equivalent in tile space. **/ | |
public boolean convertObjectToTileSpace = false; | |
/** Whether to flip all Y coordinates so that Y positive is up. All LibGDX renderers require flipped Y coordinates, and | |
* thus flipY set to true. This parameter is included for non-rendering related purposes of TMX files, or custom renderers. */ | |
public boolean flipY = true; | |
} | |
protected static final int FLAG_FLIP_HORIZONTALLY = 0x80000000; | |
protected static final int FLAG_FLIP_VERTICALLY = 0x40000000; | |
protected static final int FLAG_FLIP_DIAGONALLY = 0x20000000; | |
protected static final int MASK_CLEAR = 0xE0000000; | |
protected XmlReader xml = new XmlReader(); | |
protected XmlReader.Element root; | |
protected boolean convertObjectToTileSpace; | |
protected boolean flipY = true; | |
protected int mapTileWidth; | |
protected int mapTileHeight; | |
protected int mapWidthInPixels; | |
protected int mapHeightInPixels; | |
protected TiledMap map; | |
public HijackedBaseTmxMapLoader (FileHandleResolver resolver) { | |
super(resolver); | |
} | |
@Override | |
public Array<AssetDescriptor> getDependencies (String fileName, FileHandle tmxFile, P parameter) { | |
this.root = xml.parse(tmxFile); | |
TextureLoader.TextureParameter textureParameter = new TextureLoader.TextureParameter(); | |
if (parameter != null) { | |
textureParameter.genMipMaps = parameter.generateMipMaps; | |
textureParameter.minFilter = parameter.textureMinFilter; | |
textureParameter.magFilter = parameter.textureMagFilter; | |
} | |
return getDependencyAssetDescriptors(tmxFile, textureParameter); | |
} | |
protected abstract Array<AssetDescriptor> getDependencyAssetDescriptors (FileHandle tmxFile, TextureLoader.TextureParameter textureParameter); | |
/** | |
* Loads the map data, given the XML root element | |
* | |
* @param tmxFile the Filehandle of the tmx file | |
* @param parameter | |
* @return the {@link TiledMap} | |
*/ | |
protected TiledMap loadTiledMap (FileHandle tmxFile, P parameter) { | |
this.map = new TiledMap(); | |
if (parameter != null) { | |
this.convertObjectToTileSpace = parameter.convertObjectToTileSpace; | |
this.flipY = parameter.flipY; | |
} else { | |
this.convertObjectToTileSpace = false; | |
this.flipY = true; | |
} | |
String mapOrientation = root.getAttribute("orientation", null); | |
int mapWidth = root.getIntAttribute("width", 0); | |
int mapHeight = root.getIntAttribute("height", 0); | |
int tileWidth = root.getIntAttribute("tilewidth", 0); | |
int tileHeight = root.getIntAttribute("tileheight", 0); | |
int hexSideLength = root.getIntAttribute("hexsidelength", 0); | |
String staggerAxis = root.getAttribute("staggeraxis", null); | |
String staggerIndex = root.getAttribute("staggerindex", null); | |
String mapBackgroundColor = root.getAttribute("backgroundcolor", null); | |
MapProperties mapProperties = map.getProperties(); | |
if (mapOrientation != null) { | |
mapProperties.put("orientation", mapOrientation); | |
} | |
mapProperties.put("width", mapWidth); | |
mapProperties.put("height", mapHeight); | |
mapProperties.put("tilewidth", tileWidth); | |
mapProperties.put("tileheight", tileHeight); | |
mapProperties.put("hexsidelength", hexSideLength); | |
if (staggerAxis != null) { | |
mapProperties.put("staggeraxis", staggerAxis); | |
} | |
if (staggerIndex != null) { | |
mapProperties.put("staggerindex", staggerIndex); | |
} | |
if (mapBackgroundColor != null) { | |
mapProperties.put("backgroundcolor", mapBackgroundColor); | |
} | |
this.mapTileWidth = tileWidth; | |
this.mapTileHeight = tileHeight; | |
this.mapWidthInPixels = mapWidth * tileWidth; | |
this.mapHeightInPixels = mapHeight * tileHeight; | |
if (mapOrientation != null) { | |
if ("staggered".equals(mapOrientation)) { | |
if (mapHeight > 1) { | |
this.mapWidthInPixels += tileWidth / 2; | |
this.mapHeightInPixels = mapHeightInPixels / 2 + tileHeight / 2; | |
} | |
} | |
} | |
XmlReader.Element properties = root.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(map.getProperties(), properties); | |
} | |
Array<XmlReader.Element> tilesets = root.getChildrenByName("tileset"); | |
for (XmlReader.Element element : tilesets) { | |
loadTileSet(element, tmxFile); | |
root.removeChild(element); | |
} | |
for (int i = 0, j = root.getChildCount(); i < j; i++) { | |
XmlReader.Element element = root.getChild(i); | |
loadLayer(map, map.getLayers(), element, tmxFile); | |
} | |
return map; | |
} | |
protected void loadLayer (TiledMap map, MapLayers parentLayers, XmlReader.Element element, FileHandle tmxFile) { | |
String name = element.getName(); | |
if (name.equals("group")) { | |
loadLayerGroup(map, parentLayers, element, tmxFile); | |
} else if (name.equals("layer")) { | |
loadTileLayer(map, parentLayers, element); | |
} else if (name.equals("objectgroup")) { | |
loadObjectGroup(map, parentLayers, element); | |
} else if (name.equals("imagelayer")) { | |
loadImageLayer(map, parentLayers, element, tmxFile); | |
} | |
} | |
protected void loadLayerGroup (TiledMap map, MapLayers parentLayers, XmlReader.Element element, FileHandle tmxFile) { | |
if (element.getName().equals("group")) { | |
MapGroupLayer groupLayer = new MapGroupLayer(); | |
loadBasicLayerInfo(groupLayer, element); | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(groupLayer.getProperties(), properties); | |
} | |
for (int i = 0, j = element.getChildCount(); i < j; i++) { | |
XmlReader.Element child = element.getChild(i); | |
loadLayer(map, groupLayer.getLayers(), child, tmxFile); | |
} | |
for (MapLayer layer : groupLayer.getLayers()) { | |
layer.setParent(groupLayer); | |
} | |
parentLayers.add(groupLayer); | |
} | |
} | |
protected void loadTileLayer (TiledMap map, MapLayers parentLayers, XmlReader.Element element) { | |
if (element.getName().equals("layer")) { | |
int width = element.getIntAttribute("width", 0); | |
int height = element.getIntAttribute("height", 0); | |
int tileWidth = map.getProperties().get("tilewidth", Integer.class); | |
int tileHeight = map.getProperties().get("tileheight", Integer.class); | |
TiledMapTileLayer layer = new TiledMapTileLayer(width, height, tileWidth, tileHeight); | |
loadBasicLayerInfo(layer, element); | |
int[] ids = getTileIds(element, width, height); | |
TiledMapTileSets tilesets = map.getTileSets(); | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
int id = ids[y * width + x]; | |
boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0); | |
boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0); | |
boolean flipDiagonally = ((id & FLAG_FLIP_DIAGONALLY) != 0); | |
TiledMapTile tile = tilesets.getTile(id & ~MASK_CLEAR); | |
if (tile != null) { | |
TiledMapTileLayer.Cell cell = createTileLayerCell(flipHorizontally, flipVertically, flipDiagonally); | |
cell.setTile(tile); | |
layer.setCell(x, flipY ? height - 1 - y : y, cell); | |
} | |
} | |
} | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(layer.getProperties(), properties); | |
} | |
parentLayers.add(layer); | |
} | |
} | |
protected void loadObjectGroup (TiledMap map, MapLayers parentLayers, XmlReader.Element element) { | |
if (element.getName().equals("objectgroup")) { | |
MapLayer layer = new MapLayer(); | |
loadBasicLayerInfo(layer, element); | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(layer.getProperties(), properties); | |
} | |
for (XmlReader.Element objectElement : element.getChildrenByName("object")) { | |
loadObject(map, layer, objectElement); | |
} | |
parentLayers.add(layer); | |
} | |
} | |
protected void loadImageLayer (TiledMap map, MapLayers parentLayers, XmlReader.Element element, FileHandle tmxFile) { | |
if (element.getName().equals("imagelayer")) { | |
float x = 0; | |
float y = 0; | |
if (element.hasAttribute("offsetx")) { | |
x = Float.parseFloat(element.getAttribute("offsetx", "0")); | |
} else { | |
x = Float.parseFloat(element.getAttribute("x", "0")); | |
} | |
if (element.hasAttribute("offsety")) { | |
y = Float.parseFloat(element.getAttribute("offsety", "0")); | |
} else { | |
y = Float.parseFloat(element.getAttribute("y", "0")); | |
} | |
if (flipY) y = mapHeightInPixels - y; | |
XmlReader.Element image = element.getChildByName("image"); | |
if (image != null) { | |
String source = image.getAttribute("source"); | |
FileHandle handle = getRelativeFileHandle(tmxFile, source); | |
} | |
HijackedMapImageLayer layer = new HijackedMapImageLayer(x, y); | |
loadBasicLayerInfo(layer, element); | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(layer.getProperties(), properties); | |
} | |
parentLayers.add(layer); | |
} | |
} | |
protected void loadBasicLayerInfo (MapLayer layer, XmlReader.Element element) { | |
String name = element.getAttribute("name", null); | |
float opacity = Float.parseFloat(element.getAttribute("opacity", "1.0")); | |
boolean visible = element.getIntAttribute("visible", 1) == 1; | |
float offsetX = element.getFloatAttribute("offsetx", 0); | |
float offsetY = element.getFloatAttribute("offsety", 0); | |
layer.setName(name); | |
layer.setOpacity(opacity); | |
layer.setVisible(visible); | |
layer.setOffsetX(offsetX); | |
layer.setOffsetY(offsetY); | |
} | |
protected void loadObject (TiledMap map, MapLayer layer, XmlReader.Element element) { | |
loadObject(map, layer.getObjects(), element, mapHeightInPixels); | |
} | |
protected void loadObject (TiledMap map, TiledMapTile tile, XmlReader.Element element) { | |
loadObject(map, tile.getObjects(), element, tile.getTextureRegion().getRegionHeight()); | |
} | |
protected void loadObject (TiledMap map, MapObjects objects, XmlReader.Element element, float heightInPixels) { | |
if (element.getName().equals("object")) { | |
MapObject object = null; | |
float scaleX = convertObjectToTileSpace ? 1.0f / mapTileWidth : 1.0f; | |
float scaleY = convertObjectToTileSpace ? 1.0f / mapTileHeight : 1.0f; | |
float x = element.getFloatAttribute("x", 0) * scaleX; | |
float y = (flipY ? (heightInPixels - element.getFloatAttribute("y", 0)) : element.getFloatAttribute("y", 0)) * scaleY; | |
float width = element.getFloatAttribute("width", 0) * scaleX; | |
float height = element.getFloatAttribute("height", 0) * scaleY; | |
if (element.getChildCount() > 0) { | |
XmlReader.Element child = null; | |
if ((child = element.getChildByName("polygon")) != null) { | |
String[] points = child.getAttribute("points").split(" "); | |
float[] vertices = new float[points.length * 2]; | |
for (int i = 0; i < points.length; i++) { | |
String[] point = points[i].split(","); | |
vertices[i * 2] = Float.parseFloat(point[0]) * scaleX; | |
vertices[i * 2 + 1] = Float.parseFloat(point[1]) * scaleY * (flipY ? -1 : 1); | |
} | |
Polygon polygon = new Polygon(vertices); | |
polygon.setPosition(x, y); | |
object = new PolygonMapObject(polygon); | |
} else if ((child = element.getChildByName("polyline")) != null) { | |
String[] points = child.getAttribute("points").split(" "); | |
float[] vertices = new float[points.length * 2]; | |
for (int i = 0; i < points.length; i++) { | |
String[] point = points[i].split(","); | |
vertices[i * 2] = Float.parseFloat(point[0]) * scaleX; | |
vertices[i * 2 + 1] = Float.parseFloat(point[1]) * scaleY * (flipY ? -1 : 1); | |
} | |
Polyline polyline = new Polyline(vertices); | |
polyline.setPosition(x, y); | |
object = new PolylineMapObject(polyline); | |
} else if ((child = element.getChildByName("ellipse")) != null) { | |
object = new EllipseMapObject(x, flipY ? y - height : y, width, height); | |
} | |
} | |
if (object == null) { | |
String gid = null; | |
if ((gid = element.getAttribute("gid", null)) != null) { | |
int id = (int)Long.parseLong(gid); | |
boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0); | |
boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0); | |
TiledMapTile tile = map.getTileSets().getTile(id & ~MASK_CLEAR); | |
TiledMapTileMapObject tiledMapTileMapObject = new TiledMapTileMapObject(tile, flipHorizontally, flipVertically); | |
TextureRegion textureRegion = tiledMapTileMapObject.getTextureRegion(); | |
tiledMapTileMapObject.getProperties().put("gid", id); | |
tiledMapTileMapObject.setX(x); | |
tiledMapTileMapObject.setY(flipY ? y : y - height); | |
float objectWidth = element.getFloatAttribute("width", textureRegion.getRegionWidth()); | |
float objectHeight = element.getFloatAttribute("height", textureRegion.getRegionHeight()); | |
tiledMapTileMapObject.setScaleX(scaleX * (objectWidth / textureRegion.getRegionWidth())); | |
tiledMapTileMapObject.setScaleY(scaleY * (objectHeight / textureRegion.getRegionHeight())); | |
tiledMapTileMapObject.setRotation(element.getFloatAttribute("rotation", 0)); | |
object = tiledMapTileMapObject; | |
} else { | |
object = new RectangleMapObject(x, flipY ? y - height : y, width, height); | |
} | |
} | |
object.setName(element.getAttribute("name", null)); | |
String rotation = element.getAttribute("rotation", null); | |
if (rotation != null) { | |
object.getProperties().put("rotation", Float.parseFloat(rotation)); | |
} | |
String type = element.getAttribute("type", null); | |
if (type != null) { | |
object.getProperties().put("type", type); | |
} | |
int id = element.getIntAttribute("id", 0); | |
if (id != 0) { | |
object.getProperties().put("id", id); | |
} | |
object.getProperties().put("x", x); | |
if (object instanceof TiledMapTileMapObject) { | |
object.getProperties().put("y", y); | |
} else { | |
object.getProperties().put("y", (flipY ? y - height : y)); | |
} | |
object.getProperties().put("width", width); | |
object.getProperties().put("height", height); | |
object.setVisible(element.getIntAttribute("visible", 1) == 1); | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(object.getProperties(), properties); | |
} | |
objects.add(object); | |
} | |
} | |
protected void loadProperties (MapProperties properties, XmlReader.Element element) { | |
if (element == null) return; | |
if (element.getName().equals("properties")) { | |
for (XmlReader.Element property : element.getChildrenByName("property")) { | |
String name = property.getAttribute("name", null); | |
String value = property.getAttribute("value", null); | |
String type = property.getAttribute("type", null); | |
if (value == null) { | |
value = property.getText(); | |
} | |
Object castValue = castProperty(name, value, type); | |
properties.put(name, castValue); | |
} | |
} | |
} | |
private Object castProperty (String name, String value, String type) { | |
if (type == null) { | |
return value; | |
} else if (type.equals("int")) { | |
return Integer.valueOf(value); | |
} else if (type.equals("float")) { | |
return Float.valueOf(value); | |
} else if (type.equals("bool")) { | |
return Boolean.valueOf(value); | |
} else if (type.equals("color")) { | |
// Tiled uses the format #AARRGGBB | |
String opaqueColor = value.substring(3); | |
String alpha = value.substring(1, 3); | |
return Color.valueOf(opaqueColor + alpha); | |
} else { | |
throw new GdxRuntimeException("Wrong type given for property " + name + ", given : " + type | |
+ ", supported : string, bool, int, float, color"); | |
} | |
} | |
protected TiledMapTileLayer.Cell createTileLayerCell (boolean flipHorizontally, boolean flipVertically, boolean flipDiagonally) { | |
TiledMapTileLayer.Cell cell = new TiledMapTileLayer.Cell(); | |
if (flipDiagonally) { | |
if (flipHorizontally && flipVertically) { | |
cell.setFlipHorizontally(true); | |
cell.setRotation(Cell.ROTATE_270); | |
} else if (flipHorizontally) { | |
cell.setRotation(Cell.ROTATE_270); | |
} else if (flipVertically) { | |
cell.setRotation(Cell.ROTATE_90); | |
} else { | |
cell.setFlipVertically(true); | |
cell.setRotation(Cell.ROTATE_270); | |
} | |
} else { | |
cell.setFlipHorizontally(flipHorizontally); | |
cell.setFlipVertically(flipVertically); | |
} | |
return cell; | |
} | |
static public int[] getTileIds (XmlReader.Element element, int width, int height) { | |
XmlReader.Element data = element.getChildByName("data"); | |
String encoding = data.getAttribute("encoding", null); | |
if (encoding == null) { // no 'encoding' attribute means that the encoding is XML | |
throw new GdxRuntimeException("Unsupported encoding (XML) for TMX Layer Data"); | |
} | |
int[] ids = new int[width * height]; | |
if (encoding.equals("csv")) { | |
String[] array = data.getText().split(","); | |
for (int i = 0; i < array.length; i++) | |
ids[i] = (int)Long.parseLong(array[i].trim()); | |
} else { | |
if (true) | |
if (encoding.equals("base64")) { | |
InputStream is = null; | |
try { | |
String compression = data.getAttribute("compression", null); | |
byte[] bytes = Base64Coder.decode(data.getText()); | |
if (compression == null) | |
is = new ByteArrayInputStream(bytes); | |
else if (compression.equals("gzip")) | |
is = new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(bytes), bytes.length)); | |
else if (compression.equals("zlib")) | |
is = new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(bytes))); | |
else | |
throw new GdxRuntimeException("Unrecognised compression (" + compression + ") for TMX Layer Data"); | |
byte[] temp = new byte[4]; | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
int read = is.read(temp); | |
while (read < temp.length) { | |
int curr = is.read(temp, read, temp.length - read); | |
if (curr == -1) break; | |
read += curr; | |
} | |
if (read != temp.length) | |
throw new GdxRuntimeException("Error Reading TMX Layer Data: Premature end of tile data"); | |
ids[y * width + x] = unsignedByteToInt(temp[0]) | unsignedByteToInt(temp[1]) << 8 | |
| unsignedByteToInt(temp[2]) << 16 | unsignedByteToInt(temp[3]) << 24; | |
} | |
} | |
} catch (IOException e) { | |
throw new GdxRuntimeException("Error Reading TMX Layer Data - IOException: " + e.getMessage()); | |
} finally { | |
StreamUtils.closeQuietly(is); | |
} | |
} else { | |
// any other value of 'encoding' is one we're not aware of, probably a feature of a future version of Tiled | |
// or another editor | |
throw new GdxRuntimeException("Unrecognised encoding (" + encoding + ") for TMX Layer Data"); | |
} | |
} | |
return ids; | |
} | |
protected static int unsignedByteToInt (byte b) { | |
return b & 0xFF; | |
} | |
protected static FileHandle getRelativeFileHandle (FileHandle file, String path) { | |
StringTokenizer tokenizer = new StringTokenizer(path, "\\/"); | |
FileHandle result = file.parent(); | |
while (tokenizer.hasMoreElements()) { | |
String token = tokenizer.nextToken(); | |
if (token.equals("..")) | |
result = result.parent(); | |
else { | |
result = result.child(token); | |
} | |
} | |
return result; | |
} | |
protected void loadTileSet (XmlReader.Element element, FileHandle tmxFile) { | |
if (element.getName().equals("tileset")) { | |
int firstgid = element.getIntAttribute("firstgid", 1); | |
String imageSource = ""; | |
int imageWidth = 0; | |
int imageHeight = 0; | |
FileHandle image = null; | |
String source = element.getAttribute("source", null); | |
if (source != null) { | |
FileHandle tsx = getRelativeFileHandle(tmxFile, source); | |
try { | |
element = xml.parse(tsx); | |
XmlReader.Element imageElement = element.getChildByName("image"); | |
if (imageElement != null) { | |
imageSource = imageElement.getAttribute("source"); | |
imageWidth = imageElement.getIntAttribute("width", 0); | |
imageHeight = imageElement.getIntAttribute("height", 0); | |
image = getRelativeFileHandle(tsx, imageSource); | |
} | |
} catch (SerializationException e) { | |
throw new GdxRuntimeException("Error parsing external tileset."); | |
} | |
} else { | |
XmlReader.Element imageElement = element.getChildByName("image"); | |
if (imageElement != null) { | |
imageSource = imageElement.getAttribute("source"); | |
imageWidth = imageElement.getIntAttribute("width", 0); | |
imageHeight = imageElement.getIntAttribute("height", 0); | |
image = getRelativeFileHandle(tmxFile, imageSource); | |
} | |
} | |
String name = element.get("name", null); | |
int tilewidth = element.getIntAttribute("tilewidth", 0); | |
int tileheight = element.getIntAttribute("tileheight", 0); | |
int spacing = element.getIntAttribute("spacing", 0); | |
int margin = element.getIntAttribute("margin", 0); | |
XmlReader.Element offset = element.getChildByName("tileoffset"); | |
int offsetX = 0; | |
int offsetY = 0; | |
if (offset != null) { | |
offsetX = offset.getIntAttribute("x", 0); | |
offsetY = offset.getIntAttribute("y", 0); | |
} | |
TiledMapTileSet tileSet = new TiledMapTileSet(); | |
// TileSet | |
tileSet.setName(name); | |
final MapProperties tileSetProperties = tileSet.getProperties(); | |
XmlReader.Element properties = element.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(tileSetProperties, properties); | |
} | |
tileSetProperties.put("firstgid", firstgid); | |
// Tiles | |
Array<XmlReader.Element> tileElements = element.getChildrenByName("tile"); | |
addStaticTiles(tmxFile, tileSet, element, tileElements, name, firstgid, tilewidth, tileheight, spacing, | |
margin, source, offsetX, offsetY, imageSource, imageWidth, imageHeight, image); | |
Array<AnimatedTiledMapTile> animatedTiles = new Array<AnimatedTiledMapTile>(); | |
for (XmlReader.Element tileElement : tileElements) { | |
int localtid = tileElement.getIntAttribute("id", 0); | |
TiledMapTile tile = tileSet.getTile(firstgid + localtid); | |
if (tile != null) { | |
AnimatedTiledMapTile animatedTile = createAnimatedTile(tileSet, tile, tileElement, firstgid); | |
if (animatedTile != null) { | |
animatedTiles.add(animatedTile); | |
tile = animatedTile; | |
} | |
addTileProperties(tile, tileElement); | |
addTileObjectGroup(tile, tileElement); | |
} | |
} | |
// replace original static tiles by animated tiles | |
for (AnimatedTiledMapTile animatedTile : animatedTiles) { | |
tileSet.putTile(animatedTile.getId(), animatedTile); | |
} | |
map.getTileSets().addTileSet(tileSet); | |
} | |
} | |
protected abstract void addStaticTiles (FileHandle tmxFile, TiledMapTileSet tileset, | |
XmlReader.Element element, Array<XmlReader.Element> tileElements, String name, int firstgid, int tilewidth, int tileheight, int spacing, | |
int margin, String source, int offsetX, int offsetY, String imageSource, int imageWidth, int imageHeight, FileHandle image); | |
protected void addTileProperties (TiledMapTile tile, XmlReader.Element tileElement) { | |
String terrain = tileElement.getAttribute("terrain", null); | |
if (terrain != null) { | |
tile.getProperties().put("terrain", terrain); | |
} | |
String probability = tileElement.getAttribute("probability", null); | |
if (probability != null) { | |
tile.getProperties().put("probability", probability); | |
} | |
XmlReader.Element properties = tileElement.getChildByName("properties"); | |
if (properties != null) { | |
loadProperties(tile.getProperties(), properties); | |
} | |
} | |
protected void addTileObjectGroup (TiledMapTile tile, XmlReader.Element tileElement) { | |
XmlReader.Element objectgroupElement = tileElement.getChildByName("objectgroup"); | |
if (objectgroupElement != null) { | |
for (XmlReader.Element objectElement : objectgroupElement.getChildrenByName("object")) { | |
loadObject(map, tile, objectElement); | |
} | |
} | |
} | |
protected AnimatedTiledMapTile createAnimatedTile (TiledMapTileSet tileSet, TiledMapTile tile, XmlReader.Element tileElement, | |
int firstgid) { | |
XmlReader.Element animationElement = tileElement.getChildByName("animation"); | |
if (animationElement != null) { | |
Array<StaticTiledMapTile> staticTiles = new Array<StaticTiledMapTile>(); | |
IntArray intervals = new IntArray(); | |
for (XmlReader.Element frameElement : animationElement.getChildrenByName("frame")) { | |
staticTiles.add((StaticTiledMapTile)tileSet.getTile(firstgid + frameElement.getIntAttribute("tileid"))); | |
intervals.add(frameElement.getIntAttribute("duration")); | |
} | |
AnimatedTiledMapTile animatedTile = new AnimatedTiledMapTile(intervals, staticTiles); | |
animatedTile.setId(tile.getId()); | |
return animatedTile; | |
} | |
return null; | |
} | |
protected void addStaticTiledMapTile (TiledMapTileSet tileSet, int tileId, float offsetX, | |
float offsetY) { | |
TiledMapTile tile = new HijackedStaticTiledMap(); | |
tile.setId(tileId); | |
tile.setOffsetX(offsetX); | |
tile.setOffsetY(flipY ? -offsetY : offsetY); | |
tileSet.putTile(tileId, tile); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.graphics.g2d.TextureRegion; | |
import com.badlogic.gdx.maps.MapLayer; | |
public class HijackedMapImageLayer extends MapLayer { | |
private float x; | |
private float y; | |
public HijackedMapImageLayer (float x, float y) { | |
this.x = x; | |
this.y = y; | |
} | |
public TextureRegion getTextureRegion () { | |
return null; | |
} | |
public void setTextureRegion (TextureRegion region) { | |
} | |
public float getX () { | |
return x; | |
} | |
public void setX (float x) { | |
this.x = x; | |
} | |
public float getY () { | |
return y; | |
} | |
public void setY (float y) { | |
this.y = y; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.graphics.g2d.TextureRegion; | |
import com.badlogic.gdx.maps.MapObjects; | |
import com.badlogic.gdx.maps.MapProperties; | |
import com.badlogic.gdx.maps.tiled.TiledMapTile; | |
/** @brief Represents a non changing {@link TiledMapTile} (can be cached) */ | |
public class HijackedStaticTiledMap implements TiledMapTile { | |
private int id; | |
private TiledMapTile.BlendMode blendMode = BlendMode.ALPHA; | |
private MapProperties properties; | |
private MapObjects objects; | |
private float offsetX; | |
private float offsetY; | |
@Override | |
public int getId () { | |
return id; | |
} | |
@Override | |
public void setId (int id) { | |
this.id = id; | |
} | |
@Override | |
public BlendMode getBlendMode () { | |
return blendMode; | |
} | |
@Override | |
public void setBlendMode (BlendMode blendMode) { | |
this.blendMode = blendMode; | |
} | |
@Override | |
public MapProperties getProperties () { | |
if (properties == null) { | |
properties = new MapProperties(); | |
} | |
return properties; | |
} | |
@Override | |
public MapObjects getObjects() { | |
if (objects == null) { | |
objects = new MapObjects(); | |
} | |
return objects; | |
} | |
@Override | |
public TextureRegion getTextureRegion () { | |
return null; | |
} | |
@Override | |
public void setTextureRegion(TextureRegion textureRegion) { | |
} | |
@Override | |
public float getOffsetX () { | |
return offsetX; | |
} | |
@Override | |
public void setOffsetX (float offsetX) { | |
this.offsetX = offsetX; | |
} | |
@Override | |
public float getOffsetY () { | |
return offsetY; | |
} | |
@Override | |
public void setOffsetY (float offsetY) { | |
this.offsetY = offsetY; | |
} | |
/** Creates a static tile with the given region | |
*/ | |
public HijackedStaticTiledMap () { | |
} | |
/** Copy constructor | |
* | |
* @param copy the StaticTiledMapTile to copy. */ | |
public HijackedStaticTiledMap (HijackedStaticTiledMap copy) { | |
if (copy.properties != null) { | |
getProperties().putAll(copy.properties); | |
} | |
this.objects = copy.objects; | |
this.id = copy.id; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.assets.AssetDescriptor; | |
import com.badlogic.gdx.assets.AssetManager; | |
import com.badlogic.gdx.assets.loaders.FileHandleResolver; | |
import com.badlogic.gdx.assets.loaders.TextureLoader; | |
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver; | |
import com.badlogic.gdx.files.FileHandle; | |
import com.badlogic.gdx.graphics.g2d.TextureRegion; | |
import com.badlogic.gdx.maps.ImageResolver; | |
import com.badlogic.gdx.maps.ImageResolver.AssetManagerImageResolver; | |
import com.badlogic.gdx.maps.ImageResolver.DirectImageResolver; | |
import com.badlogic.gdx.maps.MapProperties; | |
import com.badlogic.gdx.maps.tiled.BaseTmxMapLoader; | |
import com.badlogic.gdx.maps.tiled.TiledMap; | |
import com.badlogic.gdx.maps.tiled.TiledMapTileSet; | |
import com.badlogic.gdx.utils.Array; | |
import com.badlogic.gdx.utils.ObjectMap; | |
import com.badlogic.gdx.utils.XmlReader.Element; | |
/** @brief synchronous loader for TMX maps created with the Tiled tool */ | |
public class HijackedTmxLoader extends HijackedBaseTmxMapLoader<HijackedTmxLoader.Parameters> { | |
public static class Parameters extends BaseTmxMapLoader.Parameters { | |
} | |
public HijackedTmxLoader () { | |
super(new InternalFileHandleResolver()); | |
} | |
/** Creates loader | |
* | |
* @param resolver */ | |
public HijackedTmxLoader (FileHandleResolver resolver) { | |
super(resolver); | |
} | |
/** Loads the {@link TiledMap} from the given file. The file is resolved via the {@link FileHandleResolver} set in the | |
* constructor of this class. By default it will resolve to an internal file. The map will be loaded for a y-up coordinate | |
* system. | |
* @param fileName the filename | |
* @return the TiledMap */ | |
public TiledMap load (String fileName) { | |
return load(fileName, new HijackedTmxLoader.Parameters()); | |
} | |
/** Loads the {@link TiledMap} from the given file. The file is resolved via the {@link FileHandleResolver} set in the | |
* constructor of this class. By default it will resolve to an internal file. | |
* @param fileName the filename | |
* @param parameter specifies whether to use y-up, generate mip maps etc. | |
* @return the TiledMap */ | |
public TiledMap load (String fileName, HijackedTmxLoader.Parameters parameter) { | |
FileHandle tmxFile = resolve(fileName); | |
this.root = xml.parse(tmxFile); | |
TiledMap map = loadTiledMap(tmxFile, parameter); | |
return map; | |
} | |
@Override | |
public void loadAsync (AssetManager manager, String fileName, FileHandle tmxFile, Parameters parameter) { | |
this.map = loadTiledMap(tmxFile, parameter); | |
} | |
@Override | |
public TiledMap loadSync (AssetManager manager, String fileName, FileHandle file, Parameters parameter) { | |
return map; | |
} | |
@Override | |
protected Array<AssetDescriptor> getDependencyAssetDescriptors (FileHandle tmxFile, TextureLoader.TextureParameter textureParameter) { | |
Array<AssetDescriptor> descriptors = new Array<AssetDescriptor>(); | |
final Array<FileHandle> fileHandles = getDependencyFileHandles(tmxFile); | |
for (FileHandle handle : fileHandles) { | |
descriptors.add(new AssetDescriptor(handle, null, textureParameter)); | |
} | |
return descriptors; | |
} | |
private Array<FileHandle> getDependencyFileHandles (FileHandle tmxFile) { | |
Array<FileHandle> fileHandles = new Array<FileHandle>(); | |
// TileSet descriptors | |
for (Element tileset : root.getChildrenByName("tileset")) { | |
String source = tileset.getAttribute("source", null); | |
if (source != null) { | |
FileHandle tsxFile = getRelativeFileHandle(tmxFile, source); | |
tileset = xml.parse(tsxFile); | |
Element imageElement = tileset.getChildByName("image"); | |
if (imageElement != null) { | |
String imageSource = tileset.getChildByName("image").getAttribute("source"); | |
FileHandle image = getRelativeFileHandle(tsxFile, imageSource); | |
fileHandles.add(image); | |
} else { | |
for (Element tile : tileset.getChildrenByName("tile")) { | |
String imageSource = tile.getChildByName("image").getAttribute("source"); | |
FileHandle image = getRelativeFileHandle(tsxFile, imageSource); | |
fileHandles.add(image); | |
} | |
} | |
} else { | |
Element imageElement = tileset.getChildByName("image"); | |
if (imageElement != null) { | |
String imageSource = tileset.getChildByName("image").getAttribute("source"); | |
FileHandle image = getRelativeFileHandle(tmxFile, imageSource); | |
fileHandles.add(image); | |
} else { | |
for (Element tile : tileset.getChildrenByName("tile")) { | |
String imageSource = tile.getChildByName("image").getAttribute("source"); | |
FileHandle image = getRelativeFileHandle(tmxFile, imageSource); | |
fileHandles.add(image); | |
} | |
} | |
} | |
} | |
// ImageLayer descriptors | |
for (Element imageLayer : root.getChildrenByName("imagelayer")) { | |
Element image = imageLayer.getChildByName("image"); | |
String source = image.getAttribute("source", null); | |
if (source != null) { | |
FileHandle handle = getRelativeFileHandle(tmxFile, source); | |
fileHandles.add(handle); | |
} | |
} | |
return fileHandles; | |
} | |
@Override | |
protected void addStaticTiles (FileHandle tmxFile, TiledMapTileSet tileSet, Element element, | |
Array<Element> tileElements, String name, int firstgid, int tilewidth, int tileheight, int spacing, int margin, | |
String source, int offsetX, int offsetY, String imageSource, int imageWidth, int imageHeight, FileHandle image) { | |
MapProperties props = tileSet.getProperties(); | |
if (image != null) { | |
props.put("imagesource", imageSource); | |
props.put("imagewidth", imageWidth); | |
props.put("imageheight", imageHeight); | |
props.put("tilewidth", tilewidth); | |
props.put("tileheight", tileheight); | |
props.put("margin", margin); | |
props.put("spacing", spacing); | |
int id = firstgid; | |
} else { | |
// Every tile has its own image source | |
for (Element tileElement : tileElements) { | |
Element imageElement = tileElement.getChildByName("image"); | |
if (imageElement != null) { | |
imageSource = imageElement.getAttribute("source"); | |
if (source != null) { | |
image = getRelativeFileHandle(getRelativeFileHandle(tmxFile, source), imageSource); | |
} else { | |
image = getRelativeFileHandle(tmxFile, imageSource); | |
} | |
} | |
int tileId = firstgid + tileElement.getIntAttribute("id"); | |
addStaticTiledMapTile(tileSet, tileId, offsetX, offsetY); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.assets.loaders.FileHandleResolver; | |
import com.badlogic.gdx.files.FileHandle; | |
import com.badlogic.gdx.maps.tiled.TiledMap; | |
import java.io.File; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class MyServer { | |
private TiledMap getMap(){ | |
return new HijackedTmxLoader(new MyFileHandleResolver()) | |
.load("path_to_my_map"); | |
} | |
public class MyFileHandleResolver implements FileHandleResolver{ | |
@Override | |
public FileHandle resolve(String fileName) { | |
return new FileHandle(new File(fileName)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment