From 15ca6721792d699830d537715dafc2293be1b8aa Mon Sep 17 00:00:00 2001 From: Anuken <arnukren@gmail.com> Date: Thu, 3 Oct 2024 14:44:33 -0400 Subject: [PATCH] In-game editor UI improvements --- .../sprites/blocks/environment/remove-ore.png | Bin 0 -> 496 bytes .../blocks/environment/remove-wall.png | Bin 0 -> 253 bytes core/assets/bundles/bundle.properties | 2 + core/assets/icons/icons.properties | 2 + core/src/mindustry/content/Blocks.java | 6 +- .../src/mindustry/editor/MapEditorDialog.java | 8 +- core/src/mindustry/input/MobileInput.java | 12 +- core/src/mindustry/net/CrashHandler.java | 2 +- .../mindustry/ui/fragments/HudFragment.java | 104 ++++++++++++++++-- core/src/mindustry/world/Block.java | 5 + core/src/mindustry/world/Build.java | 8 +- .../world/blocks/ConstructBlock.java | 2 + .../world/blocks/environment/RemoveOre.java | 51 +++++++++ .../world/blocks/environment/RemoveWall.java | 50 +++++++++ gradle.properties | 2 +- 15 files changed, 230 insertions(+), 24 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/remove-ore.png create mode 100644 core/assets-raw/sprites/blocks/environment/remove-wall.png create mode 100644 core/src/mindustry/world/blocks/environment/RemoveOre.java create mode 100644 core/src/mindustry/world/blocks/environment/RemoveWall.java diff --git a/core/assets-raw/sprites/blocks/environment/remove-ore.png b/core/assets-raw/sprites/blocks/environment/remove-ore.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9a0a91bfd8927d88afe6d66332b05cb05ce14f GIT binary patch literal 496 zcmV<M0T2F(P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp) z=>Px$s!2paR9J=WmOo3wKp4iK6X_-tS|^7rQMwjNql>%X;!=Y6A<Q?(?vQ?nB5qy$ z1a5(XxJjEOAWjyX9U2F@Be{Fu{5iE<@+`f(UU+`@-h1yI&}zpLvJpj*8vOj)tNhSC zJ}LA+(pS}X)(Zf@Rgz@+Iq~JW0D#k*J2h7AWGUSo0KCU1W6T;LSuG3wzB54I8L;LY z#6C6Y;^>W>91gDqHD3ooTs4aUI6HhNjTON2eU=AFR!bunn#$M$&RhqPFikb}{6Z8J zfU{oIGS@-$TmXQ%>sD@+0bnaC5@~N_taR%6LLUQibs+OStB^{~CZPa|^?*|l1giaS zb)c@uV`!r~E2p&c2($nSpvl?QMIEoY`gIb{CZRw{0^Y_C>UdM23Lx!`Fb720O=cK_ z&;Gn|evB=}3ZlkVNOMk<IrpEj1u_zVd9Uln)auL3DUmtwaxnh+9gYQHKEF6MH3yhu z*zIfzed@;3S8rp^0&G((02KupiN9KXDF7#GJDNy;SC#_kQQ%a!5>k)at>pmsqOJt! mb~c4ba8co&TxI610N@+s1FR)(a@=$P0000<MNUMnLSTZvN!HN- literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/remove-wall.png b/core/assets-raw/sprites/blocks/environment/remove-wall.png new file mode 100644 index 0000000000000000000000000000000000000000..be52153748bff7167802bc7940623ccbb8036526 GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}+dW+zLn2z= zhDY-?7;rf2KMl266#g;f^Z6e)Vz{HFCVy0Kyu?v5`=-H0U(58U=_PDA)n;s4rLLVW z^zE4Bupv)=CyPF(NOm5hL}x4Kf&)H<#szF~o~>mSMY9<zJH^?%8GHV0J%2Lo_ert! zLK%*Ww(Yx+SM8~Ai?N$~Z`^_c(_nM|LgS#0svGuE3bIZwrMy}_w2odn>`^7--c@a= zq1be-YmfCI7KsF{Z!agroi6U&E3bC=Ng0E8_7sKP>%$p=USRNa^>bP0l+XkK@yuRc literal 0 HcmV?d00001 diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 08f271d82d..d39528c634 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -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 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 64963dd203..e04db3aa06 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -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 diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 66947331b2..6fac7f0e9b 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -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; diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index c1f3a6e888..29a18cb200 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -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(); } } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index ce16f8d915..eff27140cb 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -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; } diff --git a/core/src/mindustry/net/CrashHandler.java b/core/src/mindustry/net/CrashHandler.java index b559d654e8..cb60f4ef33 100644 --- a/core/src/mindustry/net/CrashHandler.java +++ b/core/src/mindustry/net/CrashHandler.java @@ -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 diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index cf7a2866b5..c676f67bb1 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -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 diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 7b83ab0ae2..eaafecee8c 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -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){ diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 6288a0d235..5388ea9789 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -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; diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index a68424552b..0a49f8212f 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -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)); } diff --git a/core/src/mindustry/world/blocks/environment/RemoveOre.java b/core/src/mindustry/world/blocks/environment/RemoveOre.java new file mode 100644 index 0000000000..b50d019c4f --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/RemoveOre.java @@ -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); + } + +} diff --git a/core/src/mindustry/world/blocks/environment/RemoveWall.java b/core/src/mindustry/world/blocks/environment/RemoveWall.java new file mode 100644 index 0000000000..039997acdc --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/RemoveWall.java @@ -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); + } + +} diff --git a/gradle.properties b/gradle.properties index 10164c81f1..3f9f316bab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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