Implemented correct map loading, legacy format support

This commit is contained in:
Anuken 2019-03-12 10:36:04 -04:00
parent 0fd0abc6c0
commit 20427fdffa
15 changed files with 474 additions and 180 deletions

View file

@ -30,6 +30,8 @@ import java.util.Locale;
@SuppressWarnings("unchecked")
public class Vars{
/**IO buffer size.*/
public static final int bufferSize = 8192;
/**global charset*/
public static final Charset charset = Charset.forName("UTF-8");
/**main application name, capitalized*/

View file

@ -235,7 +235,7 @@ public class World implements ApplicationListener{
try{
createTiles(map.width, map.height);
tiles = MapIO.readTiles(map, tiles);
MapIO.readTiles(map, tiles);
prepareTiles(tiles);
}catch(Exception e){
Log.err(e);

View file

@ -2,6 +2,12 @@ package io.anuke.mindustry.editor;
import io.anuke.annotations.Annotations.Struct;
import io.anuke.arc.collection.LongArray;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.TileOp;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import static io.anuke.mindustry.Vars.content;
public class DrawOperation{
private LongArray array = new LongArray();
@ -17,12 +23,28 @@ public class DrawOperation{
public void undo(MapEditor editor){
for(int i = 0; i < array.size; i++){
long l = array.get(i);
set(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.from(l));
}
}
public void redo(MapEditor editor){
for(int i = 0; i < array.size; i++){
long l = array.get(i);
set(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.to(l));
}
}
void set(Tile tile, byte type, byte to){
if(type == OpType.floor.ordinal()){
tile.setFloor((Floor)content.block(to));
}else if(type == OpType.block.ordinal()){
tile.setBlock(content.block(to));
}else if(type == OpType.rotation.ordinal()){
tile.setRotation(to);
}else if(type == OpType.team.ordinal()){
tile.setTeam(Team.all[to]);
}else if(type == OpType.ore.ordinal()){
tile.setOre(to);
}
}
@ -39,6 +61,7 @@ public class DrawOperation{
floor,
block,
rotation,
team
team,
ore
}
}

View file

@ -6,6 +6,10 @@ import io.anuke.mindustry.gen.TileOp;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.modules.ConsumeModule;
import io.anuke.mindustry.world.modules.ItemModule;
import io.anuke.mindustry.world.modules.LiquidModule;
import io.anuke.mindustry.world.modules.PowerModule;
import static io.anuke.mindustry.Vars.ui;
@ -28,7 +32,7 @@ public class EditorTile extends Tile{
Block previous = block();
if(previous == type) return;
super.setBlock(type);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous.id, type.id));
op(TileOp.get(x, y, (byte)OpType.block.ordinal(), previous.id, type.id));
}
@Override
@ -36,7 +40,7 @@ public class EditorTile extends Tile{
byte previous = getTeamID();
if(previous == team.ordinal()) return;
super.setTeam(team);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous, (byte)team.ordinal()));
op(TileOp.get(x, y, (byte)OpType.team.ordinal(), previous, (byte)team.ordinal()));
}
@Override
@ -44,7 +48,35 @@ public class EditorTile extends Tile{
byte previous = getRotation();
if(previous == rotation) return;
super.setRotation(rotation);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous, rotation));
op(TileOp.get(x, y, (byte)OpType.rotation.ordinal(), previous, rotation));
}
@Override
public void setOre(byte ore){
byte previous = getRotation();
if(previous == ore) return;
super.setOre(ore);
op(TileOp.get(x, y, (byte)OpType.ore.ordinal(), previous, ore));
}
@Override
protected void preChanged(){
super.setTeam(Team.none);
}
@Override
protected void changed(){
entity = null;
Block block = block();
if(block.hasEntity()){
entity = block.newEntity();
entity.cons = new ConsumeModule(entity);
if(block.hasItems) entity.items = new ItemModule();
if(block.hasLiquids) entity.liquids = new LiquidModule();
if(block.hasPower) entity.power = new PowerModule();
}
}
private static void op(long op){

View file

@ -3,6 +3,7 @@ package io.anuke.mindustry.editor;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Pack;
import io.anuke.arc.util.Structs;
import io.anuke.mindustry.content.Blocks;

View file

@ -1,5 +1,6 @@
package io.anuke.mindustry.io;
import io.anuke.arc.collection.IntIntMap;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.collection.ObjectMap.Entry;
import io.anuke.arc.files.FileHandle;
@ -13,26 +14,40 @@ import io.anuke.mindustry.game.MappableContent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.CachedTile;
import io.anuke.mindustry.world.LegacyColorMapper;
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.mindustry.world.blocks.Floor;
import java.io.*;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import static io.anuke.mindustry.Vars.bufferSize;
import static io.anuke.mindustry.Vars.content;
import static io.anuke.mindustry.Vars.world;
/** Reads and writes map files.*/
public class MapIO{
private static final int version = 1;
public static final int version = 1;
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
private static ObjectMap<String, Block> missingBlocks;
private static void initBlocks(){
if(missingBlocks != null) return;
missingBlocks = ObjectMap.of(
"stained-stone", Blocks.moss
);
}
public static boolean isImage(FileHandle file){
try(InputStream stream = file.read()){
try(InputStream stream = file.read(32)){
for(int i1 : pngHeader){
if(stream.read() != i1){
return false;
@ -45,8 +60,20 @@ public class MapIO{
}
//TODO implement
public static Pixmap generatePreview(Map map){
return null;
public static Pixmap generatePreview(Map map) throws IOException{
Pixmap pixmap = new Pixmap(map.width, map.height, Format.RGBA8888);
CachedTile tile = new CachedTile(){
@Override
protected void changed(){
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, colorFor(floor(), block(), getTeam()));
}
};
readTiles(map, (x, y) -> {
tile.x = (short)x;
tile.y = (short)y;
return tile;
});
return pixmap;
}
public static Pixmap generatePreview(Tile[][] tiles){
@ -60,6 +87,222 @@ public class MapIO{
return pixmap;
}
public static int colorFor(Block floor, Block wall, Team team){
if(wall.synthetic()){
return team.intColor;
}
return Color.rgba8888(wall.solid ? wall.color : floor.color);
}
public static void writeMap(FileHandle file, Map map, Tile[][] tiles) throws IOException{
OutputStream output = file.write(false, bufferSize);
{
DataOutputStream stream = new DataOutputStream(output);
stream.writeInt(version);
stream.writeInt(Version.build);
stream.writeShort(tiles.length);
stream.writeShort(tiles[0].length);
stream.writeByte((byte)map.tags.size);
for(Entry<String, String> entry : map.tags.entries()){
stream.writeUTF(entry.key);
stream.writeUTF(entry.value);
}
}
try(DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(output))){
int width = map.width, height = map.height;
SaveIO.getSaveWriter().writeContentHeader(stream);
//floor first
for(int i = 0; i < tiles.length * tiles[0].length; i++){
Tile tile = tiles[i % width][i / width];
stream.writeByte(tile.getFloorID());
stream.writeByte(tile.getOre());
int consecutives = 0;
for(int j = i + 1; j < width * height && consecutives < 255; j++){
Tile nextTile = tiles[j % width][j / width];
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getOre() != tile.getOre()){
break;
}
consecutives++;
}
stream.writeByte(consecutives);
i += consecutives;
}
//then blocks
for(int i = 0; i < tiles.length * tiles[0].length; i++){
Tile tile = tiles[i % width][i / width];
stream.writeByte(tile.getBlockID());
if(tile.block() instanceof BlockPart){
stream.writeByte(tile.link);
}else if(tile.entity != null){
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation
stream.writeShort((short)tile.entity.health); //health
tile.entity.writeConfig(stream);
}else{
//write consecutive non-entity blocks
int consecutives = 0;
for(int j = i + 1; j < width * height && consecutives < 255; j++){
Tile nextTile = tiles[j % width][j / width];
if(nextTile.block() != tile.block()){
break;
}
consecutives++;
}
stream.writeByte(consecutives);
i += consecutives;
}
}
}
}
public static Map readMap(FileHandle file, boolean custom) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read(1024))){
ObjectMap<String, String> tags = new ObjectMap<>();
//meta is uncompressed
int version = stream.readInt();
if(version == 0){
return readLegacyMap(file, custom);
}
int build = stream.readInt();
short width = stream.readShort(), height = stream.readShort();
byte tagAmount = stream.readByte();
for(int i = 0; i < tagAmount; i++){
String name = stream.readUTF();
String value = stream.readUTF();
tags.put(name, value);
}
return new Map(file, width, height, tags, custom, version, build);
}
}
/**Reads tiles from a map, version-agnostic.*/
public static void readTiles(Map map, Tile[][] tiles) throws IOException{
readTiles(map, (x, y) -> tiles[x][y]);
}
/**Reads tiles from a map, version-agnostic.*/
public static void readTiles(Map map, TileProvider tiles) throws IOException{
if(map.version == 0){
readLegacyMmapTiles(map.file, tiles);
}else if(map.version == version){
readTiles(map.file, map.width, map.height, tiles);
}else{
throw new IOException("Unknown map version. What?");
}
}
/**Reads tiles from a map in the new build-65 format.*/
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
readTiles(file, width, height, (x, y) -> tiles[x][y]);
}
/**Reads tiles from a map in the new build-65 format.*/
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
try(BufferedInputStream input = file.read(bufferSize)){
//read map
{
DataInputStream stream = new DataInputStream(input);
stream.readInt(); //version
stream.readInt(); //build
stream.readInt(); //width + height
byte tagAmount = stream.readByte();
for(int i = 0; i < tagAmount; i++){
stream.readUTF();
stream.readUTF();
}
}
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
MappableContent[][] c = SaveIO.getSaveWriter().readContentHeader(stream);
try{
content.setTemporaryMapper(c);
//read floor and create tiles first
for(int i = 0; i < width * height; i++){
int x = i % width, y = i / width;
byte floorid = stream.readByte();
byte oreid = stream.readByte();
int consecutives = stream.readUnsignedByte();
Tile tile = tiles.get(x, y);
tile.setFloor((Floor)content.block(floorid));
tile.setOre(oreid);
for(int j = i + 1; j < i + 1 + consecutives; j++){
int newx = j % width, newy = j / width;
Tile newTile = tiles.get(newx, newy);
newTile.setFloor((Floor)content.block(floorid));
newTile.setOre(oreid);
}
i += consecutives;
}
//read blocks
for(int i = 0; i < width * height; i++){
int x = i % width, y = i / width;
Block block = content.block(stream.readByte());
Tile tile = tiles.get(x, y);
tile.setBlock(block);
if(block == Blocks.part){
tile.link = stream.readByte();
}else if(tile.entity != null){
byte tr = stream.readByte();
short health = stream.readShort();
byte team = Pack.leftByte(tr);
byte rotation = Pack.rightByte(tr);
tile.setTeam(Team.all[team]);
tile.entity.health = health;
tile.setRotation(rotation);
tile.entity.readConfig(stream);
}else{ //no entity/part, read consecutives
int consecutives = stream.readUnsignedByte();
for(int j = i + 1; j < i + 1 + consecutives; j++){
int newx = j % width, newy = j / width;
tiles.get(newx, newy).setBlock(block);
}
i += consecutives;
}
}
}finally{
content.setTemporaryMapper(null);
}
}
}
}
//region legacy IO
/**Reads a pixmap in the 3.5 pixmap format.*/
public static void readLegacyPixmap(Pixmap pixmap, Tile[][] tiles){
for(int x = 0; x < pixmap.getWidth(); x++){
@ -96,100 +339,88 @@ public class MapIO{
}
}
//TODO implement
/**Reads a pixmap in the old 4.0 .mmap format.*/
private static void readLegacyMmap(FileHandle file, Tile[][] tiles) throws IOException{
private static void readLegacyMmapTiles(FileHandle file, Tile[][] tiles) throws IOException{
readLegacyMmapTiles(file, (x, y) -> tiles[x][y]);
}
public static int colorFor(Block floor, Block wall, Team team){
if(wall.synthetic()){
return team.intColor;
}
return Color.rgba8888(wall.solid ? wall.color : floor.color);
}
//TODO implement
/**Reads a mmap in the old 4.0 .mmap format.*/
private static void readLegacyMmapTiles(FileHandle file, TileProvider tiles) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
stream.readInt(); //version
byte tagAmount = stream.readByte();
public static void writeMap(FileHandle file, Map map, Tile[][] tiles) throws IOException{
OutputStream output = file.write(false);
try(DataOutputStream stream = new DataOutputStream(output)){
stream.writeInt(version);
stream.writeInt(Version.build);
stream.writeShort(tiles.length);
stream.writeShort(tiles[0].length);
stream.writeByte((byte)map.tags.size);
for(Entry<String, String> entry : map.tags.entries()){
stream.writeUTF(entry.key);
stream.writeUTF(entry.value);
}
}
try(DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(output))){
SaveIO.getSaveWriter().writeContentHeader(stream);
//floor first
for(int i = 0; i < tiles.length * tiles[0].length; i++){
Tile tile = world.tile(i % world.width(), i / world.width());
stream.writeByte(tile.getFloorID());
stream.writeByte(tile.getOre());
int consecutives = 0;
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
Tile nextTile = world.tile(j % world.width(), j / world.width());
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getOre() != tile.getOre()){
break;
}
consecutives++;
}
stream.writeByte(consecutives);
i += consecutives;
for(int i = 0; i < tagAmount; i++){
stream.readUTF(); //key
stream.readUTF(); //val
}
//then blocks
for(int i = 0; i < tiles.length * tiles[0].length; i++){
Tile tile = world.tile(i % world.width(), i / world.width());
stream.writeByte(tile.getBlockID());
initBlocks();
if(tile.block() instanceof BlockPart){
stream.writeByte(tile.link);
}else if(tile.entity != null){
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation
stream.writeShort((short)tile.entity.health); //health
tile.entity.writeConfig(stream);
}else{
//write consecutive non-entity blocks
int consecutives = 0;
//block id -> real id map
IntIntMap map = new IntIntMap();
IntIntMap oreMap = new IntIntMap();
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
Tile nextTile = world.tile(j % world.width(), j / world.width());
if(nextTile.block() != tile.block()){
break;
short blocks = stream.readShort();
for(int i = 0; i < blocks; i++){
short id = stream.readShort();
String name = stream.readUTF();
Block block = content.getByName(ContentType.block, name);
if(block == null){
//substitute for replacement in missingBlocks if possible
if(missingBlocks.containsKey(name)){
block = missingBlocks.get(name);
}else if(name.startsWith("ore-")){ //an ore floor combination
String[] split = name.split("-");
String itemName = split[1], floorName = split[2];
Item item = content.getByName(ContentType.item, itemName);
Block floor = content.getByName(ContentType.block, floorName);
if(item != null && floor != null){
oreMap.put(id, item.id);
block = floor;
}else{
block = Blocks.air;
}
consecutives++;
}else{
block = Blocks.air;
}
stream.writeByte(consecutives);
i += consecutives;
}
map.put(id, block.id);
}
short width = stream.readShort(), height = stream.readShort();
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
Tile tile = tiles.get(x, y);
byte floorb = stream.readByte();
byte blockb = stream.readByte();
byte rotTeamb = stream.readByte();
byte linkb = stream.readByte();
stream.readByte(); //unused stuff
tile.setFloor((Floor)content.block(map.get(floorb, 0)));
tile.setBlock(content.block(map.get(blockb, 0)));
tile.setRotation(Pack.leftByte(rotTeamb));
if(tile.block() == Blocks.part){
tile.setLinkByte(linkb);
}
if(oreMap.containsKey(floorb)){
tile.setOre((byte)oreMap.get(floorb, 0));
}
}
}
}
}
public static Map readMap(FileHandle file, boolean custom) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read())){
private static Map readLegacyMap(FileHandle file, boolean custom) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
ObjectMap<String, String> tags = new ObjectMap<>();
//meta is uncompressed
int version = stream.readInt();
int build = stream.readInt();
short width = stream.readShort(), height = stream.readShort();
if(version != 0) throw new IOException("Attempted to read non-legacy map in legacy method!");
byte tagAmount = stream.readByte();
for(int i = 0; i < tagAmount; i++){
@ -198,83 +429,21 @@ public class MapIO{
tags.put(name, value);
}
return new Map(file, width, height, tags, custom);
}
}
public static Tile[][] readTiles(Map map, Tile[][] tiles) throws IOException{
return readTiles(map.file, map.width, map.height, tiles);
}
public static Tile[][] readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
readMap(file, false);
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(file.read()))){
MappableContent[][] c = SaveIO.getSaveWriter().readContentHeader(stream);
try{
content.setTemporaryMapper(c);
//read floor and create tiles first
for(int i = 0; i < width * height; i++){
int x = i % width, y = i / width;
byte floorid = stream.readByte();
byte oreid = stream.readByte();
int consecutives = stream.readUnsignedByte();
tiles[x][y] = new Tile(x, y, floorid, (byte)0);
tiles[x][y].setOre(oreid);
for(int j = i + 1; j < i + 1 + consecutives; j++){
int newx = j % width, newy = j / width;
Tile newTile = new Tile(newx, newy, floorid, (byte)0);
newTile.setOre(oreid);
tiles[newx][newy] = newTile;
}
i += consecutives;
}
//read blocks
for(int i = 0; i < width * height; i++){
int x = i % width, y = i / width;
Block block = content.block(stream.readByte());
Tile tile = tiles[x][y];
tile.setBlock(block);
if(block == Blocks.part){
tile.link = stream.readByte();
}else if(tile.entity != null){
byte tr = stream.readByte();
short health = stream.readShort();
byte team = Pack.leftByte(tr);
byte rotation = Pack.rightByte(tr);
tile.setTeam(Team.all[team]);
tile.entity.health = health;
tile.setRotation(rotation);
tile.entity.readConfig(stream);
}else{ //no entity/part, read consecutives
int consecutives = stream.readUnsignedByte();
for(int j = i + 1; j < i + 1 + consecutives; j++){
int newx = j % width, newy = j / width;
tiles[newx][newy].setBlock(block);
}
i += consecutives;
}
}
return tiles;
}finally{
content.setTemporaryMapper(null);
short blocks = stream.readShort();
for(int i = 0; i < blocks; i++){
stream.readShort();
stream.readUTF();
}
short width = stream.readShort(), height = stream.readShort();
//note that build 64 is the default build of all maps <65; while this can be inaccurate it's better than nothing
return new Map(file, width, height, tags, custom, 0, 64);
}
}
//endregion
interface TileProvider{
Tile get(int x, int y);
}
}

