diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 1155215b4d..1b1e986783 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -274,6 +274,8 @@ filter.option.wall = Wall filter.option.ore = Ore filter.option.floor2 = Secondary Floor filter.option.threshold2 = Secondary Threshold +filter.option.radius = Radius +filter.option.percentile = Percentile width = Width: height = Height: menu = Menu diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 8361e8bd7d..2cabb24a56 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -233,7 +233,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ hide(); //only reset the player; logic.reset() will clear entities, which we do not want player.reset(); - state.rules = Gamemode.editor.apply(new Rules()); + state.rules = Gamemode.editor.apply(lastSavedRules.copy()); world.setMap(new Map(StringMap.of( "name", "Editor Playtesting", "width", editor.width(), diff --git a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java index 02d5453b22..4a26bff475 100644 --- a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java @@ -27,21 +27,22 @@ import static io.anuke.mindustry.Vars.*; @SuppressWarnings("unchecked") public class MapGenerateDialog extends FloatingDialog{ + private final Supplier[] filterTypes = new Supplier[]{NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new, MedianFilter::new}; private final MapEditor editor; + private Pixmap pixmap; private Texture texture; private GenerateInput input = new GenerateInput(); private Array filters = new Array<>(); private int scaling = mobile ? 3 : 1; - private Supplier[] filterTypes = new Supplier[]{NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new}; private Table filterTable; private AsyncExecutor executor = new AsyncExecutor(1); private AsyncResult result; private boolean generating; - private DummyTile returnTile = new DummyTile(); + private GenTile returnTile = new GenTile(); - private DummyTile[][] buffer1, buffer2; + private GenTile[][] buffer1, buffer2; public MapGenerateDialog(MapEditor editor){ super("$editor.generate"); @@ -98,12 +99,12 @@ public class MapGenerateDialog extends FloatingDialog{ rebuildFilters(); } - DummyTile[][] create(){ - DummyTile[][] out = new DummyTile[editor.width() / scaling][editor.height() / scaling]; + GenTile[][] create(){ + GenTile[][] out = new GenTile[editor.width() / scaling][editor.height() / scaling]; for(int x = 0; x < out.length; x++){ for(int y = 0; y < out[0].length; y++){ - out[x][y] = new DummyTile(); + out[x][y] = new GenTile(); } } return out; @@ -187,7 +188,7 @@ public class MapGenerateDialog extends FloatingDialog{ selection.show(); } - DummyTile dset(Tile tile){ + GenTile dset(Tile tile){ returnTile.set(tile); return returnTile; } @@ -208,11 +209,11 @@ public class MapGenerateDialog extends FloatingDialog{ } //writeback buffer - DummyTile[][] writeTiles = new DummyTile[editor.width()][editor.height()]; + GenTile[][] writeTiles = new GenTile[editor.width()][editor.height()]; for(int x = 0; x < editor.width(); x++){ for(int y = 0; y < editor.height(); y++){ - writeTiles[x][y] = new DummyTile(); + writeTiles[x][y] = new GenTile(); } } @@ -233,7 +234,7 @@ public class MapGenerateDialog extends FloatingDialog{ for(int x = 0; x < editor.width(); x++){ for(int y = 0; y < editor.height(); y++){ Tile tile = editor.tile(x, y); - DummyTile write = writeTiles[x][y]; + GenTile write = writeTiles[x][y]; tile.rotation(write.rotation); tile.setFloor((Floor)content.block(write.floor)); @@ -278,7 +279,7 @@ public class MapGenerateDialog extends FloatingDialog{ for(int px = 0; px < pixmap.getWidth(); px++){ for(int py = 0; py < pixmap.getHeight(); py++){ int x = px * scaling, y = py * scaling; - DummyTile tile = buffer1[px][py]; + GenTile tile = buffer1[px][py]; input.begin(editor, x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); filter.apply(input); buffer2[px][py].set(input.floor, input.block, input.ore, Team.all[tile.team], tile.rotation); @@ -299,7 +300,7 @@ public class MapGenerateDialog extends FloatingDialog{ Tile tile = editor.tile(px * scaling, py * scaling); color = MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), Team.none); }else{ - DummyTile tile = buffer1[px][py]; + GenTile tile = buffer1[px][py]; color = MapIO.colorFor(content.block(tile.floor), content.block(tile.block), content.block(tile.ore), Team.none); } pixmap.drawPixel(px, pixmap.getHeight() - 1 - py, color); @@ -321,7 +322,7 @@ public class MapGenerateDialog extends FloatingDialog{ }); } - public static class DummyTile{ + public static class GenTile{ public byte team, rotation; public short block, floor, ore; @@ -333,7 +334,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.rotation = (byte)rotation; } - void set(DummyTile other){ + void set(GenTile other){ this.floor = other.floor; this.block = other.block; this.ore = other.ore; diff --git a/core/src/io/anuke/mindustry/editor/generation/DistortFilter.java b/core/src/io/anuke/mindustry/editor/generation/DistortFilter.java index f2233be7bf..3fab21d3a5 100644 --- a/core/src/io/anuke/mindustry/editor/generation/DistortFilter.java +++ b/core/src/io/anuke/mindustry/editor/generation/DistortFilter.java @@ -1,6 +1,6 @@ package io.anuke.mindustry.editor.generation; -import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile; +import io.anuke.mindustry.editor.MapGenerateDialog.GenTile; import io.anuke.mindustry.editor.generation.FilterOption.SliderOption; import io.anuke.mindustry.world.blocks.Floor; @@ -11,14 +11,14 @@ public class DistortFilter extends GenerateFilter{ { options( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 400f), - new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 400f), + new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) ); } @Override public void apply(){ - DummyTile tile = in.tile(in.x / (in.scaling) + (noise(in.x, in.y, scl, mag) - mag / 2f) / in.scaling, in.y / (in.scaling) + (noise(in.x, in.y + o, scl, mag) - mag / 2f) / in.scaling); + GenTile tile = in.tile(in.x / (in.scaling) + (noise(in.x, in.y, scl, mag) - mag / 2f) / in.scaling, in.y / (in.scaling) + (noise(in.x, in.y + o, scl, mag) - mag / 2f) / in.scaling); in.floor = content.block(tile.floor); if(!content.block(tile.block).synthetic() && !in.block.synthetic()) in.block = content.block(tile.block); diff --git a/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java b/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java index bd8551b23a..9105a7b4e8 100644 --- a/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java +++ b/core/src/io/anuke/mindustry/editor/generation/GenerateFilter.java @@ -7,14 +7,14 @@ import io.anuke.arc.util.noise.RidgedPerlin; import io.anuke.arc.util.noise.Simplex; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.editor.MapEditor; -import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile; +import io.anuke.mindustry.editor.MapGenerateDialog.GenTile; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.Floor; public abstract class GenerateFilter{ - protected float o = (float)(Math.random() * 10000000.0); - protected long seed; - protected GenerateInput in; + protected transient float o = (float)(Math.random() * 10000000.0); + protected transient long seed; + protected transient GenerateInput in; public FilterOption[] options; @@ -88,12 +88,12 @@ public abstract class GenerateFilter{ pnoise.setSeed((int)(filter.seed + 1)); } - DummyTile tile(float x, float y){ + GenTile tile(float x, float y){ return buffer.get(Mathf.clamp((int)x, 0, width - 1), Mathf.clamp((int)y, 0, height - 1)); } public interface TileProvider{ - DummyTile get(int x, int y); + GenTile get(int x, int y); } } } diff --git a/core/src/io/anuke/mindustry/editor/generation/MedianFilter.java b/core/src/io/anuke/mindustry/editor/generation/MedianFilter.java new file mode 100644 index 0000000000..548b861f8c --- /dev/null +++ b/core/src/io/anuke/mindustry/editor/generation/MedianFilter.java @@ -0,0 +1,46 @@ +package io.anuke.mindustry.editor.generation; + +import io.anuke.arc.collection.IntArray; +import io.anuke.arc.math.Mathf; +import io.anuke.mindustry.editor.MapGenerateDialog.GenTile; +import io.anuke.mindustry.editor.generation.FilterOption.SliderOption; + +import static io.anuke.mindustry.Vars.content; + +public class MedianFilter extends GenerateFilter{ + float radius = 2; + float percentile = 0.5f; + IntArray blocks = new IntArray(), floors = new IntArray(); + + { + options( + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), + new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) + ); + } + + @Override + public void apply(){ + int rad = (int)radius; + blocks.clear(); + floors.clear(); + for(int x = -rad; x <= rad; x++){ + for(int y = -rad; y <= rad; y++){ + if(Mathf.dst2(x, y) > rad*rad) continue; + + GenTile tile = in.tile(in.x + x, in.y + y); + blocks.add(tile.block); + floors.add(tile.floor); + } + } + + floors.sort(); + blocks.sort(); + + int index = Math.min((int)(floors.size * percentile), floors.size - 1); + int floor = floors.get(index), block = blocks.get(index); + + in.floor = content.block(floor); + if(!content.block(block).synthetic() && !in.block.synthetic()) in.block = content.block(block); + } +}