From 24cfb000de8021625d4617842d5b4c13707034d0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Jul 2025 16:09:45 -0400 Subject: [PATCH] Better colored floor/wall support --- .../blocks/environment/colored-floor.png | Bin 0 -> 181 bytes .../blocks/environment/colored-wall.png | Bin 0 -> 266 bytes core/assets/bundles/bundle.properties | 1 + core/src/mindustry/content/Blocks.java | 6 -- core/src/mindustry/editor/EditorTile.java | 1 + core/src/mindustry/editor/MapRenderer.java | 6 ++ core/src/mindustry/input/InputHandler.java | 3 + core/src/mindustry/io/MapIO.java | 26 ++++++++- core/src/mindustry/io/SaveVersion.java | 1 + .../mindustry/ui/fragments/HudFragment.java | 18 ++++++ .../ui/fragments/PlacementFragment.java | 28 ++++----- core/src/mindustry/world/Block.java | 2 + core/src/mindustry/world/WorldContext.java | 3 + .../blocks/environment/ColoredFloor.java | 8 ++- .../world/blocks/environment/ColoredWall.java | 16 ++++-- .../world/blocks/environment/Floor.java | 13 ----- .../mindustry/desktop/DesktopLauncher.java | 30 +++++----- gradle.properties | 2 +- tools/src/mindustry/tools/Generators.java | 54 ++++++++++-------- 19 files changed, 134 insertions(+), 84 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/colored-floor.png create mode 100644 core/assets-raw/sprites/blocks/environment/colored-wall.png diff --git a/core/assets-raw/sprites/blocks/environment/colored-floor.png b/core/assets-raw/sprites/blocks/environment/colored-floor.png new file mode 100644 index 0000000000000000000000000000000000000000..c7993a66231ab136ed428479beac5011e93bba87 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V957$ zaSVxQO}5$i`Cfe+Ba07n=Fb((5)u*;5e1$zc54P*T{L<3yJXShQcPF2$;_WA!MC9G z>5nsVA508hH3YKvSS4IxT+Am?dSC^!o2U^wFG z;usRq`u3VNU$X%Z+k^QX-X&{}T$;JJJv}{_eZr=x$p=I{q+?_`G;NC zN?K-3W@+h|wctq_FVdQ&MBb@0BRIvmjD0& literal 0 HcmV?d00001 diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 22bd9db7e7..24dc105d5b 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -121,6 +121,7 @@ continue = Continue maps.none = [lightgray]No maps found! invalid = Invalid pickcolor = Pick Color +color = Color preparingconfig = Preparing Config preparingcontent = Preparing Content uploadingcontent = Uploading Content diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 19ddda6744..cf8a61d3b3 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -905,16 +905,10 @@ public class Blocks{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; - //there is no proper support for displaying colors or placing with colors - inEditor = false; }}; coloredWall = new ColoredWall("colored-wall"){{ autotile = true; - //there is no proper support for displaying colors or placing with colors - inEditor = false; - //TODO: should this apply darkness? - //fillsTile = false; }}; Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index ddf666b1a9..be85c77812 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -36,6 +36,7 @@ public class EditorTile extends Tile{ op(DrawOperation.opFloor, floor.id); this.floor = type; + type.floorChanged(this); } @Override diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index f3249f40ee..a2b383a727 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -134,6 +134,10 @@ public class MapRenderer implements Disposable{ width, height, tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg()); }else{ + if(floor instanceof ColoredFloor){ + mesh.setColor(Tmp.c1.set(tile.extraData | 0xff)); + } + region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)]; mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8); @@ -155,6 +159,8 @@ public class MapRenderer implements Disposable{ if(wall == Blocks.cliff){ mesh.setColor(Tmp.c1.set(floor.mapColor).mul(1.6f)); region = ((Cliff)Blocks.cliff).editorCliffs[tile.data & 0xff]; + }else if(wall instanceof ColoredWall){ + mesh.setColor(Tmp.c1.set(tile.extraData | 0xff)); } offsetX = tilesize / 2f - region.width * region.scl() / 2f; diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index d47747fafc..523ba91b87 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -1627,6 +1627,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ /** Draws a placement icon for a specific block. */ protected void drawPlan(int x, int y, Block block, int rotation){ bplan.set(x, y, rotation, block); + if(block.saveConfig){ + bplan.config = block.lastConfig; + } bplan.animScale = 1f; block.drawPlan(bplan, allPlans(), validPlace(x, y, block, rotation)); } diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 8676d62f5a..fc6fb98395 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -139,6 +139,23 @@ public class MapIO{ } return tile; } + + @Override + public void onReadTileData(){ + //colored floor/wall tile data will affect the map preview + + if(!tile.block().synthetic() && tile.block() != Blocks.air){ + int color = tile.block().minimapColor(tile); + if(color != 0){ + walls.set(tile.x, walls.height - 1 - tile.y, color); + } + }else if(tile.overlay() == Blocks.air && tile.block() == Blocks.air){ + int color = tile.floor().minimapColor(tile); + if(color != 0){ + floors.set(tile.x, floors.height - 1 - tile.y, color); + } + } + } })); floors.draw(walls, true); @@ -154,7 +171,14 @@ public class MapIO{ for(int x = 0; x < pixmap.width; x++){ for(int y = 0; y < pixmap.height; y++){ Tile tile = tiles.getn(x, y); - pixmap.set(x, pixmap.height - 1 - y, colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team())); + int color = 0; + if(!tile.block().synthetic() && tile.block() != Blocks.air){ + color = tile.block().minimapColor(tile); + }else if(tile.overlay() == Blocks.air && tile.block() == Blocks.air){ + color = tile.floor().minimapColor(tile); + } + if(color == 0) color = colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team()); + pixmap.set(x, pixmap.height - 1 - y, color); } } return pixmap; diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index d05c91f501..9ddb6519a2 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -347,6 +347,7 @@ public abstract class SaveVersion extends SaveFileReader{ tile.floorData = floorData; tile.overlayData = overlayData; tile.extraData = extraData; + context.onReadTileData(); } if(hadEntity){ diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index cac1defa52..e7d68e8fb6 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -78,6 +78,24 @@ public class HudFragment{ .name("editor/search").maxTextLength(maxNameLength).get().setMessageText("@players.search"); }).growX().pad(-2).padLeft(6f); cont.row(); + cont.collapser(t -> { + t.button(b -> { + b.margin(4f); + b.left(); + b.table(Tex.pane, in -> { + in.image(Tex.whiteui).update(i -> { + if(control.input.block != null && control.input.block.lastConfig instanceof Integer col){ + i.color.set(col | 0xff); + } + }).grow(); + }).margin(4).size(50f).padRight(10); + b.add("@color"); + }, Styles.cleart, () -> ui.picker.show(control.input.block != null && control.input.block.lastConfig instanceof Integer col ? new Color(col | 0xff) : new Color(Color.white), false, col -> { + if(control.input.block != null){ + control.input.block.lastConfig = col.rgba8888(); + } + })).left().width(250f).pad(3f).row(); + }, () -> control.input.block != null && control.input.block.showColorEdit).growX().row(); cont.add(pane).expandY().top().left(); rebuildBlockSelection(blockSelection, ""); diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 60b1ab27b1..c64becb38d 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -126,39 +126,41 @@ public class PlacementFragment{ } boolean updatePick(InputHandler input){ - if(Core.input.keyTap(Binding.pick) && player.isBuilder() && !Core.scene.hasDialog()){ //mouse eyedropper select - var build = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); + Tile tile = world.tileWorld(Core.input.mouseWorldX(), Core.input.mouseWorldY()); + if(tile != null && Core.input.keyTap(Binding.pick) && player.isBuilder() && !Core.scene.hasDialog()){ //mouse eyedropper select + var build = tile.build; //can't middle click buildings in fog if(build != null && build.inFogTo(player.team())){ build = null; } - Block tryRecipe = build == null ? null : build instanceof ConstructBuild c ? c.current : build.block; + Block tryBlock = build == null ? null : build instanceof ConstructBuild c ? c.current : build.block; Object tryConfig = build == null || !build.block.copyConfig ? null : build.config(); + if(tryBlock != null && tryBlock.showColorEdit && tryConfig == null){ + tryConfig = tile.extraData; + } + for(BuildPlan req : player.unit().plans()){ if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){ - tryRecipe = req.block; + tryBlock = req.block; tryConfig = req.config; break; } } - if(tryRecipe == null && state.rules.editor){ - var tile = world.tileWorld(Core.input.mouseWorldX(), Core.input.mouseWorldY()); - if(tile != null){ - tryRecipe = + if(tryBlock == null && state.rules.editor){ + tryBlock = tile.block() != Blocks.air ? tile.block() : tile.overlay() != Blocks.air ? tile.overlay() : tile.floor() != Blocks.air ? tile.floor() : null; - } } - if(tryRecipe != null && ((tryRecipe.isVisible() && unlocked(tryRecipe)) || state.rules.editor)){ - input.block = tryRecipe; - tryRecipe.lastConfig = tryConfig; - if(tryRecipe.isVisible()){ + if(tryBlock != null && ((tryBlock.isVisible() && unlocked(tryBlock)) || state.rules.editor)){ + input.block = tryBlock; + tryBlock.lastConfig = tryConfig; + if(tryBlock.isVisible()){ currentCategory = input.block.category; } return true; diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 3884ad8041..3692214102 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -80,6 +80,8 @@ public class Block extends UnlockableContent implements Senseable{ public boolean displayFlow = true; /** whether this block is visible in the editor */ public boolean inEditor = true; + /** if true, a color picker will be shown for the lastConfig field in the in-game-editor, and will be assigned as an integer. */ + public boolean showColorEdit; /** the last configuration value applied to this block. */ public @Nullable Object lastConfig; /** whether to save the last config and apply it to newly placed blocks */ diff --git a/core/src/mindustry/world/WorldContext.java b/core/src/mindustry/world/WorldContext.java index f0a2fc4b63..e43cfa3197 100644 --- a/core/src/mindustry/world/WorldContext.java +++ b/core/src/mindustry/world/WorldContext.java @@ -26,6 +26,9 @@ public interface WorldContext{ /** Called when a building is finished reading. */ default void onReadBuilding(){} + /** Called when data finishes reading for a tile. */ + default void onReadTileData(){} + default @Nullable Sector getSector(){ return null; } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 7940de4f41..e850405e72 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -24,12 +24,14 @@ public class ColoredFloor extends Floor{ public ColoredFloor(String name){ super(name); saveData = true; + showColorEdit = true; + saveConfig = true; } @Override public void init(){ super.init(); - defaultColorRgba = defaultColor.rgba(); + lastConfig = defaultColorRgba = defaultColor.rgba(); } @Override @@ -132,7 +134,9 @@ public class ColoredFloor extends Floor{ @Override public void floorChanged(Tile tile){ //reset to white - tile.extraData = defaultColorRgba; + if(tile.extraData == 0){ + tile.extraData = defaultColorRgba; + } } @Override diff --git a/core/src/mindustry/world/blocks/environment/ColoredWall.java b/core/src/mindustry/world/blocks/environment/ColoredWall.java index 68f568544f..1d48e25ec3 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredWall.java +++ b/core/src/mindustry/world/blocks/environment/ColoredWall.java @@ -19,17 +19,19 @@ public class ColoredWall extends StaticWall{ public ColoredWall(String name){ super(name); saveData = true; + showColorEdit = true; + saveConfig = true; } @Override public void init(){ super.init(); - defaultColorRgba = defaultColor.rgba(); + lastConfig = defaultColorRgba = defaultColor.rgba(); } @Override public void drawBase(Tile tile){ - //make sure to mask out the alpha channel - it's generally undesirable, and leads to invisible blocks when the data is not initialized + //make sure to mask out the alpha channel - it's generally undesirable, and leads to invisible blocks when thtoe data is not initialized Draw.color(tile.extraData | 0xff); super.drawBase(tile); Draw.color(); @@ -37,8 +39,10 @@ public class ColoredWall extends StaticWall{ @Override public void blockChanged(Tile tile){ - //reset to white - tile.extraData = defaultColorRgba; + //reset to white on first placement + if(tile.extraData == 0){ + tile.extraData = defaultColorRgba; + } } @Override @@ -59,12 +63,12 @@ public class ColoredWall extends StaticWall{ @Override public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ - return other != null && other.block() == this && ((tile.extraData & flagIgnoreDifferentColor) != 0 || tile.extraData == other.extraData); + return other != null && other.block() == this && ((tile.extraData == flagIgnoreDifferentColor) || tile.extraData == other.extraData); } @Override public boolean isDarkened(Tile tile){ - return (tile.extraData & flagApplyDarkness) != 0; + return (tile.extraData == flagApplyDarkness); } @Override diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index e00c183ec7..2a15220aee 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -378,19 +378,6 @@ public class Floor extends Block{ } } - //'new' style of edges with shadows instead of colors, not used currently - protected void drawEdgesFlat(Tile tile, boolean sameLayer){ - for(int i = 0; i < 4; i++){ - Tile other = tile.nearby(i); - if(other != null && doEdge(tile, other, other.floor())){ - Color color = other.floor().mapColor; - Draw.color(color.r, color.g, color.b, 1f); - Draw.rect(edgeRegion, tile.worldx(), tile.worldy(), i*90); - } - } - Draw.color(); - } - public int realBlendId(Tile tile){ if(tile.floor().isLiquid && !tile.overlay().isAir() && !(tile.overlay() instanceof OreBlock)){ return -((tile.overlay().blendId) | (tile.floor().blendId << 15)); diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index 5fd21d90f1..0ae268953c 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -31,7 +31,7 @@ import static mindustry.Vars.*; public class DesktopLauncher extends ClientLauncher{ public final static long discordID = 610508934456934412L; public final String[] args; - + boolean useDiscord = !OS.hasProp("nodiscord"), loadError = false; Throwable steamError; @@ -48,21 +48,17 @@ public class DesktopLauncher extends ClientLauncher{ for(int i = 0; i < arg.length; i++){ if(arg[i].charAt(0) == '-'){ String name = arg[i].substring(1); - try{ - switch(name){ - case "width": width = Strings.parseInt(arg[i + 1], width); break; - case "height": height = Strings.parseInt(arg[i + 1], height); break; - case "glMajor": gl30Major = Strings.parseInt(arg[i + 1], gl30Major); - case "glMinor": gl30Minor = Strings.parseInt(arg[i + 1], gl30Minor); - case "gl3": gl30 = true; break; - case "gl2": gl30 = false; break; - case "coreGl": coreProfile = true; break; - case "antialias": samples = 16; break; - case "debug": Log.level = LogLevel.debug; break; - case "maximized": maximized = Boolean.parseBoolean(arg[i + 1]); break; - } - }catch(NumberFormatException number){ - Log.warn("Invalid parameter number value."); + switch(name){ + case "width": width = Strings.parseInt(arg[i + 1], width); break; + case "height": height = Strings.parseInt(arg[i + 1], height); break; + case "glMajor": gl30Major = Strings.parseInt(arg[i + 1], gl30Major); + case "glMinor": gl30Minor = Strings.parseInt(arg[i + 1], gl30Minor); + case "gl3": gl30 = true; break; + case "gl2": gl30 = false; break; + case "coreGl": coreProfile = true; break; + case "antialias": samples = 16; break; + case "debug": Log.level = LogLevel.debug; break; + case "maximized": maximized = Boolean.parseBoolean(arg[i + 1]); break; } } } @@ -75,7 +71,7 @@ public class DesktopLauncher extends ClientLauncher{ public DesktopLauncher(String[] args){ this.args = args; - + Version.init(); boolean useSteam = Version.modifier.contains("steam"); testMobile = Seq.with(args).contains("-testMobile"); diff --git a/gradle.properties b/gradle.properties index 5e1d3a2b35..4626577d07 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=ae3b50eaca +archash=f18ba925db diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index b092275e12..76f8cec5f6 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -394,34 +394,38 @@ public class Generators{ save(padded, region.name); } - if(!regions[0].found()){ + Pixmap image; + + if(regions[0].found()){ + image = get(regions[0]); + + int i = 0; + for(TextureRegion region : regions){ + i++; + if(i != regions.length || last == null){ + image.draw(get(region), true); + }else{ + image.draw(last, true); + } + + //draw shard (default team top) on top of first sprite + if(region == block.teamRegions[Team.sharded.id] && shardTeamTop != null){ + image.draw(shardTeamTop, true); + } + } + + if(!(regions.length == 1 && regions[0] == Core.atlas.find(block.name) && shardTeamTop == null)){ + save(image, "block-" + block.name + "-full"); + } + + save(image, "../editor/" + block.name + "-icon-editor"); + saveScaled(image, "../ui/block-" + block.name + "-ui", Math.min(image.width, maxUiIcon)); + }else if(gens.containsKey(block)){ + image = gens.get(block); + }else{ continue; } - Pixmap image = get(regions[0]); - - int i = 0; - for(TextureRegion region : regions){ - i++; - if(i != regions.length || last == null){ - image.draw(get(region), true); - }else{ - image.draw(last, true); - } - - //draw shard (default team top) on top of first sprite - if(region == block.teamRegions[Team.sharded.id] && shardTeamTop != null){ - image.draw(shardTeamTop, true); - } - } - - if(!(regions.length == 1 && regions[0] == Core.atlas.find(block.name) && shardTeamTop == null)){ - save(image, "block-" + block.name + "-full"); - } - - save(image, "../editor/" + block.name + "-icon-editor"); - saveScaled(image, "../ui/block-" + block.name + "-ui", Math.min(image.width, maxUiIcon)); - boolean hasEmpty = false; Color average = new Color(), c = new Color(); float asum = 0f;