In-game editor UI improvements

This commit is contained in:
Anuken 2024-10-03 14:44:33 -04:00
parent 24daa1e933
commit 15ca672179
15 changed files with 230 additions and 24 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

@ -1563,6 +1563,8 @@ block.graphite-press.name = Graphite Press
block.multi-press.name = Multi-Press
block.constructing = {0} [lightgray](Constructing)
block.spawn.name = Enemy Spawn
block.remove-wall.name = Remove Wall
block.remove-ore.name = Remove Ore
block.core-shard.name = Core: Shard
block.core-foundation.name = Core: Foundation
block.core-nucleus.name = Core: Nucleus

View File

@ -588,3 +588,5 @@
63094=cat|cat
63093=world-switch|block-world-switch-ui
63092=dynamic|status-dynamic-ui
63091=remove-wall|block-remove-wall-ui
63090=remove-ore|block-remove-ore-ui

View File

@ -43,7 +43,7 @@ public class Blocks{
public static Block
//environment
air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
air, spawn, removeWall, removeOre, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
dacite, rhyolite, rhyoliteCrater, roughRhyolite, regolith, yellowStone, redIce, redStone, denseRedStone,
arkyciteFloor, arkyicStone,
redmat, bluemat,
@ -174,6 +174,10 @@ public class Blocks{
spawn = new SpawnBlock("spawn");
removeWall = new RemoveWall("remove-wall");
removeOre = new RemoveOre("remove-ore");
cliff = new Cliff("cliff"){{
inEditor = false;
saveData = true;

View File

@ -715,7 +715,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
private void addBlockSelection(Table cont){
blockSelection = new Table();
pane = new ScrollPane(blockSelection);
pane = new ScrollPane(blockSelection, Styles.smallPane);
pane.setFadeScrollBars(false);
pane.setOverscroll(true, false);
pane.exited(() -> {
@ -732,7 +732,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
cont.row();
cont.table(Tex.underline, extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX();
cont.row();
cont.add(pane).expandY().top().left();
cont.add(pane).expandY().growX().top().left();
rebuildBlockSelection("");
}
@ -762,7 +762,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|| (!searchText.isEmpty() && !block.localizedName.toLowerCase().contains(searchText.toLowerCase()))
) continue;
ImageButton button = new ImageButton(Tex.whiteui, Styles.squareTogglei);
ImageButton button = new ImageButton(Tex.whiteui, Styles.clearNoneTogglei);
button.getStyle().imageUp = new TextureRegionDrawable(region);
button.clicked(() -> editor.drawBlock = block);
button.resizeImage(8 * 4f);
@ -771,7 +771,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
if(i == 0) editor.drawBlock = block;
if(++i % 4 == 0){
if(++i % 6 == 0){
blockSelection.row();
}
}

View File

@ -265,11 +265,11 @@ public class MobileInput extends InputHandler implements GestureListener{
}).name("confirmplace");
}
boolean showCancel(){
return !player.dead() && (player.unit().isBuilding() || block != null || mode == breaking || !selectPlans.isEmpty()) && !hasSchem();
public boolean showCancel(){
return !player.dead() && (player.unit().isBuilding() || block != null || mode == breaking || !selectPlans.isEmpty()) && !hasSchematic();
}
boolean hasSchem(){
public boolean hasSchematic(){
return lastSchematic != null && !selectPlans.isEmpty();
}
@ -290,7 +290,7 @@ public class MobileInput extends InputHandler implements GestureListener{
});
group.fill(t -> {
t.visible(() -> !showCancel() && block == null && !hasSchem());
t.visible(() -> !showCancel() && block == null && !hasSchematic() && !state.rules.editor);
t.bottom().left();
t.button("@command.queue", Icon.rightOpen, Styles.clearTogglet, () -> {
@ -310,7 +310,7 @@ public class MobileInput extends InputHandler implements GestureListener{
});
group.fill(t -> {
t.visible(this::hasSchem);
t.visible(this::hasSchematic);
t.bottom().left();
t.table(Tex.pane, b -> {
b.defaults().size(50f);
@ -759,7 +759,7 @@ public class MobileInput extends InputHandler implements GestureListener{
payloadTarget = null;
}
if(locked || block != null || scene.hasField() || hasSchem() || selectPlans.size > 0){
if(locked || block != null || scene.hasField() || hasSchematic() || selectPlans.size > 0){
commandMode = false;
}

View File

@ -64,7 +64,7 @@ public class CrashHandler{
//don't create crash logs for custom builds, as it's expected
if(OS.username.equals("anuke") && !"steam".equals(Version.modifier)){
// System.exit(1);
System.exit(1);
}
//attempt to load version regardless

View File

@ -14,6 +14,7 @@ import arc.scene.ui.ImageButton.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
@ -27,8 +28,11 @@ import mindustry.input.*;
import mindustry.net.Packets.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.storage.*;
import mindustry.world.blocks.storage.CoreBlock.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
import static mindustry.gen.Tex.*;
@ -49,6 +53,80 @@ public class HudFragment{
private Table lastUnlockLayout;
private long lastToast;
private Seq<Block> blocksOut = new Seq<>();
private void addBlockSelection(Table cont){
Table blockSelection = new Table();
var pane = new ScrollPane(blockSelection, Styles.smallPane);
pane.setFadeScrollBars(false);
Planet[] last = {state.rules.planet};
pane.update(() -> {
if(pane.hasScroll()){
Element result = Core.scene.getHoverElement();
if(result == null || !result.isDescendantOf(pane)){
Core.scene.setScrollFocus(null);
}
}
if(state.rules.planet != last[0]){
last[0] = state.rules.planet;
rebuildBlockSelection(blockSelection, "");
}
});
cont.table(search -> {
search.image(Icon.zoom).padRight(8);
search.field("", text -> rebuildBlockSelection(blockSelection, text)).growX()
.name("editor/search").maxTextLength(maxNameLength).get().setMessageText("@players.search");
}).growX().pad(-2).padLeft(6f);
cont.row();
cont.add(pane).expandY().top().left();
rebuildBlockSelection(blockSelection, "");
}
private void rebuildBlockSelection(Table blockSelection, String searchText){
blockSelection.clear();
blocksOut.clear();
blocksOut.addAll(Vars.content.blocks());
blocksOut.sort((b1, b2) -> {
int synth = Boolean.compare(b1.synthetic(), b2.synthetic());
if(synth != 0) return synth;
int ore = Boolean.compare(b1 instanceof OverlayFloor && b1 != Blocks.removeOre, b2 instanceof OverlayFloor && b2 != Blocks.removeOre);
if(ore != 0) return ore;
return Integer.compare(b1.id, b2.id);
});
int i = 0;
for(Block block : blocksOut){
TextureRegion region = block.uiIcon;
if(!Core.atlas.isFound(region)
|| (!block.inEditor && !(block instanceof RemoveWall) && !(block instanceof RemoveOre))
|| !block.isOnPlanet(state.rules.planet)
|| block.buildVisibility == BuildVisibility.debugOnly
|| (!searchText.isEmpty() && !block.localizedName.toLowerCase().contains(searchText.toLowerCase()))
) continue;
ImageButton button = new ImageButton(Tex.whiteui, Styles.clearNoneTogglei);
button.getStyle().imageUp = new TextureRegionDrawable(region);
button.clicked(() -> control.input.block = block);
button.resizeImage(8 * 4f);
button.update(() -> button.setChecked(control.input.block == block));
blockSelection.add(button).size(48f).tooltip(block.localizedName);
if(++i % 6 == 0){
blockSelection.row();
}
}
if(i == 0){
blockSelection.add("@none.found").padLeft(54f).padTop(10f);
}
}
public void build(Group parent){
//warn about guardian/boss waves
@ -247,26 +325,38 @@ public class HudFragment{
editorMain.name = "editor";
editorMain.table(Tex.buttonEdge4, t -> {
//t.margin(0f);
t.name = "teams";
t.add("@editor.teams").growX().left();
t.row();
t.table(teams -> {
t.top().table(teams -> {
teams.left();
int i = 0;
for(Team team : Team.baseTeams){
ImageButton button = teams.button(Tex.whiteui, Styles.clearNoneTogglei, 40f, () -> Call.setPlayerTeamEditor(player, team))
ImageButton button = teams.button(Tex.whiteui, Styles.clearNoneTogglei, 38f, () -> Call.setPlayerTeamEditor(player, team))
.size(50f).margin(6f).get();
button.getImageCell().grow();
button.getStyle().imageUpColor = team.color;
button.update(() -> button.setChecked(player.team() == team));
if(++i % 3 == 0){
if(++i % 6 == 0){
teams.row();
}
}
}).left();
}).top().left();
t.row();
t.table(blocks -> {
addBlockSelection(blocks);
}).fillX().left();
}).width(dsize * 5 + 4f);
if(mobile){
editorMain.row().spacerY(() -> {
if(control.input instanceof MobileInput mob){
if(mob.hasSchematic()) return 156f;
if(mob.showCancel()) return 50f;
}
return 0f;
});
}
editorMain.visible(() -> shown && state.isEditor());
//fps display

View File

@ -920,6 +920,11 @@ public class Block extends UnlockableContent implements Senseable{
placeBegan(tile, previous);
}
/** Called when building of this block ends. */
public void placeEnded(Tile tile, @Nullable Unit builder){
}
/** Called right before building of this block begins. */
public void beforePlaceBegan(Tile tile, Block previous){

View File

@ -199,6 +199,10 @@ public class Build{
if(tile == null) return false;
if(!type.canPlaceOn(tile, team, rotation)){
return false;
}
//floors have different checks
if(type.isFloor()){
return type.isOverlay() ? tile.overlay() != type : tile.floor() != type;
@ -213,10 +217,6 @@ public class Build{
return false;
}
if(!type.canPlaceOn(tile, team, rotation)){
return false;
}
int offsetx = -(type.size - 1) / 2;
int offsety = -(type.size - 1) / 2;

View File

@ -110,6 +110,8 @@ public class ConstructBlock extends Block{
if(shouldPlay()) block.placeSound.at(tile, block.placePitchChange ? calcPitch(true) : 1f);
}
block.placeEnded(tile, builder);
Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config));
}

View File

@ -0,0 +1,51 @@
package mindustry.world.blocks.environment;
import arc.graphics.g2d.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.world.*;
public class RemoveOre extends OverlayFloor{
public RemoveOre(String name){
super(name);
allowRectanglePlacement = true;
placeEffect = Fx.rotateBlock;
instantBuild = true;
ignoreBuildDarkness = true;
placeableLiquid = true;
inEditor = false;
variants = 0;
}
@Override
public void drawPlan(BuildPlan plan, Eachable<BuildPlan> list, boolean valid, float alpha){
Draw.reset();
Draw.alpha(alpha * (valid ? 1f : 0.2f));
float prevScale = Draw.scl;
Draw.scl *= plan.animScale;
drawPlanRegion(plan, list);
Draw.scl = prevScale;
Draw.reset();
}
@Override
public boolean canPlaceOn(Tile tile, Team team, int rotation){
return tile.overlay() != Blocks.air;
}
@Override
public boolean canReplace(Block other){
return true;
}
@Override
public void placeEnded(Tile tile, @Nullable Unit builder){
tile.setOverlay(Blocks.air);
}
}

View File

@ -0,0 +1,50 @@
package mindustry.world.blocks.environment;
import arc.graphics.g2d.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.world.*;
public class RemoveWall extends Block{
public RemoveWall(String name){
super(name);
allowRectanglePlacement = true;
placeEffect = Fx.rotateBlock;
instantBuild = true;
ignoreBuildDarkness = true;
placeableLiquid = true;
inEditor = false;
}
@Override
public void drawPlan(BuildPlan plan, Eachable<BuildPlan> list, boolean valid, float alpha){
Draw.reset();
Draw.alpha(alpha * (valid ? 1f : 0.2f));
float prevScale = Draw.scl;
Draw.scl *= plan.animScale;
drawPlanRegion(plan, list);
Draw.scl = prevScale;
Draw.reset();
}
@Override
public boolean canPlaceOn(Tile tile, Team team, int rotation){
return tile.block() != Blocks.air;
}
@Override
public boolean canReplace(Block other){
return other != Blocks.air && !other.synthetic();
}
@Override
public void placeEnded(Tile tile, @Nullable Unit builder){
tile.setBlock(Blocks.air);
}
}

View File

@ -26,4 +26,4 @@ org.gradle.caching=true
org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000
android.enableR8.fullMode=false
archash=66ae776c9f
archash=bf2ab4d045