Merge branches 'master' and 'new-map-format' of https://github.com/Anuken/Mindustry
@@ -178,12 +178,14 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
ui.showError("$save.import.invalid");
|
ui.showError("$save.import.invalid");
|
||||||
}
|
}
|
||||||
}else if(map){ //open map
|
}else if(map){ //open map
|
||||||
|
FileHandle file = Core.files.local("temp-map." + mapExtension);
|
||||||
|
file.write(inStream, false);
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
System.out.println("Opening map.");
|
System.out.println("Opening map.");
|
||||||
if(!ui.editor.isShown()){
|
if(!ui.editor.isShown()){
|
||||||
ui.editor.show();
|
ui.editor.show();
|
||||||
}
|
}
|
||||||
ui.editor.beginEditMap(inStream);
|
ui.editor.beginEditMap(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ editor.description = Description:
|
|||||||
editor.name = Name:
|
editor.name = Name:
|
||||||
editor.teams = Teams
|
editor.teams = Teams
|
||||||
editor.elevation = Elevation
|
editor.elevation = Elevation
|
||||||
editor.errorimageload = Error loading file:\n[accent]{0}
|
editor.errorload = Error loading file:\n[accent]{0}
|
||||||
editor.errorimagesave = Error saving file:\n[accent]{0}
|
editor.errorsave = Error saving file:\n[accent]{0}
|
||||||
editor.generate = Generate
|
editor.generate = Generate
|
||||||
editor.resize = Resize
|
editor.resize = Resize
|
||||||
editor.loadmap = Load Map
|
editor.loadmap = Load Map
|
||||||
@@ -560,7 +560,6 @@ block.white-tree-dead.name = White Tree Dead
|
|||||||
block.white-tree.name = White Tree
|
block.white-tree.name = White Tree
|
||||||
block.spore-cluster.name = Spore Cluster
|
block.spore-cluster.name = Spore Cluster
|
||||||
block.stained-rocks.name = Stained Rocks
|
block.stained-rocks.name = Stained Rocks
|
||||||
block.stained-stone.name = Stained Stone
|
|
||||||
block.stained-rocks-red.name = Stained Rocks Red
|
block.stained-rocks-red.name = Stained Rocks Red
|
||||||
block.stained-stone-red.name = Stained Stone Red
|
block.stained-stone-red.name = Stained Stone Red
|
||||||
block.stained-rocks-yellow.name = Stained Rocks Yellow
|
block.stained-rocks-yellow.name = Stained Rocks Yellow
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 496 B |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 235 KiB |
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 164 KiB |
@@ -30,6 +30,8 @@ import java.util.Locale;
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class Vars{
|
public class Vars{
|
||||||
|
/**IO buffer size.*/
|
||||||
|
public static final int bufferSize = 8192;
|
||||||
/**global charset*/
|
/**global charset*/
|
||||||
public static final Charset charset = Charset.forName("UTF-8");
|
public static final Charset charset = Charset.forName("UTF-8");
|
||||||
/**main application name, capitalized*/
|
/**main application name, capitalized*/
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public class BlockIndexer{
|
|||||||
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){
|
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){
|
||||||
for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){
|
for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){
|
||||||
Tile res = world.tile(x, y);
|
Tile res = world.tile(x, y);
|
||||||
if(res.block() == Blocks.air && res.floor().itemDrop == item){
|
if(res.block() == Blocks.air && res.drop() == item){
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,9 +241,9 @@ public class BlockIndexer{
|
|||||||
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
||||||
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
||||||
Tile result = world.tile(x, y);
|
Tile result = world.tile(x, y);
|
||||||
if( result == null || result.floor().itemDrop == null || !scanOres.contains(result.floor().itemDrop)) continue;
|
if( result == null || result.drop() == null || !scanOres.contains(result.drop())) continue;
|
||||||
|
|
||||||
itemSet.add(result.floor().itemDrop);
|
itemSet.add(result.drop());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,8 +320,8 @@ public class BlockIndexer{
|
|||||||
Tile tile = world.tile(x, y);
|
Tile tile = world.tile(x, y);
|
||||||
|
|
||||||
//add position of quadrant to list when an ore is found
|
//add position of quadrant to list when an ore is found
|
||||||
if(tile.floor().itemDrop != null && scanOres.contains(tile.floor().itemDrop) && tile.block() == Blocks.air){
|
if(tile.drop() != null && scanOres.contains(tile.drop()) && tile.block() == Blocks.air){
|
||||||
ores.get(tile.floor().itemDrop).add(world.tile(
|
ores.get(tile.drop()).add(world.tile(
|
||||||
//make sure to clamp quadrant middle position, since it might go off bounds
|
//make sure to clamp quadrant middle position, since it might go off bounds
|
||||||
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
|
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
|
||||||
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)));
|
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)));
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import io.anuke.arc.graphics.g2d.TextureRegion;
|
|||||||
import io.anuke.mindustry.game.ContentList;
|
import io.anuke.mindustry.game.ContentList;
|
||||||
import io.anuke.mindustry.graphics.CacheLayer;
|
import io.anuke.mindustry.graphics.CacheLayer;
|
||||||
import io.anuke.mindustry.type.Category;
|
import io.anuke.mindustry.type.Category;
|
||||||
import io.anuke.mindustry.type.Item;
|
|
||||||
import io.anuke.mindustry.type.ItemStack;
|
import io.anuke.mindustry.type.ItemStack;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
@@ -28,7 +27,8 @@ import io.anuke.mindustry.world.blocks.units.UnitFactory;
|
|||||||
import io.anuke.mindustry.world.consumers.ConsumeItemFilter;
|
import io.anuke.mindustry.world.consumers.ConsumeItemFilter;
|
||||||
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
|
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.state;
|
||||||
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class Blocks implements ContentList{
|
public class Blocks implements ContentList{
|
||||||
public static Block
|
public static Block
|
||||||
@@ -39,6 +39,9 @@ public class Blocks implements ContentList{
|
|||||||
iceSnow, sandWater, duneRocks, sandRocks, stainedRocks, moss, stainedRocksRed, stainedStoneRed, stainedRocksYellow, stainedStoneYellow, stainedBoulder, grass, salt,
|
iceSnow, sandWater, duneRocks, sandRocks, stainedRocks, moss, stainedRocksRed, stainedStoneRed, stainedRocksYellow, stainedStoneYellow, stainedBoulder, grass, salt,
|
||||||
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks,
|
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks,
|
||||||
|
|
||||||
|
//ores
|
||||||
|
oreCopper, oreLead, oreScrap, oreCoal, oreTitanium, oreThorium,
|
||||||
|
|
||||||
//crafting
|
//crafting
|
||||||
siliconSmelter, kiln, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
|
siliconSmelter, kiln, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
|
||||||
melter, separator, sporePress, pulverizer, incinerator,
|
melter, separator, sporePress, pulverizer, incinerator,
|
||||||
@@ -145,7 +148,7 @@ public class Blocks implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
stone = new Floor("stone"){{
|
stone = new Floor("stone"){{
|
||||||
hasOres = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
craters = new Floor("craters"){{
|
craters = new Floor("craters"){{
|
||||||
@@ -170,12 +173,10 @@ public class Blocks implements ContentList{
|
|||||||
|
|
||||||
sand = new Floor("sand"){{
|
sand = new Floor("sand"){{
|
||||||
itemDrop = Items.sand;
|
itemDrop = Items.sand;
|
||||||
hasOres = true;
|
|
||||||
playerUnmineable = true;
|
playerUnmineable = true;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
holostone = new Floor("holostone"){{
|
holostone = new Floor("holostone"){{
|
||||||
hasOres = true;
|
|
||||||
edgeStyle = "blocky";
|
edgeStyle = "blocky";
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -226,7 +227,6 @@ public class Blocks implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
pine = new StaticWall("pine"){{
|
pine = new StaticWall("pine"){{
|
||||||
//fillsTile = false;
|
|
||||||
variants = 0;
|
variants = 0;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -253,7 +253,6 @@ public class Blocks implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
stainedStoneRed = new Floor("stained-stone-red"){{
|
stainedStoneRed = new Floor("stained-stone-red"){{
|
||||||
hasOres = true;
|
|
||||||
variants = 1;
|
variants = 1;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -308,6 +307,16 @@ public class Blocks implements ContentList{
|
|||||||
blendGroup = ignarock;
|
blendGroup = ignarock;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region ore
|
||||||
|
|
||||||
|
oreCopper = new OreBlock(Items.copper);
|
||||||
|
oreLead = new OreBlock(Items.lead);
|
||||||
|
oreScrap = new OreBlock(Items.scrap);
|
||||||
|
oreCoal = new OreBlock(Items.coal);
|
||||||
|
oreTitanium = new OreBlock(Items.titanium);
|
||||||
|
oreThorium = new OreBlock(Items.thorium);
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region crafting
|
//region crafting
|
||||||
|
|
||||||
@@ -1418,23 +1427,6 @@ public class Blocks implements ContentList{
|
|||||||
consumes.powerBuffered(120f);
|
consumes.powerBuffered(120f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion
|
|
||||||
//region ores
|
|
||||||
|
|
||||||
//create ores for every floor and item combination necessary
|
|
||||||
for(Item item : content.items()){
|
|
||||||
if(!item.genOre) continue;
|
|
||||||
|
|
||||||
for(Block block : content.blocks()){
|
|
||||||
if(block instanceof Floor && ((Floor) block).hasOres){
|
|
||||||
new OreBlock(item, (Floor) block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//special variants
|
|
||||||
new OreBlock(Items.scrap, (Floor)snow);
|
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ public class Items implements ContentList{
|
|||||||
type = ItemType.material;
|
type = ItemType.material;
|
||||||
hardness = 1;
|
hardness = 1;
|
||||||
cost = 0.6f;
|
cost = 0.6f;
|
||||||
genOre = true;
|
|
||||||
alwaysUnlocked = true;
|
alwaysUnlocked = true;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -23,7 +22,6 @@ public class Items implements ContentList{
|
|||||||
type = ItemType.material;
|
type = ItemType.material;
|
||||||
hardness = 1;
|
hardness = 1;
|
||||||
cost = 0.9f;
|
cost = 0.9f;
|
||||||
genOre = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
metaglass = new Item("metaglass", Color.valueOf("ebeef5")){{
|
metaglass = new Item("metaglass", Color.valueOf("ebeef5")){{
|
||||||
@@ -40,14 +38,12 @@ public class Items implements ContentList{
|
|||||||
explosiveness = 0.4f;
|
explosiveness = 0.4f;
|
||||||
flammability = 1f;
|
flammability = 1f;
|
||||||
hardness = 2;
|
hardness = 2;
|
||||||
genOre = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
titanium = new Item("titanium", Color.valueOf("8da1e3")){{
|
titanium = new Item("titanium", Color.valueOf("8da1e3")){{
|
||||||
type = ItemType.material;
|
type = ItemType.material;
|
||||||
hardness = 3;
|
hardness = 3;
|
||||||
cost = 1.1f;
|
cost = 1.1f;
|
||||||
genOre = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
thorium = new Item("thorium", Color.valueOf("f9a3c7")){{
|
thorium = new Item("thorium", Color.valueOf("f9a3c7")){{
|
||||||
@@ -56,11 +52,10 @@ public class Items implements ContentList{
|
|||||||
hardness = 4;
|
hardness = 4;
|
||||||
radioactivity = 1f;
|
radioactivity = 1f;
|
||||||
cost = 1.4f;
|
cost = 1.4f;
|
||||||
genOre = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
scrap = new Item("scrap", Color.valueOf("777777")){{
|
scrap = new Item("scrap", Color.valueOf("777777")){{
|
||||||
genOre = true;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
silicon = new Item("silicon", Color.valueOf("53565c")){{
|
silicon = new Item("silicon", Color.valueOf("53565c")){{
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import io.anuke.mindustry.game.Team;
|
|||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.MapException;
|
import io.anuke.mindustry.maps.MapException;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
|
||||||
import io.anuke.mindustry.maps.Maps;
|
import io.anuke.mindustry.maps.Maps;
|
||||||
import io.anuke.mindustry.maps.generators.Generator;
|
import io.anuke.mindustry.maps.generators.Generator;
|
||||||
import io.anuke.mindustry.type.ContentType;
|
import io.anuke.mindustry.type.ContentType;
|
||||||
@@ -235,12 +233,15 @@ public class World implements ApplicationListener{
|
|||||||
beginMapLoad();
|
beginMapLoad();
|
||||||
this.currentMap = map;
|
this.currentMap = map;
|
||||||
|
|
||||||
int width = map.meta.width, height = map.meta.height;
|
|
||||||
|
|
||||||
createTiles(width, height);
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
loadTileData(tiles, MapIO.readTileData(map, true));
|
createTiles(map.width, map.height);
|
||||||
|
for(int x = 0; x < map.width; x++){
|
||||||
|
for(int y = 0; y < map.height; y++){
|
||||||
|
tiles[x][y] = new Tile(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MapIO.readTiles(map, tiles);
|
||||||
|
prepareTiles(tiles);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
if(!headless){
|
if(!headless){
|
||||||
@@ -260,7 +261,7 @@ public class World implements ApplicationListener{
|
|||||||
if(state.teams.get(players[0].getTeam()).cores.size == 0){
|
if(state.teams.get(players[0].getTeam()).cores.size == 0){
|
||||||
ui.showError("$map.nospawn");
|
ui.showError("$map.nospawn");
|
||||||
invalidMap = true;
|
invalidMap = true;
|
||||||
}else if(state.rules.pvp){ //pvp maps need two cores to be valid
|
}else if(state.rules.pvp){ //pvp maps need two cores to be valid
|
||||||
invalidMap = true;
|
invalidMap = true;
|
||||||
for(Team team : Team.all){
|
for(Team team : Team.all){
|
||||||
if(state.teams.get(team).cores.size != 0 && team != players[0].getTeam()){
|
if(state.teams.get(team).cores.size != 0 && team != players[0].getTeam()){
|
||||||
@@ -416,18 +417,7 @@ public class World implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**Loads raw map tile data into a Tile[][] array, setting up multiblocks, cliffs and ores. */
|
/**Loads raw map tile data into a Tile[][] array, setting up multiblocks, cliffs and ores. */
|
||||||
void loadTileData(Tile[][] tiles, MapTileData data){
|
void loadTileData(Tile[][] tiles){
|
||||||
data.position(0, 0);
|
|
||||||
TileDataMarker marker = data.newDataMarker();
|
|
||||||
|
|
||||||
for(int y = 0; y < data.height(); y++){
|
|
||||||
for(int x = 0; x < data.width(); x++){
|
|
||||||
data.read(marker);
|
|
||||||
|
|
||||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareTiles(tiles);
|
prepareTiles(tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +1,70 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.annotations.Annotations.Struct;
|
||||||
import io.anuke.arc.collection.IntSet;
|
import io.anuke.arc.collection.LongArray;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
import io.anuke.mindustry.gen.TileOp;
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.content;
|
||||||
|
|
||||||
public class DrawOperation{
|
public class DrawOperation{
|
||||||
/**
|
private LongArray array = new LongArray();
|
||||||
* Data to apply operation to.
|
|
||||||
*/
|
|
||||||
private MapTileData data;
|
|
||||||
/**
|
|
||||||
* List of per-tile operations that occurred.
|
|
||||||
*/
|
|
||||||
private Array<TileOperation> operations = new Array<>();
|
|
||||||
/**
|
|
||||||
* Checks for duplicate operations, useful for brushes.
|
|
||||||
*/
|
|
||||||
private IntSet checks = new IntSet();
|
|
||||||
|
|
||||||
public DrawOperation(MapTileData data){
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty(){
|
public boolean isEmpty(){
|
||||||
return operations.size == 0;
|
return array.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkDuplicate(short x, short y){
|
public void addOperation(long op){
|
||||||
int i = Pack.shortInt(x, y);
|
array.add(op);
|
||||||
if(checks.contains(i)) return true;
|
|
||||||
|
|
||||||
checks.add(i);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addOperation(TileOperation op){
|
|
||||||
operations.add(op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo(MapEditor editor){
|
public void undo(MapEditor editor){
|
||||||
for(int i = operations.size - 1; i >= 0; i--){
|
for(int i = array.size - 1; i >= 0; i--){
|
||||||
TileOperation op = operations.get(i);
|
long l = array.get(i);
|
||||||
data.position(op.x, op.y);
|
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.from(l));
|
||||||
data.write(op.from);
|
|
||||||
editor.renderer().updatePoint(op.x, op.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redo(MapEditor editor){
|
public void redo(MapEditor editor){
|
||||||
for(TileOperation op : operations){
|
for(int i = 0; i < array.size; i++){
|
||||||
data.position(op.x, op.y);
|
long l = array.get(i);
|
||||||
data.write(op.to);
|
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.to(l));
|
||||||
editor.renderer().updatePoint(op.x, op.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TileOperation{
|
void set(MapEditor editor, Tile tile, byte type, byte to){
|
||||||
public short x, y;
|
editor.load(() -> {
|
||||||
public TileDataMarker from;
|
if(type == OpType.floor.ordinal()){
|
||||||
public TileDataMarker to;
|
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.setOreByte(to);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
editor.renderer().updatePoint(tile.x, tile.y);
|
||||||
|
}
|
||||||
|
|
||||||
public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to){
|
@Struct
|
||||||
this.x = x;
|
class TileOpStruct{
|
||||||
this.y = y;
|
short x;
|
||||||
this.from = from;
|
short y;
|
||||||
this.to = to;
|
byte type;
|
||||||
}
|
byte from;
|
||||||
|
byte to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum OpType{
|
||||||
|
floor,
|
||||||
|
block,
|
||||||
|
rotation,
|
||||||
|
team,
|
||||||
|
ore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.content.Blocks;
|
||||||
|
import io.anuke.mindustry.editor.DrawOperation.OpType;
|
||||||
|
import io.anuke.mindustry.game.Team;
|
||||||
|
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.blocks.OreBlock;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class EditorTile extends Tile{
|
||||||
|
|
||||||
|
public EditorTile(int x, int y, byte floor, byte wall){
|
||||||
|
super(x, y, floor, wall);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Team getTeam(){
|
||||||
|
return Team.all[getTeamID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloor(Floor type){
|
||||||
|
if(type instanceof OreBlock){
|
||||||
|
//don't place on liquids
|
||||||
|
if(!floor().isLiquid) setOreByte(type.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block previous = floor();
|
||||||
|
Block ore = oreBlock();
|
||||||
|
if(previous == type && ore == Blocks.air) return;
|
||||||
|
super.setFloor(type);
|
||||||
|
//ore may get nullified so make sure to save editrs
|
||||||
|
if(oreBlock() != ore){
|
||||||
|
op(TileOp.get(x, y, (byte)OpType.ore.ordinal(), ore.id, oreBlock().id));
|
||||||
|
}
|
||||||
|
if(previous != type){
|
||||||
|
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous.id, type.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlock(Block type){
|
||||||
|
Block previous = block();
|
||||||
|
if(previous == type) return;
|
||||||
|
super.setBlock(type);
|
||||||
|
op(TileOp.get(x, y, (byte)OpType.block.ordinal(), previous.id, type.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTeam(Team team){
|
||||||
|
byte previous = getTeamID();
|
||||||
|
if(previous == team.ordinal()) return;
|
||||||
|
super.setTeam(team);
|
||||||
|
op(TileOp.get(x, y, (byte)OpType.team.ordinal(), previous, (byte)team.ordinal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRotation(byte rotation){
|
||||||
|
byte previous = getRotation();
|
||||||
|
if(previous == rotation) return;
|
||||||
|
super.setRotation(rotation);
|
||||||
|
op(TileOp.get(x, y, (byte)OpType.rotation.ordinal(), previous, rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOreByte(byte ore){
|
||||||
|
byte previous = getOreByte();
|
||||||
|
if(previous == ore) return;
|
||||||
|
super.setOreByte(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){
|
||||||
|
ui.editor.editor.addTileOp(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,34 +7,31 @@ import io.anuke.arc.input.KeyCode;
|
|||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.DataPosition;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import io.anuke.mindustry.world.Pos;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
|
||||||
|
|
||||||
public enum EditorTool{
|
public enum EditorTool{
|
||||||
pick{
|
pick{
|
||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
if(!Structs.inBounds(x, y, editor.getMap().width(), editor.getMap().height())) return;
|
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
|
||||||
|
|
||||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
Tile tile = editor.tile(x, y);
|
||||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
|
||||||
byte link = editor.getMap().read(x, y, DataPosition.link);
|
|
||||||
|
|
||||||
if(link != 0){
|
Block floor = tile.floor(), block = tile.block();
|
||||||
|
byte link = tile.getLinkByte();
|
||||||
|
|
||||||
|
if(block instanceof BlockPart && link != 0){
|
||||||
x -= (Pack.leftByte(link) - 8);
|
x -= (Pack.leftByte(link) - 8);
|
||||||
y -= (Pack.rightByte(link) - 8);
|
y -= (Pack.rightByte(link) - 8);
|
||||||
bf = editor.getMap().read(x, y, DataPosition.floor);
|
|
||||||
bw = editor.getMap().read(x, y, DataPosition.wall);
|
tile = editor.tile(x, y);
|
||||||
|
block = tile.block();
|
||||||
}
|
}
|
||||||
|
|
||||||
Block block = content.block(bw == 0 ? bf : bw);
|
editor.drawBlock = block == Blocks.air ? floor : block;
|
||||||
editor.setDrawBlock(block);
|
|
||||||
ui.editor.updateSelectedBlock();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pencil{
|
pencil{
|
||||||
@@ -67,7 +64,7 @@ public enum EditorTool{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
editor.draw(x, y, isPaint(), editor.getDrawBlock(), 0.012);
|
editor.draw(x, y, isPaint(), editor.drawBlock, 0.012);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
line{
|
line{
|
||||||
@@ -81,56 +78,57 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
IntArray stack = new IntArray();
|
IntArray stack = new IntArray();
|
||||||
int width;
|
Block dest;
|
||||||
byte be, dest;
|
boolean isfloor;
|
||||||
boolean floor;
|
MapEditor data;
|
||||||
MapTileData data;
|
|
||||||
|
|
||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
if(!Structs.inBounds(x, y, editor.getMap().width(), editor.getMap().height())) return;
|
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
|
||||||
|
Tile tile = editor.tile(x, y);
|
||||||
|
|
||||||
if(editor.getDrawBlock().isMultiblock()){
|
if(editor.drawBlock.isMultiblock()){
|
||||||
//don't fill multiblocks, thanks
|
//don't fill multiblocks, thanks
|
||||||
pencil.touched(editor, x, y);
|
pencil.touched(editor, x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = editor.getMap();
|
data = editor;
|
||||||
|
isfloor = editor.drawBlock instanceof Floor;
|
||||||
|
|
||||||
floor = editor.getDrawBlock() instanceof Floor;
|
Block floor = tile.floor();
|
||||||
|
Block block = tile.block();
|
||||||
|
boolean synth = editor.drawBlock.synthetic();
|
||||||
|
|
||||||
byte bf = data.read(x, y, DataPosition.floor);
|
dest = isfloor ? floor : block;
|
||||||
byte bw = data.read(x, y, DataPosition.wall);
|
Block draw = editor.drawBlock;
|
||||||
boolean synth = editor.getDrawBlock().synthetic();
|
|
||||||
byte brt = Pack.byteByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal());
|
|
||||||
|
|
||||||
dest = floor ? bf : bw;
|
if(dest == draw || block == Blocks.part || block.isMultiblock()){
|
||||||
byte draw = editor.getDrawBlock().id;
|
|
||||||
|
|
||||||
if(dest == draw || content.block(bw) instanceof BlockPart || content.block(bw).isMultiblock()){
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = editor.getMap().width();
|
int width = editor.width();
|
||||||
int height = editor.getMap().height();
|
int height = editor.height();
|
||||||
|
|
||||||
IntPositionConsumer writer = (px, py) -> {
|
IntPositionConsumer writer = (px, py) -> {
|
||||||
TileDataMarker prev = editor.getPrev(px, py, false);
|
Tile write = editor.tile(px, py);
|
||||||
|
|
||||||
if(floor){
|
if(isfloor){
|
||||||
data.write(px, py, DataPosition.floor, draw);
|
write.setFloor((Floor)draw);
|
||||||
}else{
|
}else{
|
||||||
data.write(px, py, DataPosition.wall, draw);
|
write.setBlock(draw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(synth){
|
if(synth){
|
||||||
data.write(px, py, DataPosition.rotationTeam, brt);
|
write.setTeam(editor.drawTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.onWrite(px, py, prev);
|
if(draw.rotate){
|
||||||
|
write.setRotation((byte)editor.rotation);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(isAlt()){
|
if(isAlt()){
|
||||||
|
//fill all of the same type regardless of borders
|
||||||
for(int cx = 0; cx < width; cx++){
|
for(int cx = 0; cx < width; cx++){
|
||||||
for(int cy = 0; cy < height; cy++){
|
for(int cy = 0; cy < height; cy++){
|
||||||
if(eq(cx, cy)){
|
if(eq(cx, cy)){
|
||||||
@@ -139,28 +137,28 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if(isAlt2()){
|
}else if(isAlt2()){
|
||||||
|
//fill all teams.
|
||||||
for(int cx = 0; cx < width; cx++){
|
for(int cx = 0; cx < width; cx++){
|
||||||
for(int cy = 0; cy < height; cy++){
|
for(int cy = 0; cy < height; cy++){
|
||||||
byte w = data.read(cx, cy, DataPosition.wall);
|
Tile write = editor.tile(cx, cy);
|
||||||
if(content.block(w).synthetic()){
|
if(write.block().synthetic()){
|
||||||
TileDataMarker prev = editor.getPrev(cx, cy, false);
|
write.setTeam(editor.drawTeam);
|
||||||
data.write(cx, cy, DataPosition.rotationTeam, (byte)editor.getDrawTeam().ordinal());
|
|
||||||
editor.onWrite(cx, cy, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
//normal fill
|
||||||
int x1;
|
int x1;
|
||||||
boolean spanAbove, spanBelow;
|
boolean spanAbove, spanBelow;
|
||||||
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
|
||||||
stack.add(asi(x, y));
|
stack.add(Pos.get(x, y));
|
||||||
|
|
||||||
while(stack.size > 0){
|
while(stack.size > 0){
|
||||||
int popped = stack.pop();
|
int popped = stack.pop();
|
||||||
x = popped % width;
|
x = Pos.x(popped);
|
||||||
y = popped / width;
|
y = Pos.y(popped);
|
||||||
|
|
||||||
x1 = x;
|
x1 = x;
|
||||||
while(x1 >= 0 && eq(x1, y)) x1--;
|
while(x1 >= 0 && eq(x1, y)) x1--;
|
||||||
@@ -170,14 +168,14 @@ public enum EditorTool{
|
|||||||
writer.accept(x1, y);
|
writer.accept(x1, y);
|
||||||
|
|
||||||
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
||||||
stack.add(asi(x1, y - 1));
|
stack.add(Pos.get(x1, y - 1));
|
||||||
spanAbove = true;
|
spanAbove = true;
|
||||||
}else if(spanAbove && y > 0 && eq(x1, y - 1)){
|
}else if(spanAbove && eq(x1, y - 1)){
|
||||||
spanAbove = false;
|
spanAbove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||||
stack.add(asi(x1, y + 1));
|
stack.add(Pos.get(x1, y + 1));
|
||||||
spanBelow = true;
|
spanBelow = true;
|
||||||
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||||
spanBelow = false;
|
spanBelow = false;
|
||||||
@@ -189,15 +187,9 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean eq(int px, int py){
|
boolean eq(int px, int py){
|
||||||
byte nbf = data.read(px, py, DataPosition.floor);
|
Tile tile = data.tile(px, py);
|
||||||
byte nbw = data.read(px, py, DataPosition.wall);
|
|
||||||
byte nbe = data.read(px, py, DataPosition.elevation);
|
|
||||||
|
|
||||||
return (floor ? nbf : nbw) == dest && nbe == be;
|
return (isfloor ? tile.floor() : tile.block()) == dest;
|
||||||
}
|
|
||||||
|
|
||||||
int asi(int x, int y){
|
|
||||||
return x + y * width;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
zoom;
|
zoom;
|
||||||
|
|||||||
@@ -1,88 +1,150 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
|
import io.anuke.arc.util.Log;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.editor.DrawOperation.TileOperation;
|
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
import io.anuke.mindustry.gen.TileOp;
|
||||||
import io.anuke.mindustry.maps.MapTileData.DataPosition;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class MapEditor{
|
public class MapEditor{
|
||||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
||||||
|
|
||||||
private MapTileData map;
|
|
||||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
private ObjectMap<String, String> tags = new ObjectMap<>();
|
||||||
private MapRenderer renderer = new MapRenderer(this);
|
private MapRenderer renderer = new MapRenderer(this);
|
||||||
|
private Tile[][] tiles;
|
||||||
|
|
||||||
private int brushSize = 1;
|
private OperationStack stack = new OperationStack();
|
||||||
private int rotation;
|
private DrawOperation currentOp;
|
||||||
private Block drawBlock = Blocks.stone;
|
private boolean loading;
|
||||||
private Team drawTeam = Team.blue;
|
|
||||||
|
|
||||||
public MapTileData getMap(){
|
public int brushSize = 1;
|
||||||
return map;
|
public int rotation;
|
||||||
}
|
public Block drawBlock = Blocks.stone;
|
||||||
|
public Team drawTeam = Team.blue;
|
||||||
|
|
||||||
public ObjectMap<String, String> getTags(){
|
public ObjectMap<String, String> getTags(){
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEdit(MapTileData map, ObjectMap<String, String> tags, boolean clear){
|
public void beginEdit(int width, int height){
|
||||||
this.map = map;
|
reset();
|
||||||
this.brushSize = 1;
|
|
||||||
this.tags = tags;
|
|
||||||
|
|
||||||
if(clear){
|
loading = true;
|
||||||
for(int x = 0; x < map.width(); x++){
|
tiles = createTiles(width, height);
|
||||||
for(int y = 0; y < map.height(); y++){
|
renderer.resize(width(), height());
|
||||||
map.write(x, y, DataPosition.floor, Blocks.stone.id);
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginEdit(Map map) throws IOException{
|
||||||
|
reset();
|
||||||
|
|
||||||
|
loading = true;
|
||||||
|
tiles = createTiles(map.width, map.height);
|
||||||
|
tags.putAll(map.tags);
|
||||||
|
MapIO.readTiles(map, tiles);
|
||||||
|
checkTiles();
|
||||||
|
renderer.resize(width(), height());
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginEdit(Tile[][] tiles){
|
||||||
|
reset();
|
||||||
|
|
||||||
|
this.tiles = tiles;
|
||||||
|
checkTiles();
|
||||||
|
renderer.resize(width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
//adds missing blockparts
|
||||||
|
void checkTiles(){
|
||||||
|
//clear block parts first
|
||||||
|
for(int x = 0; x < width(); x ++){
|
||||||
|
for(int y = 0; y < height(); y++){
|
||||||
|
if(tiles[x][y].block() == Blocks.part){
|
||||||
|
tiles[x][y].setBlock(Blocks.air);
|
||||||
|
tiles[x][y].setLinkByte((byte)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set up missing blockparts
|
||||||
|
for(int x = 0; x < width(); x ++){
|
||||||
|
for(int y = 0; y < height(); y ++){
|
||||||
|
Block drawBlock = tiles[x][y].block();
|
||||||
|
if(drawBlock.isMultiblock()){
|
||||||
|
int offsetx = -(drawBlock.size - 1) / 2;
|
||||||
|
int offsety = -(drawBlock.size - 1) / 2;
|
||||||
|
for(int dx = 0; dx < drawBlock.size; dx++){
|
||||||
|
for(int dy = 0; dy < drawBlock.size; dy++){
|
||||||
|
int worldx = dx + offsetx + x;
|
||||||
|
int worldy = dy + offsety + y;
|
||||||
|
|
||||||
|
if(Structs.inBounds(worldx, worldy, width(), height()) && !(dx + offsetx == 0 && dy + offsety == 0)){
|
||||||
|
Tile tile = tiles[worldx][worldy];
|
||||||
|
tile.setBlock(Blocks.part);
|
||||||
|
tile.setLinkByte(Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(Runnable r){
|
||||||
|
loading = true;
|
||||||
|
r.run();
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**Creates a 2-D array of EditorTiles with stone as the floor block.*/
|
||||||
|
public Tile[][] createTiles(int width, int height){
|
||||||
|
tiles = new Tile[width][height];
|
||||||
|
|
||||||
|
for(int x = 0; x < width; x++){
|
||||||
|
for(int y = 0; y < height; y++){
|
||||||
|
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map createMap(FileHandle file){
|
||||||
|
return new Map(file, width(), height(), new ObjectMap<>(tags), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset(){
|
||||||
|
clearOp();
|
||||||
|
brushSize = 1;
|
||||||
drawBlock = Blocks.stone;
|
drawBlock = Blocks.stone;
|
||||||
renderer.resize(map.width(), map.height());
|
tags = new ObjectMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDrawRotation(){
|
public Tile[][] tiles(){
|
||||||
return rotation;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDrawRotation(int rotation){
|
public Tile tile(int x, int y){
|
||||||
this.rotation = rotation;
|
return tiles[x][y];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Team getDrawTeam(){
|
public int width(){
|
||||||
return drawTeam;
|
return tiles.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDrawTeam(Team team){
|
public int height(){
|
||||||
this.drawTeam = team;
|
return tiles[0].length;
|
||||||
}
|
|
||||||
|
|
||||||
public Block getDrawBlock(){
|
|
||||||
return drawBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDrawBlock(Block block){
|
|
||||||
this.drawBlock = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBrushSize(){
|
|
||||||
return brushSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBrushSize(int size){
|
|
||||||
this.brushSize = size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(int x, int y, boolean paint){
|
public void draw(int x, int y, boolean paint){
|
||||||
@@ -94,15 +156,12 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
||||||
byte writeID = drawBlock.id;
|
|
||||||
byte partID = Blocks.part.id;
|
|
||||||
byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
|
||||||
|
|
||||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||||
|
|
||||||
if(drawBlock.isMultiblock()){
|
if(drawBlock.isMultiblock()){
|
||||||
x = Mathf.clamp(x, (drawBlock.size-1)/2, map.width() - drawBlock.size/2 - 1);
|
|
||||||
y = Mathf.clamp(y, (drawBlock.size-1)/2, map.height() - drawBlock.size/2 - 1);
|
x = Mathf.clamp(x, (drawBlock.size-1)/2, width() - drawBlock.size/2 - 1);
|
||||||
|
y = Mathf.clamp(y, (drawBlock.size-1)/2, height() - drawBlock.size/2 - 1);
|
||||||
|
|
||||||
int offsetx = -(drawBlock.size - 1) / 2;
|
int offsetx = -(drawBlock.size - 1) / 2;
|
||||||
int offsety = -(drawBlock.size - 1) / 2;
|
int offsety = -(drawBlock.size - 1) / 2;
|
||||||
@@ -113,68 +172,61 @@ public class MapEditor{
|
|||||||
int worldx = dx + offsetx + x;
|
int worldx = dx + offsetx + x;
|
||||||
int worldy = dy + offsety + y;
|
int worldy = dy + offsety + y;
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, map.width(), map.height())){
|
if(Structs.inBounds(worldx, worldy, width(), height())){
|
||||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
Tile tile = tiles[worldx][worldy];
|
||||||
|
|
||||||
if(i == 1){
|
if(i == 1){
|
||||||
map.write(worldx, worldy, DataPosition.wall, partID);
|
tile.setBlock(Blocks.part);
|
||||||
map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam);
|
tile.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
|
||||||
map.write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
|
||||||
}else{
|
}else{
|
||||||
byte link = map.read(worldx, worldy, DataPosition.link);
|
byte link = tile.getLinkByte();
|
||||||
byte block = map.read(worldx, worldy, DataPosition.wall);
|
Block block = tile.block();
|
||||||
|
|
||||||
if(link != 0){
|
if(link != 0){
|
||||||
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
|
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
|
||||||
}else if(content.block(block).isMultiblock()){
|
}else if(block.isMultiblock()){
|
||||||
removeLinked(worldx, worldy);
|
removeLinked(worldx, worldy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onWrite(worldx, worldy, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TileDataMarker prev = getPrev(x, y, false);
|
Tile tile = tiles[x][y];
|
||||||
|
tile.setBlock(drawBlock);
|
||||||
map.write(x, y, DataPosition.wall, writeID);
|
tile.setTeam(drawTeam);
|
||||||
map.write(x, y, DataPosition.link, (byte) 0);
|
|
||||||
map.write(x, y, DataPosition.rotationTeam, rotationTeam);
|
|
||||||
|
|
||||||
onWrite(x, y, prev);
|
|
||||||
}else{
|
}else{
|
||||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
||||||
int wx = x + rx, wy = y + ry;
|
int wx = x + rx, wy = y + ry;
|
||||||
|
|
||||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height() || (paint && !isfloor && content.block(map.read(wx, wy, DataPosition.wall)) == Blocks.air)){
|
if(wx < 0 || wy < 0 || wx >= width() || wy >= height() || (paint && !isfloor && tiles[wx][wy].block() == Blocks.air)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileDataMarker prev = getPrev(wx, wy, true);
|
Tile tile = tiles[wx][wy];
|
||||||
|
|
||||||
if(!isfloor){
|
if(!isfloor){
|
||||||
byte link = map.read(wx, wy, DataPosition.link);
|
byte link = tile.getLinkByte();
|
||||||
|
Log.info("Remove linkd: " + tiles[x][y]);
|
||||||
|
|
||||||
if(content.block(map.read(wx, wy, DataPosition.wall)).isMultiblock()){
|
if(tile.block().isMultiblock()){
|
||||||
removeLinked(wx, wy);
|
removeLinked(wx, wy);
|
||||||
}else if(link != 0){
|
}else if(link != 0 && tiles[x][y].block() == Blocks.part){
|
||||||
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
|
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isfloor){
|
if(isfloor){
|
||||||
map.write(wx, wy, DataPosition.floor, writeID);
|
tile.setFloor((Floor)drawBlock);
|
||||||
}else{
|
}else{
|
||||||
map.write(wx, wy, DataPosition.wall, writeID);
|
tile.setBlock(drawBlock);
|
||||||
map.write(wx, wy, DataPosition.link, (byte) 0);
|
if(drawBlock.synthetic()){
|
||||||
map.write(wx, wy, DataPosition.rotationTeam, rotationTeam);
|
tile.setTeam(drawTeam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onWrite(x + rx, y + ry, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,77 +234,86 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeLinked(int x, int y){
|
private void removeLinked(int x, int y){
|
||||||
Block block = content.block(map.read(x, y, DataPosition.wall));
|
Block block = tiles[x][y].block();
|
||||||
|
|
||||||
int offsetx = -(block.size - 1) / 2;
|
int offsetx = -(block.size - 1) / 2;
|
||||||
int offsety = -(block.size - 1) / 2;
|
int offsety = -(block.size - 1) / 2;
|
||||||
for(int dx = 0; dx < block.size; dx++){
|
for(int dx = 0; dx < block.size; dx++){
|
||||||
for(int dy = 0; dy < block.size; dy++){
|
for(int dy = 0; dy < block.size; dy++){
|
||||||
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
||||||
if(Structs.inBounds(worldx, worldy, map.width(), map.height())){
|
if(Structs.inBounds(worldx, worldy, width(), height())){
|
||||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
tiles[worldx][worldy].setTeam(Team.none);
|
||||||
|
tiles[worldx][worldy].setBlock(Blocks.air);
|
||||||
map.write(worldx, worldy, DataPosition.link, (byte) 0);
|
|
||||||
map.write(worldx, worldy, DataPosition.rotationTeam, (byte) 0);
|
|
||||||
map.write(worldx, worldy, DataPosition.wall, (byte) 0);
|
|
||||||
|
|
||||||
onWrite(worldx, worldy, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkDupes(int x, int y){
|
|
||||||
return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWrite(int x, int y, TileDataMarker previous){
|
|
||||||
if(previous == null){
|
|
||||||
renderer.updatePoint(x, y);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TileDataMarker current = map.new TileDataMarker();
|
|
||||||
map.position(x, y);
|
|
||||||
map.read(current);
|
|
||||||
|
|
||||||
Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current));
|
|
||||||
renderer.updatePoint(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
TileDataMarker getPrev(int x, int y, boolean checkDupes){
|
|
||||||
if(checkDupes && checkDupes(x, y)){
|
|
||||||
return null;
|
|
||||||
}else{
|
|
||||||
TileDataMarker marker = map.newDataMarker();
|
|
||||||
map.position(x, y);
|
|
||||||
map.read(marker);
|
|
||||||
return marker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapRenderer renderer(){
|
public MapRenderer renderer(){
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resize(int width, int height){
|
public void resize(int width, int height){
|
||||||
MapTileData previous = map;
|
clearOp();
|
||||||
int offsetX = -(width - previous.width())/2, offsetY = -(height - previous.height())/2;
|
|
||||||
|
|
||||||
map = new MapTileData(width, height);
|
Tile[][] previous = tiles;
|
||||||
for(int x = 0; x < map.width(); x++){
|
int offsetX = -(width - width())/2, offsetY = -(height - height())/2;
|
||||||
for(int y = 0; y < map.height(); y++){
|
loading = true;
|
||||||
|
|
||||||
|
tiles = new Tile[width][height];
|
||||||
|
for(int x = 0; x < width; x++){
|
||||||
|
for(int y = 0; y < height; y++){
|
||||||
int px = offsetX + x, py = offsetY + y;
|
int px = offsetX + x, py = offsetY + y;
|
||||||
if(Structs.inBounds(px, py, previous.width(), previous.height())){
|
if(Structs.inBounds(px, py, previous.length, previous[0].length)){
|
||||||
map.write(x, y, DataPosition.floor, previous.read(px, py, DataPosition.floor));
|
tiles[x][y] = previous[px][py];
|
||||||
map.write(x, y, DataPosition.wall, previous.read(px, py, DataPosition.wall));
|
tiles[x][y].x = (short)x;
|
||||||
map.write(x, y, DataPosition.link, previous.read(px, py, DataPosition.link));
|
tiles[x][y].y = (short)y;
|
||||||
map.write(x, y, DataPosition.rotationTeam, previous.read(px, py, DataPosition.rotationTeam));
|
|
||||||
}else{
|
}else{
|
||||||
map.write(x, y, DataPosition.floor, Blocks.stone.id);
|
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.resize(width, height);
|
renderer.resize(width, height);
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearOp(){
|
||||||
|
stack.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undo(){
|
||||||
|
if(stack.canUndo()){
|
||||||
|
stack.undo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redo(){
|
||||||
|
if(stack.canRedo()){
|
||||||
|
stack.redo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canUndo(){
|
||||||
|
return stack.canUndo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRedo(){
|
||||||
|
return stack.canRedo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flushOp(){
|
||||||
|
if(currentOp == null || currentOp.isEmpty()) return;
|
||||||
|
stack.add(currentOp);
|
||||||
|
currentOp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTileOp(long data){
|
||||||
|
if(loading) return;
|
||||||
|
|
||||||
|
if(currentOp == null) currentOp = new DrawOperation();
|
||||||
|
currentOp.addOperation(data);
|
||||||
|
|
||||||
|
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.editor;
|
|||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.function.Consumer;
|
import io.anuke.arc.function.Consumer;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
@@ -23,21 +22,17 @@ import io.anuke.mindustry.core.Platform;
|
|||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.MapMeta;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Block.Icon;
|
import io.anuke.mindustry.world.Block.Icon;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class MapEditorDialog extends Dialog implements Disposable{
|
public class MapEditorDialog extends Dialog implements Disposable{
|
||||||
private MapEditor editor;
|
public final MapEditor editor;
|
||||||
private MapView view;
|
private MapView view;
|
||||||
private MapInfoDialog infoDialog;
|
private MapInfoDialog infoDialog;
|
||||||
private MapLoadDialog loadDialog;
|
private MapLoadDialog loadDialog;
|
||||||
@@ -48,8 +43,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
private boolean shownWithMap = false;
|
private boolean shownWithMap = false;
|
||||||
private Array<Block> blocksOut = new Array<>();
|
private Array<Block> blocksOut = new Array<>();
|
||||||
|
|
||||||
private ButtonGroup<ImageButton> blockgroup;
|
|
||||||
|
|
||||||
public MapEditorDialog(){
|
public MapEditorDialog(){
|
||||||
super("", "dialog");
|
super("", "dialog");
|
||||||
|
|
||||||
@@ -89,17 +82,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
createDialog("$editor.import",
|
createDialog("$editor.import",
|
||||||
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable) loadDialog::show,
|
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable) loadDialog::show,
|
||||||
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable) () ->
|
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable) () ->
|
||||||
Platform.instance.showFileChooser("$loadimage", "Map Files", file -> ui.loadAnd(() -> {
|
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
DataInputStream stream = new DataInputStream(file.read());
|
//TODO what if it's an image? users should be warned for their stupidity
|
||||||
|
editor.beginEdit(MapIO.readMap(file, true));
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
|
||||||
MapTileData data = MapIO.readTileData(stream, meta, false);
|
|
||||||
|
|
||||||
editor.beginEdit(data, meta.tags, false);
|
|
||||||
view.clearStack();
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}), true, mapExtension),
|
}), true, mapExtension),
|
||||||
@@ -108,39 +96,32 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
|
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
MapTileData data = MapIO.readLegacyPixmap(new Pixmap(file));
|
Pixmap pixmap = new Pixmap(file);
|
||||||
|
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
|
||||||
editor.beginEdit(data, editor.getTags(), false);
|
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
|
||||||
view.clearStack();
|
editor.beginEdit(tiles);
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}), true, "png")
|
}), true, "png")));
|
||||||
));
|
|
||||||
|
|
||||||
t.addImageTextButton("$editor.export", "icon-save-map", isize, () -> createDialog("$editor.export",
|
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
|
||||||
"$editor.exportfile", "$editor.exportfile.description", "icon-file", (Runnable) () ->
|
Platform.instance.showFileChooser("$editor.savemap", "Map Files", file -> {
|
||||||
Platform.instance.showFileChooser("$saveimage", "Map Files", file -> {
|
|
||||||
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
|
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
|
||||||
FileHandle result = file;
|
FileHandle result = file;
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(!editor.getTags().containsKey("name")){
|
if(!editor.getTags().containsKey("name")){
|
||||||
editor.getTags().put("name", result.nameWithoutExtension());
|
editor.getTags().put("name", result.nameWithoutExtension());
|
||||||
}
|
}
|
||||||
MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap());
|
MapIO.writeMap(result, editor.createMap(result), editor.tiles());
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorimagesave", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, false, mapExtension)));
|
}, false, mapExtension));
|
||||||
|
|
||||||
t.row();
|
|
||||||
|
|
||||||
t.row();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
menu.cont.row();
|
menu.cont.row();
|
||||||
@@ -151,24 +132,19 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
||||||
|
|
||||||
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
||||||
if(!(editor.getMap().width() == x && editor.getMap().height() == y)){
|
if(!(editor.width() == x && editor.height() == y)){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
editor.resize(x, y);
|
editor.resize(x, y);
|
||||||
view.clearStack();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loadDialog = new MapLoadDialog(map ->
|
loadDialog = new MapLoadDialog(map ->
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try(DataInputStream stream = new DataInputStream(map.stream.get())){
|
try{
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
editor.beginEdit(map);
|
||||||
MapTileData data = MapIO.readTileData(stream, meta, false);
|
|
||||||
|
|
||||||
editor.beginEdit(data, meta.tags, false);
|
|
||||||
view.clearStack();
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -200,10 +176,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
shown(() -> {
|
shown(() -> {
|
||||||
saved = true;
|
saved = true;
|
||||||
Platform.instance.beginForceLandscape();
|
Platform.instance.beginForceLandscape();
|
||||||
view.clearStack();
|
editor.clearOp();
|
||||||
Core.scene.setScrollFocus(view);
|
Core.scene.setScrollFocus(view);
|
||||||
if(!shownWithMap){
|
if(!shownWithMap){
|
||||||
editor.beginEdit(new MapTileData(200, 200), new ObjectMap<>(), true);
|
editor.beginEdit(200, 200);
|
||||||
}
|
}
|
||||||
shownWithMap = false;
|
shownWithMap = false;
|
||||||
|
|
||||||
@@ -211,6 +187,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
});
|
});
|
||||||
|
|
||||||
hidden(() -> {
|
hidden(() -> {
|
||||||
|
editor.clearOp();
|
||||||
Platform.instance.updateRPC();
|
Platform.instance.updateRPC();
|
||||||
Platform.instance.endForceLandscape();
|
Platform.instance.endForceLandscape();
|
||||||
});
|
});
|
||||||
@@ -225,13 +202,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
String name = editor.getTags().get("name", "");
|
String name = editor.getTags().get("name", "");
|
||||||
|
|
||||||
if(name.isEmpty()){
|
if(name.isEmpty()){
|
||||||
ui.showError("$editor.save.noname");
|
infoDialog.show();
|
||||||
|
Core.app.post(() -> ui.showError("$editor.save.noname"));
|
||||||
}else{
|
}else{
|
||||||
Map map = world.maps.getByName(name);
|
Map map = world.maps.all().find(m -> m.name().equals(name));
|
||||||
if(map != null && !map.custom){
|
if(map != null && !map.custom){
|
||||||
ui.showError("$editor.save.overwrite");
|
ui.showError("$editor.save.overwrite");
|
||||||
}else{
|
}else{
|
||||||
world.maps.saveMap(name, editor.getMap(), editor.getTags());
|
world.maps.saveMap(editor.getTags(), editor.tiles());
|
||||||
ui.showInfoFade("$editor.saved");
|
ui.showInfoFade("$editor.saved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,18 +271,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
editor.renderer().dispose();
|
editor.renderer().dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEditMap(InputStream is){
|
public void beginEditMap(FileHandle file){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
|
Map map = MapIO.readMap(file, true);
|
||||||
shownWithMap = true;
|
shownWithMap = true;
|
||||||
DataInputStream stream = new DataInputStream(is);
|
editor.beginEdit(map);
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
|
||||||
editor.beginEdit(MapIO.readTileData(stream, meta, false), meta.tags, false);
|
|
||||||
is.close();
|
|
||||||
show();
|
show();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -317,16 +293,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
saved = false;
|
saved = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSelectedBlock(){
|
|
||||||
Block block = editor.getDrawBlock();
|
|
||||||
for(int j = 0; j < Vars.content.blocks().size; j++){
|
|
||||||
if(block.id == j && j < blockgroup.getButtons().size){
|
|
||||||
blockgroup.getButtons().get(j).setChecked(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPane(){
|
public boolean hasPane(){
|
||||||
return Core.scene.getScrollFocus() == pane || Core.scene.getKeyboardFocus() != this;
|
return Core.scene.getScrollFocus() == pane || Core.scene.getKeyboardFocus() != this;
|
||||||
}
|
}
|
||||||
@@ -370,15 +336,15 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
tools.row();
|
tools.row();
|
||||||
|
|
||||||
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, () -> view.undo()).get();
|
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, editor::undo).get();
|
||||||
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, () -> view.redo()).get();
|
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, editor::redo).get();
|
||||||
|
|
||||||
addTool.accept(EditorTool.pick);
|
addTool.accept(EditorTool.pick);
|
||||||
|
|
||||||
tools.row();
|
tools.row();
|
||||||
|
|
||||||
undo.setDisabled(() -> !view.getStack().canUndo());
|
undo.setDisabled(() -> !editor.canUndo());
|
||||||
redo.setDisabled(() -> !view.getStack().canRedo());
|
redo.setDisabled(() -> !editor.canRedo());
|
||||||
|
|
||||||
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
|
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
|
||||||
redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE));
|
redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE));
|
||||||
@@ -393,9 +359,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
addTool.accept(EditorTool.fill);
|
addTool.accept(EditorTool.fill);
|
||||||
addTool.accept(EditorTool.spray);
|
addTool.accept(EditorTool.spray);
|
||||||
|
|
||||||
ImageButton rotate = tools.addImageButton("icon-arrow-16", "clear", 16 * 2f, () -> editor.setDrawRotation((editor.getDrawRotation() + 1) % 4)).get();
|
ImageButton rotate = tools.addImageButton("icon-arrow-16", "clear", 16 * 2f, () -> editor.rotation = (editor.rotation + 1) % 4).get();
|
||||||
rotate.getImage().update(() -> {
|
rotate.getImage().update(() -> {
|
||||||
rotate.getImage().setRotation(editor.getDrawRotation() * 90);
|
rotate.getImage().setRotation(editor.rotation * 90);
|
||||||
rotate.getImage().setOrigin(Align.center);
|
rotate.getImage().setOrigin(Align.center);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -415,8 +381,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
button.margin(4f);
|
button.margin(4f);
|
||||||
button.getImageCell().grow();
|
button.getImageCell().grow();
|
||||||
button.getStyle().imageUpColor = team.color;
|
button.getStyle().imageUpColor = team.color;
|
||||||
button.clicked(() -> editor.setDrawTeam(team));
|
button.clicked(() -> editor.drawTeam = team);
|
||||||
button.update(() -> button.setChecked(editor.getDrawTeam() == team));
|
button.update(() -> button.setChecked(editor.drawTeam == team));
|
||||||
teamgroup.add(button);
|
teamgroup.add(button);
|
||||||
tools.add(button);
|
tools.add(button);
|
||||||
|
|
||||||
@@ -429,7 +395,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
mid.table("underline", t -> {
|
mid.table("underline", t -> {
|
||||||
Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false);
|
Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false);
|
||||||
slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int) (float) f]));
|
slider.moved(f -> editor.brushSize = MapEditor.brushSizes[(int) (float) f]);
|
||||||
|
|
||||||
t.top();
|
t.top();
|
||||||
t.add("$editor.brush");
|
t.add("$editor.brush");
|
||||||
@@ -456,22 +422,28 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyTap(KeyCode.ESCAPE)){
|
||||||
|
if(!menu.isShown()){
|
||||||
|
menu.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.R)){
|
if(Core.input.keyTap(KeyCode.R)){
|
||||||
editor.setDrawRotation((editor.getDrawRotation() + 1) % 4);
|
editor.rotation = Mathf.mod(editor.rotation + 1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.E)){
|
if(Core.input.keyTap(KeyCode.E)){
|
||||||
editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4));
|
editor.rotation = Mathf.mod(editor.rotation - 1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ctrl keys (undo, redo, save)
|
//ctrl keys (undo, redo, save)
|
||||||
if(UIUtils.ctrl()){
|
if(UIUtils.ctrl()){
|
||||||
if(Core.input.keyTap(KeyCode.Z)){
|
if(Core.input.keyTap(KeyCode.Z)){
|
||||||
view.undo();
|
editor.undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.Y)){
|
if(Core.input.keyTap(KeyCode.Y)){
|
||||||
view.redo();
|
editor.redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.S)){
|
if(Core.input.keyTap(KeyCode.S)){
|
||||||
@@ -498,7 +470,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
pane.setFadeScrollBars(false);
|
pane.setFadeScrollBars(false);
|
||||||
pane.setOverscroll(true, false);
|
pane.setOverscroll(true, false);
|
||||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||||
blockgroup = group;
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@@ -521,9 +492,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
ImageButton button = new ImageButton("white", "clear-toggle");
|
ImageButton button = new ImageButton("white", "clear-toggle");
|
||||||
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
||||||
button.clicked(() -> editor.setDrawBlock(block));
|
button.clicked(() -> editor.drawBlock = block);
|
||||||
button.resizeImage(8 * 4f);
|
button.resizeImage(8 * 4f);
|
||||||
button.update(() -> button.setChecked(editor.getDrawBlock() == block));
|
button.update(() -> button.setChecked(editor.drawBlock == block));
|
||||||
group.add(button);
|
group.add(button);
|
||||||
content.add(button).size(50f);
|
content.add(button).size(50f);
|
||||||
|
|
||||||
@@ -534,7 +505,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
group.getButtons().get(2).setChecked(true);
|
group.getButtons().get(2).setChecked(true);
|
||||||
|
|
||||||
table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().localizedName).width(200f).center()).growX();
|
table.table("underline", extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX();
|
||||||
table.row();
|
table.row();
|
||||||
table.add(pane).growY().fillX();
|
table.add(pane).growY().fillX();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ import io.anuke.arc.graphics.g2d.Draw;
|
|||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Disposable;
|
import io.anuke.arc.util.Disposable;
|
||||||
import io.anuke.arc.util.Pack;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||||
import io.anuke.mindustry.maps.MapTileData.DataPosition;
|
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
|
||||||
import static io.anuke.mindustry.Vars.tilesize;
|
import static io.anuke.mindustry.Vars.tilesize;
|
||||||
|
|
||||||
public class MapRenderer implements Disposable{
|
public class MapRenderer implements Disposable{
|
||||||
@@ -102,27 +100,24 @@ public class MapRenderer implements Disposable{
|
|||||||
private void render(int wx, int wy){
|
private void render(int wx, int wy){
|
||||||
int x = wx / chunksize, y = wy / chunksize;
|
int x = wx / chunksize, y = wy / chunksize;
|
||||||
IndexedRenderer mesh = chunks[x][y];
|
IndexedRenderer mesh = chunks[x][y];
|
||||||
byte bf = editor.getMap().read(wx, wy, DataPosition.floor);
|
Tile tile = editor.tiles()[wx][wy];
|
||||||
byte bw = editor.getMap().read(wx, wy, DataPosition.wall);
|
|
||||||
byte btr = editor.getMap().read(wx, wy, DataPosition.rotationTeam);
|
|
||||||
byte rotation = Pack.leftByte(btr);
|
|
||||||
Team team = Team.all[Pack.rightByte(btr)];
|
|
||||||
|
|
||||||
Block floor = content.block(bf);
|
Team team = tile.getTeam();
|
||||||
Block wall = content.block(bw);
|
Block floor = tile.floor();
|
||||||
|
Block wall = tile.block();
|
||||||
|
|
||||||
TextureRegion region;
|
TextureRegion region;
|
||||||
|
|
||||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||||
|
|
||||||
if(bw != 0 && (wall.synthetic() || wall == Blocks.part)){
|
if(wall != Blocks.air && (wall.synthetic() || wall == Blocks.part)){
|
||||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||||
|
|
||||||
if(wall.rotate){
|
if(wall.rotate){
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
||||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, rotation * 90 - 90);
|
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.getRotation() * 90 - 90);
|
||||||
}else{
|
}else{
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
|
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
|
||||||
@@ -140,10 +135,12 @@ public class MapRenderer implements Disposable{
|
|||||||
if(wall.update || wall.destructible){
|
if(wall.update || wall.destructible){
|
||||||
mesh.setColor(team.color);
|
mesh.setColor(team.color);
|
||||||
region = Core.atlas.find("block-border-editor");
|
region = Core.atlas.find("block-border-editor");
|
||||||
}else if(!wall.synthetic() && bw != 0){
|
}else if(!wall.synthetic() && wall != Blocks.air){
|
||||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||||
offsetX = tilesize/2f - region.getWidth()/2f * Draw.scl;
|
offsetX = tilesize/2f - region.getWidth()/2f * Draw.scl;
|
||||||
offsetY = tilesize/2f - region.getHeight()/2f * Draw.scl;
|
offsetY = tilesize/2f - region.getHeight()/2f * Draw.scl;
|
||||||
|
}else if(wall == Blocks.air && tile.oreBlock() != null){
|
||||||
|
region = tile.oreBlock().editorVariantRegions()[Mathf.randomSeed(idxWall, 0, tile.oreBlock().editorVariantRegions().length-1)];;
|
||||||
}else{
|
}else{
|
||||||
region = Core.atlas.find("clear-editor");
|
region = Core.atlas.find("clear-editor");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.function.BiConsumer;
|
import io.anuke.arc.function.IntPositionConsumer;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.scene.ui.layout.Table;
|
import io.anuke.arc.scene.ui.layout.Table;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
|
|
||||||
public class MapResizeDialog extends FloatingDialog{
|
public class MapResizeDialog extends FloatingDialog{
|
||||||
private static final int minSize = 50, maxSize = 500, increment = 50;
|
private static final int minSize = 50, maxSize = 500, increment = 50;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
public MapResizeDialog(MapEditor editor, BiConsumer<Integer, Integer> cons){
|
public MapResizeDialog(MapEditor editor, IntPositionConsumer cons){
|
||||||
super("$editor.resizemap");
|
super("$editor.resizemap");
|
||||||
shown(() -> {
|
shown(() -> {
|
||||||
cont.clear();
|
cont.clear();
|
||||||
MapTileData data = editor.getMap();
|
width = editor.width();
|
||||||
width = data.width();
|
height = editor.height();
|
||||||
height = data.height();
|
|
||||||
|
|
||||||
Table table = new Table();
|
Table table = new Table();
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class MapSaveDialog extends FloatingDialog{
|
|||||||
shown(() -> {
|
shown(() -> {
|
||||||
cont.clear();
|
cont.clear();
|
||||||
cont.label(() -> {
|
cont.label(() -> {
|
||||||
Map map = world.maps.getByName(field.getText());
|
Map map = world.maps.byName(field.getText());
|
||||||
if(map != null){
|
if(map != null){
|
||||||
if(map.custom){
|
if(map.custom){
|
||||||
return "$editor.overwrite";
|
return "$editor.overwrite";
|
||||||
@@ -69,7 +69,7 @@ public class MapSaveDialog extends FloatingDialog{
|
|||||||
if(field.getText().isEmpty()){
|
if(field.getText().isEmpty()){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Map map = world.maps.getByName(field.getText());
|
Map map = world.maps.byName(field.getText());
|
||||||
return map != null && !map.custom;
|
return map != null && !map.custom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import io.anuke.arc.scene.event.Touchable;
|
|||||||
import io.anuke.arc.scene.ui.TextField;
|
import io.anuke.arc.scene.ui.TextField;
|
||||||
import io.anuke.arc.scene.ui.layout.Unit;
|
import io.anuke.arc.scene.ui.layout.Unit;
|
||||||
import io.anuke.arc.util.Tmp;
|
import io.anuke.arc.util.Tmp;
|
||||||
import io.anuke.mindustry.editor.DrawOperation.TileOperation;
|
|
||||||
import io.anuke.mindustry.graphics.Pal;
|
import io.anuke.mindustry.graphics.Pal;
|
||||||
import io.anuke.mindustry.input.Binding;
|
import io.anuke.mindustry.input.Binding;
|
||||||
import io.anuke.mindustry.ui.GridImage;
|
import io.anuke.mindustry.ui.GridImage;
|
||||||
@@ -29,8 +28,9 @@ import static io.anuke.mindustry.Vars.ui;
|
|||||||
public class MapView extends Element implements GestureListener{
|
public class MapView extends Element implements GestureListener{
|
||||||
private MapEditor editor;
|
private MapEditor editor;
|
||||||
private EditorTool tool = EditorTool.pencil;
|
private EditorTool tool = EditorTool.pencil;
|
||||||
private OperationStack stack = new OperationStack();
|
//private OperationStack stack = new OperationStack();
|
||||||
private DrawOperation op;
|
//private DrawOperation op;
|
||||||
|
//private GridBits used;
|
||||||
private Bresenham2 br = new Bresenham2();
|
private Bresenham2 br = new Bresenham2();
|
||||||
private boolean updated = false;
|
private boolean updated = false;
|
||||||
private float offsetx, offsety;
|
private float offsetx, offsety;
|
||||||
@@ -87,8 +87,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
mousex = x;
|
mousex = x;
|
||||||
mousey = y;
|
mousey = y;
|
||||||
|
|
||||||
op = new DrawOperation(editor.getMap());
|
|
||||||
|
|
||||||
updated = false;
|
updated = false;
|
||||||
|
|
||||||
Point2 p = project(x, y);
|
Point2 p = project(x, y);
|
||||||
@@ -135,12 +133,7 @@ public class MapView extends Element implements GestureListener{
|
|||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(op != null && updated){
|
editor.flushOp();
|
||||||
if(!op.isEmpty()){
|
|
||||||
stack.add(op);
|
|
||||||
}
|
|
||||||
op = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
|
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
|
||||||
tool = lastTool;
|
tool = lastTool;
|
||||||
@@ -190,14 +183,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearStack(){
|
|
||||||
stack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OperationStack getStack(){
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGrid(){
|
public boolean isGrid(){
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
@@ -206,26 +191,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo(){
|
|
||||||
if(stack.canUndo()){
|
|
||||||
stack.undo(editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void redo(){
|
|
||||||
if(stack.canRedo()){
|
|
||||||
stack.redo(editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTileOp(TileOperation t){
|
|
||||||
op.addOperation(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkForDuplicates(short x, short y){
|
|
||||||
return op.checkDuplicate(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void act(float delta){
|
public void act(float delta){
|
||||||
super.act(delta);
|
super.act(delta);
|
||||||
@@ -259,14 +224,14 @@ public class MapView extends Element implements GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Point2 project(float x, float y){
|
private Point2 project(float x, float y){
|
||||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
float ratio = 1f / ((float) editor.width() / editor.height());
|
||||||
float size = Math.min(width, height);
|
float size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.getMap().width();
|
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.width();
|
||||||
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.getMap().height();
|
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.height();
|
||||||
|
|
||||||
if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){
|
if(editor.drawBlock.size % 2 == 0 && tool != EditorTool.eraser){
|
||||||
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
|
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
|
||||||
}else{
|
}else{
|
||||||
return Tmp.g1.set((int) x, (int) y);
|
return Tmp.g1.set((int) x, (int) y);
|
||||||
@@ -274,26 +239,26 @@ public class MapView extends Element implements GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 unproject(int x, int y){
|
private Vector2 unproject(int x, int y){
|
||||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
float ratio = 1f / ((float) editor.width() / editor.height());
|
||||||
float size = Math.min(width, height);
|
float size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
float px = ((float) x / editor.getMap().width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
float px = ((float) x / editor.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
||||||
float py = ((float) (y) / editor.getMap().height()) * sclheight
|
float py = ((float) (y) / editor.height()) * sclheight
|
||||||
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
||||||
return vec.set(px, py);
|
return vec.set(px, py);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
public void draw(){
|
||||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
float ratio = 1f / ((float) editor.width() / editor.height());
|
||||||
float size = Math.min(width, height);
|
float size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
float centerx = x + width / 2 + offsetx * zoom;
|
float centerx = x + width / 2 + offsetx * zoom;
|
||||||
float centery = y + height / 2 + offsety * zoom;
|
float centery = y + height / 2 + offsety * zoom;
|
||||||
|
|
||||||
image.setImageSize(editor.getMap().width(), editor.getMap().height());
|
image.setImageSize(editor.width(), editor.height());
|
||||||
|
|
||||||
if(!ScissorStack.pushScissors(rect.set(x, y, width, height))){
|
if(!ScissorStack.pushScissors(rect.set(x, y, width, height))){
|
||||||
return;
|
return;
|
||||||
@@ -318,18 +283,18 @@ public class MapView extends Element implements GestureListener{
|
|||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
||||||
if(editor.getBrushSize() == MapEditor.brushSizes[i]){
|
if(editor.brushSize == MapEditor.brushSizes[i]){
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float scaling = zoom * Math.min(width, height) / editor.getMap().width();
|
float scaling = zoom * Math.min(width, height) / editor.width();
|
||||||
|
|
||||||
Draw.color(Pal.accent);
|
Draw.color(Pal.accent);
|
||||||
Lines.stroke(Unit.dp.scl(2f));
|
Lines.stroke(Unit.dp.scl(2f));
|
||||||
|
|
||||||
if((!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
|
if((!editor.drawBlock.isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
|
||||||
if(tool == EditorTool.line && drawing){
|
if(tool == EditorTool.line && drawing){
|
||||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||||
float sx = v1.x, sy = v1.y;
|
float sx = v1.x, sy = v1.y;
|
||||||
@@ -348,11 +313,11 @@ public class MapView extends Element implements GestureListener{
|
|||||||
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
|
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
|
||||||
Point2 p = project(mousex, mousey);
|
Point2 p = project(mousex, mousey);
|
||||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||||
float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling / 2f : 0f);
|
float offset = (editor.drawBlock.size % 2 == 0 ? scaling / 2f : 0f);
|
||||||
Lines.square(
|
Lines.square(
|
||||||
v.x + scaling / 2f + offset,
|
v.x + scaling / 2f + offset,
|
||||||
v.y + scaling / 2f + offset,
|
v.y + scaling / 2f + offset,
|
||||||
scaling * editor.getDrawBlock().size / 2f);
|
scaling * editor.drawBlock.size / 2f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -252,10 +252,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
TileEntity core = unit.getClosestCore();
|
TileEntity core = unit.getClosestCore();
|
||||||
|
|
||||||
if(core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > mineDistance
|
if(core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > mineDistance
|
||||||
|| tile.floor().itemDrop == null || !unit.acceptsItem(tile.floor().itemDrop) || !canMine(tile.floor().itemDrop)){
|
|| tile.drop() == null || !unit.acceptsItem(tile.drop()) || !canMine(tile.drop())){
|
||||||
setMineTile(null);
|
setMineTile(null);
|
||||||
}else{
|
}else{
|
||||||
Item item = tile.floor().itemDrop;
|
Item item = tile.drop();
|
||||||
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.worldx(), tile.worldy()), 0.4f);
|
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.worldx(), tile.worldy()), 0.4f);
|
||||||
|
|
||||||
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
|
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
|
||||||
|
|||||||
@@ -269,7 +269,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
//TODO better smoke effect, this one is awful
|
//TODO better smoke effect, this one is awful
|
||||||
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
||||||
Mathf.chance(0.009f * Time.delta() * (1f - health / tile.block().health))){
|
Mathf.chance(0.009f * Time.delta() * (1f - health / tile.block().health))){
|
||||||
|
|
||||||
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public class MinimapRenderer implements Disposable{
|
|||||||
|
|
||||||
private int colorFor(Tile tile){
|
private int colorFor(Tile tile){
|
||||||
tile = tile.target();
|
tile = tile.target();
|
||||||
return MapIO.colorFor(tile.floor(), tile.block(), tile.getTeam());
|
return MapIO.colorFor(tile.floor(), tile.block(), tile.oreBlock(), tile.getTeam());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -230,9 +230,9 @@ public abstract class InputHandler implements InputProcessor{
|
|||||||
|
|
||||||
boolean canMine(Tile tile){
|
boolean canMine(Tile tile){
|
||||||
return !Core.scene.hasMouse()
|
return !Core.scene.hasMouse()
|
||||||
&& tile.floor().itemDrop != null && tile.floor().itemDrop.hardness <= player.mech.drillPower
|
&& tile.drop() != null && tile.drop().hardness <= player.mech.drillPower
|
||||||
&& !tile.floor().playerUnmineable
|
&& !tile.floor().playerUnmineable
|
||||||
&& player.acceptsItem(tile.floor().itemDrop)
|
&& player.acceptsItem(tile.drop())
|
||||||
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,35 +7,50 @@ import io.anuke.arc.files.FileHandle;
|
|||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.arc.graphics.Pixmap;
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
import io.anuke.arc.graphics.Pixmap.Format;
|
import io.anuke.arc.graphics.Pixmap.Format;
|
||||||
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
|
import io.anuke.arc.util.Strings;
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
|
import io.anuke.mindustry.game.MappableContent;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.MapMeta;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.DataPosition;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
|
||||||
import io.anuke.mindustry.type.ContentType;
|
import io.anuke.mindustry.type.ContentType;
|
||||||
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import io.anuke.mindustry.world.CachedTile;
|
||||||
import io.anuke.mindustry.world.LegacyColorMapper;
|
import io.anuke.mindustry.world.LegacyColorMapper;
|
||||||
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
|
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.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
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.content;
|
||||||
|
|
||||||
/**
|
/** Reads and writes map files.*/
|
||||||
* Reads and writes map files.
|
|
||||||
*/
|
|
||||||
//TODO name mapping
|
|
||||||
public class MapIO{
|
public class MapIO{
|
||||||
|
public static final int version = 1;
|
||||||
|
|
||||||
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
private static final int version = 0;
|
private static ObjectMap<String, Block> missingBlocks;
|
||||||
private static IntIntMap defaultBlockMap = new IntIntMap();
|
|
||||||
|
private static void initBlocks(){
|
||||||
|
if(missingBlocks != null) return;
|
||||||
|
|
||||||
|
missingBlocks = ObjectMap.of(
|
||||||
|
"stained-stone", Blocks.moss
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isImage(FileHandle file){
|
public static boolean isImage(FileHandle file){
|
||||||
try(InputStream stream = file.read()){
|
try(InputStream stream = file.read(32)){
|
||||||
for(int i1 : pngHeader){
|
for(int i1 : pngHeader){
|
||||||
if(stream.read() != i1){
|
if(stream.read() != i1){
|
||||||
return false;
|
return false;
|
||||||
@@ -47,44 +62,277 @@ public class MapIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadDefaultBlocks(){
|
public static Pixmap generatePreview(Map map) throws IOException{
|
||||||
for(Block block : content.blocks()){
|
Pixmap floor = new Pixmap(map.width, map.height, Format.RGBA8888);
|
||||||
defaultBlockMap.put(block.id, block.id);
|
Pixmap wall = new Pixmap(map.width, map.height, Format.RGBA8888);
|
||||||
}
|
int black = Color.rgba8888(Color.BLACK);
|
||||||
|
CachedTile tile = new CachedTile(){
|
||||||
|
@Override
|
||||||
|
public void setFloor(Floor type){
|
||||||
|
floor.drawPixel(x, floor.getHeight() - 1 - y, colorFor(type, Blocks.air, Blocks.air, getTeam()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOreByte(byte b){
|
||||||
|
if(b != 0)
|
||||||
|
floor.drawPixel(x, floor.getHeight() - 1 - y, colorFor(floor(), Blocks.air, content.block(b), getTeam()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void changed(){
|
||||||
|
super.changed();
|
||||||
|
int c = colorFor(Blocks.air, block(), Blocks.air, getTeam());
|
||||||
|
if(c != black) wall.drawPixel(x, floor.getHeight() - 1 - y, c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
readTiles(map, (x, y) -> {
|
||||||
|
tile.x = (short)x;
|
||||||
|
tile.y = (short)y;
|
||||||
|
return tile;
|
||||||
|
});
|
||||||
|
floor.drawPixmap(wall, 0, 0);
|
||||||
|
wall.dispose();
|
||||||
|
return floor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pixmap generatePixmap(MapTileData data){
|
public static Pixmap generatePreview(Tile[][] tiles){
|
||||||
Pixmap pixmap = new Pixmap(data.width(), data.height(), Format.RGBA8888);
|
Pixmap pixmap = new Pixmap(tiles.length, tiles[0].length, Format.RGBA8888);
|
||||||
data.position(0, 0);
|
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||||
|
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||||
TileDataMarker marker = data.newDataMarker();
|
Tile tile = tiles[x][y];
|
||||||
|
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.oreBlock(), tile.getTeam()));
|
||||||
for(int y = 0; y < data.height(); y++){
|
|
||||||
for(int x = 0; x < data.width(); x++){
|
|
||||||
data.read(marker);
|
|
||||||
Block floor = content.block(marker.floor);
|
|
||||||
Block wall = content.block(marker.wall);
|
|
||||||
int color = colorFor(floor, wall, Team.all[marker.team]);
|
|
||||||
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.position(0, 0);
|
|
||||||
|
|
||||||
return pixmap;
|
return pixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Reads a pixmap in the old (3.5) map format.*/
|
public static int colorFor(Block floor, Block wall, Block ore, Team team){
|
||||||
public static MapTileData readLegacyPixmap(Pixmap pixmap){
|
if(wall.synthetic()){
|
||||||
MapTileData data = new MapTileData(pixmap.getWidth(), pixmap.getHeight());
|
return team.intColor;
|
||||||
|
}
|
||||||
|
return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color);
|
||||||
|
}
|
||||||
|
|
||||||
for(int x = 0; x < data.width(); x++){
|
public static void writeMap(FileHandle file, Map map, Tile[][] tiles) throws IOException{
|
||||||
for(int y = 0; y < data.height(); y++){
|
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.getOreByte());
|
||||||
|
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.getOreByte() != tile.getOreByte()){
|
||||||
|
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(); //key
|
||||||
|
stream.readUTF(); //val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.setOreByte(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.setOreByte(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++){
|
||||||
|
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||||
int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y);
|
int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y);
|
||||||
LegacyBlock block = LegacyColorMapper.get(color);
|
LegacyBlock block = LegacyColorMapper.get(color);
|
||||||
|
Tile tile = tiles[x][y];
|
||||||
|
|
||||||
data.write(x, y, DataPosition.floor, block.floor.id);
|
tile.setFloor(block.floor);
|
||||||
data.write(x, y, DataPosition.wall, block.wall.id);
|
tile.setBlock(block.wall);
|
||||||
|
if(block.ore != null) tile.setOre(block.ore);
|
||||||
|
|
||||||
//place core
|
//place core
|
||||||
if(color == Color.rgba8888(Color.GREEN)){
|
if(color == Color.rgba8888(Color.GREEN)){
|
||||||
@@ -93,121 +341,133 @@ public class MapIO{
|
|||||||
int worldx = dx - 1 + x;
|
int worldx = dx - 1 + x;
|
||||||
int worldy = dy - 1 + y;
|
int worldy = dy - 1 + y;
|
||||||
|
|
||||||
|
//multiblock parts
|
||||||
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
|
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
|
||||||
data.write(worldx, worldy, DataPosition.wall, Blocks.part.id);
|
Tile write = tiles[worldx][worldy];
|
||||||
data.write(worldx, worldy, DataPosition.rotationTeam, Pack.byteByte((byte)0, (byte)Team.blue.ordinal()));
|
write.setBlock(Blocks.part);
|
||||||
data.write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx - 1 + 8), (byte) (dy - 1 + 8)));
|
write.setTeam(Team.blue);
|
||||||
|
write.setLinkByte(Pack.byteByte((byte) (dx - 1 + 8), (byte) (dy - 1 + 8)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.write(x, y, DataPosition.wall, Blocks.coreShard.id);
|
//actual core parts
|
||||||
data.write(x, y, DataPosition.rotationTeam, Pack.byteByte((byte)0, (byte)Team.blue.ordinal()));
|
tile.setBlock(Blocks.coreShard);
|
||||||
|
tile.setTeam(Team.blue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeMap(OutputStream stream, ObjectMap<String, String> tags, MapTileData data) throws IOException{
|
/**Reads a pixmap in the old 4.0 .mmap format.*/
|
||||||
if(defaultBlockMap == null){
|
private static void readLegacyMmapTiles(FileHandle file, Tile[][] tiles) throws IOException{
|
||||||
loadDefaultBlocks();
|
readLegacyMmapTiles(file, (x, y) -> tiles[x][y]);
|
||||||
}
|
|
||||||
|
|
||||||
MapMeta meta = new MapMeta(version, tags, data.width(), data.height(), defaultBlockMap);
|
|
||||||
|
|
||||||
DataOutputStream ds = new DataOutputStream(stream);
|
|
||||||
|
|
||||||
writeMapMeta(ds, meta);
|
|
||||||
ds.write(data.toArray());
|
|
||||||
|
|
||||||
ds.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**Reads a mmap in the old 4.0 .mmap format.*/
|
||||||
* Reads tile data, skipping meta.
|
private static void readLegacyMmapTiles(FileHandle file, TileProvider tiles) throws IOException{
|
||||||
*/
|
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
|
||||||
public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException{
|
stream.readInt(); //version
|
||||||
MapMeta meta = readMapMeta(stream);
|
byte tagAmount = stream.readByte();
|
||||||
return readTileData(stream, meta, readOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
stream.readUTF(); //key
|
||||||
|
stream.readUTF(); //val
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
initBlocks();
|
||||||
* Does not skip meta. Call after reading meta.
|
|
||||||
*/
|
//block id -> real id map
|
||||||
public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException{
|
IntIntMap map = new IntIntMap();
|
||||||
byte[] bytes = new byte[stream.available()];
|
IntIntMap oreMap = new IntIntMap();
|
||||||
stream.readFully(bytes);
|
|
||||||
return new MapTileData(bytes, meta.width, meta.height, meta.blockMap, readOnly);
|
short blocks = stream.readShort();
|
||||||
}
|
for(int i = 0; i < blocks; i++){
|
||||||
|
short id = stream.readShort();
|
||||||
/**
|
String name = stream.readUTF();
|
||||||
* Reads tile data, skipping meta tags.
|
Block block = content.getByName(ContentType.block, name);
|
||||||
*/
|
if(block == null){
|
||||||
public static MapTileData readTileData(Map map, boolean readOnly){
|
//substitute for replacement in missingBlocks if possible
|
||||||
try(DataInputStream ds = new DataInputStream(map.stream.get())){
|
if(missingBlocks.containsKey(name)){
|
||||||
return MapIO.readTileData(ds, readOnly);
|
block = missingBlocks.get(name);
|
||||||
}catch(IOException e){
|
}else if(name.startsWith("ore-")){ //an ore floor combination
|
||||||
throw new RuntimeException(e);
|
String[] split = name.split("-");
|
||||||
}
|
String itemName = split[1], floorName = Strings.join("-", Arrays.copyOfRange(split, 2, split.length));
|
||||||
}
|
Item item = content.getByName(ContentType.item, itemName);
|
||||||
|
Block oreBlock = item == null ? null : content.getByName(ContentType.block, "ore-" + item.name);
|
||||||
public static MapMeta readMapMeta(DataInputStream stream) throws IOException{
|
Block floor = missingBlocks.get(floorName, content.getByName(ContentType.block, floorName));
|
||||||
ObjectMap<String, String> tags = new ObjectMap<>();
|
if(oreBlock != null && floor != null){
|
||||||
IntIntMap map = new IntIntMap();
|
oreMap.put(id, oreBlock.id);
|
||||||
|
block = floor;
|
||||||
int version = stream.readInt();
|
}else{
|
||||||
|
block = Blocks.air;
|
||||||
byte tagAmount = stream.readByte();
|
}
|
||||||
|
}else{
|
||||||
for(int i = 0; i < tagAmount; i++){
|
block = Blocks.air;
|
||||||
String name = stream.readUTF();
|
}
|
||||||
String value = stream.readUTF();
|
|
||||||
tags.put(name, value);
|
}
|
||||||
}
|
map.put(id, block.id);
|
||||||
|
}
|
||||||
short blocks = stream.readShort();
|
short width = stream.readShort(), height = stream.readShort();
|
||||||
for(int i = 0; i < blocks; i++){
|
|
||||||
short id = stream.readShort();
|
for(int y = 0; y < height; y++){
|
||||||
String name = stream.readUTF();
|
for(int x = 0; x < width; x++){
|
||||||
Block block = content.getByName(ContentType.block, name);
|
Tile tile = tiles.get(x, y);
|
||||||
if(block == null){
|
byte floorb = stream.readByte();
|
||||||
block = Blocks.air;
|
byte blockb = stream.readByte();
|
||||||
|
byte link = stream.readByte();
|
||||||
|
byte rotTeamb = 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().synthetic()){
|
||||||
|
tile.setTeam(Team.all[Mathf.clamp(Pack.rightByte(rotTeamb), 0, Team.all.length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tile.block() == Blocks.part){
|
||||||
|
tile.setLinkByte(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oreMap.containsKey(floorb)){
|
||||||
|
tile.setOreByte((byte)oreMap.get(floorb, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
map.put(id, block.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = stream.readShort();
|
|
||||||
int height = stream.readShort();
|
|
||||||
|
|
||||||
return new MapMeta(version, tags, width, height, map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeMapMeta(DataOutputStream stream, MapMeta meta) throws IOException{
|
private static Map readLegacyMap(FileHandle file, boolean custom) throws IOException{
|
||||||
stream.writeInt(meta.version);
|
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
|
||||||
stream.writeByte((byte) meta.tags.size);
|
ObjectMap<String, String> tags = new ObjectMap<>();
|
||||||
|
|
||||||
for(Entry<String, String> entry : meta.tags.entries()){
|
int version = stream.readInt();
|
||||||
stream.writeUTF(entry.key);
|
if(version != 0) throw new IOException("Attempted to read non-legacy map in legacy method!");
|
||||||
stream.writeUTF(entry.value);
|
byte tagAmount = stream.readByte();
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
String name = stream.readUTF();
|
||||||
|
String value = stream.readUTF();
|
||||||
|
tags.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.writeShort(content.blocks().size);
|
|
||||||
for(Block block : content.blocks()){
|
|
||||||
stream.writeShort(block.id);
|
|
||||||
stream.writeUTF(block.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.writeShort(meta.width);
|
|
||||||
stream.writeShort(meta.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int colorFor(Block floor, Block wall, Team team){
|
//endregion
|
||||||
if(wall.synthetic()){
|
|
||||||
return team.intColor;
|
interface TileProvider{
|
||||||
}
|
Tile get(int x, int y);
|
||||||
return Color.rgba8888(wall.solid ? wall.color : floor.color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,8 +14,8 @@ import io.anuke.mindustry.game.Rules;
|
|||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.gen.Serialization;
|
import io.anuke.mindustry.gen.Serialization;
|
||||||
import io.anuke.mindustry.type.ContentType;
|
import io.anuke.mindustry.type.ContentType;
|
||||||
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@@ -43,18 +43,37 @@ public abstract class SaveFileVersion{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeMap(DataOutputStream stream) throws IOException{
|
public void writeMap(DataOutputStream stream) throws IOException{
|
||||||
|
|
||||||
//write world size
|
//write world size
|
||||||
stream.writeShort(world.width());
|
stream.writeShort(world.width());
|
||||||
stream.writeShort(world.height());
|
stream.writeShort(world.height());
|
||||||
|
|
||||||
|
//floor first
|
||||||
for(int i = 0; i < world.width() * world.height(); i++){
|
for(int i = 0; i < world.width() * world.height(); i++){
|
||||||
Tile tile = world.tile(i % world.width(), i / world.width());
|
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||||
|
|
||||||
stream.writeByte(tile.getFloorID());
|
stream.writeByte(tile.getFloorID());
|
||||||
|
stream.writeByte(tile.getOreByte());
|
||||||
|
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.getOreByte() != tile.getOreByte()){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
consecutives++;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.writeByte(consecutives);
|
||||||
|
i += consecutives;
|
||||||
|
}
|
||||||
|
|
||||||
|
//blocks
|
||||||
|
for(int i = 0; i < world.width() * world.height(); i++){
|
||||||
|
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||||
stream.writeByte(tile.getBlockID());
|
stream.writeByte(tile.getBlockID());
|
||||||
|
|
||||||
if(tile.block() instanceof BlockPart){
|
if(tile.block() == Blocks.part){
|
||||||
stream.writeByte(tile.link);
|
stream.writeByte(tile.link);
|
||||||
}else if(tile.entity != null){
|
}else if(tile.entity != null){
|
||||||
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation
|
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation
|
||||||
@@ -67,13 +86,14 @@ public abstract class SaveFileVersion{
|
|||||||
|
|
||||||
tile.entity.writeConfig(stream);
|
tile.entity.writeConfig(stream);
|
||||||
tile.entity.write(stream);
|
tile.entity.write(stream);
|
||||||
}else if(tile.block() == Blocks.air){
|
}else{
|
||||||
|
//write consecutive non-entity blocks
|
||||||
int consecutives = 0;
|
int consecutives = 0;
|
||||||
|
|
||||||
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
||||||
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
||||||
|
|
||||||
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air){
|
if(nextTile.block() != tile.block()){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,14 +114,34 @@ public abstract class SaveFileVersion{
|
|||||||
|
|
||||||
Tile[][] tiles = world.createTiles(width, height);
|
Tile[][] tiles = world.createTiles(width, height);
|
||||||
|
|
||||||
|
//read floor and create tiles first
|
||||||
for(int i = 0; i < width * height; i++){
|
for(int i = 0; i < width * height; i++){
|
||||||
int x = i % width, y = i / width;
|
int x = i % width, y = i / width;
|
||||||
byte floorid = stream.readByte();
|
byte floorid = stream.readByte();
|
||||||
byte wallid = stream.readByte();
|
byte oreid = stream.readByte();
|
||||||
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
Tile tile = new Tile(x, y, floorid, wallid);
|
tiles[x][y] = new Tile(x, y, floorid, (byte)0);
|
||||||
|
tiles[x][y].setOreByte(oreid);
|
||||||
|
|
||||||
if(wallid == Blocks.part.id){
|
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.setOreByte(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();
|
tile.link = stream.readByte();
|
||||||
}else if(tile.entity != null){
|
}else if(tile.entity != null){
|
||||||
byte tr = stream.readByte();
|
byte tr = stream.readByte();
|
||||||
@@ -121,19 +161,16 @@ public abstract class SaveFileVersion{
|
|||||||
|
|
||||||
tile.entity.readConfig(stream);
|
tile.entity.readConfig(stream);
|
||||||
tile.entity.read(stream);
|
tile.entity.read(stream);
|
||||||
}else if(wallid == 0){
|
}else{
|
||||||
int consecutives = stream.readUnsignedByte();
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||||
int newx = j % width, newy = j / width;
|
int newx = j % width, newy = j / width;
|
||||||
Tile newTile = new Tile(newx, newy, floorid, wallid);
|
tiles[newx][newy].setBlock(block);
|
||||||
tiles[newx][newy] = newTile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i += consecutives;
|
i += consecutives;
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles[x][y] = tile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content.setTemporaryMapper(null);
|
content.setTemporaryMapper(null);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static DataInputStream getSlotStream(int slot){
|
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){
|
public static boolean isSaveValid(int slot){
|
||||||
@@ -60,7 +60,7 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSaveValid(FileHandle file){
|
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){
|
public static boolean isSaveValid(DataInputStream stream){
|
||||||
@@ -95,7 +95,7 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void write(FileHandle file){
|
public static void write(FileHandle file){
|
||||||
write(new DeflaterOutputStream(file.write(false)){
|
write(new DeflaterOutputStream(file.write(false, bufferSize)){
|
||||||
byte[] tmp = {0};
|
byte[] tmp = {0};
|
||||||
|
|
||||||
public void write(int var1) throws IOException {
|
public void write(int var1) throws IOException {
|
||||||
@@ -120,12 +120,12 @@ public class SaveIO{
|
|||||||
public static void load(FileHandle file) throws SaveException{
|
public static void load(FileHandle file) throws SaveException{
|
||||||
try{
|
try{
|
||||||
//try and load; if any exception at all occurs
|
//try and load; if any exception at all occurs
|
||||||
load(new InflaterInputStream(file.read()));
|
load(new InflaterInputStream(file.read(bufferSize)));
|
||||||
}catch(SaveException e){
|
}catch(SaveException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
|
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
|
||||||
if(backup.exists()){
|
if(backup.exists()){
|
||||||
load(new InflaterInputStream(backup.read()));
|
load(new InflaterInputStream(backup.read(bufferSize)));
|
||||||
}else{
|
}else{
|
||||||
throw new SaveException(e.getCause());
|
throw new SaveException(e.getCause());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class SaveMeta{
|
|||||||
this.build = build;
|
this.build = build;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.timePlayed = timePlayed;
|
this.timePlayed = timePlayed;
|
||||||
this.map = world.maps.getByName(map);
|
this.map = world.maps.all().find(m -> m.fileName().equals(map));
|
||||||
this.wave = wave;
|
this.wave = wave;
|
||||||
this.rules = rules;
|
this.rules = rules;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.anuke.mindustry.io.versions;
|
package io.anuke.mindustry.io.versions;
|
||||||
|
|
||||||
import io.anuke.arc.util.Strings;
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
import io.anuke.arc.util.Time;
|
import io.anuke.arc.util.Time;
|
||||||
import io.anuke.mindustry.game.Version;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.gen.Serialization;
|
import io.anuke.mindustry.gen.Serialization;
|
||||||
@@ -34,8 +34,8 @@ public class Save16 extends SaveFileVersion{
|
|||||||
state.rules.spawns = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get().spawns;
|
state.rules.spawns = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get().spawns;
|
||||||
}
|
}
|
||||||
String mapname = stream.readUTF();
|
String mapname = stream.readUTF();
|
||||||
Map map = world.maps.getByName(mapname);
|
Map map = world.maps.all().find(m -> m.fileName().equals(mapname));
|
||||||
if(map == null) map = new Map(Strings.capitalize(mapname), 1, 1);
|
if(map == null) map = new Map(customMapDirectory.child(mapname), 1, 1, new ObjectMap<>(), true);
|
||||||
world.setMap(map);
|
world.setMap(map);
|
||||||
|
|
||||||
int wave = stream.readInt();
|
int wave = stream.readInt();
|
||||||
@@ -62,7 +62,7 @@ public class Save16 extends SaveFileVersion{
|
|||||||
|
|
||||||
//--GENERAL STATE--
|
//--GENERAL STATE--
|
||||||
Serialization.writeRules(stream, state.rules);
|
Serialization.writeRules(stream, state.rules);
|
||||||
stream.writeUTF(world.getMap().name); //map name
|
stream.writeUTF(world.getMap().fileName()); //map name
|
||||||
|
|
||||||
stream.writeInt(state.wave); //wave
|
stream.writeInt(state.wave); //wave
|
||||||
stream.writeFloat(state.wavetime); //wave countdown
|
stream.writeFloat(state.wavetime); //wave countdown
|
||||||
|
|||||||
@@ -1,44 +1,75 @@
|
|||||||
package io.anuke.mindustry.maps;
|
package io.anuke.mindustry.maps;
|
||||||
|
|
||||||
import io.anuke.arc.graphics.Texture;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
import io.anuke.arc.function.Supplier;
|
import io.anuke.arc.files.FileHandle;
|
||||||
|
import io.anuke.arc.graphics.Texture;
|
||||||
import java.io.InputStream;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
|
|
||||||
public class Map{
|
public class Map{
|
||||||
/** Internal map name. This is the filename, without any extensions.*/
|
|
||||||
public final String name;
|
|
||||||
/** Whether this is a custom map.*/
|
/** Whether this is a custom map.*/
|
||||||
public final boolean custom;
|
public final boolean custom;
|
||||||
/** Metadata. Author description, display name, etc.*/
|
/** Metadata. Author description, display name, etc.*/
|
||||||
public final MapMeta meta;
|
public final ObjectMap<String, String> tags;
|
||||||
/** Supplies a new input stream with the data of this map.*/
|
/** Base file of this map.*/
|
||||||
public final Supplier<InputStream> stream;
|
public final FileHandle file;
|
||||||
|
/** Format version.*/
|
||||||
|
public final int version;
|
||||||
|
/** Map width/height, shorts.*/
|
||||||
|
public int width, height;
|
||||||
/** Preview texture.*/
|
/** Preview texture.*/
|
||||||
public Texture texture;
|
public Texture texture;
|
||||||
|
/** Build that this map was created in. -1 = unknown or custom build.*/
|
||||||
|
public int build;
|
||||||
|
|
||||||
public Map(String name, MapMeta meta, boolean custom, Supplier<InputStream> streamSupplier){
|
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom, int version, int build){
|
||||||
this.name = name;
|
|
||||||
this.custom = custom;
|
this.custom = custom;
|
||||||
this.meta = meta;
|
this.tags = tags;
|
||||||
this.stream = streamSupplier;
|
this.file = file;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.version = version;
|
||||||
|
this.build = build;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map(String unknownName, int width, int height){
|
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom, int version){
|
||||||
this(unknownName, new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null);
|
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(){
|
||||||
|
return file.nameWithoutExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName(){
|
public String getDisplayName(){
|
||||||
return meta.tags.get("name", name);
|
return tags.get("name", fileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String author(){
|
||||||
|
return tag("author");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String description(){
|
||||||
|
return tag("description");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name(){
|
||||||
|
return tag("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String tag(String name){
|
||||||
|
return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Core.bundle.get("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "Map{" +
|
return "Map{" +
|
||||||
"name='" + name + '\'' +
|
"file='" + file + '\'' +
|
||||||
", custom=" + custom +
|
", custom=" + custom +
|
||||||
", meta=" + meta +
|
", tags=" + tags +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package io.anuke.mindustry.maps;
|
|
||||||
|
|
||||||
import io.anuke.arc.Core;
|
|
||||||
import io.anuke.arc.collection.IntIntMap;
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
|
|
||||||
//todo: specify preferred game rules here; can be overriden
|
|
||||||
public class MapMeta{
|
|
||||||
public final int version;
|
|
||||||
public final ObjectMap<String, String> tags;
|
|
||||||
public final int width, height;
|
|
||||||
public final IntIntMap blockMap;
|
|
||||||
|
|
||||||
public MapMeta(int version, ObjectMap<String, String> tags, int width, int height, IntIntMap blockMap){
|
|
||||||
this.version = version;
|
|
||||||
this.tags = tags;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.blockMap = blockMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String author(){
|
|
||||||
return tag("author");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String description(){
|
|
||||||
return tag("description");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String name(){
|
|
||||||
return tag("name");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String tag(String name){
|
|
||||||
return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Core.bundle.get("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return "MapMeta{" +
|
|
||||||
"tags=" + tags +
|
|
||||||
", width=" + width +
|
|
||||||
", height=" + height +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
package io.anuke.mindustry.maps;
|
|
||||||
|
|
||||||
import io.anuke.arc.collection.IntIntMap;
|
|
||||||
import io.anuke.arc.util.Pack;
|
|
||||||
import io.anuke.arc.util.Structs;
|
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
|
||||||
import io.anuke.mindustry.world.Block;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class MapTileData{
|
|
||||||
/**
|
|
||||||
* Tile size: 5 bytes. <br>
|
|
||||||
* 0: ground tile <br>
|
|
||||||
* 1: wall tile <br>
|
|
||||||
* 2: rotation + team <br>
|
|
||||||
* 3: link (x/y) <br>
|
|
||||||
* 4: elevation <br>
|
|
||||||
*/
|
|
||||||
private final static int TILE_SIZE = 5;
|
|
||||||
|
|
||||||
private final ByteBuffer buffer;
|
|
||||||
private final int width, height;
|
|
||||||
private final boolean readOnly;
|
|
||||||
|
|
||||||
private IntIntMap map;
|
|
||||||
|
|
||||||
public MapTileData(int width, int height){
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.map = null;
|
|
||||||
this.readOnly = false;
|
|
||||||
buffer = ByteBuffer.allocate(width * height * TILE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapTileData(byte[] bytes, int width, int height, IntIntMap mapping, boolean readOnly){
|
|
||||||
buffer = ByteBuffer.wrap(bytes);
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.map = mapping;
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
|
|
||||||
if(mapping != null && !readOnly){
|
|
||||||
buffer.position(0);
|
|
||||||
TileDataMarker marker = new TileDataMarker();
|
|
||||||
for(int i = 0; i < width * height; i++){
|
|
||||||
read(marker);
|
|
||||||
|
|
||||||
//strip blockparts from map data, as they can be invalid
|
|
||||||
if(marker.wall == Blocks.part.id){
|
|
||||||
marker.wall = Blocks.air.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.position(i * TILE_SIZE);
|
|
||||||
|
|
||||||
//write mapped marker
|
|
||||||
write(marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.position(0);
|
|
||||||
for(int x = 0; x < width; x ++){
|
|
||||||
for(int y = 0; y < height; y ++){
|
|
||||||
//add missing blockparts
|
|
||||||
Block drawBlock = Vars.content.block(read(x, y, DataPosition.wall));
|
|
||||||
if(drawBlock.isMultiblock()){
|
|
||||||
int offsetx = -(drawBlock.size - 1) / 2;
|
|
||||||
int offsety = -(drawBlock.size - 1) / 2;
|
|
||||||
for(int dx = 0; dx < drawBlock.size; dx++){
|
|
||||||
for(int dy = 0; dy < drawBlock.size; dy++){
|
|
||||||
int worldx = dx + offsetx + x;
|
|
||||||
int worldy = dy + offsety + y;
|
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, width, height) && !(dx + offsetx == 0 && dy + offsety == 0)){
|
|
||||||
write(worldx, worldy, DataPosition.wall, Blocks.part.id);
|
|
||||||
write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.position(0);
|
|
||||||
this.map = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toArray(){
|
|
||||||
return buffer.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int width(){
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int height(){
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a byte to a specific position.
|
|
||||||
*/
|
|
||||||
public void write(int x, int y, DataPosition position, byte data){
|
|
||||||
buffer.put((x + width * y) * TILE_SIZE + position.ordinal(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a byte at a specific position.
|
|
||||||
*/
|
|
||||||
public byte read(int x, int y, DataPosition position){
|
|
||||||
return buffer.get((x + width * y) * TILE_SIZE + position.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the next tile data.
|
|
||||||
*/
|
|
||||||
public TileDataMarker read(TileDataMarker marker){
|
|
||||||
marker.read(buffer);
|
|
||||||
return marker;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes this tile data marker.
|
|
||||||
*/
|
|
||||||
public void write(TileDataMarker marker){
|
|
||||||
marker.write(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets read position to the specified coordinates
|
|
||||||
*/
|
|
||||||
public void position(int x, int y){
|
|
||||||
buffer.position((x + width * y) * TILE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileDataMarker newDataMarker(){
|
|
||||||
return new TileDataMarker();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DataPosition{
|
|
||||||
floor, wall, link, rotationTeam, elevation
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TileDataMarker{
|
|
||||||
public byte floor, wall;
|
|
||||||
public byte link;
|
|
||||||
public byte rotation;
|
|
||||||
public byte team;
|
|
||||||
public byte elevation;
|
|
||||||
|
|
||||||
public void read(ByteBuffer buffer){
|
|
||||||
floor = buffer.get();
|
|
||||||
wall = buffer.get();
|
|
||||||
link = buffer.get();
|
|
||||||
byte rt = buffer.get();
|
|
||||||
elevation = buffer.get();
|
|
||||||
rotation = Pack.leftByte(rt);
|
|
||||||
team = Pack.rightByte(rt);
|
|
||||||
|
|
||||||
if(map != null){
|
|
||||||
floor = (byte) map.get(floor, Blocks.stone.id);
|
|
||||||
wall = (byte) map.get(wall, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(ByteBuffer buffer){
|
|
||||||
if(readOnly) throw new IllegalArgumentException("This data is read-only.");
|
|
||||||
buffer.put(floor);
|
|
||||||
buffer.put(wall);
|
|
||||||
buffer.put(link);
|
|
||||||
buffer.put(Pack.byteByte(rotation, team));
|
|
||||||
buffer.put(elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,166 +1,155 @@
|
|||||||
package io.anuke.mindustry.maps;
|
package io.anuke.mindustry.maps;
|
||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
|
import io.anuke.arc.collection.Array;
|
||||||
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.graphics.Texture;
|
import io.anuke.arc.graphics.Texture;
|
||||||
import io.anuke.arc.collection.Array;
|
|
||||||
import io.anuke.arc.util.Disposable;
|
import io.anuke.arc.util.Disposable;
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
import io.anuke.mindustry.io.MapIO;
|
|
||||||
import io.anuke.arc.function.Supplier;
|
|
||||||
import io.anuke.arc.util.Log;
|
import io.anuke.arc.util.Log;
|
||||||
|
import io.anuke.arc.util.Time;
|
||||||
|
import io.anuke.mindustry.io.MapIO;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Maps implements Disposable{
|
public class Maps implements Disposable{
|
||||||
/**List of all built-in maps.*/
|
/** List of all built-in maps. */
|
||||||
private static final String[] defaultMapNames = {};
|
private static final String[] defaultMapNames = {"impact0079"};
|
||||||
/**Tile format version.*/
|
/** All maps stored in an ordered array. */
|
||||||
private static final int version = 0;
|
private Array<Map> maps = new Array<>();
|
||||||
|
|
||||||
/**Maps map names to the real maps.*/
|
/** Returns a list of all maps, including custom ones. */
|
||||||
private ObjectMap<String, Map> maps = new ObjectMap<>();
|
|
||||||
/**All maps stored in an ordered array.*/
|
|
||||||
private Array<Map> allMaps = new Array<>();
|
|
||||||
/**Temporary array used for returning things.*/
|
|
||||||
private Array<Map> returnArray = new Array<>();
|
|
||||||
|
|
||||||
/**Returns a list of all maps, including custom ones.*/
|
|
||||||
public Array<Map> all(){
|
public Array<Map> all(){
|
||||||
return allMaps;
|
return maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of only custom maps.*/
|
/** Returns a list of only custom maps. */
|
||||||
public Array<Map> customMaps(){
|
public Array<Map> customMaps(){
|
||||||
returnArray.clear();
|
return maps.select(m -> m.custom);
|
||||||
for(Map map : allMaps){
|
|
||||||
if(map.custom) returnArray.add(map);
|
|
||||||
}
|
|
||||||
return returnArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of only default maps.*/
|
/** Returns a list of only default maps. */
|
||||||
public Array<Map> defaultMaps(){
|
public Array<Map> defaultMaps(){
|
||||||
returnArray.clear();
|
return maps.select(m -> !m.custom);
|
||||||
for(Map map : allMaps){
|
|
||||||
if(!map.custom) returnArray.add(map);
|
|
||||||
}
|
|
||||||
return returnArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns map by internal name.*/
|
public Map byName(String name){
|
||||||
public Map getByName(String name){
|
return maps.find(m -> m.name().equals(name));
|
||||||
return maps.get(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Loads a map from the map folder and returns it. Should only be used for zone maps.
|
/**
|
||||||
* Does not add this map to the map list.*/
|
* Loads a map from the map folder and returns it. Should only be used for zone maps.
|
||||||
|
* Does not add this map to the map list.
|
||||||
|
*/
|
||||||
public Map loadInternalMap(String name){
|
public Map loadInternalMap(String name){
|
||||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||||
|
|
||||||
try(DataInputStream ds = new DataInputStream(file.read())) {
|
try{
|
||||||
return new Map(name, MapIO.readMapMeta(ds), false, file::read);
|
return MapIO.readMap(file, false);
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Load all maps. Should be called at application start.*/
|
/** Load all maps. Should be called at application start. */
|
||||||
public void load(){
|
public void load(){
|
||||||
|
Time.mark();
|
||||||
try{
|
try{
|
||||||
for (String name : defaultMapNames) {
|
for(String name : defaultMapNames){
|
||||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||||
loadMap(file.nameWithoutExtension(), file::read, false);
|
loadMap(file, false);
|
||||||
}
|
}
|
||||||
}catch (IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCustomMaps();
|
loadCustomMaps();
|
||||||
|
Log.info("Time to load maps: {0}", Time.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Save a map. This updates all values and stored data necessary.*/
|
/** Save a custom map to the directory. This updates all values and stored data necessary.
|
||||||
public void saveMap(String name, MapTileData data, ObjectMap<String, String> tags){
|
* The tags are copied to prevent mutation later.*/
|
||||||
|
public void saveMap(ObjectMap<String, String> baseTags, Tile[][] data){
|
||||||
|
|
||||||
try{
|
try{
|
||||||
//create copy of tags to prevent mutation later
|
ObjectMap<String, String> tags = new ObjectMap<>(baseTags);
|
||||||
ObjectMap<String, String> newTags = new ObjectMap<>();
|
String name = tags.get("name");
|
||||||
newTags.putAll(tags);
|
if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?");
|
||||||
tags = newTags;
|
|
||||||
|
|
||||||
FileHandle file = customMapDirectory.child(name + "." + mapExtension);
|
FileHandle file = customMapDirectory.child(name + "." + mapExtension);
|
||||||
MapIO.writeMap(file.write(false), tags, data);
|
|
||||||
|
|
||||||
if(maps.containsKey(name)){
|
//find map with the same exact display name
|
||||||
if(maps.get(name).texture != null) {
|
Map other = maps.find(m -> m.getDisplayName().equals(name));
|
||||||
maps.get(name).texture.dispose();
|
|
||||||
maps.get(name).texture = null;
|
if(other != null){
|
||||||
|
//dispose of map if it's already there
|
||||||
|
if(other.texture != null){
|
||||||
|
other.texture.dispose();
|
||||||
|
other.texture = null;
|
||||||
}
|
}
|
||||||
allMaps.removeValue(maps.get(name), true);
|
maps.remove(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = new Map(name, new MapMeta(version, tags, data.width(), data.height(), null), true, getStreamFor(name));
|
//create map, write it, etc etc etc
|
||||||
|
Map map = new Map(file, data.length, data[0].length, tags, true);
|
||||||
|
MapIO.writeMap(file, map, data);
|
||||||
|
|
||||||
if(!headless){
|
if(!headless){
|
||||||
map.texture = new Texture(MapIO.generatePixmap(data));
|
map.texture = new Texture(MapIO.generatePreview(data));
|
||||||
}
|
}
|
||||||
allMaps.add(map);
|
maps.add(map);
|
||||||
|
}catch(IOException e){
|
||||||
maps.put(name, map);
|
|
||||||
}catch (IOException e){
|
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Removes a map completely.*/
|
/** Import a map, then save it. This updates all values and stored data necessary. */
|
||||||
|
public void importMap(FileHandle file, Map map) throws IOException{
|
||||||
|
file.copyTo(customMapDirectory.child(file.name()));
|
||||||
|
if(!headless){
|
||||||
|
map.texture = new Texture(MapIO.generatePreview(map));
|
||||||
|
}
|
||||||
|
maps.add(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a map completely. */
|
||||||
public void removeMap(Map map){
|
public void removeMap(Map map){
|
||||||
if(map.texture != null){
|
if(map.texture != null){
|
||||||
map.texture.dispose();
|
map.texture.dispose();
|
||||||
map.texture = null;
|
map.texture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
maps.remove(map.name);
|
maps.remove(map);
|
||||||
allMaps.removeValue(map, true);
|
map.file.delete();
|
||||||
|
|
||||||
customMapDirectory.child(map.name + "." + mapExtension).delete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMap(String name, Supplier<InputStream> supplier, boolean custom) throws IOException{
|
private void loadMap(FileHandle file, boolean custom) throws IOException{
|
||||||
try(DataInputStream ds = new DataInputStream(supplier.get())) {
|
Map map = MapIO.readMap(file, custom);
|
||||||
MapMeta meta = MapIO.readMapMeta(ds);
|
|
||||||
Map map = new Map(name, meta, custom, supplier);
|
|
||||||
|
|
||||||
if (!headless){
|
if(!headless){
|
||||||
map.texture = new Texture(MapIO.generatePixmap(MapIO.readTileData(ds, meta, true)));
|
map.texture = new Texture(MapIO.generatePreview(map));
|
||||||
}
|
|
||||||
|
|
||||||
maps.put(map.name, map);
|
|
||||||
allMaps.add(map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maps.add(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCustomMaps(){
|
private void loadCustomMaps(){
|
||||||
for(FileHandle file : customMapDirectory.list()){
|
for(FileHandle file : customMapDirectory.list()){
|
||||||
try{
|
try{
|
||||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||||
loadMap(file.nameWithoutExtension(), file::read, true);
|
loadMap(file, true);
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
}catch(Exception e){
|
||||||
Log.err("Failed to load custom map file '{0}'!", file);
|
Log.err("Failed to load custom map file '{0}'!", file);
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns an input stream supplier for a given map name.*/
|
|
||||||
private Supplier<InputStream> getStreamFor(String name){
|
|
||||||
return customMapDirectory.child(name + "." + mapExtension)::read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose(){
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,6 @@ import io.anuke.arc.util.noise.Simplex;
|
|||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
|
||||||
|
|
||||||
public class BasicGenerator extends RandomGenerator{
|
public class BasicGenerator extends RandomGenerator{
|
||||||
private Array<Item> ores;
|
private Array<Item> ores;
|
||||||
@@ -31,13 +29,14 @@ public class BasicGenerator extends RandomGenerator{
|
|||||||
public void generate(int x, int y){
|
public void generate(int x, int y){
|
||||||
floor = Blocks.stone;
|
floor = Blocks.stone;
|
||||||
|
|
||||||
if(ores != null && ((Floor) floor).hasOres){
|
if(ores != null){
|
||||||
int offsetX = x - 4, offsetY = y + 23;
|
int offsetX = x - 4, offsetY = y + 23;
|
||||||
for(int i = ores.size - 1; i >= 0; i--){
|
for(int i = ores.size - 1; i >= 0; i--){
|
||||||
Item entry = ores.get(i);
|
Item entry = ores.get(i);
|
||||||
if(Math.abs(0.5f - sim.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), offsetX, offsetY)) > 0.23f &&
|
if(Math.abs(0.5f - sim.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), offsetX, offsetY)) > 0.23f &&
|
||||||
Math.abs(0.5f - sim2.octaveNoise2D(1, 1, 1f / (40 + i * 4), offsetX, offsetY)) > 0.32f){
|
Math.abs(0.5f - sim2.octaveNoise2D(1, 1, 1f / (40 + i * 4), offsetX, offsetY)) > 0.32f){
|
||||||
floor = OreBlock.get(floor, entry);
|
|
||||||
|
//floor = OreBlock.get(floor, entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,17 @@ import io.anuke.mindustry.content.Blocks;
|
|||||||
import io.anuke.mindustry.content.Items;
|
import io.anuke.mindustry.content.Items;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
|
||||||
import io.anuke.mindustry.type.ItemStack;
|
import io.anuke.mindustry.type.ItemStack;
|
||||||
import io.anuke.mindustry.type.Loadout;
|
import io.anuke.mindustry.type.Loadout;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
|
||||||
import io.anuke.mindustry.world.blocks.StaticWall;
|
import io.anuke.mindustry.world.blocks.StaticWall;
|
||||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||||
import io.anuke.mindustry.world.blocks.storage.StorageBlock;
|
import io.anuke.mindustry.world.blocks.storage.StorageBlock;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class MapGenerator extends Generator{
|
public class MapGenerator extends Generator{
|
||||||
@@ -73,112 +71,112 @@ public class MapGenerator extends Generator{
|
|||||||
public void init(Loadout loadout){
|
public void init(Loadout loadout){
|
||||||
this.loadout = loadout;
|
this.loadout = loadout;
|
||||||
map = world.maps.loadInternalMap(mapName);
|
map = world.maps.loadInternalMap(mapName);
|
||||||
width = map.meta.width;
|
width = map.width;
|
||||||
height = map.meta.height;
|
height = map.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(Tile[][] tiles){
|
public void generate(Tile[][] tiles){
|
||||||
MapTileData data = MapIO.readTileData(map, true);
|
try{
|
||||||
|
for(int x = 0; x < width; x++){
|
||||||
data.position(0, 0);
|
for(int y = 0; y < height; y++){
|
||||||
TileDataMarker marker = data.newDataMarker();
|
tiles[x][y] = new Tile(x, y);
|
||||||
Array<Point2> players = new Array<>();
|
|
||||||
Array<Point2> enemies = new Array<>();
|
|
||||||
|
|
||||||
for(int y = 0; y < data.height(); y++){
|
|
||||||
for(int x = 0; x < data.width(); x++){
|
|
||||||
data.read(marker);
|
|
||||||
|
|
||||||
if(content.block(marker.wall) instanceof CoreBlock){
|
|
||||||
players.add(new Point2(x, y));
|
|
||||||
marker.wall = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(enemySpawns != -1 && content.block(marker.wall) == Blocks.spawn){
|
|
||||||
enemies.add(new Point2(x, y));
|
|
||||||
marker.wall = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Simplex simplex = new Simplex(Mathf.random(99999));
|
MapIO.readTiles(map, tiles);
|
||||||
|
Array<Point2> players = new Array<>();
|
||||||
|
Array<Point2> enemies = new Array<>();
|
||||||
|
|
||||||
for(int x = 0; x < data.width(); x++){
|
for(int x = 0; x < width; x++){
|
||||||
for(int y = 0; y < data.height(); y++){
|
for(int y = 0; y < height; y++){
|
||||||
final double scl = 10;
|
if(tiles[x][y].block() instanceof CoreBlock){
|
||||||
Tile tile = tiles[x][y];
|
players.add(new Point2(x, y));
|
||||||
int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, data.width()-1);
|
tiles[x][y].setBlock(Blocks.air);
|
||||||
int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, data.height()-1);
|
}
|
||||||
|
|
||||||
if((tile.block() instanceof StaticWall
|
if(tiles[x][y].block() == Blocks.spawn){
|
||||||
|
enemies.add(new Point2(x, y));
|
||||||
|
tiles[x][y].setBlock(Blocks.air);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Simplex simplex = new Simplex(Mathf.random(99999));
|
||||||
|
|
||||||
|
for(int x = 0; x < width; x++){
|
||||||
|
for(int y = 0; y < height; y++){
|
||||||
|
final double scl = 10;
|
||||||
|
Tile tile = tiles[x][y];
|
||||||
|
int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, width - 1);
|
||||||
|
int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, height - 1);
|
||||||
|
|
||||||
|
if((tile.block() instanceof StaticWall
|
||||||
&& tiles[newX][newY].block() instanceof StaticWall)
|
&& tiles[newX][newY].block() instanceof StaticWall)
|
||||||
|| (tile.block() == Blocks.air && !tiles[newX][newY].block().synthetic())
|
|| (tile.block() == Blocks.air && !tiles[newX][newY].block().synthetic())
|
||||||
|| (tiles[newX][newY].block() == Blocks.air && tile.block() instanceof StaticWall)){
|
|| (tiles[newX][newY].block() == Blocks.air && tile.block() instanceof StaticWall)){
|
||||||
tile.setBlock(tiles[newX][newY].block());
|
tile.setBlock(tiles[newX][newY].block());
|
||||||
}
|
|
||||||
|
|
||||||
if(distortFloor){
|
|
||||||
tile.setFloor(tiles[newX][newY].floor());
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Decoration decor : decorations){
|
|
||||||
if(tile.block() == Blocks.air && !(decor.wall instanceof Floor) && tile.floor() == decor.floor && Mathf.chance(decor.chance)){
|
|
||||||
tile.setBlock(decor.wall);
|
|
||||||
}else if(tile.floor() == decor.floor && decor.wall instanceof Floor && Mathf.chance(decor.chance)){
|
|
||||||
tile.setFloor((Floor)decor.wall);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){
|
if(distortFloor){
|
||||||
for(ItemStack stack : storageDrops){
|
tile.setFloor(tiles[newX][newY].floor());
|
||||||
if(Mathf.chance(0.3)){
|
}
|
||||||
tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity));
|
|
||||||
|
for(Decoration decor : decorations){
|
||||||
|
if(tile.block() == Blocks.air && !(decor.wall instanceof Floor) && tile.floor() == decor.floor && Mathf.chance(decor.chance)){
|
||||||
|
tile.setBlock(decor.wall);
|
||||||
|
}else if(tile.floor() == decor.floor && decor.wall instanceof Floor && Mathf.chance(decor.chance)){
|
||||||
|
tile.setFloor((Floor)decor.wall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(enemySpawns != -1){
|
if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){
|
||||||
if(enemySpawns > enemies.size){
|
for(ItemStack stack : storageDrops){
|
||||||
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
|
if(Mathf.chance(0.3)){
|
||||||
}
|
tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity));
|
||||||
|
|
||||||
enemies.shuffle();
|
|
||||||
for(int i = 0; i < enemySpawns; i++){
|
|
||||||
Point2 point = enemies.get(i);
|
|
||||||
tiles[point.x][point.y].setBlock(Blocks.spawn);
|
|
||||||
|
|
||||||
int rad = 10, frad = 12;
|
|
||||||
|
|
||||||
for(int x = -rad; x <= rad; x++){
|
|
||||||
for(int y = -rad; y <= rad; y++){
|
|
||||||
int wx = x + point.x, wy = y + point.y;
|
|
||||||
double dst = Mathf.dst(x, y);
|
|
||||||
if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){
|
|
||||||
Tile tile = tiles[wx][wy];
|
|
||||||
if(tile.floor() instanceof OreBlock){
|
|
||||||
OreBlock block = (OreBlock)tile.floor();
|
|
||||||
tile.setFloor(block.base);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(enemySpawns != -1){
|
||||||
|
if(enemySpawns > enemies.size){
|
||||||
|
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
enemies.shuffle();
|
||||||
|
for(int i = 0; i < enemySpawns; i++){
|
||||||
|
Point2 point = enemies.get(i);
|
||||||
|
tiles[point.x][point.y].setBlock(Blocks.spawn);
|
||||||
|
|
||||||
|
int rad = 10, frad = 12;
|
||||||
|
|
||||||
|
for(int x = -rad; x <= rad; x++){
|
||||||
|
for(int y = -rad; y <= rad; y++){
|
||||||
|
int wx = x + point.x, wy = y + point.y;
|
||||||
|
double dst = Mathf.dst(x, y);
|
||||||
|
if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){
|
||||||
|
Tile tile = tiles[wx][wy];
|
||||||
|
tile.clearOre();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 core = players.random();
|
||||||
|
if(core == null){
|
||||||
|
throw new IllegalArgumentException("All zone maps must have a core.");
|
||||||
|
}
|
||||||
|
|
||||||
|
loadout.setup(core.x, core.y);
|
||||||
|
|
||||||
|
world.prepareTiles(tiles);
|
||||||
|
world.setMap(map);
|
||||||
|
}catch(IOException e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2 core = players.random();
|
|
||||||
if(core == null){
|
|
||||||
throw new IllegalArgumentException("All zone maps must have a core.");
|
|
||||||
}
|
|
||||||
|
|
||||||
loadout.setup(core.x, core.y);
|
|
||||||
|
|
||||||
world.prepareTiles(tiles);
|
|
||||||
world.setMap(map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Decoration{
|
public static class Decoration{
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ public class NetworkIO{
|
|||||||
try(DataOutputStream stream = new DataOutputStream(os)){
|
try(DataOutputStream stream = new DataOutputStream(os)){
|
||||||
//--GENERAL STATE--
|
//--GENERAL STATE--
|
||||||
Serialization.writeRules(stream, state.rules);
|
Serialization.writeRules(stream, state.rules);
|
||||||
stream.writeUTF(world.getMap().name); //map name
|
stream.writeUTF(world.getMap().name()); //map name
|
||||||
|
|
||||||
//write tags
|
//write tags
|
||||||
ObjectMap<String, String> tags = world.getMap().meta.tags;
|
ObjectMap<String, String> tags = world.getMap().tags;
|
||||||
stream.writeByte(tags.size);
|
stream.writeByte(tags.size);
|
||||||
for(Entry<String, String> entry : tags.entries()){
|
for(Entry<String, String> entry : tags.entries()){
|
||||||
stream.writeUTF(entry.key);
|
stream.writeUTF(entry.key);
|
||||||
@@ -105,7 +105,7 @@ public class NetworkIO{
|
|||||||
//map
|
//map
|
||||||
world.spawner.read(stream);
|
world.spawner.read(stream);
|
||||||
SaveIO.getSaveWriter().readMap(stream);
|
SaveIO.getSaveWriter().readMap(stream);
|
||||||
world.setMap(new Map(map, 0, 0));
|
world.setMap(new Map(customMapDirectory.child(map), 0, 0, new ObjectMap<>(), true));
|
||||||
|
|
||||||
state.teams = new Teams();
|
state.teams = new Teams();
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ public class NetworkIO{
|
|||||||
int maxlen = 32;
|
int maxlen = 32;
|
||||||
|
|
||||||
String host = (headless ? "Server" : players[0].name);
|
String host = (headless ? "Server" : players[0].name);
|
||||||
String map = world.getMap() == null ? "None" : world.getMap().name;
|
String map = world.getMap() == null ? "None" : world.getMap().name();
|
||||||
|
|
||||||
host = host.substring(0, Math.min(host.length(), maxlen));
|
host = host.substring(0, Math.min(host.length(), maxlen));
|
||||||
map = map.substring(0, Math.min(map.length(), maxlen));
|
map = map.substring(0, Math.min(map.length(), maxlen));
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import io.anuke.arc.collection.Array;
|
|||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.scene.ui.layout.Table;
|
import io.anuke.arc.scene.ui.layout.Table;
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.game.UnlockableContent;
|
import io.anuke.mindustry.game.UnlockableContent;
|
||||||
import io.anuke.mindustry.ui.ContentDisplay;
|
import io.anuke.mindustry.ui.ContentDisplay;
|
||||||
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.content;
|
||||||
|
|
||||||
public class Item extends UnlockableContent implements Comparable<Item>{
|
public class Item extends UnlockableContent implements Comparable<Item>{
|
||||||
public final Color color;
|
public final Color color;
|
||||||
@@ -28,8 +31,6 @@ public class Item extends UnlockableContent implements Comparable<Item>{
|
|||||||
* 1 cost = 1 tick added to build time
|
* 1 cost = 1 tick added to build time
|
||||||
*/
|
*/
|
||||||
public float cost = 3f;
|
public float cost = 3f;
|
||||||
/**Whether this item has ores generated for it.*/
|
|
||||||
public boolean genOre = false;
|
|
||||||
/**If true, item is always unlocked.*/
|
/**If true, item is always unlocked.*/
|
||||||
public boolean alwaysUnlocked = false;
|
public boolean alwaysUnlocked = false;
|
||||||
|
|
||||||
@@ -101,6 +102,6 @@ public class Item extends UnlockableContent implements Comparable<Item>{
|
|||||||
|
|
||||||
/**Allocates a new array containing all items the generate ores.*/
|
/**Allocates a new array containing all items the generate ores.*/
|
||||||
public static Array<Item> getAllOres(){
|
public static Array<Item> getAllOres(){
|
||||||
return Vars.content.items().select(i -> i.genOre);
|
return content.blocks().select(b -> b instanceof OreBlock).map(b -> ((Floor)b).itemDrop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,10 @@ package io.anuke.mindustry.type;
|
|||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.IntMap;
|
import io.anuke.arc.collection.IntMap;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.content.Items;
|
|
||||||
import io.anuke.mindustry.game.Content;
|
import io.anuke.mindustry.game.Content;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Pos;
|
import io.anuke.mindustry.world.Pos;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
|
||||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.defaultTeam;
|
import static io.anuke.mindustry.Vars.defaultTeam;
|
||||||
@@ -27,7 +24,7 @@ public class Loadout extends Content{
|
|||||||
put('2', new BlockEntry(Blocks.coreFoundation));
|
put('2', new BlockEntry(Blocks.coreFoundation));
|
||||||
put('3', new BlockEntry(Blocks.coreNucleus));
|
put('3', new BlockEntry(Blocks.coreNucleus));
|
||||||
|
|
||||||
put('C', new BlockEntry(Blocks.mechanicalDrill, Items.copper));
|
put('C', new BlockEntry(Blocks.mechanicalDrill, Blocks.oreCopper));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private final IntMap<BlockEntry> blocks = new IntMap<>();
|
private final IntMap<BlockEntry> blocks = new IntMap<>();
|
||||||
@@ -79,8 +76,7 @@ public class Loadout extends Content{
|
|||||||
tile.setRotation((byte)entry.value.rotation);
|
tile.setRotation((byte)entry.value.rotation);
|
||||||
if(entry.value.ore != null){
|
if(entry.value.ore != null){
|
||||||
for(Tile t : tile.getLinkedTiles(outArray)){
|
for(Tile t : tile.getLinkedTiles(outArray)){
|
||||||
Floor floor = t.floor();
|
t.setOre(entry.value.ore);
|
||||||
t.setFloor(OreBlock.get(floor, entry.value.ore) == null ? OreBlock.get(Blocks.stone, entry.value.ore) : OreBlock.get(floor, entry.value.ore));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,10 +89,10 @@ public class Loadout extends Content{
|
|||||||
|
|
||||||
static class BlockEntry{
|
static class BlockEntry{
|
||||||
final Block block;
|
final Block block;
|
||||||
final Item ore;
|
final Block ore;
|
||||||
final int rotation;
|
final int rotation;
|
||||||
|
|
||||||
BlockEntry(Block block, Item ore){
|
BlockEntry(Block block, Block ore){
|
||||||
this.block = block;
|
this.block = block;
|
||||||
this.ore = ore;
|
this.ore = ore;
|
||||||
this.rotation = 0;
|
this.rotation = 0;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class CustomGameDialog extends FloatingDialog{
|
|||||||
image.row();
|
image.row();
|
||||||
image.add("[accent]" + map.getDisplayName()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
|
image.add("[accent]" + map.getDisplayName()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
|
||||||
image.row();
|
image.row();
|
||||||
image.label((() -> Core.bundle.format("level.highscore", Core.settings.getInt("hiscore" + map.name, 0)))).pad(3f);
|
image.label((() -> Core.bundle.format("level.highscore", Core.settings.getInt("hiscore" + map.fileName(), 0)))).pad(3f);
|
||||||
|
|
||||||
BorderImage border = new BorderImage(map.texture, 3f);
|
BorderImage border = new BorderImage(map.texture, 3f);
|
||||||
border.setScaling(Scaling.fit);
|
border.setScaling(Scaling.fit);
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class LoadDialog extends FloatingDialog{
|
|||||||
|
|
||||||
button.defaults().padBottom(3);
|
button.defaults().padBottom(3);
|
||||||
button.row();
|
button.row();
|
||||||
button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().meta.name())));
|
button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().getDisplayName())));
|
||||||
button.row();
|
button.row();
|
||||||
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
|
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
|
||||||
button.row();
|
button.row();
|
||||||
|
|||||||
@@ -15,12 +15,8 @@ import io.anuke.mindustry.Vars;
|
|||||||
import io.anuke.mindustry.core.Platform;
|
import io.anuke.mindustry.core.Platform;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.MapMeta;
|
|
||||||
import io.anuke.mindustry.maps.MapTileData;
|
|
||||||
import io.anuke.mindustry.ui.BorderImage;
|
import io.anuke.mindustry.ui.BorderImage;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class MapsDialog extends FloatingDialog{
|
public class MapsDialog extends FloatingDialog{
|
||||||
@@ -33,22 +29,25 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
|
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
|
||||||
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
||||||
try{
|
try{
|
||||||
DataInputStream stream = new DataInputStream(file.read());
|
Map map = MapIO.readMap(file, true);
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
String name = map.tags.get("name", file.nameWithoutExtension());
|
||||||
MapTileData data = MapIO.readTileData(stream, meta, true);
|
|
||||||
stream.close();
|
|
||||||
|
|
||||||
String name = meta.tags.get("name", file.nameWithoutExtension());
|
Map conflict = world.maps.all().find(m -> m.fileName().equals(file.nameWithoutExtension()) || m.name().equals(file.name()));
|
||||||
|
|
||||||
if(world.maps.getByName(name) != null && !world.maps.getByName(name).custom){
|
if(conflict != null && !conflict.custom){
|
||||||
ui.showError(Core.bundle.format("editor.import.exists", name));
|
ui.showError(Core.bundle.format("editor.import.exists", name));
|
||||||
}else if(world.maps.getByName(name) != null){
|
}else if(conflict != null){
|
||||||
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||||
world.maps.saveMap(name, data, meta.tags);
|
try{
|
||||||
setup();
|
world.maps.importMap(file, map);
|
||||||
|
setup();
|
||||||
|
}catch(Exception e){
|
||||||
|
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
world.maps.saveMap(name, data, meta.tags);
|
world.maps.importMap(file, map);
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
||||||
button.clearChildren();
|
button.clearChildren();
|
||||||
button.margin(9);
|
button.margin(9);
|
||||||
button.add(map.meta.tags.get("name", map.name)).width(mapsize - 18f).center().get().setEllipsis(true);
|
button.add(map.getDisplayName()).width(mapsize - 18f).center().get().setEllipsis(true);
|
||||||
button.row();
|
button.row();
|
||||||
button.addImage("white").growX().pad(4).color(Color.GRAY);
|
button.addImage("white").growX().pad(4).color(Color.GRAY);
|
||||||
button.row();
|
button.row();
|
||||||
@@ -129,15 +128,15 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
|
|
||||||
t.add("$editor.name").padRight(10).color(Color.GRAY).padTop(0);
|
t.add("$editor.name").padRight(10).color(Color.GRAY).padTop(0);
|
||||||
t.row();
|
t.row();
|
||||||
t.add(map.meta.tags.get("name", map.name)).growX().wrap().padTop(2);
|
t.add(map.getDisplayName()).growX().wrap().padTop(2);
|
||||||
t.row();
|
t.row();
|
||||||
t.add("$editor.author").padRight(10).color(Color.GRAY);
|
t.add("$editor.author").padRight(10).color(Color.GRAY);
|
||||||
t.row();
|
t.row();
|
||||||
t.add(map.meta.author()).growX().wrap().padTop(2);
|
t.add(map.author()).growX().wrap().padTop(2);
|
||||||
t.row();
|
t.row();
|
||||||
t.add("$editor.description").padRight(10).color(Color.GRAY).top();
|
t.add("$editor.description").padRight(10).color(Color.GRAY).top();
|
||||||
t.row();
|
t.row();
|
||||||
t.add(map.meta.description()).growX().wrap().padTop(2);
|
t.add(map.description()).growX().wrap().padTop(2);
|
||||||
t.row();
|
t.row();
|
||||||
t.add("$editor.oregen.info").padRight(10).color(Color.GRAY);
|
t.add("$editor.oregen.info").padRight(10).color(Color.GRAY);
|
||||||
}).height(mapsize).width(mapsize);
|
}).height(mapsize).width(mapsize);
|
||||||
@@ -146,7 +145,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
|
|
||||||
table.addImageTextButton("$editor.openin", "icon-load-map", 16 * 2, () -> {
|
table.addImageTextButton("$editor.openin", "icon-load-map", 16 * 2, () -> {
|
||||||
try{
|
try{
|
||||||
Vars.ui.editor.beginEditMap(map.stream.get());
|
Vars.ui.editor.beginEditMap(map.file);
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
hide();
|
hide();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -156,7 +155,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
}).fillX().height(54f).marginLeft(10);
|
}).fillX().height(54f).marginLeft(10);
|
||||||
|
|
||||||
table.addImageTextButton("$delete", "icon-trash-16", 16 * 2, () -> {
|
table.addImageTextButton("$delete", "icon-trash-16", 16 * 2, () -> {
|
||||||
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name), () -> {
|
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
|
||||||
world.maps.removeMap(map);
|
world.maps.removeMap(map);
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
setup();
|
setup();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import io.anuke.arc.scene.ui.ButtonGroup;
|
|||||||
import io.anuke.arc.scene.ui.Image;
|
import io.anuke.arc.scene.ui.Image;
|
||||||
import io.anuke.arc.scene.ui.ImageButton;
|
import io.anuke.arc.scene.ui.ImageButton;
|
||||||
import io.anuke.arc.scene.ui.layout.Table;
|
import io.anuke.arc.scene.ui.layout.Table;
|
||||||
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.type.TileEntity;
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
import io.anuke.mindustry.game.EventType.UnlockEvent;
|
import io.anuke.mindustry.game.EventType.UnlockEvent;
|
||||||
@@ -26,7 +27,6 @@ import io.anuke.mindustry.type.ItemStack;
|
|||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Block.Icon;
|
import io.anuke.mindustry.world.Block.Icon;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -340,6 +340,6 @@ public class PlacementFragment extends Fragment{
|
|||||||
|
|
||||||
/** Returns the block currently being hovered over in the world. */
|
/** Returns the block currently being hovered over in the world. */
|
||||||
Block tileDisplayBlock(){
|
Block tileDisplayBlock(){
|
||||||
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.floor() instanceof OreBlock ? hoverTile.floor() : null;
|
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.oreBlock() != Blocks.air ? hoverTile.oreBlock() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
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
|
||||||
|
public Team getTeam(){
|
||||||
|
return Team.all[getTeamID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,8 @@ package io.anuke.mindustry.world;
|
|||||||
import io.anuke.arc.collection.IntMap;
|
import io.anuke.arc.collection.IntMap;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.content.Items;
|
|
||||||
import io.anuke.mindustry.game.ContentList;
|
import io.anuke.mindustry.game.ContentList;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
|
||||||
|
|
||||||
public class LegacyColorMapper implements ContentList{
|
public class LegacyColorMapper implements ContentList{
|
||||||
private static IntMap<LegacyBlock> blockMap = new IntMap<>();
|
private static IntMap<LegacyBlock> blockMap = new IntMap<>();
|
||||||
@@ -38,10 +36,14 @@ public class LegacyColorMapper implements ContentList{
|
|||||||
map("6e501e", Blocks.stainedStoneRed);
|
map("6e501e", Blocks.stainedStoneRed);
|
||||||
map("ed5334", Blocks.stainedStoneRed);
|
map("ed5334", Blocks.stainedStoneRed);
|
||||||
map("292929", Blocks.tar);
|
map("292929", Blocks.tar);
|
||||||
map("c3a490", OreBlock.get(Blocks.stone, Items.copper));
|
map("c3a490", Blocks.stone, Blocks.air, Blocks.oreCopper);
|
||||||
map("161616", OreBlock.get(Blocks.stone, Items.coal));
|
map("161616", Blocks.stone, Blocks.air, Blocks.oreCoal);
|
||||||
map("6277bc", OreBlock.get(Blocks.stone, Items.titanium));
|
map("6277bc", Blocks.stone, Blocks.air, Blocks.oreTitanium);
|
||||||
map("83bc58", OreBlock.get(Blocks.stone, Items.thorium));
|
map("83bc58", Blocks.stone, Blocks.air, Blocks.oreThorium);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void map(String color, Block block, Block wall, Block ore){
|
||||||
|
blockMap.put(Color.rgba8888(Color.valueOf(color)), new LegacyBlock(block, wall, ore));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void map(String color, Block block, Block wall){
|
private void map(String color, Block block, Block wall){
|
||||||
@@ -55,10 +57,18 @@ public class LegacyColorMapper implements ContentList{
|
|||||||
public static class LegacyBlock{
|
public static class LegacyBlock{
|
||||||
public final Floor floor;
|
public final Floor floor;
|
||||||
public final Block wall;
|
public final Block wall;
|
||||||
|
public final Block ore;
|
||||||
|
|
||||||
public LegacyBlock(Block floor, Block wall){
|
public LegacyBlock(Block floor, Block wall){
|
||||||
this.floor = (Floor) floor;
|
this.floor = (Floor) floor;
|
||||||
this.wall = wall;
|
this.wall = wall;
|
||||||
|
this.ore = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LegacyBlock(Block floor, Block wall, Block ore){
|
||||||
|
this.floor = (Floor) floor;
|
||||||
|
this.wall = wall;
|
||||||
|
this.ore = ore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import io.anuke.arc.math.geom.Position;
|
|||||||
import io.anuke.arc.math.geom.Vector2;
|
import io.anuke.arc.math.geom.Vector2;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.entities.type.TileEntity;
|
|
||||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||||
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
import io.anuke.mindustry.world.modules.ConsumeModule;
|
import io.anuke.mindustry.world.modules.ConsumeModule;
|
||||||
@@ -39,10 +40,13 @@ public class Tile implements Position, TargetTrait{
|
|||||||
private byte rotation;
|
private byte rotation;
|
||||||
/** Team ordinal. */
|
/** Team ordinal. */
|
||||||
private byte team;
|
private byte team;
|
||||||
|
/**Ore that is on top of this (floor) block.*/
|
||||||
|
private byte ore = 0;
|
||||||
|
|
||||||
public Tile(int x, int y){
|
public Tile(int x, int y){
|
||||||
this.x = (short) x;
|
this.x = (short) x;
|
||||||
this.y = (short) y;
|
this.y = (short) y;
|
||||||
|
wall = floor = (Floor)Blocks.air;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tile(int x, int y, byte floor, byte wall){
|
public Tile(int x, int y, byte floor, byte wall){
|
||||||
@@ -159,6 +163,7 @@ public class Tile implements Position, TargetTrait{
|
|||||||
|
|
||||||
public void setFloor(Floor type){
|
public void setFloor(Floor type){
|
||||||
this.floor = type;
|
this.floor = type;
|
||||||
|
this.ore = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getRotation(){
|
public byte getRotation(){
|
||||||
@@ -213,6 +218,14 @@ public class Tile implements Position, TargetTrait{
|
|||||||
return link != 0;
|
return link != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getLinkByte(){
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkByte(byte b){
|
||||||
|
this.link = b;
|
||||||
|
}
|
||||||
|
|
||||||
/** Sets this to a linked tile, which sets the block to a part. dx and dy can only be -8-7. */
|
/** Sets this to a linked tile, which sets the block to a part. dx and dy can only be -8-7. */
|
||||||
public void setLinked(byte dx, byte dy){
|
public void setLinked(byte dx, byte dy){
|
||||||
setBlock(Blocks.part);
|
setBlock(Blocks.part);
|
||||||
@@ -316,6 +329,30 @@ public class Tile implements Position, TargetTrait{
|
|||||||
return getTeam() == Team.none || team == getTeam();
|
return getTeam() == Team.none || team == getTeam();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getOreByte(){
|
||||||
|
return ore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOreByte(byte ore){
|
||||||
|
this.ore = ore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOre(Block floor){
|
||||||
|
setOreByte(floor.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearOre(){
|
||||||
|
this.ore = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Floor oreBlock(){
|
||||||
|
return (Floor)content.block(ore);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item drop(){
|
||||||
|
return ore == 0 ? floor.itemDrop : ((Floor)content.block(ore)).itemDrop;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateOcclusion(){
|
public void updateOcclusion(){
|
||||||
cost = 1;
|
cost = 1;
|
||||||
boolean occluded = false;
|
boolean occluded = false;
|
||||||
@@ -343,7 +380,7 @@ public class Tile implements Position, TargetTrait{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preChanged(){
|
protected void preChanged(){
|
||||||
block().removed(this);
|
block().removed(this);
|
||||||
if(entity != null){
|
if(entity != null){
|
||||||
entity.removeFromProximity();
|
entity.removeFromProximity();
|
||||||
@@ -351,7 +388,7 @@ public class Tile implements Position, TargetTrait{
|
|||||||
team = 0;
|
team = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changed(){
|
protected void changed(){
|
||||||
if(entity != null){
|
if(entity != null){
|
||||||
entity.remove();
|
entity.remove();
|
||||||
entity = null;
|
entity = null;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.anuke.arc.graphics.g2d.TextureRegion;
|
|||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.math.geom.Geometry;
|
import io.anuke.arc.math.geom.Geometry;
|
||||||
import io.anuke.arc.math.geom.Point2;
|
import io.anuke.arc.math.geom.Point2;
|
||||||
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.content.Fx;
|
import io.anuke.mindustry.content.Fx;
|
||||||
import io.anuke.mindustry.content.StatusEffects;
|
import io.anuke.mindustry.content.StatusEffects;
|
||||||
import io.anuke.mindustry.entities.Effects.Effect;
|
import io.anuke.mindustry.entities.Effects.Effect;
|
||||||
@@ -45,8 +46,6 @@ public class Floor extends Block{
|
|||||||
public Liquid liquidDrop = null;
|
public Liquid liquidDrop = null;
|
||||||
/** item that drops from this block, used for drills */
|
/** item that drops from this block, used for drills */
|
||||||
public Item itemDrop = null;
|
public Item itemDrop = null;
|
||||||
/** Whether ores generate on this block. */
|
|
||||||
public boolean hasOres = false;
|
|
||||||
/** whether this block can be drowned in */
|
/** whether this block can be drowned in */
|
||||||
public boolean isLiquid;
|
public boolean isLiquid;
|
||||||
/** Heat of this block, 0 at baseline. Used for calculating output of thermal generators.*/
|
/** Heat of this block, 0 at baseline. Used for calculating output of thermal generators.*/
|
||||||
@@ -110,6 +109,10 @@ public class Floor extends Block{
|
|||||||
Mathf.random.setSeed(tile.pos());
|
Mathf.random.setSeed(tile.pos());
|
||||||
|
|
||||||
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
||||||
|
Floor floor = tile.oreBlock();
|
||||||
|
if(floor != Blocks.air){
|
||||||
|
floor.draw(tile);
|
||||||
|
}
|
||||||
|
|
||||||
drawEdges(tile);
|
drawEdges(tile);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,18 @@
|
|||||||
package io.anuke.mindustry.world.blocks;
|
package io.anuke.mindustry.world.blocks;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
import io.anuke.arc.graphics.g2d.Draw;
|
import io.anuke.arc.graphics.g2d.Draw;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.Block;
|
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
public class OreBlock extends Floor{
|
public class OreBlock extends Floor{
|
||||||
private static final ObjectMap<Item, ObjectMap<Block, Floor>> oreBlockMap = new ObjectMap<>();
|
|
||||||
|
|
||||||
public Floor base;
|
public OreBlock(Item ore){
|
||||||
|
super("ore-" + ore.name);
|
||||||
public OreBlock(Item ore, Floor base){
|
this.localizedName = ore.localizedName();
|
||||||
super("ore-" + ore.name + "-" + base.name);
|
|
||||||
this.localizedName = ore.localizedName() + " " + base.localizedName;
|
|
||||||
this.itemDrop = ore;
|
this.itemDrop = ore;
|
||||||
this.base = base;
|
|
||||||
this.variants = 3;
|
this.variants = 3;
|
||||||
this.edge = base.name;
|
|
||||||
this.blendGroup = base.blendGroup;
|
|
||||||
this.color.set(ore.color);
|
this.color.set(ore.color);
|
||||||
|
|
||||||
oreBlockMap.getOr(ore, ObjectMap::new).put(base, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -38,22 +28,5 @@ public class OreBlock extends Floor{
|
|||||||
@Override
|
@Override
|
||||||
public void draw(Tile tile){
|
public void draw(Tile tile){
|
||||||
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
||||||
|
|
||||||
drawEdges(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doEdge(Floor floor, boolean f){
|
|
||||||
return floor != base && super.doEdge(floor, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean edgeOnto(Floor other){
|
|
||||||
return other != base;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Floor get(Block floor, Item item){
|
|
||||||
if(!oreBlockMap.containsKey(item) || !oreBlockMap.get(item).containsKey(floor)) return null;
|
|
||||||
return oreBlockMap.get(item).get(floor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import io.anuke.mindustry.entities.type.TileEntity;
|
|||||||
import io.anuke.mindustry.graphics.Layer;
|
import io.anuke.mindustry.graphics.Layer;
|
||||||
import io.anuke.mindustry.graphics.Pal;
|
import io.anuke.mindustry.graphics.Pal;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
|
import io.anuke.mindustry.type.ItemType;
|
||||||
import io.anuke.mindustry.ui.Bar;
|
import io.anuke.mindustry.ui.Bar;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
@@ -182,7 +183,7 @@ public class Drill extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
itemArray.sort((item1, item2) -> Integer.compare(oreCount.get(item1, 0), oreCount.get(item2, 0)));
|
itemArray.sort((item1, item2) -> Integer.compare(oreCount.get(item1, 0), oreCount.get(item2, 0)));
|
||||||
itemArray.sort((item1, item2) -> item1.genOre && !item2.genOre ? 1 : item1.genOre == item2.genOre ? 0 : -1);
|
itemArray.sort((item1, item2) -> Boolean.compare(item1.type == ItemType.material, item2.type == ItemType.material));
|
||||||
|
|
||||||
if(itemArray.size == 0){
|
if(itemArray.size == 0){
|
||||||
return;
|
return;
|
||||||
@@ -259,12 +260,12 @@ public class Drill extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Item getDrop(Tile tile){
|
public Item getDrop(Tile tile){
|
||||||
return tile.floor().itemDrop;
|
return tile.drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid(Tile tile){
|
public boolean isValid(Tile tile){
|
||||||
if(tile == null) return false;
|
if(tile == null) return false;
|
||||||
Item drops = tile.floor().itemDrop;
|
Item drops = tile.drop();
|
||||||
return drops != null && drops.hardness <= tier;
|
return drops != null && drops.hardness <= tier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ public class DesktopPlatform extends Platform{
|
|||||||
if(world.getMap() == null){
|
if(world.getMap() == null){
|
||||||
presence.details = "Unknown Map";
|
presence.details = "Unknown Map";
|
||||||
}else if(!state.rules.waves){
|
}else if(!state.rules.waves){
|
||||||
presence.details = Strings.capitalize(world.getMap().name);
|
presence.details = Strings.capitalize(world.getMap().getDisplayName());
|
||||||
}else{
|
}else{
|
||||||
presence.details = Strings.capitalize(world.getMap().name) + " | Wave " + state.wave;
|
presence.details = Strings.capitalize(world.getMap().getDisplayName()) + " | Wave " + state.wave;
|
||||||
presence.largeImageText = "Wave " + state.wave;
|
presence.largeImageText = "Wave " + state.wave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class IOSLauncher extends IOSApplication.Delegate {
|
|||||||
ui.editor.show();
|
ui.editor.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.editor.beginEditMap(file.read());
|
ui.editor.beginEditMap(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
private FileHandle currentLogFile;
|
private FileHandle currentLogFile;
|
||||||
private boolean inExtraRound;
|
private boolean inExtraRound;
|
||||||
private Task lastTask;
|
private Task lastTask;
|
||||||
private RulePreset lastPreset;
|
|
||||||
|
|
||||||
public ServerControl(String[] args){
|
public ServerControl(String[] args){
|
||||||
Core.settings.defaults(
|
Core.settings.defaults(
|
||||||
@@ -144,11 +143,11 @@ public class ServerControl implements ApplicationListener{
|
|||||||
|
|
||||||
Call.onInfoMessage((state.rules.pvp
|
Call.onInfoMessage((state.rules.pvp
|
||||||
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
|
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
|
||||||
+ "\nNext selected map:[accent] "+map.name+"[]"
|
+ "\nNext selected map:[accent] "+map.name()+"[]"
|
||||||
+ (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+
|
+ (map.author() != null ? " by[accent] " + map.author() + "[]" : "") + "."+
|
||||||
"\nNew game begins in " + roundExtraTime + " seconds.");
|
"\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;
|
Map fmap = map;
|
||||||
|
|
||||||
@@ -199,7 +198,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
|
|
||||||
if(lastTask != null) lastTask.cancel();
|
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){
|
if(result == null){
|
||||||
err("No map with name &y'{0}'&lr found.", arg[0]);
|
err("No map with name &y'{0}'&lr found.", arg[0]);
|
||||||
@@ -252,7 +251,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
if(!world.maps.all().isEmpty()){
|
if(!world.maps.all().isEmpty()){
|
||||||
info("Maps:");
|
info("Maps:");
|
||||||
for(Map map : world.maps.all()){
|
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{
|
}else{
|
||||||
info("No maps found.");
|
info("No maps found.");
|
||||||
@@ -265,7 +264,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
info("Status: &rserver closed");
|
info("Status: &rserver closed");
|
||||||
}else{
|
}else{
|
||||||
info("Status:");
|
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){
|
if(state.rules.waves){
|
||||||
info("&ly {0} enemies.", unitGroups[Team.red.ordinal()].size());
|
info("&ly {0} enemies.", unitGroups[Team.red.ordinal()].size());
|
||||||
|
|||||||
@@ -194,8 +194,8 @@ public class ApplicationTests{
|
|||||||
resetWorld();
|
resetWorld();
|
||||||
SaveIO.loadFromSlot(0);
|
SaveIO.loadFromSlot(0);
|
||||||
|
|
||||||
assertEquals(world.width(), map.meta.width);
|
assertEquals(world.width(), map.width);
|
||||||
assertEquals(world.height(), map.meta.height);
|
assertEquals(world.height(), map.height);
|
||||||
assertTrue(state.teams.get(defaultTeam).cores.size > 0);
|
assertTrue(state.teams.get(defaultTeam).cores.size > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
|
||||||
|
public class MapTests{
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void launchApplication(){
|
||||||
|
ApplicationTests.launchApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
@@ -88,6 +88,7 @@ def antialias = {File file ->
|
|||||||
|
|
||||||
ImageIO.write(out, "png", file)
|
ImageIO.write(out, "png", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
task swapColors(){
|
task swapColors(){
|
||||||
doLast{
|
doLast{
|
||||||
if (project.hasProperty("colors")) {
|
if (project.hasProperty("colors")) {
|
||||||
|
|||||||
@@ -206,11 +206,10 @@ public class Generators {
|
|||||||
|
|
||||||
OreBlock ore = (OreBlock)block;
|
OreBlock ore = (OreBlock)block;
|
||||||
Item item = ore.itemDrop;
|
Item item = ore.itemDrop;
|
||||||
Block base = ore.base;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
//get base image to draw on
|
//get base image to draw on
|
||||||
Image image = ImagePacker.get(base.name + (i+1));
|
Image image = new Image(32, 32);
|
||||||
Image shadow = ImagePacker.get(item.name + (i+1));
|
Image shadow = ImagePacker.get(item.name + (i+1));
|
||||||
|
|
||||||
int offset = image.width()/tilesize;
|
int offset = image.width()/tilesize;
|
||||||
@@ -228,8 +227,8 @@ public class Generators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
image.draw(ImagePacker.get(item.name + (i+1)));
|
image.draw(ImagePacker.get(item.name + (i+1)));
|
||||||
image.save("../blocks/environment/ore-" + item.name + "-" + base.name + (i+1));
|
image.save("../blocks/environment/ore-" + item.name + (i+1));
|
||||||
image.save("../editor/editor-ore-" + item.name + "-" + base.name + (i+1));
|
image.save("../editor/editor-ore-" + item.name + (i+1));
|
||||||
|
|
||||||
//save icons
|
//save icons
|
||||||
image.save(block.name + "-icon-full");
|
image.save(block.name + "-icon-full");
|
||||||
|
|||||||