View file

@ -48,7 +48,7 @@ public class SaveIO{
}
public static DataInputStream getSlotStream(int slot){
return new DataInputStream(new InflaterInputStream(fileFor(slot).read()));
return new DataInputStream(new InflaterInputStream(fileFor(slot).read(bufferSize)));
}
public static boolean isSaveValid(int slot){
@ -60,7 +60,7 @@ public class SaveIO{
}
public static boolean isSaveValid(FileHandle file){
return isSaveValid(new DataInputStream(new InflaterInputStream(file.read())));
return isSaveValid(new DataInputStream(new InflaterInputStream(file.read(bufferSize))));
}
public static boolean isSaveValid(DataInputStream stream){
@ -95,7 +95,7 @@ public class SaveIO{
}
public static void write(FileHandle file){
write(new DeflaterOutputStream(file.write(false)){
write(new DeflaterOutputStream(file.write(false, bufferSize)){
byte[] tmp = {0};
public void write(int var1) throws IOException {
@ -120,12 +120,12 @@ public class SaveIO{
public static void load(FileHandle file) throws SaveException{
try{
//try and load; if any exception at all occurs
load(new InflaterInputStream(file.read()));
load(new InflaterInputStream(file.read(bufferSize)));
}catch(SaveException e){
e.printStackTrace();
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
if(backup.exists()){
load(new InflaterInputStream(backup.read()));
load(new InflaterInputStream(backup.read(bufferSize)));
}else{
throw new SaveException(e.getCause());
}

View file

@ -4,6 +4,7 @@ import io.anuke.arc.Core;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Texture;
import io.anuke.mindustry.io.MapIO;
public class Map{
/** Whether this is a custom map.*/
@ -12,17 +13,31 @@ public class Map{
public final ObjectMap<String, String> tags;
/** Base file of this map.*/
public final FileHandle file;
/**Map width/height, shorts.*/
/** Format version.*/
public final int version;
/** Map width/height, shorts.*/
public int width, height;
/** Preview texture.*/
public Texture texture;
/** Build that this map was created in. -1 = unknown or custom build.*/
public int build;
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom){
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom, int version, int build){
this.custom = custom;
this.tags = tags;
this.file = file;
this.width = width;
this.height = height;
this.version = version;
this.build = build;
}
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom, int version){
this(file, width, height, tags, custom, version, -1);
}
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom){
this(file, width, height, tags, custom, MapIO.version);
}
public String fileName(){

View file

@ -103,7 +103,7 @@ public class Maps implements Disposable{
}
/** Import a map, then save it. This updates all values and stored data necessary. */
public void importMap(FileHandle file, Map map){
public void importMap(FileHandle file, Map map) throws IOException{
file.copyTo(customMapDirectory.child(file.name()));
if(!headless){
map.texture = new Texture(MapIO.generatePreview(map));

View file

@ -39,8 +39,13 @@ public class MapsDialog extends FloatingDialog{
ui.showError(Core.bundle.format("editor.import.exists", name));
}else if(conflict != null){
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
world.maps.importMap(file, map);
setup();
try{
world.maps.importMap(file, map);
setup();
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
Log.err(e);
}
});
}else{
world.maps.importMap(file, map);

View file

@ -0,0 +1,46 @@
package io.anuke.mindustry.world;
import io.anuke.arc.collection.IntMap;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.modules.ConsumeModule;
import io.anuke.mindustry.world.modules.ItemModule;
import io.anuke.mindustry.world.modules.LiquidModule;
import io.anuke.mindustry.world.modules.PowerModule;
/**A tile which does not trigger change events and whose entity types are cached.
* Prevents garbage when loading previews.*/
public class CachedTile extends Tile{
private static IntMap<TileEntity> entities = new IntMap<>();
public CachedTile(){
super(0, 0);
}
@Override
protected void preChanged(){
super.setTeam(Team.none);
}
@Override
protected void changed(){
entity = null;
Block block = block();
if(block.hasEntity()){
//cache all entity types so only one is ever created per block type. do not add it.
if(!entities.containsKey(block.id)){
TileEntity n = block.newEntity();
n.cons = new ConsumeModule(entity);
if(block.hasItems) n.items = new ItemModule();
if(block.hasLiquids) n.liquids = new LiquidModule();
if(block.hasPower) n.power = new PowerModule();
entities.put(block.id, n);
}
entity = entities.get(block.id);
}
}
}

View file

@ -361,7 +361,7 @@ public class Tile implements Position, TargetTrait{
}
}
private void preChanged(){
protected void preChanged(){
block().removed(this);
if(entity != null){
entity.removeFromProximity();
@ -369,7 +369,7 @@ public class Tile implements Position, TargetTrait{
team = 0;
}
private void changed(){
protected void changed(){
if(entity != null){
entity.remove();
entity = null;

View file

@ -113,7 +113,7 @@ public class IOSLauncher extends IOSApplication.Delegate {
ui.editor.show();
}
ui.editor.beginEditMap(file.read());
ui.editor.beginEditMap(file);
});
}
});

View file

@ -144,11 +144,11 @@ public class ServerControl implements ApplicationListener{
Call.onInfoMessage((state.rules.pvp
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
+ "\nNext selected map:[accent] "+map.name+"[]"
+ (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+
+ "\nNext selected map:[accent] "+map.name()+"[]"
+ (map.author() != null ? " by[accent] " + map.author() + "[]" : "") + "."+
"\nNew game begins in " + roundExtraTime + " seconds.");
info("Selected next map to be {0}.", map.name);
info("Selected next map to be {0}.", map.name());
Map fmap = map;
@ -199,7 +199,7 @@ public class ServerControl implements ApplicationListener{
if(lastTask != null) lastTask.cancel();
Map result = world.maps.all().find(map -> map.name.equalsIgnoreCase(arg[0]));
Map result = world.maps.all().find(map -> map.name().equalsIgnoreCase(arg[0]));
if(result == null){
err("No map with name &y'{0}'&lr found.", arg[0]);
@ -252,7 +252,7 @@ public class ServerControl implements ApplicationListener{
if(!world.maps.all().isEmpty()){
info("Maps:");
for(Map map : world.maps.all()){
info(" &ly{0}: &lb&fi{1} / {2}x{3}", map.name, map.custom ? "Custom" : "Default", map.meta.width, map.meta.height);
info(" &ly{0}: &lb&fi{1} / {2}x{3}", map.name(), map.custom ? "Custom" : "Default", map.width, map.height);
}
}else{
info("No maps found.");
@ -265,7 +265,7 @@ public class ServerControl implements ApplicationListener{
info("Status: &rserver closed");
}else{
info("Status:");
info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name), state.wave);
info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave);
if(state.rules.waves){
info("&ly {0} enemies.", unitGroups[Team.red.ordinal()].size());

View file

@ -88,6 +88,7 @@ def antialias = {File file ->
ImageIO.write(out, "png", file)
}
task swapColors(){
doLast{
if (project.hasProperty("colors")) {