From 3d5363692c7516d84cefa95d786966754e231a77 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Jun 2025 21:24:56 -0400 Subject: [PATCH 01/37] wip crux floor --- .../blocks/environment/crux-floor-1-autotile.png | Bin 0 -> 2800 bytes .../sprites/blocks/environment/crux-floor-1.png | Bin 0 -> 121 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 10 +++++++++- gradle.properties | 2 +- .../src/mindustry/tools/ImageTileGenerator.java | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-1.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..d73a9a72dce29f6ee9dda94c0ba3a8c3a5c82a7c GIT binary patch literal 2800 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 W-y{Du2N)O_7(8A5T-G@yGywqO85)oP literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1.png b/core/assets-raw/sprites/blocks/environment/crux-floor-1.png new file mode 100644 index 0000000000000000000000000000000000000000..66f26a95bfd636d9f5418b162307ac982af3710e GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U@-P{ zaSVxQeS6N3k->oD$bsdTZb|+x>f)K!-57KCx_$TDvz81fz+n b.asFloor().wall = darkMetal); diff --git a/gradle.properties b/gradle.properties index ce43e41c4b..a8e0be2bf0 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=79c4cf021d +archash=9b55a5d628 diff --git a/tools/src/mindustry/tools/ImageTileGenerator.java b/tools/src/mindustry/tools/ImageTileGenerator.java index bc5c01138d..4f9b1e98d8 100644 --- a/tools/src/mindustry/tools/ImageTileGenerator.java +++ b/tools/src/mindustry/tools/ImageTileGenerator.java @@ -56,7 +56,7 @@ public class ImageTileGenerator{ for(int i = 0; i < 47; i++){ int cx = i % 12, cy = i / 12; Pixmap cropped = out.crop(cx * cellSize, cy * cellSize, cellSize, cellSize); - outputDir.child(name + "-" + i).writePng(cropped); + outputDir.child(name + "-" + i + ".png").writePng(cropped); cropped.dispose(); } From 25d822afd24a50cb60d0da8ee50dadeff6800009 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 27 Jun 2025 12:09:44 -0400 Subject: [PATCH 02/37] Static wall autotile support --- .../mindustry/world/blocks/TileBitmask.java | 11 ++++++ .../world/blocks/environment/Floor.java | 5 +-- .../world/blocks/environment/StaticWall.java | 36 +++++++++++++++---- tools/src/mindustry/tools/Generators.java | 28 ++++++++++----- 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/core/src/mindustry/world/blocks/TileBitmask.java b/core/src/mindustry/world/blocks/TileBitmask.java index f911469267..b8ebacf6a9 100644 --- a/core/src/mindustry/world/blocks/TileBitmask.java +++ b/core/src/mindustry/world/blocks/TileBitmask.java @@ -1,5 +1,8 @@ package mindustry.world.blocks; +import arc.*; +import arc.graphics.g2d.*; + public class TileBitmask{ /** Autotile bitmasks for 8-directional sprites (see tile-gen)*/ public static final int[] values = { @@ -20,4 +23,12 @@ public class TileBitmask{ 3, 0, 3, 0, 15, 42, 15, 12, 3, 0, 3, 0, 15, 42, 15, 12, 2, 1, 2, 1, 9, 45, 9, 19, 2, 1, 2, 1, 14, 18, 14, 13, }; + + public static TextureRegion[] load(String name){ + var regions = new TextureRegion[47]; + for(int i = 0; i < 47; i++){ + regions[i] = Core.atlas.find(name + "-" + i); + } + return regions; + } } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 7b9f9ebe3f..343c94f50b 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -141,10 +141,7 @@ public class Floor extends Block{ } if(autotile){ - autotileRegions = new TextureRegion[47]; - for(int i = 0; i < 47; i++){ - autotileRegions[i] = Core.atlas.find(name + "-" + i); - } + autotileRegions = TileBitmask.load(name); } if(Core.atlas.has(name + "-edge")){ diff --git a/core/src/mindustry/world/blocks/environment/StaticWall.java b/core/src/mindustry/world/blocks/environment/StaticWall.java index c65c8a186b..a287b2a419 100644 --- a/core/src/mindustry/world/blocks/environment/StaticWall.java +++ b/core/src/mindustry/world/blocks/environment/StaticWall.java @@ -8,12 +8,17 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.graphics.*; import mindustry.world.*; +import mindustry.world.blocks.*; import static mindustry.Vars.*; public class StaticWall extends Prop{ public @Load("@-large") TextureRegion large; public TextureRegion[][] split; + /** If true, this wall uses autotiling; variants are not supported. See https://github.com/GglLfr/tile-gen*/ + public boolean autotile; + + protected TextureRegion[] autotileRegions; public StaticWall(String name){ super(name); @@ -30,15 +35,28 @@ public class StaticWall extends Prop{ @Override public void drawBase(Tile tile){ - int rx = tile.x / 2 * 2; - int ry = tile.y / 2 * 2; + if(autotile){ + int bits = 0; - if(Core.atlas.isFound(large) && eq(rx, ry) && Mathf.randomSeed(Point2.pack(rx, ry)) < 0.5 && split.length >= 2 && split[0].length >= 2){ - Draw.rect(split[tile.x % 2][1 - tile.y % 2], tile.worldx(), tile.worldy()); - }else if(variants > 0){ - Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); + for(int i = 0; i < 8; i++){ + Tile other = tile.nearby(Geometry.d8[i]); + if(other != null && other.block() == this){ + bits |= (1 << i); + } + } + + Draw.rect(autotileRegions[TileBitmask.values[bits]], tile.worldx(), tile.worldy()); }else{ - Draw.rect(region, tile.worldx(), tile.worldy()); + int rx = tile.x / 2 * 2; + int ry = tile.y / 2 * 2; + + if(Core.atlas.isFound(large) && eq(rx, ry) && Mathf.randomSeed(Point2.pack(rx, ry)) < 0.5 && split.length >= 2 && split[0].length >= 2){ + Draw.rect(split[tile.x % 2][1 - tile.y % 2], tile.worldx(), tile.worldy()); + }else if(variants > 0){ + Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); + }else{ + Draw.rect(region, tile.worldx(), tile.worldy()); + } } //draw ore on top @@ -59,6 +77,10 @@ public class StaticWall extends Prop{ } } } + + if(autotile){ + autotileRegions = TileBitmask.load(name); + } } @Override diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 8fbda7d9f8..a7c46b41e6 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -70,23 +70,32 @@ public class Generators{ ObjectMap gens = new ObjectMap<>(); generate("autotiles", () -> { - for(Floor floor : content.blocks().select(b -> b.isFloor() && b.asFloor().autotile).as()){ - Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + floor.name + "-autotile.png"); + for(Block block : content.blocks().select(b -> (b.isFloor() && b.asFloor().autotile) || (b instanceof StaticWall && ((StaticWall)b).autotile))){ + Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name + "-autotile.png"), iconPath = basePath.parent().child(block.name + ".png"); if(basePath.exists()){ //theoretically this might not finish in time, but I doubt that will ever happen mainExecutor.submit(() -> { try{ - ImageTileGenerator.generate(basePath, floor.name, new Fi("../../../assets-raw/sprites_out/blocks/environment/" + floor.name)); + ImageTileGenerator.generate(basePath, block.name, new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name)); }catch(Throwable e){ - Log.err("Failed to autotile: " + floor.name, e); + Log.err("Failed to autotile: " + block.name, e); }finally{ //the raw autotile source image must never be included, it isn't useful basePath.delete(); } }); + + if(!iconPath.exists()){ + //save the bottom right region as the "main" sprite for previews + Pixmap out = new Pixmap(basePath); + Pixmap cropped = out.crop(96, 96, 32, 32); + iconPath.writePng(cropped); + out.dispose(); + gens.put(block, cropped); + } }else{ - Log.warn("Autotile floor '@' not found: @", floor.name, basePath.absolutePath()); + Log.warn("Autotile floor '@' not found: @", block.name, basePath.absolutePath()); } } }); @@ -819,14 +828,15 @@ public class Generators{ }); generate("edges", () -> { - content.blocks().each(b -> b instanceof Floor && !(b instanceof OverlayFloor), floor -> { + content.blocks().each(b -> b instanceof Floor && !(b instanceof OverlayFloor) && !b.isAir(), floor -> { if(has(floor.name + "-edge") || floor.blendGroup != floor){ return; } try{ - Pixmap image = gens.get(floor, get(floor.getGeneratedIcons()[0])); + Pixmap image = gens.get(floor); + if(image == null) image = get(floor.getGeneratedIcons()[0]); Pixmap edge = get("edge-stencil"); Pixmap result = new Pixmap(edge.width, edge.height); @@ -838,7 +848,9 @@ public class Generators{ save(result, "../blocks/environment/" + floor.name + "-edge"); - }catch(Exception ignored){} + }catch(Exception e){ + Log.err("Failed to generate edge for " + floor, e); + } }); }); From 4790c8013b64ea84018d0ee1adda4b459a6ea8cf Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 27 Jun 2025 12:09:44 -0400 Subject: [PATCH 03/37] Static wall autotile support --- .../mindustry/world/blocks/TileBitmask.java | 11 ++++++ .../world/blocks/environment/Floor.java | 5 +-- .../world/blocks/environment/StaticWall.java | 36 +++++++++++++++---- .../world/blocks/logic/LogicBlock.java | 5 +-- tools/src/mindustry/tools/Generators.java | 28 ++++++++++----- 5 files changed, 64 insertions(+), 21 deletions(-) diff --git a/core/src/mindustry/world/blocks/TileBitmask.java b/core/src/mindustry/world/blocks/TileBitmask.java index f911469267..b8ebacf6a9 100644 --- a/core/src/mindustry/world/blocks/TileBitmask.java +++ b/core/src/mindustry/world/blocks/TileBitmask.java @@ -1,5 +1,8 @@ package mindustry.world.blocks; +import arc.*; +import arc.graphics.g2d.*; + public class TileBitmask{ /** Autotile bitmasks for 8-directional sprites (see tile-gen)*/ public static final int[] values = { @@ -20,4 +23,12 @@ public class TileBitmask{ 3, 0, 3, 0, 15, 42, 15, 12, 3, 0, 3, 0, 15, 42, 15, 12, 2, 1, 2, 1, 9, 45, 9, 19, 2, 1, 2, 1, 14, 18, 14, 13, }; + + public static TextureRegion[] load(String name){ + var regions = new TextureRegion[47]; + for(int i = 0; i < 47; i++){ + regions[i] = Core.atlas.find(name + "-" + i); + } + return regions; + } } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 7b9f9ebe3f..343c94f50b 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -141,10 +141,7 @@ public class Floor extends Block{ } if(autotile){ - autotileRegions = new TextureRegion[47]; - for(int i = 0; i < 47; i++){ - autotileRegions[i] = Core.atlas.find(name + "-" + i); - } + autotileRegions = TileBitmask.load(name); } if(Core.atlas.has(name + "-edge")){ diff --git a/core/src/mindustry/world/blocks/environment/StaticWall.java b/core/src/mindustry/world/blocks/environment/StaticWall.java index c65c8a186b..a287b2a419 100644 --- a/core/src/mindustry/world/blocks/environment/StaticWall.java +++ b/core/src/mindustry/world/blocks/environment/StaticWall.java @@ -8,12 +8,17 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.graphics.*; import mindustry.world.*; +import mindustry.world.blocks.*; import static mindustry.Vars.*; public class StaticWall extends Prop{ public @Load("@-large") TextureRegion large; public TextureRegion[][] split; + /** If true, this wall uses autotiling; variants are not supported. See https://github.com/GglLfr/tile-gen*/ + public boolean autotile; + + protected TextureRegion[] autotileRegions; public StaticWall(String name){ super(name); @@ -30,15 +35,28 @@ public class StaticWall extends Prop{ @Override public void drawBase(Tile tile){ - int rx = tile.x / 2 * 2; - int ry = tile.y / 2 * 2; + if(autotile){ + int bits = 0; - if(Core.atlas.isFound(large) && eq(rx, ry) && Mathf.randomSeed(Point2.pack(rx, ry)) < 0.5 && split.length >= 2 && split[0].length >= 2){ - Draw.rect(split[tile.x % 2][1 - tile.y % 2], tile.worldx(), tile.worldy()); - }else if(variants > 0){ - Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); + for(int i = 0; i < 8; i++){ + Tile other = tile.nearby(Geometry.d8[i]); + if(other != null && other.block() == this){ + bits |= (1 << i); + } + } + + Draw.rect(autotileRegions[TileBitmask.values[bits]], tile.worldx(), tile.worldy()); }else{ - Draw.rect(region, tile.worldx(), tile.worldy()); + int rx = tile.x / 2 * 2; + int ry = tile.y / 2 * 2; + + if(Core.atlas.isFound(large) && eq(rx, ry) && Mathf.randomSeed(Point2.pack(rx, ry)) < 0.5 && split.length >= 2 && split[0].length >= 2){ + Draw.rect(split[tile.x % 2][1 - tile.y % 2], tile.worldx(), tile.worldy()); + }else if(variants > 0){ + Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); + }else{ + Draw.rect(region, tile.worldx(), tile.worldy()); + } } //draw ore on top @@ -59,6 +77,10 @@ public class StaticWall extends Prop{ } } } + + if(autotile){ + autotileRegions = TileBitmask.load(name); + } } @Override diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index d4de29df11..8d1dfe0683 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -32,6 +32,7 @@ import static mindustry.Vars.*; public class LogicBlock extends Block{ private static final int maxByteLen = 1024 * 100; + private static final int maxLinks = 6000; public static final int maxNameLength = 32; public int maxInstructionScale = 5; @@ -198,7 +199,7 @@ public class LogicBlock extends Block{ byte[] bytes = new byte[bytelen]; stream.readFully(bytes); - int total = stream.readInt(); + int total = Math.min(stream.readInt(), maxLinks); Seq links = new Seq<>(); @@ -274,7 +275,7 @@ public class LogicBlock extends Block{ links.clear(); - int total = stream.readInt(); + int total = Math.min(stream.readInt(), maxLinks); if(version == 0){ //old version just had links, ignore those diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 8fbda7d9f8..a7c46b41e6 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -70,23 +70,32 @@ public class Generators{ ObjectMap gens = new ObjectMap<>(); generate("autotiles", () -> { - for(Floor floor : content.blocks().select(b -> b.isFloor() && b.asFloor().autotile).as()){ - Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + floor.name + "-autotile.png"); + for(Block block : content.blocks().select(b -> (b.isFloor() && b.asFloor().autotile) || (b instanceof StaticWall && ((StaticWall)b).autotile))){ + Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name + "-autotile.png"), iconPath = basePath.parent().child(block.name + ".png"); if(basePath.exists()){ //theoretically this might not finish in time, but I doubt that will ever happen mainExecutor.submit(() -> { try{ - ImageTileGenerator.generate(basePath, floor.name, new Fi("../../../assets-raw/sprites_out/blocks/environment/" + floor.name)); + ImageTileGenerator.generate(basePath, block.name, new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name)); }catch(Throwable e){ - Log.err("Failed to autotile: " + floor.name, e); + Log.err("Failed to autotile: " + block.name, e); }finally{ //the raw autotile source image must never be included, it isn't useful basePath.delete(); } }); + + if(!iconPath.exists()){ + //save the bottom right region as the "main" sprite for previews + Pixmap out = new Pixmap(basePath); + Pixmap cropped = out.crop(96, 96, 32, 32); + iconPath.writePng(cropped); + out.dispose(); + gens.put(block, cropped); + } }else{ - Log.warn("Autotile floor '@' not found: @", floor.name, basePath.absolutePath()); + Log.warn("Autotile floor '@' not found: @", block.name, basePath.absolutePath()); } } }); @@ -819,14 +828,15 @@ public class Generators{ }); generate("edges", () -> { - content.blocks().each(b -> b instanceof Floor && !(b instanceof OverlayFloor), floor -> { + content.blocks().each(b -> b instanceof Floor && !(b instanceof OverlayFloor) && !b.isAir(), floor -> { if(has(floor.name + "-edge") || floor.blendGroup != floor){ return; } try{ - Pixmap image = gens.get(floor, get(floor.getGeneratedIcons()[0])); + Pixmap image = gens.get(floor); + if(image == null) image = get(floor.getGeneratedIcons()[0]); Pixmap edge = get("edge-stencil"); Pixmap result = new Pixmap(edge.width, edge.height); @@ -838,7 +848,9 @@ public class Generators{ save(result, "../blocks/environment/" + floor.name + "-edge"); - }catch(Exception ignored){} + }catch(Exception e){ + Log.err("Failed to generate edge for " + floor, e); + } }); }); From 1220a7a4a8b6b51bc18ceee629d8023b59ed45c4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 10 Jul 2025 19:47:39 -0400 Subject: [PATCH 04/37] Floor experiment progress --- .../environment/crux-floor-1-autotile.png | Bin 2800 -> 1609 bytes .../environment/crux-floor-2-autotile.png | Bin 0 -> 994 bytes .../sprites/blocks/environment/plating.png | Bin 0 -> 1154 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 12 +++++++++++- .../world/blocks/environment/Floor.java | 12 +++++++++--- 6 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/plating.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png index d73a9a72dce29f6ee9dda94c0ba3a8c3a5c82a7c..c9bb24e5ec4a70b615634b2e9bbc74bab171e11c 100644 GIT binary patch delta 1580 zcmew$dXi^?K|LF@r;B4q#hkZu4U29Y2)JtY^*<=I+WBoqNsxN(xxC*3Vd}l_9)z5_ zV8p=K-T!wt!#$s_6Jquoe)Bdd?7Z>!-{ky6K$$RG(UQYgOPR$qnqy*Ur2- ze?0ipZ_B^uul_e<%8@P<%#tiPxzRRe+qRxazyHNw7qdl(v@gzVDhg2Zkb3a%xO3!c ztr=<>?1@cxKVLqb{(^n`q*x=kr^nl`HZA@#S=r&`L4o@l zO@y|*QJ*ArHi`Ml8E%`I^$v^Ydn}pd%C;j$?pq$y*}7vFUhRJ&vOyzOu|l3R>*9<3 zHyFGV)+YSsZ#5O(@+!UO+TZm?2PXaCetDB6de7_yw-{EQK0425!BzhyZhrq)^Df}L z&5{%K<^EL0X_-tF|L;mB%v5WbSEMlcfP`-Ix?H9(`{V^a43dma2VWM>ZMb^AUV`K9 z17<~`q=S(nZcUdS+rRt%=)uNcl8e7>{Pe82LC(ENAkMu>iP>X5|AmTO9GOg~|Mni-H?eEEc|xX}Uj|(`5c4uE1OMA5}JNTYTMd{mdD$&2uC+ z32QA}@_$O}f{4d!`dH)|ZA9-hMLW(@I}lj^H^gApod0Cy>t8DnHy5*AoE~vcj zmu`LLYA>efc&4cMw|5Unya6dt_1j^7ql{19Hs4EY_SkwJKR(887rEs5h?dUlOwa za*INDyN$$SdYB!P+p9ic>o_)h|N^Xi<6j+Z9*tQM$2sMXGSceesKD&n*nQ##wb+@#@uc3&Y$%Nsy`Bx;<;g z0Vn(93$K|YZUkQL=8SS&&!3R!?z>v;!mSLUR7f6t(=JzbcFLT`Tc_s*=hoEMcK_2+ z|L6Ojb;-KgwF#9;5v!*P|9@7_yqxoi!ZYTzz7y(A*+Dt@W5~s?8-qMdH;Fgd%s7xG zEy(R^S?m4x+~5B81^ZskcCz~7 z{+Tdz&f?6@TU7kzebVN`opNV>tbbE{>BWY}`=c_ByfAqD|G!qktOjoFfAM&`3AlBO13x1_d0I_suGZdL$a2DG0!rLHF9+H$puCjC7jZ0xqeD(T; zx_d)llfkBcXM+!LI7&p?XY*aC7I3?EejdxWdYP7qU%S^aRq-A=@#}TakDkbWM~TSz zEqoWE1x&t7yzrXYL;9c}Q?xv%mwi@4n7+!U$p@~TcYS>I11mI%@7%GH|A8TA&fl0j zkhET>r|UamjiAXv!D?phP~{a{zZu2zU3FeOE5qw|jSXwBK|FtW%ij}!*YGDWWUH#p pU{gpq$x_Vc&=h;&)uR9W%ICiaq(}PnFfcGMc)I$ztaD0e0syJ8{FMLz literal 2800 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 W-y{Du2N)O_7(8A5T-G@yGywqO85)oP diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..58b7aedf4ad2786942ae43228bd9e727c5a17477 GIT binary patch literal 994 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z&yv( z#WAE}&fB@ZMOPenTGd6|7bHB7Tpq#puAbq6z)V@qcMRIAgu>tCMOXbbe*e2{!Hrjw z=GorOjja3e>&KVxOxtQ+*fPA}W-?%BoYBm1#*yJ!%^f3~+W*sDz4%#ndrRze*SeZ1 zEB?pZ*U5d_-nai${bcKg>Q7T${+?!a_*9zmV>(yElh-Fc?YCr)*eu>->~em(?Yx}- zS&b<_*Y9Hf!ne)()DLl1hflv3_5EMR;87PJb)>$SFQDk(^Y5o;*Vq60Bw4L=@yGQ; zehVx)4#==1_CHOV>h+u5x4U;9+du8D zwZnV$IOEA1yTv=}*ZzOx&!A*+o=0iLEM|qK&pmog?Q6}Ov$B{fBSOyqGT(h<;;aK5 z|1W4YSRek=GQF`QAus3~qrkyEbJlUb*?Ugz?z*-r1`kGX04$VqNC|hgWmwVx4vabT zn7_oO_vh80Esf-}=hm3`bbdMW(Udon+#bb$I={Qo$<6;?YdLf2nF)VR$Jsi(FMaoB zjc~yh_W+ZBTmMC}LW6Vzzrv=~3*{Js9Kb$W!7gy~Y5+fjCd7AN*adDbz964aUdsZ}{m5*XsTHheqVToy;6B_f~ODZ*`t?(Y1j= z%3u=*nz?V7JKmh%KD*@8^r!RxF*t2{RQAnAQ`%9*-tGPRCDZ$s+dD8%2`~6!^MyU* z$i=FLH$Q^;CwRP{yVpm9)7qmyLZdcFq^hCX``^+n{2QL{`EIp)Yi;b}>x<+Rg#H)U zGKAO7@!&CjDSwYN%nS|^4TZ< zvAnT{oq_)brwKe|LV^pNPWWI6_U0P)i0cR4Z&oJ+e_o(g1xl-n@AKX3{y&pFGj_l1 zn|Xi4k}a+Ib~1SEtJ9fS=)vmn>1%RlUve?uf;_&9yNlhXO!^ literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/plating.png b/core/assets-raw/sprites/blocks/environment/plating.png new file mode 100644 index 0000000000000000000000000000000000000000..534913714bea917d40a795ae91515f1cbd888ec0 GIT binary patch literal 1154 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z+&U+ z;uumf=WO)eJSj(kdCqlQ8oA;ek<%&~mpFJ#%y^u>;mM&z-<%c1JzugHL}?u{UgD@B zs#?bzWZ^w+=gqnE=i2^I@&0!3?z``I&zyVnW=CaBmF1dn?+!zWF9*4Q|7B-j@L9Hb z(epdK>!PpUyI;Tc*u}o9ubXTb806fWzh-fEA6oiQQX$WnR$(qE@kWu%iCVMA? z#0mC_u7;D-cd50?m0t9kw@chV>X+Nc?`?|@-=hh9|T?+E&J4G2plnS1F z|K0!SP>0x^IWBq*M|1xqa8|ymHdWO8rV^Yeux#Vxmp&!}`?haWEhy&dE(l{Vc=Bnd zj=wUKT0*bGl{ts3O3ZgXi*=ZMEGziV6zhQNYXv*JSDy@-vHAehN3&oxx25|ny&rT` zxhb4@%W9%ja67D%Lxin)Uo?wX>NHRB1&<7$@=da}F7hs6YgW=r;R9KLuX#`jX*y&F{x>8G>=6~EoSrL-p8yH4=S zojnEIT5(%;Jj&vlb-{BUZ`GVv&n8rDUKtv_>s!P*g{mo0Lae$G>!+>VT-O=t-K{ds zxFg5$$Ymjw^tzZk-?p_JT<|}>;mWh6Zj+fMCQp;u;$D>aM^54L#2FKh$?j6%KXrM< zC$UArM6{g@U&gTmJr!H8^^xDTBh;AvK$UniQ*WjO_;3uJncb+g8 zDIIw{Kc#7@QViEmnGZi6{bTT+RG9av`>6Kqgq5!ZG*=3g`^HJFS|22zv(4J*^C4HR zRRu3S_kHu6v`dYnONCjl!RGm@WwR7Gw2xf-7P`VEu2ipK;;oJ)M!MO*twOSOAN9mv1iYoGo2&q(=@+8JzcZ!oYOiK9L1k3T;hMh zI{AqG&h%+#_!sX8-f~6AqA{y{nn-!qw1}ou`-gKScYWo`)>Tw{hFP5#x|rg+xkVps*~;j>d!CuqoQMOe6WjZA9%>v|I+1@v$AW|LNq2ZWctxhJ RV_;xl@O1TaS?83{1OPYV4fg;5 literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index c503a0a1e8..c184afb202 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -601,3 +601,4 @@ 63081=basalt-vent|block-basalt-vent-ui 63080=tile-logic-display|block-tile-logic-display-ui 63079=crux-floor-1|block-crux-floor-1-ui +63078=crux-floor-2|block-crux-floor-2-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 0ebea668b2..0ecebafba9 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -59,7 +59,7 @@ public class Blocks{ shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, pebbles, tendrils, //ores @@ -315,6 +315,7 @@ public class Blocks{ solid = true; variants = 0; canShadow = false; + drawEdgeOut = false; }}; empty = new EmptyFloor("empty"); @@ -810,10 +811,19 @@ public class Blocks{ darkMetal = new StaticWall("dark-metal"); cruxFloor1 = new Floor("crux-floor-1"){{ + autotile = true; + emitLight = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + + cruxFloor2 = new Floor("crux-floor-2"){{ autotile = true; emitLight = true; lightRadius = 30f; lightColor = Team.crux.color.cpy().a(0.3f); + drawEdgeOut = false; + drawEdgeIn = false; }}; Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index a4bbd0b5f5..b67ecf9313 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -80,6 +80,10 @@ public class Floor extends Block{ public int tilingVariants = 0; /** If true, this floor uses autotiling; variants are not supported. See https://github.com/GglLfr/tile-gen*/ public boolean autotile = false; + /** If true (default), this floor will draw edges of other floors on itself. */ + public boolean drawEdgeIn = true; + /** If true (default), this floor will draw its edges onto other floors. */ + public boolean drawEdgeOut = true; protected TextureRegion[][][] tilingRegions; protected TextureRegion[] autotileRegions; @@ -236,7 +240,9 @@ public class Floor extends Block{ } Draw.alpha(1f); - drawEdges(tile); + if(drawEdgeIn){ + drawEdges(tile); + } drawOverlay(tile); } @@ -295,7 +301,7 @@ public class Floor extends Block{ Point2 point = Geometry.d8[i]; Tile other = tile.nearby(point); //special case: empty is, well, empty, so never draw emptiness on top, as that would just be an incorrect black texture - if(other != null && other.floor().cacheLayer == layer && other.floor().edges(tile.x, tile.y) != null && other.floor() != Blocks.empty){ + if(other != null && other.floor().drawEdgeOut && other.floor().cacheLayer == layer && other.floor().edges(tile.x, tile.y) != null){ if(!blended.getAndSet(other.floor().id)){ blenders.add(other.floor()); dirs[i] = other.floorID(); @@ -316,7 +322,7 @@ public class Floor extends Block{ Point2 point = Geometry.d8[i]; Tile other = tile.nearby(point); - if(other != null && doEdge(tile, other, other.floor()) && other.floor().cacheLayer == realCache && other.floor().edges(tile.x, tile.y) != null && other.floor() != Blocks.empty){ + if(other != null && other.floor().drawEdgeOut && doEdge(tile, other, other.floor()) && other.floor().cacheLayer == realCache && other.floor().edges(tile.x, tile.y) != null){ if(!blended.getAndSet(other.floor().id)){ blenders.add(other.floor()); } From 8c3840b7acfa1677f27dfb64a0a5e14df6c87a54 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 11 Jul 2025 17:51:59 -0400 Subject: [PATCH 05/37] More floor stuff --- .../sprites/blocks/environment/grate-detailed.png | Bin 0 -> 359 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 9 ++++++++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 core/assets-raw/sprites/blocks/environment/grate-detailed.png diff --git a/core/assets-raw/sprites/blocks/environment/grate-detailed.png b/core/assets-raw/sprites/blocks/environment/grate-detailed.png new file mode 100644 index 0000000000000000000000000000000000000000..b295bc8169c05ef29126fafe6f4013e16db8168b GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U{v&U zaSVxQJsNH;)?^?s=Sd-pT*<<3k&Cu&i)*@ecvbrZzxm|{wDwHUQLJCqY%ufWrrn-5 zK3?!=2-wbRrKs?+%4XrByxB)TzyEA{%=t&mzJQa898be{6?5L*m}}E^{(IC;mhvBJ zvn$kHb~J`eOy0!x>vQJE#(dG1PbWF{9KTp7Yf|&0t#Q($w#G}37!K%Nzb&# z$Jz!BX3e8}d6$T>H+WrJoIf{s_d~IG-=J*y6RcWIuDk(iO*}`wabIPTZu@@3M>Yb!9^K zXU~ZTu5sjWF1aCVUhkME>}NUQGRsYNE5)ATy?oK~3x1sY-gK$_sQuH1i8+&}D;F>@ PFfe$!`njxgN@xNAMoXBU literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index c184afb202..b63ed7edf8 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -602,3 +602,4 @@ 63080=tile-logic-display|block-tile-logic-display-ui 63079=crux-floor-1|block-crux-floor-1-ui 63078=crux-floor-2|block-crux-floor-2-ui +63077=crux-floor-3|block-crux-floor-3-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 0ecebafba9..ad0c194adb 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -59,7 +59,7 @@ public class Blocks{ shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, pebbles, tendrils, //ores @@ -826,6 +826,13 @@ public class Blocks{ drawEdgeIn = false; }}; + cruxFloor3 = new Floor("crux-floor-3"){{ + autotile = true; + emitLight = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) .each(b -> b.asFloor().wall = darkMetal); From f9b6e3c0a622cdac340cd590a5000be2537969cf Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 11 Jul 2025 19:07:31 -0400 Subject: [PATCH 06/37] More tile progress --- .../environment/crux-floor-1-flat-autotile.png | Bin 0 -> 1521 bytes .../blocks/environment/crux-floor-3-autotile.png | Bin 0 -> 1094 bytes .../blocks/environment/crux-floor-4-autotile.png | Bin 0 -> 1147 bytes .../sprites/blocks/environment/pipes.png | Bin 0 -> 296 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 9 ++++++++- tools/src/mindustry/tools/Generators.java | 5 +++-- 7 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-1-flat-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-3-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/pipes.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1-flat-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-1-flat-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..a5bbed72ead6be4eefa69de8b8f2b53518185a61 GIT binary patch literal 1521 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z`EMg z#WAE}&fB@ZdAAJ&TBj~>*SIxzv)(SBqW{cWY+d$vPq5yiE!w5*b@<`qKlKic+cx|) zF+MNidh+n@`Sx=E^<1OgZRKBZVJXjqIYtgerx;FZGOIl2{@NP9zkYTR1OIgI@6~bZ zu4^7|dh+)x@2|@K^Zx(;`*qG=$sZGwz9wPNieLl<#`xq{uwj+Bj%e=iC&3|5Dik>aJ;L)48!gECDFY>&Y9?M$L z-Mk;%N&m#vtrpI+9$qHo6xhlHRR8m)&&!v1bnm; z>QNH>f5Gd4nWg^q*X{NiYi1^d&CyLeZofz5&aXBXvx8#q)g;UgTzs0OBJ6Rr^U8uF z?_Z@&*v7eKrr>^UW}Q@~ia+moHca7Muw3SZ%7&w7mUz#0&^{-oA?)DRu=j~ejQWMH z&8$w-|2UkGT>C_aN!juJbNd**H%~H;-fR;7Kka34Lx=J~xj6SGJ?4VccgIA^f3>{B$9P5PF&UBFK(|av)!1LU_>T6HjjT)Z>hg5$#cD_z2W6Ito%KI&^ z&C_{RtCV5#fBVP(KfhLgFV*69T>B_OmeanNOyj7X9ujk)GjtQ!qGr#)#GfGaH5DBt=Udx$ZPdpQzsH9wb zzl*D5R?C@Rcc(WBPM#1se=DDWE~n5h51%jWA0k+CYgN>KF<0m`ZL5DJ8573cktOdP zbA^8^-FZ;?KH}S#?{@Vnekvz^Y+vzKCM#FPL1g}KxwGfP?pj{y;{4Wk_|>_EtNt>k zy;+fYlqFi{jf~dUn`&izSIrIz&bqt5-{GkJmgEy<%X@CC6sq~p53NPgDy zfPUr1Z!Z?ylV{kwcv+}$#(SBnmd<|+9&2VDF#7P1;Z}-yW9L7HTT?in9nY_O9-yt( zvCDZ?_grV)*#~~_>&PqP+q%h5Ah$gv+`2tVlJnaKE1?~?Ekh2mh&{?#cu)Sop}tvh zJ_g)h|1pS_UD=Ywv~sR4o(V42$RWD4V?U^Xyk$>{^fpD*YC z?{?4s`o8)0-tx7~xzWr^{=MWVi2kD*$h}pt_Q_$B?WPW|CLL zyJBw3CG!jN3f@9SujkKWGE!08Y?sL=V9PlZls8Uzo>+6gR8+u}bLQ9g)6b=!QBqUf zY?m#o5GADYW#WqO><{Ex%0S6!!I#-=4u4E4`QIvKybgAJR-aYR(C<3o+VX!v-^I-T zGTMkZde4vkBWnJaQAga-yMD_L?W^(&X1Ljk&OsEZ%Xucusb4UWoz4HrpFIo=3=E#G KelF{r5}E+tWx0s} literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-3-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-3-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..5a30bd7107e32977c4c9d7b64ae8f3aeead44a22 GIT binary patch literal 1094 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z{23^ z;uumf=k1)`fijLFt~a-ScoLA%$-&{^xuQ$tgu^zb32Q?%R2MRcG^RK{JTaNQZ$a6% z-On%ke6O|szGb_2?%eI~@6MY0GV$EIfA7BiT(e={zdymhE6J?@v9)xGw+P zd~yD~rEmXD|8Y~ihPu|LJS>RMF+}>fihO16ry$vi5EIpKs6Da=@6SxtPJ}fq2ssm4Le}KWcy8JngVu z&Ej*nb)%ne!L$B6*4-utXWCclA6UqF?oXt7^R{~|>HpR+Y|&%d*Jp3dpxfQB{;@un z!)m1muYYtiUs%NP!>TTn;TlLfUbexsyWr9KpYLO{Kin5>xTSQ(IpDK$>w~+DD|DS~ zSxoJ{IKns`as^*0uJ|eFv>{x4pv{oDVSMS$tN0M9u_j>dS7Ns}E) zg&%x>n!cXt&a4M#^yAp9Ob^bq-^Ksn5=;8OCvFp*h3EX-T*kEhUdz0iuZPW#|G61` zFj}f)>ndN~y7h@fRpuHEz2WF0+f=(nDO$8%xxe%Ap z6Mitxlat#mwouN=|KI!g|C7E~eX~D){ud+1!C!x3KF5dm|C|0}_wU`epI;X@{Xa1% z%Cz15$KRi4|1g-wv(?qt6$!n#!IED0P3yo~&U1err7j2-p7V3@Zw5Wzf@l7DES8`Y zldWFx+PB~t|2Iay>tD}Seu_J*=AC&pXWty7{}sjQSu3)??>};0jk44ofy`glX=O&z+&p@ z;uumf=j~j_qT2>MuCcy-6Fkd4Dc)LlJNNv(Zvr3nX5LwN*F^H_#N0_tKN%nHjg{%& z$5T65LFLf=eYO8TKDRi}e&IujmF$#{^W)~n^Z75I{Dx)I;=cb+9;$3w+ykN<#Q$gh zWLLYesN?_LTb>T`UX%9D`xt+De%O7^%mWN34>FwmIe|H*>CS?AzmKzTPTqQCzsvp% z7K?M6U$!?|RUO-3!F7Nos_N)|Ep`xnWWN>X5tgVmkK^aC%$x6WGJE@vzn`yP{a^p@ zSL)ZVTeD_H)u&9_^DQ#^>)C0Ix~gZq8SVa@PSBSv)@8{0yJE&Q#;PkDt7jhwvRCpA zK49vl=al;)OK(k-y;KO(;PM-tkj}A$fz*;v)>F*%h;=MO9z?-lD_4 zL-fJD$Zb*gxi6^%)CyktB{#u`@pxq&|GuOZp|7i*%$Tm!?OtPCuyvpKlGP25ZSJo* z{yy?Pvq;mVW<~_MyoYPYH-n?9I@j;q`{KS{ZOs?wK89E6LRWuH<1s$)>2~@@-!-;v zQTMfH^8`q>Z2jK5ha;=@e9kHsz3f-IIlKuawfs5rn6}+9+`MAF`?c>4C-*Xx`rd7> zyE5BVF`O}hoy~&}hWs`&E?Qr|I9c?+;?x6i3--s>7t21#o$Px0u4VV%pK)J8bFP}7 zWQ>|ykzN1q-q*D^7U|~-T&(h`V!q+n%;EgEBxt>9}_7^h` zSZ_Y(Uq-f<)u|nfSAKuK`fHw{Hp^BPXOOAy88i77+?&7t+V_T=91GS=UG2T=3wy(c zgoY<@bU|K0;|sgP{C^DdzJy+oSJ<#m^b32z0{N+F%oTe$vi^4Dyc63ub=uC`tN)$& z&6quZuj_oP2EpT%)9f^_tmC9l_N$@cdJ|XS$MzFLgVsU&5!&fVFYum@?MJCAb zfY6+)G77Jl`vf&SFH{}-A2VMtL1F!Q{Yx!XzVggGZkbJ6e=)ELERf@z7Qi9&Q1$$- z-SssS!qXX}>KT~dp12@?z{6VW3wy?u?YHLNKlQWHey-ma_JBok zvKQqKFbeuMF!pq&G0AbiZ?N)QVt?S=0(*uMW@Z(3W|j7T49y?Er5Gq5aJceY?*;z@ shJ3XH3`{mN8=NL^l+OFQ?7z6cZBAo`-@B_A7#J8lUHx3vIVCg!06Vi6O8@`> literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/pipes.png b/core/assets-raw/sprites/blocks/environment/pipes.png new file mode 100644 index 0000000000000000000000000000000000000000..25962a405b4537e81cc4b093d49f49e579e19492 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V0h%| z;usRq`gZzh-opw!ZN5`2PiVZ|>iy)_%%arJn8|^MlwO_`?JD@tEEf96UTK59ulTyUf4=EF&Vouv|KN^ zwoUJxNTY~SOXSyiX9PE_VlHX;&$dBip%#Owf?hZK)sIDfrlN)|HzzVI?F;8#RKXh3 zQGCwi`oUMMLWk$<)vWn!B2s!dH#S6;zxBOV=x+{>ptaM!Nt`xbn0o1RoL*7+?MWvsx?c&ooNZ0DzYHoVpj>=n#!l0uKhZ}}L=z`(%Z>FVdQ&MBb@0QhWp Ap#T5? literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index b63ed7edf8..461b780be5 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -603,3 +603,4 @@ 63079=crux-floor-1|block-crux-floor-1-ui 63078=crux-floor-2|block-crux-floor-2-ui 63077=crux-floor-3|block-crux-floor-3-ui +63076=crux-floor-4|block-crux-floor-4-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index ad0c194adb..d2136d8652 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -59,7 +59,7 @@ public class Blocks{ shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, pebbles, tendrils, //ores @@ -833,6 +833,13 @@ public class Blocks{ drawEdgeIn = false; }}; + cruxFloor4 = new Floor("crux-floor-4"){{ + autotile = true; + emitLight = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) .each(b -> b.asFloor().wall = darkMetal); diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index a7c46b41e6..4c5a847e6d 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -89,8 +89,9 @@ public class Generators{ if(!iconPath.exists()){ //save the bottom right region as the "main" sprite for previews Pixmap out = new Pixmap(basePath); - Pixmap cropped = out.crop(96, 96, 32, 32); + Pixmap cropped = out.crop(32, 32, 32, 32); iconPath.writePng(cropped); + iconPath.parent().parent().parent().child("editor").child("editor-" + block.name + ".png").writePng(cropped); out.dispose(); gens.put(block, cropped); } @@ -830,7 +831,7 @@ public class Generators{ generate("edges", () -> { content.blocks().each(b -> b instanceof Floor && !(b instanceof OverlayFloor) && !b.isAir(), floor -> { - if(has(floor.name + "-edge") || floor.blendGroup != floor){ + if(has(floor.name + "-edge") || floor.blendGroup != floor || (!floor.drawEdgeOut)){ return; } From 7119d6852ce4b5b96aced3dfefc75394bd0ba9fc Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 11 Jul 2025 20:09:14 -0400 Subject: [PATCH 07/37] More tile progress --- .../environment/crux-floor-2-autotile.png | Bin 994 -> 1018 bytes .../environment/crux-floor-4-autotile.aseprite | Bin 0 -> 2176 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.aseprite diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png index 58b7aedf4ad2786942ae43228bd9e727c5a17477..1be5e1576c436b6ff44fbe0ff98a82a6cc242f5d 100644 GIT binary patch delta 983 zcmaFF{)>HrVf_|Q7srr_IdA9s7F{tAXjKpCb2xZz^RfuGcl8X16i?`hls8-r5xgET z?e5<%lfTzm2c$(^{k!I(|LVUVzMj5(pZmtAh2`uE^f?a5uq5y?8L%_X_`KulhcAC; zA9=8T`t-BgUT->KC#{Hg|h!EJBnJ+evKpT+XxWyXbH_2CRG`}MQ_i?cd>_i7Tre*FCW41bkZ|D$ejny@p@Xl6LG@*aD{=I^r~-&?14+D^H_66~^b&tx9#(mA>{ z<9+G37jFX>{ae4(g6WIh$656=dt&!={Lg;-{vV4%)8{h^O{**!lq}A_P^!4GOEP4# z@QK7g+t>Hs*!DePaeLDq#@NI2SvZbOscEO@O?C&C&qY@18@^jreU|ate$4)z(&RCst^LgHa89lL=I{truQ(tTzaN@K3Z4TqVv0lA<0di zQ^0}QO^lJr0BrHBWxp9@SiZKFvr8Y|-K?&9xP0RK6@PWUG9I~;_F(O6<}0_-MGKmg zPw%?7IOCLC!28lS9&;e~mXEtm%5oI_i z-=D^$@FO|MmVJl#fm@~T_MX4@Z~Yfpu8VKJ?!1;=|1>?1gyBk&i=YL&#rGH&H^WEnAi}cffD~dB5y#8JF68}mDj(z*|FV^LpV~mQ; zw#!ccl6`$Gi;yVWYKGz!{0V$t8P6=VYgiH6yT?z#e;>OK*a;u@F$C_OmHC=E;6Mb# zIiG$pRG&WihI#rL<`oxbY_elGC@&vb%g|)cKIs<&OT8S(sMSagXEJy$zxwa~9P16@ R@(c_N44$rjF6*2UngBK0%n$$o delta 959 zcmeyx{)l~oVf`FW7srr_IdA9s7F}`RX;l|-Uy$%Ta(M*XyLyHP0yAYb-!W*f5(uODB&Gi|GRVaxD>o5_HkaYi%48Apa^HFu0`YX47r z_2OsQ?Jcp>UF&M5toR>qUnlozd*A+3^^>g|sy|J2`Fonx;Ztc!{g3Hf4NqR5__W`W zJz}$XkFm@7>9+H7{%19&{9M0_`3v7R>r+3(Ssgz8Uex!09fL<*eAJQpV!nW)f6u?4 zo?T!6>yu=)(#0Rw5BV*y(P%O}3IlH*w^`0sIV_ z5dVE)7r43jf_y@eTfO!V`!DPQM$H^A_!ZJh1Vg^FFR)NK7W<98;in^9tM}_48j=5Y zGIP|w+*`#pz14ZnMb`!fDT7TMXa>Jw?s#*4`|OfW)1S`&$KbT-QQ0>eO=(9Jd$;%N zmrUuP>5Q5c*$W%Me~yKgWZ|_>sTu0fsO8CahqWXqf1FVX52#HHE$Np9k|R zEc$+xAwN@#VUoSvSr&&+$Cp&`eTZYqzP|Il?C)Ryx1B3?Gcirh+Ir-a%TxbT$8=NNaYFAthY-f1X14K6W3bvyM;^=XwT@MzHh&nP1F4 v7EFH`wRT*8qP@@_u5*KM1|L#>`ok<*bL`XplDwS^3=9mOu6{1-oD!Mpug7q?p`)Sq26M76oP` zh5s2C7+4v65-U@S`amAdsw;lZ+ z2M91+{H!odhGAPV=eFYi!aQAWf{ime8s56Eh`VwwDDtZAbL~s@HNQT;|M~NML&cH5 z@88S)u%2@9FMr)%zSNTci|fk{oQwZz|MfiIji25B-v2#bE^*EM`}KcTyY_#(e(~?t z{eAEL%l^Mqd^ok_|JFb4&(qlR*8iXN?1WRQf4Ab%j9LG;w50y+`o+Jq>t*l8|9<^qRLS4(-}s+@p73{Ty~X^4_x^6J zudrsm82`Kdy5x#~x9oN1_kVx0e_4G5J8E$KPyc(^Oy}%^C-Udg13vTTrw4rDUvIqP zSNnhC3;+7hwH~&6@o)M4riIu4e~DfYEpqYi{r_?=~^4*F1Z~7M$r|~cMZv&-~|F`}{|43(l^Jo3b{Zs${ z;5+>E^UZnSE(Z;A?y5 zAAN4M=jHEfFE1`~@0Qc8+VW!XFiw~BUw%G&CKm9w^78-b*?a22F829e!PvY0wzDoX zCtxjJ%bM;R~pTR#;9`EKL$ zU9**ccYRoFxoC&`_Y*~nE#JLMetpAq&@Ktrzv72#k&pW+7BUrmF z{P*U9Gklim@7|q1^t(EttSzfv?A;u3<6oN>oC|z=zRAjct3CHCnXCVFRuqT)1`Ebd zy!QV2>ibuEWWql$F1}Ki+Gkrm<7QpTIgV9w*}n~r+}#~K`=$G{o&#?-nxDSamtt~! z>Yo#H1aG`|Pw}_h^-m89!B_r0w%t(m=5FuY zSY7wGrRl#-x5}RtY<=2)?o-yYn|W?;-HTlk-!F69oO8DS9VCR_2%g-OUY9am$9|Tw zS4qF^^}8}R!&~If3LdrH;NRuik3U zz1G@L*xT(A%Ezz%c_FhkerEFd z_upZGRV{Ml?(XiHpuk%2V&k{lRVK&p>7|1M=WEBCofm9RzNphZ)PF`Yaj9J3_Y-xx zr$8a~YGP%-?v?xgS!m(&K<@i@@jH+I{bSPp?|&}vZT(&5)$UjAocH<%{_g*N;MK-* z^Rlw7GFz|DeS7^%or${$C>^bynZ8>R9Bg}MOP$?hYQM{S8aNQsQ*Rc}pBTFdl*(T1 zS5EFRJSG7peyW81_`hB9xb3q8wo*_rh^(4&Px`fW|MHC<&)hlde_!?Y=P6;;|0cZL n|N7jO#lL Date: Sat, 12 Jul 2025 12:33:11 -0400 Subject: [PATCH 08/37] More floor stuff --- .../environment/crux-floor-2-autotile.png | Bin 1018 -> 1038 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png index 1be5e1576c436b6ff44fbe0ff98a82a6cc242f5d..86de0953bfec5c6ec9985dc94ec09193de301f58 100644 GIT binary patch delta 982 zcmeyx-p4V)u>ORni(^Q|oVRm*i-ZjYT7|om12#yn*PPb)Tb{wfWl!@Xz71XzeIo6R zF9mzo-QVslvU}>g=NqG5y{!E6>F3M$%r`#iRWS*0Ga0Zm&S+*h^t|b{tJ`BkEq`#O%KeQ zW4x$iPVmXHB^LcR*6(6EBT=J1<)1!R!-M0CzSV~@u-H!%{O7-p(d*d%KfnGyd(J=K z&gkC6u>aSMYQ-3$1R5+k4$OH~+hDu&z0CJQ)4gwsS)oqyT*s()d)iso#h>5YJRY6- zwO;q8w!@ds>!-flIGSDmv3~8}N8t=g7U#K?Rzxu?G<`m!*L3{KTt`#WMj5fIoByBF zD_o+s;b>j3*nz2uwX-fexNIC2QGte0zEuYJFh;)O3}_&={#>7mUT!rw8)ndpu$?Jl_VasHZ%@B3dcRP>H}l+9Gk5N&RR4c(9^ARVM(R(s)2}xPP4@Pi(%FUo zn0jzsV{Tx7!!oOx;ml+iW~q9W*NopvKj?n3`LpwDoHAc=)c^Ly-`Sr1nLo=rPcHF0 zo6sM_VoPiOl?)vJX6)Q@##xP_$v#bQ?Prg5j8nFox|{pIIH=>Qw)T($w?X?qhG!S# z56Jvt?l^Y!#BY{QC%-qiF0kY{ATv)~K`MN6PCdg6Zcw}#xZjgsFvV{bpXE7+d7@`# z{nNWC-|*mk{~CLSgYnFs^$bn>`M$6lwCfy@0V{{(w4dx6r&nyrQe8Wjfq{X+)78&q Iol`;+0P`5d-v9sr delta 983 zcmeC<_{BcKuzriDi(^Q|oVRm*i>??5w5o^nIUGE$=_?O1Ja_d{#|p?fA!xFUr%4Y&wb<5!gBTn`Wy#jSQ7Y{4A>cGeBN>O!GK(drd5^o)W9;GiEF8zC)U?y{Cc6X6=OQch4d1P*zm%CiVRqmG+r{^j zVG$Dd+)GObu&w`#W2YTXXRJ=S`8;pIjGov_9sj?-sV_DUIPv1({sQxW<2(oVPx-`H zwZ1q#UAAGdY15*A>$jfQf(C4REkodLsZWdwtl)5NuR-PhVp#M|;|lwXIT!O;?=P@x zm>}umP|IMrxO>4aJBE{rhWAoy8D_|1YOQAyxLEyu$u+y542!;bAFZov(fQrOkmM%M zDd52DCdSBQ0JeD6vfm6cEMHs8*`*KfZdO-4Tt4yrioZHv8IRmad$9I3^Oalaq6JOL zr+3|3oN>x6;C<;Ek2xP*Ls$a;Pk%F6q^dz~U%+jhcg$0IzQ?6+&x?Ql;%%+nV;O}< z|LdcE&sJveubb1sZ~RAIPnf;1%HBhUjrYI_r5BU<10GMf_x$G-c7cn(GaI&>h%y|M z?@wb=_>mlB%f3VWz^&4Ed(YqdxBiPP*TpwqcV0`&c3l1D^=(!Z{p`EK+5Mf&N#6~!42UjMFoiGL*n$G&~~7wdA)F-FB^ z+hwPJ$-cgpMM#uwHAC?V{sg|SjAs_wHLQs3-Q%a=zmMGq?1T^d7y@_C%6!cna3BKW zoKL?Ps!yMM!#sTr^NNczHrX*8l$VdJWoWWzpY)4?rCttX)M_M$GZ{RWU;TG~j`ap{ Rc?Jds22WQ%mvv4FO#t@>%e?>q From 0939076b4dc498006ea8262dbcebcb6c10f4c78f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 12 Jul 2025 17:28:39 -0400 Subject: [PATCH 09/37] Better tile custom data support --- core/src/mindustry/io/SaveIO.java | 2 +- core/src/mindustry/io/SaveVersion.java | 36 ++++++++++++++++++----- core/src/mindustry/io/versions/Save8.java | 1 + core/src/mindustry/io/versions/Save9.java | 11 +++++++ core/src/mindustry/world/Tile.java | 10 +++++-- 5 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 core/src/mindustry/io/versions/Save9.java diff --git a/core/src/mindustry/io/SaveIO.java b/core/src/mindustry/io/SaveIO.java index dea4ce7b72..7f6bb42845 100644 --- a/core/src/mindustry/io/SaveIO.java +++ b/core/src/mindustry/io/SaveIO.java @@ -20,7 +20,7 @@ public class SaveIO{ /** Save format header. */ public static final byte[] header = {'M', 'S', 'A', 'V'}; public static final IntMap versions = new IntMap<>(); - public static final Seq versionArray = Seq.with(new Save1(), new Save2(), new Save3(), new Save4(), new Save5(), new Save6(), new Save7(), new Save8()); + public static final Seq versionArray = Seq.with(new Save1(), new Save2(), new Save3(), new Save4(), new Save5(), new Save6(), new Save7(), new Save8(), new Save9()); static{ for(SaveVersion version : versionArray){ diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 70cb4b3f46..2efcd50070 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -235,11 +235,21 @@ public abstract class SaveVersion extends SaveFileReader{ boolean savedata = tile.floor().saveData || tile.overlay().saveData || tile.block().saveData; - byte packed = (byte)((tile.build != null ? 1 : 0) | (savedata ? 2 : 0)); + //in the old version, the second bit was set to indicate presence of data, but that approach was flawed - it didn't allow buildings + data on the same tile + //so now the third bit is used instead + byte packed = (byte)((tile.build != null ? 1 : 0) | (savedata ? 4 : 0)); - //make note of whether there was an entity/rotation here + //make note of whether there was an entity or custom tile data here stream.writeByte(packed); + if(savedata){ + //the new 'extra data' format writes 7 bytes of data instead of 1 + stream.writeByte(tile.data); + stream.writeByte(tile.floorData); + stream.writeByte(tile.overlayData); + stream.writeInt(tile.extraData); + } + //only write the entity for multiblocks once - in the center if(tile.build != null){ if(tile.isCenter()){ @@ -251,9 +261,7 @@ public abstract class SaveVersion extends SaveFileReader{ }else{ stream.writeBoolean(false); } - }else if(savedata){ - stream.writeByte(tile.data); - }else{ + }else if(!savedata){ //don't write consecutive blocks when there is custom data //write consecutive non-entity blocks int consecutives = 0; @@ -310,7 +318,16 @@ public abstract class SaveVersion extends SaveFileReader{ boolean isCenter = true; byte packedCheck = stream.readByte(); boolean hadEntity = (packedCheck & 1) != 0; - boolean hadData = (packedCheck & 2) != 0; + //old data format (bit 2): 1 byte only if no building is present + //new data format (bit 3): 7 bytes (3x block-specific bytes + 1x 4-byte extra data int) + boolean hadDataOld = (packedCheck & 2) != 0, hadDataNew = (packedCheck & 4) != 0; + + if(hadDataNew){ + tile.data = stream.readByte(); + tile.floorData = stream.readByte(); + tile.overlayData = stream.readByte(); + tile.extraData = stream.readInt(); + } if(hadEntity){ isCenter = stream.readBoolean(); @@ -339,9 +356,12 @@ public abstract class SaveVersion extends SaveFileReader{ context.onReadBuilding(); } - }else if(hadData){ + }else if(hadDataOld || hadDataNew){ //never read consecutive blocks if there's any kind of data tile.setBlock(block); - tile.data = stream.readByte(); + if(hadDataOld){ + //the old data format was only read in the case where there is no building, and only contained a single byte + tile.data = stream.readByte(); + } }else{ int consecutives = stream.readUnsignedByte(); diff --git a/core/src/mindustry/io/versions/Save8.java b/core/src/mindustry/io/versions/Save8.java index 8dc1c0ca01..b65984b044 100644 --- a/core/src/mindustry/io/versions/Save8.java +++ b/core/src/mindustry/io/versions/Save8.java @@ -2,6 +2,7 @@ package mindustry.io.versions; import mindustry.io.*; +/** Adds support for the marker binary data region. The code is unchanged here, because it was easier to add a >= 8 check in the SaveVersion class itself. */ public class Save8 extends SaveVersion{ public Save8(){ diff --git a/core/src/mindustry/io/versions/Save9.java b/core/src/mindustry/io/versions/Save9.java new file mode 100644 index 0000000000..08d1786e18 --- /dev/null +++ b/core/src/mindustry/io/versions/Save9.java @@ -0,0 +1,11 @@ +package mindustry.io.versions; + +import mindustry.io.*; + +/** Adds support for the new 7-byte custom tile data. This can read Save8 data, but Save8 doesn't know how to handle this version's output, thus the version change. */ +public class Save9 extends SaveVersion{ + + public Save9(){ + super(9); + } +} diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 52e656e87d..ee5e19436f 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -26,8 +26,14 @@ public class Tile implements Position, QuadTreeObject, Displayable{ private static final TileFloorChangeEvent floorChange = new TileFloorChangeEvent(); private static final ObjectSet tileSet = new ObjectSet<>(); - /** Extra data for very specific blocks. */ - public byte data; + /** + * Extra data for specific blocks. Only saved if Block#saveData is true. + * It is generally recommended that blocks only access data in their own category unless necessary - for example, a floor should not read/write overlay data. + * However, one byte may sometimes not be enough to hold enough data, in which case "overlapping" data storage is necessary. + * */ + public byte data, floorData, overlayData; + /** Even more data for blocks. Use with caution; any floor/block can access this value. Due to 8-byte alignment of Java objects, this extra 4-byte field can be added with no additional cost.*/ + public int extraData; /** Tile entity, usually null. */ public @Nullable Building build; public short x, y; From e53201347fc914385e030e92b58e0fedf0afc167 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 12 Jul 2025 18:16:26 -0400 Subject: [PATCH 10/37] Colored floor tile --- .../environment/colored-floor-autotile.png | Bin 0 -> 542 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 17 ++++--- .../mindustry/graphics/MinimapRenderer.java | 1 + core/src/mindustry/io/SaveVersion.java | 8 +-- core/src/mindustry/world/Tile.java | 8 +++ .../blocks/environment/ColoredFloor.java | 47 ++++++++++++++++++ .../world/blocks/environment/Floor.java | 3 ++ 8 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/colored-floor-autotile.png create mode 100644 core/src/mindustry/world/blocks/environment/ColoredFloor.java diff --git a/core/assets-raw/sprites/blocks/environment/colored-floor-autotile.png b/core/assets-raw/sprites/blocks/environment/colored-floor-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c7d8da227361bcd47826cffeb761921365ab7a GIT binary patch literal 542 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z<9&c z#WAE}&f7Z|I}bUCI9x20fcS9ZSOJ zhqIXY>aPD{5(IZ`V+50 z(^uV@FFSsoU%S&%e*O2W?~m<&$RnWMfb7jXW$zCC+fe;>a?Q@A_3zf${@?lAe;;Gc zzhBeNlpOi<{8|mifoJ`n&*ZqDtIx_!N6|_k(9V5lj63n2@lcI?L;n+~wSO5Gd~uhN U{TE`!z`(%Z>FVdQ&MBb@00tY*wg3PC literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 461b780be5..06c302ee2e 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -604,3 +604,4 @@ 63078=crux-floor-2|block-crux-floor-2-ui 63077=crux-floor-3|block-crux-floor-3-ui 63076=crux-floor-4|block-crux-floor-4-ui +63075=colored-floor|block-colored-floor-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index d2136d8652..7444472600 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -11,7 +11,6 @@ import mindustry.entities.effect.*; import mindustry.entities.part.DrawPart.*; import mindustry.entities.part.*; import mindustry.entities.pattern.*; -import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -59,7 +58,7 @@ public class Blocks{ shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, coloredFloor, pebbles, tendrils, //ores @@ -819,23 +818,27 @@ public class Blocks{ cruxFloor2 = new Floor("crux-floor-2"){{ autotile = true; - emitLight = true; - lightRadius = 30f; - lightColor = Team.crux.color.cpy().a(0.3f); + //emitLight = true; + //lightRadius = 30f; + //lightColor = Team.crux.color.cpy().a(0.3f); drawEdgeOut = false; drawEdgeIn = false; }}; cruxFloor3 = new Floor("crux-floor-3"){{ autotile = true; - emitLight = true; drawEdgeOut = false; drawEdgeIn = false; }}; cruxFloor4 = new Floor("crux-floor-4"){{ autotile = true; - emitLight = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + + coloredFloor = new ColoredFloor("colored-floor"){{ + autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index de42d08957..1eb24a901b 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -360,6 +360,7 @@ public class MinimapRenderer{ if(tile == null) return 0; Block real = realBlock(tile); int bc = real.minimapColor(tile); + if(bc == 0 && tile.block() == Blocks.air && tile.overlay() == Blocks.air) bc = tile.floor().minimapColor(tile); Color color = Tmp.c1.set(bc == 0 ? MapIO.colorFor(real, tile.floor(), tile.overlay(), tile.team()) : bc); color.mul(1f - Mathf.clamp(world.getDarkness(tile.x, tile.y) / 4f)); diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 2efcd50070..b6d55a6814 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -209,7 +209,7 @@ public abstract class SaveVersion extends SaveFileReader{ //floor + overlay for(int i = 0; i < world.width() * world.height(); i++){ - Tile tile = world.rawTile(i % world.width(), i / world.width()); + Tile tile = world.tiles.geti(i); stream.writeShort(tile.floorID()); stream.writeShort(tile.overlayID()); int consecutives = 0; @@ -230,10 +230,10 @@ public abstract class SaveVersion extends SaveFileReader{ //blocks for(int i = 0; i < world.width() * world.height(); i++){ - Tile tile = world.rawTile(i % world.width(), i / world.width()); + Tile tile = world.tiles.geti(i); stream.writeShort(tile.blockID()); - boolean savedata = tile.floor().saveData || tile.overlay().saveData || tile.block().saveData; + boolean savedata = tile.shouldSaveData(); //in the old version, the second bit was set to indicate presence of data, but that approach was flawed - it didn't allow buildings + data on the same tile //so now the third bit is used instead @@ -268,7 +268,7 @@ public abstract class SaveVersion extends SaveFileReader{ for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ Tile nextTile = world.rawTile(j % world.width(), j / world.width()); - if(nextTile.blockID() != tile.blockID()){ + if(nextTile.blockID() != tile.blockID() || savedata != nextTile.shouldSaveData()){ break; } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index ee5e19436f..fac7607edb 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -311,6 +311,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{ if(!world.isGenerating() && prev != type){ Events.fire(floorChange.set(this, prev, type)); } + + if(this.floor != prev){ + this.floor.floorChanged(this); + } } public boolean isEditorTile(){ @@ -564,6 +568,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{ null : null; } + public boolean shouldSaveData(){ + return floor.saveData || overlay.saveData || block.saveData; + } + public int staticDarkness(){ return block.solid && block.fillsTile && !block.synthetic() ? data : 0; } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java new file mode 100644 index 0000000000..ddb7080f82 --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -0,0 +1,47 @@ +package mindustry.world.blocks.environment; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import mindustry.world.*; + +public class ColoredFloor extends Floor{ + public Color defaultColor = Color.white; + protected int defaultColorRgba; + + public ColoredFloor(String name){ + super(name); + saveData = true; + } + + @Override + public void init(){ + super.init(); + 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 + Draw.color(tile.extraData | 0xff); + super.drawBase(tile); + Draw.color(); + } + + @Override + public void drawOverlay(Tile tile){ + //make sure color doesn't carry over + Draw.color(); + super.drawOverlay(tile); + } + + @Override + public void floorChanged(Tile tile){ + //reset to white + tile.extraData = defaultColorRgba; + } + + @Override + public int minimapColor(Tile tile){ + return tile.extraData | 0xff; + } +} diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index b67ecf9313..5e0695deff 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -268,6 +268,9 @@ public class Floor extends Block{ return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")}; } + /** Called when this floor is set on the specified tile. */ + public void floorChanged(Tile tile){} + /** @return whether to index this floor by flag */ public boolean shouldIndex(Tile tile){ return true; From 88b2f9c2bc3afa18a5f08651764ee04451d50cdc Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 12 Jul 2025 19:22:53 -0400 Subject: [PATCH 11/37] Funny experiments with colored floors --- .../src/mindustry/graphics/FloorRenderer.java | 9 +- .../blocks/environment/ColoredFloor.java | 100 +++++++++++++++++- .../world/blocks/environment/Floor.java | 6 +- 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 754d6d7d27..15e110f708 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -514,7 +514,14 @@ public class FloorRenderer{ @Override protected void draw(Texture texture, float[] spriteVertices, int offset, int count){ - throw new IllegalArgumentException("cache vertices unsupported"); + if(spriteVertices.length != spriteSize){ + throw new IllegalArgumentException("cached vertices must be in non-mixcolor format (20 per sprite, 5 per vertex)"); + } + + float[] verts = vertices; + int idx = vidx; + System.arraycopy(spriteVertices, offset, verts, idx, spriteSize); + vidx += spriteSize; } } } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index ddb7080f82..954ec3e1ef 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -2,9 +2,20 @@ package mindustry.world.blocks.environment; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.*; import mindustry.world.*; +import mindustry.world.blocks.*; public class ColoredFloor extends Floor{ + /** If the alpha value of the color is set to this value, different colors are ignored and no border is drawn. */ + public static final int flagIgnoreDifferentColor = 1; + /** If the alpha value of the color is set to this value, colors are interpolated across corners. This is essentially linear filtering for the whole "image". */ + public static final int flagSmoothBlend = 2; + + private static final float[] verts = new float[20]; + public Color defaultColor = Color.white; protected int defaultColorRgba; @@ -23,10 +34,92 @@ public class ColoredFloor extends Floor{ 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 Draw.color(tile.extraData | 0xff); - super.drawBase(tile); + if((tile.extraData & 0xff) == flagSmoothBlend){ + //Only autotiling is supported right now for the sake of simplicity + int bits = 0; + + for(int i = 0; i < 8; i++){ + Tile other = tile.nearby(Geometry.d8[i]); + //force flagIgnoreDifferentColor by bypassing checkAutotileSame + if(other != null && other.floor().blendGroup == blendGroup){ + bits |= (1 << i); + } + } + var region = autotileRegions[TileBitmask.values[bits]]; + float s = Vars.tilesize/2f; + float x = tile.worldx(), y = tile.worldy(); + + verts[0] = x - s; + verts[1] = y - s; + verts[2] = sample(this, tile.x, tile.y, tile.x - 1, tile.y - 1, tile.x, tile.y - 1, tile.x - 1, tile.y); + verts[3] = region.u; + verts[4] = region.v2; + + verts[5] = x + s; + verts[6] = y - s; + verts[7] = sample(this, tile.x, tile.y, tile.x, tile.y - 1, tile.x + 1, tile.y - 1, tile.x + 1, tile.y); + verts[8] = region.u2; + verts[9] = region.v2; + + verts[10] = x + s; + verts[11] = y + s; + verts[12] = sample(this, tile.x, tile.y, tile.x + 1, tile.y + 1, tile.x, tile.y + 1, tile.x + 1, tile.y); + verts[13] = region.u2; + verts[14] = region.v; + + verts[15] = x - s; + verts[16] = y + s; + verts[17] = sample(this, tile.x, tile.y, tile.x - 1, tile.y + 1, tile.x, tile.y + 1, tile.x - 1, tile.y); + verts[18] = region.u; + verts[19] = region.v; + + Draw.vert(region.texture, verts, 0, verts.length); + }else{ + super.drawBase(tile); + } Draw.color(); } + static float sample(Block target, int tx1, int ty1, int tx2, int ty2, int tx3, int ty3, int tx4, int ty4){ + int total = 0; + float r = 0f, g = 0f, b = 0f; + Tile t1 = Vars.world.tile(tx1, ty1); + Tile t2 = Vars.world.tile(tx2, ty2); + Tile t3 = Vars.world.tile(tx3, ty3); + Tile t4 = Vars.world.tile(tx4, ty4); + + //manually unrolled loops, hooray + if(t1 != null && t1.floor() == target){ + total ++; + r += Color.ri(t1.extraData); + g += Color.gi(t1.extraData); + b += Color.bi(t1.extraData); + } + + if(t2 != null && t2.floor() == target){ + total ++; + r += Color.ri(t2.extraData); + g += Color.gi(t2.extraData); + b += Color.bi(t2.extraData); + } + + if(t3 != null && t3.floor() == target){ + total ++; + r += Color.ri(t3.extraData); + g += Color.gi(t3.extraData); + b += Color.bi(t3.extraData); + } + + if(t4 != null && t4.floor() == target){ + total ++; + r += Color.ri(t4.extraData); + g += Color.gi(t4.extraData); + b += Color.bi(t4.extraData); + } + + return Color.toFloatBits((int)(r/total), (int)(g/total), (int)(b/total), 255); + } + @Override public void drawOverlay(Tile tile){ //make sure color doesn't carry over @@ -40,6 +133,11 @@ public class ColoredFloor extends Floor{ tile.extraData = defaultColorRgba; } + @Override + public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ + return other != null && other.floor().blendGroup == blendGroup && ((tile.extraData & 0xff) == flagIgnoreDifferentColor || tile.extraData == other.extraData); + } + @Override public int minimapColor(Tile tile){ return tile.extraData | 0xff; diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 5e0695deff..e334dc625c 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -229,7 +229,7 @@ public class Floor extends Block{ for(int i = 0; i < 8; i++){ Tile other = tile.nearby(Geometry.d8[i]); - if(other != null && other.floor().blendGroup == blendGroup){ + if(checkAutotileSame(tile, other)){ bits |= (1 << i); } } @@ -246,6 +246,10 @@ public class Floor extends Block{ drawOverlay(tile); } + public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ + return other != null && other.floor().blendGroup == blendGroup; + } + public int variant(int x, int y){ return Mathf.randomSeed(Point2.pack(x, y), 0, Math.max(0, variantRegions.length - 1)); } From b3ee9884ab490891641fc90f52119bca7890c1b9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 13 Jul 2025 01:29:18 -0400 Subject: [PATCH 12/37] more floors --- .../environment/crux-floor-5-autotile.aseprite | Bin 0 -> 3435 bytes .../environment/crux-floor-5-autotile.png | Bin 0 -> 1904 bytes .../crux-floor-6-autotile-old.aseprite | Bin 0 -> 1155 bytes .../environment/crux-floor-6-autotile.aseprite | Bin 0 -> 23551 bytes .../environment/crux-floor-6-autotile.png | Bin 0 -> 13056 bytes core/assets/icons/icons.properties | 2 ++ core/src/mindustry/content/Blocks.java | 16 +++++++++++++++- .../world/blocks/environment/ColoredFloor.java | 2 +- 8 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.aseprite create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile-old.aseprite create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.aseprite create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..1a8af32f198383e306c83748d152fe8f2542e9ea GIT binary patch literal 3435 zcmd1iWng%)l#!u?uPVqB8BiJ5u1GGLudXlAl7B&91DNrUBt(BzmIiZXM{7#J8> zp<(zRt{W8W6?5JmHsobs;9xeeO;P{1l~-|#r}6C-t0)4${xN2&*l%B`rhw!>1*p1r{4dxw{H)4y8H6y`gx3@|4#fb=KZ)n z`N@9^=2d@Y{4kskzxh9|SN*pa?3dYb_dmWrxZ?AV{q~#hJ^p`hO-cOQ z{aZmHQu2Rs`MF2&{CEGqxx4wtb)!%57yrN6yLr$5rK!*2@BV)=ck|{CDc#{j=-$*u~ne`?Kb5pMTYzh4o*h9^ETv zL*RV2u^56ac zVvo>w(+l_aUVQKM=k?8-{|nhde!g2Xr&{~(_jTf-Ki{1>w|nY8_wPKbYRcW7-+8=0 z^x5%x*|qPY@1H#N=g0cwE%w0||G%0yQS1KPdH+}adpy4t;(o9vz(l>O^>2Ht7yrUH zJ&r&A=2raO{~Gq^>%VM?3IBHg^!d;CrJ~kp|IU9JZdYHBzO;HPD12q-|4(Pjs#sd> z`hWeibhdSm=e}G2=KtM4pZ}hG_4jq?{H;}cKb=gE-`lskU-sJ0-M_me74Fn8mt1gH zJH4Ugzie89`1dZ!1$*DyG4I~Fzlbg4zNqmB`L|8qK7@jc1ttbo237_{u~5lS$xt!p z?Je)TI}SW70rBc5jMzQ4?QGe;^FOD|8K(md(|$RN?LHA^df=|Z(RIr$4qC{|-#`ES z`F{PgKVm{GYU=*|`1;ju|NlRxXV3V(*|&=Cka%XzcH!O2Up@ZnDm}m4YTo&GD}Png zDEIWwJtz76e8s%@!ad*5rqxV0uDZ{W{^akXO}6JGd)7ws#HW1|?wxND+Iw?v=-jD(`QBb5x!dvm{YggW(rsQVJf3w-S#0h5wJ9-&E7GFQWh5V2H??T9#P&H8 z%U$0^DVopzIM?{qI>Fs(=W>63>j}5ozA5efi5Ih{-u^6W828X-l5zF%skNJn+-ux> z_x|1f?_KX1hwrwt&i=BTboNI<-#LeGb3gt)l~;2v{r<-7?nmx7&wQt!EO|QOn9;e5 zhSu|IkKdCsnzpegbdu>zpv~NshPutd0SiVIn{q>Bw=l48*UA+Fei$woB zg~vOr_tkHE`o>W1rt`6HJvVn2#ZAnw+@I3(a`*JThbqe-PnDhjd){1*^!#ntC1$>_ zth;hPXPdFo?c|@3jhx zliNPW?&nBOsdG7|^?XH)Wb(TgZ!5q2J$1p*dVb|`j>qNCb!0bxHoku`YtCA*H?PUg zxM?)+{m!k&bIi2DkAXtK`03{NH*Pya*d=Gc;nm)gs*^nLTZ}JBY|P&pv;HGj`j(Hu$CG8=>O7V?_Wsmj4?2u;-WU7ry2kY5(HzufF+J z^Q*t6V#%-Hi!1jmo*TJap*lYE&TEC)hQ;#RHhz7#mv6%P&+ksirMx#fX9xH^IVSh~+V}Dk&)2?~WvSh>_MFG#ox3(ieAL$`okso7t`KYE!|M(_hQ%tJ&(lzgeDmef9jdSgCKBHz;* zyl%59duhQg`+Na*c}yK-i&(JpK3||HbH4WaGs|WEhwXTOo4mQa0UN_I!-Aa`(nMx> z_IP&P?O*q$WM`Yaxx5~mYPrgK34yZ g@A__Z$}VT`yPKcq=T7^2{rUY>d;YQeI{cam0Ph+A2mk;8 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..c812412fc0ce6da5932885df1d76614f75100109 GIT binary patch literal 1904 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

BC@wBtmVtqRMS&Sf-G2rK237{2#LCnnd9b7~ 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 literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 06c302ee2e..c3f4c0a6cc 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -605,3 +605,5 @@ 63077=crux-floor-3|block-crux-floor-3-ui 63076=crux-floor-4|block-crux-floor-4-ui 63075=colored-floor|block-colored-floor-ui +63074=crux-floor-5|block-crux-floor-5-ui +63073=crux-floor-6|block-crux-floor-6-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 7444472600..483b750426 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -58,7 +58,7 @@ public class Blocks{ shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, coloredFloor, + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, coloredFloor, pebbles, tendrils, //ores @@ -837,10 +837,24 @@ public class Blocks{ drawEdgeIn = false; }}; + cruxFloor5 = new Floor("crux-floor-5"){{ + autotile = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + + cruxFloor6 = new Floor("crux-floor-6"){{ + autotile = true; + drawEdgeOut = false; + drawEdgeIn = false; + }}; + coloredFloor = new ColoredFloor("colored-floor"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; + //there is no proper support for displaying colors or placing with colors + inEditor = false; }}; Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 954ec3e1ef..7e1985907a 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -34,7 +34,7 @@ public class ColoredFloor extends Floor{ 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 Draw.color(tile.extraData | 0xff); - if((tile.extraData & 0xff) == flagSmoothBlend){ + if((tile.extraData & 0xff) == flagSmoothBlend && autotile){ //Only autotiling is supported right now for the sake of simplicity int bits = 0; From 7cc000ed46a90c5ee9a5fa98bc250e02ed9e7a1c Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 13 Jul 2025 17:00:12 -0400 Subject: [PATCH 13/37] Made tiles not clear overlay on setFloor + cleanup/refactor --- core/src/mindustry/editor/DrawOperation.java | 75 ++++++++++--------- core/src/mindustry/editor/EditorTile.java | 30 ++++---- core/src/mindustry/editor/EditorTool.java | 2 +- core/src/mindustry/editor/MapEditor.java | 3 +- .../mindustry/entities/comp/BuilderComp.java | 2 +- core/src/mindustry/io/MapIO.java | 2 +- core/src/mindustry/world/Build.java | 6 +- core/src/mindustry/world/Tile.java | 19 +---- .../world/blocks/ConstructBlock.java | 4 +- .../blocks/environment/ColoredFloor.java | 17 +++++ .../world/blocks/environment/Floor.java | 3 + 11 files changed, 85 insertions(+), 78 deletions(-) diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 6ef2d2e3b4..163546bfc3 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -10,6 +10,13 @@ import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; public class DrawOperation{ + static final int + opFloor = 0, + opBlock = 1, + opRotation = 2, + opTeam = 3, + opOverlay = 4; + private LongSeq array = new LongSeq(); public boolean isEmpty(){ @@ -39,42 +46,44 @@ public class DrawOperation{ } short getTile(Tile tile, byte type){ - if(type == OpType.floor.ordinal()){ - return tile.floorID(); - }else if(type == OpType.block.ordinal()){ - return tile.blockID(); - }else if(type == OpType.rotation.ordinal()){ - return tile.build == null ? 0 : (byte)tile.build.rotation; - }else if(type == OpType.team.ordinal()){ - return (byte)tile.getTeamID(); - }else if(type == OpType.overlay.ordinal()){ - return tile.overlayID(); - } - throw new IllegalArgumentException("Invalid type."); + return switch(type){ + case opFloor -> tile.floorID(); + case opOverlay -> tile.overlayID(); + case opBlock -> tile.blockID(); + case opRotation -> tile.build == null ? 0 : (byte)tile.build.rotation; + case opTeam -> (byte)tile.getTeamID(); + default -> throw new IllegalArgumentException("Invalid type."); + }; } void setTile(Tile tile, byte type, short to){ editor.load(() -> { - if(type == OpType.floor.ordinal()){ - if(content.block(to) instanceof Floor floor){ - tile.setFloor(floor); + switch(type){ + case opFloor -> { + if(content.block(to) instanceof Floor floor){ + tile.setFloor(floor); + } } - }else if(type == OpType.block.ordinal()){ - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); - - Block block = content.block(to); - tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); - if(tile.build != null){ - tile.build.enabled = true; + case opOverlay -> { + if(content.block(to) instanceof Floor floor){ + tile.setOverlay(floor); + } } + case opBlock -> { + tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); - }else if(type == OpType.rotation.ordinal()){ - if(tile.build != null) tile.build.rotation = to; - }else if(type == OpType.team.ordinal()){ - tile.setTeam(Team.get(to)); - }else if(type == OpType.overlay.ordinal()){ - tile.setOverlayID(to); + Block block = content.block(to); + tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); + if(tile.build != null){ + tile.build.enabled = true; + } + + tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + } + case opRotation -> { + if(tile.build != null) tile.build.rotation = to; + } + case opTeam -> tile.setTeam(Team.get(to)); } }); editor.renderer.updatePoint(tile.x, tile.y); @@ -87,12 +96,4 @@ public class DrawOperation{ byte type; short value; } - - public enum OpType{ - floor, - block, - rotation, - team, - overlay - } } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index b4ff3f1296..4a744772a6 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -2,7 +2,6 @@ package mindustry.editor; import arc.func.*; import mindustry.content.*; -import mindustry.editor.DrawOperation.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.world.*; @@ -27,17 +26,16 @@ public class EditorTile extends Tile{ if(type instanceof OverlayFloor){ //don't place on liquids if(floor.hasSurface() || !type.needsSurface){ - setOverlayID(type.id); + setOverlay(type); } return; } - if(floor == type && overlayID() == 0) return; - if(overlayID() != 0) op(OpType.overlay, overlayID()); - if(floor != type) op(OpType.floor, floor.id); + if(floor == type) return; + + op(DrawOperation.opFloor, floor.id); this.floor = type; - this.overlay = (Floor)Blocks.air; } @Override @@ -59,14 +57,14 @@ public class EditorTile extends Tile{ if(!isCenter()){ EditorTile cen = (EditorTile)build.tile; - cen.op(OpType.rotation, (byte)build.rotation); - cen.op(OpType.team, (byte)build.team.id); - cen.op(OpType.block, block.id); + cen.op(DrawOperation.opRotation, (byte)build.rotation); + cen.op(DrawOperation.opTeam, (byte)build.team.id); + cen.op(DrawOperation.opBlock, block.id); update(); }else{ - if(build != null) op(OpType.rotation, (byte)build.rotation); - if(build != null) op(OpType.team, (byte)build.team.id); - op(OpType.block, block.id); + if(build != null) op(DrawOperation.opRotation, (byte)build.rotation); + if(build != null) op(DrawOperation.opTeam, (byte)build.team.id); + op(DrawOperation.opBlock, block.id); } @@ -81,7 +79,7 @@ public class EditorTile extends Tile{ } if(getTeamID() == team.id) return; - op(OpType.team, (byte)getTeamID()); + op(DrawOperation.opTeam, (byte)getTeamID()); super.setTeam(team); getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); @@ -96,7 +94,7 @@ public class EditorTile extends Tile{ if(!floor.hasSurface() && overlay.asFloor().needsSurface && (overlay instanceof OreBlock || !floor.supportsOverlay)) return; if(overlay() == overlay) return; - op(OpType.overlay, this.overlay.id); + op(DrawOperation.opOverlay, this.overlay.id); super.setOverlay(overlay); } @@ -162,7 +160,7 @@ public class EditorTile extends Tile{ return state.isGame() || editor.isLoading() || world.isGenerating(); } - private void op(OpType type, short value){ - editor.addTileOp(TileOp.get(x, y, (byte)type.ordinal(), value)); + private void op(int type, short value){ + editor.addTileOp(TileOp.get(x, y, (byte)type, value)); } } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 50c7a2aca9..6848ae8f40 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -131,7 +131,7 @@ public enum EditorTool{ Block dest = tile.floor(); if(dest == editor.drawBlock) return; tester = t -> t.floor() == dest; - setter = t -> t.setFloorUnder(editor.drawBlock.asFloor()); + setter = t -> t.setFloor(editor.drawBlock.asFloor()); }else{ Block dest = tile.block(); if(dest == editor.drawBlock) return; diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 38839e6108..7df7f67ea6 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -7,7 +7,6 @@ import arc.math.*; import arc.math.geom.*; import arc.struct.*; import mindustry.content.*; -import mindustry.editor.DrawOperation.*; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; @@ -166,7 +165,7 @@ public class MapEditor{ } }else if(!(tile.block().isMultiblock() && !drawBlock.isMultiblock())){ if(drawBlock.rotate && tile.build != null && tile.build.rotation != rotation){ - addTileOp(TileOp.get(tile.x, tile.y, (byte)OpType.rotation.ordinal(), (byte)rotation)); + addTileOp(TileOp.get(tile.x, tile.y, (byte)DrawOperation.opRotation, (byte)rotation)); } tile.setBlock(drawBlock, drawTeam, rotation); diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 65bacbbd2c..3ab723995c 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -145,7 +145,7 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{ !Structs.contains(current.block.requirements, i -> !core.items.has(i.item, Math.min(Mathf.round(i.amount * state.rules.buildCostMultiplier), 1))); if(hasAll){ - Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation); + Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation, current.block.instantBuild ? current.config : null); if(!net.client() && current.block.instantBuild){ if(plans.size > 0){ diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 26cc9cd8ac..8676d62f5a 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -200,7 +200,7 @@ public class MapIO{ for(Tile tile : tiles){ //default to stone floor if(tile.floor() == Blocks.air){ - tile.setFloorUnder((Floor)Blocks.stone); + tile.setFloor((Floor)Blocks.stone); } } } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 8340229257..6948e6910e 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -66,9 +66,9 @@ public class Build{ Events.fire(new BlockBuildBeginEvent(tile, team, unit, true)); } - /** Places a ConstructBlock at this location. */ + /** Places a ConstructBlock at this location. To preserve bandwidth, a config is only passed in the case of instant-place blocks. */ @Remote(called = Loc.server) - public static void beginPlace(@Nullable Unit unit, Block result, Team team, int x, int y, int rotation){ + public static void beginPlace(@Nullable Unit unit, Block result, Team team, int x, int y, int rotation, @Nullable Object placeConfig){ if(!validPlace(result, team, x, y, rotation)){ return; } @@ -127,7 +127,7 @@ public class Build{ if(result.instantBuild){ Events.fire(new BlockBuildBeginEvent(tile, team, unit, false)); result.placeBegan(tile, tile.block, unit); - ConstructBlock.constructFinish(tile, result, unit, (byte)rotation, team, null); + ConstructBlock.constructFinish(tile, result, unit, (byte)rotation, team, placeConfig); return; } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index fac7607edb..cab73a3586 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -290,11 +290,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{ setBlock(type, Team.derelict, 0); } - /** This resets the overlay! */ public void setFloor(Floor type){ + if(this.floor == type) return; + var prev = this.floor; this.floor = type; - this.overlay = (Floor)Blocks.air; if(!headless && !world.isGenerating() && !isEditorTile()){ renderer.blocks.removeFloorIndex(this); @@ -321,15 +321,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{ return false; } - /** Sets the floor, preserving overlay.*/ - public void setFloorUnder(Floor floor){ - Block overlay = this.overlay; - setFloor(floor); - if(this.overlay != overlay){ - setOverlay(overlay); - } - } - /** Sets the block to air. */ public void setAir(){ setBlock(Blocks.air); @@ -412,10 +403,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{ return floor.id; } - public void setOverlayID(short ore){ - setOverlay(content.block(ore)); - } - public void setOverlay(Block block){ this.overlay = (Floor)block; @@ -431,7 +418,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public void clearOverlay(){ - setOverlayID((short)0); + setOverlay(Blocks.air); } public boolean passable(){ diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 3e53462cf1..77f6288ab1 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -77,8 +77,10 @@ public class ConstructBlock extends Block{ if(block instanceof OverlayFloor overlay){ tile.setOverlay(overlay); + overlay.placed(tile, config); }else if(block instanceof Floor floor){ - tile.setFloorUnder(floor); + tile.setFloor(floor); + floor.placed(tile, config); }else{ tile.setBlock(block, team, rotation); } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 7e1985907a..2a6b2b6a2d 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -5,6 +5,7 @@ import arc.graphics.g2d.*; import arc.math.geom.*; import arc.util.*; import mindustry.*; +import mindustry.entities.units.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -133,6 +134,22 @@ public class ColoredFloor extends Floor{ tile.extraData = defaultColorRgba; } + @Override + public void placed(Tile tile, @Nullable Object config){ + //config is assumed to be an integer RGBA color + if(config instanceof Integer i){ + tile.extraData = i; + } + } + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + if(plan.config instanceof Integer i){ + Draw.tint(Tmp.c1.set(i | 0xff)); + } + drawDefaultPlanRegion(plan, list); + } + @Override public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ return other != null && other.floor().blendGroup == blendGroup && ((tile.extraData & 0xff) == flagIgnoreDifferentColor || tile.extraData == other.extraData); diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index e334dc625c..e14a517f5b 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -275,6 +275,9 @@ public class Floor extends Block{ /** Called when this floor is set on the specified tile. */ public void floorChanged(Tile tile){} + /** Called when this floor or overlay is placed on a tile. The config may be null. */ + public void placed(Tile tile, @Nullable Object config){} + /** @return whether to index this floor by flag */ public boolean shouldIndex(Tile tile){ return true; From 3a33c53e8fdaf0acc59b37b38012dbc01b553e2f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 13 Jul 2025 19:28:25 -0400 Subject: [PATCH 14/37] Cleanup --- core/src/mindustry/editor/EditorTile.java | 2 +- core/src/mindustry/editor/MapEditorDialog.java | 6 +++++- core/src/mindustry/world/Tile.java | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 4a744772a6..ddf666b1a9 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -93,7 +93,7 @@ public class EditorTile extends Tile{ } if(!floor.hasSurface() && overlay.asFloor().needsSurface && (overlay instanceof OreBlock || !floor.supportsOverlay)) return; - if(overlay() == overlay) return; + if(this.overlay == overlay) return; op(DrawOperation.opOverlay, this.overlay.id); super.setOverlay(overlay); } diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 3bab193111..2ab5c0759f 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -748,7 +748,11 @@ public class MapEditorDialog extends Dialog implements Disposable{ //ctrl keys (undo, redo, save) if(Core.input.ctrl()){ if(Core.input.keyTap(KeyCode.z)){ - editor.undo(); + if(Core.input.shift()){ + editor.redo(); + }else{ + editor.undo(); + } } if(Core.input.keyTap(KeyCode.y)){ diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index cab73a3586..b4bd9d3a97 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -308,7 +308,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ pathfinder.updateTile(this); } - if(!world.isGenerating() && prev != type){ + if(!world.isGenerating()){ Events.fire(floorChange.set(this, prev, type)); } @@ -404,6 +404,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public void setOverlay(Block block){ + if(this.overlay == block) return; + this.overlay = (Floor)block; recache(); From 015f0bbc23c92766401d89523dc65e077880696a Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 14 Jul 2025 01:56:20 -0400 Subject: [PATCH 15/37] And yet another floor --- .../environment/crux-floor-7-autotile.aseprite | Bin 0 -> 5685 bytes .../environment/crux-floor-7-autotile.png | Bin 0 -> 1149 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 17 ++++++++++++----- gradle.properties | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.aseprite create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..de23d4ea8589297dcaddfe747125b495c5b06f86 GIT binary patch literal 5685 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 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..eba9b8cb2b083ffd3820a9476e4ab0174f9021a5 GIT binary patch literal 1149 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z+&#{ z;uumf=j|NFpeF`AuI(!=-8V0bFuU`g;ecXWw*mL6)kYyQr_YsJ+gIgZW&O8pqDzwI zD;pd8*!^{mQFZ6X@Q|2w`dZ$>z8eqBK>{#snBTutV zZf5+_H2F;J8>Rk+VaHBU;9q*H@cTyu>F!3!0y49xgg>_TdTstdxDV+ z7EfO)e_2<;e&CJG?-#!=uDF)}EAGHGwP{m6y_x^`{Hp!pU0*$!k5-v$uyB6ugJ=$T z&(W%|@gDCl#uw}_;%nZ1?p^%+yuQ0YK;??H6Ik*u z!x!cZvyCa=KL5D+tJ=~20OQxZ01ly7vJ3ep$Xs$*cu$baF=?;#7v>B67xw?S^<3Kh z{NZb`ikuh)dVk%_ypi))Xu7uR4}l$J98t;d4<3pA zpWX0z@wWFjoiFPiP+gU71c~%qJ7xivRJYq{M-)p<8SL)eTiTtnAZ_w2-^Iz*n`c~_ z!++lY`ua&Pe*Fr%_mq)K(cSUoA63)e?l+_AjTxrQKH;_gbN-vH^|^mvNhZ9PpCH-# z_S+f3i*0<3ERNP*v%j7Zz1p&wp-JH!NAya*iS{e!F+RBSK}W%o#i59!;fVmlNkxW9 z&I~H;@XX+QpZmedgr30E&nx~$U*nHwEU23!xGihu=F}VwhJre%nIX&!&%ZC;aCe@i z(ye#X3~n9#w|u$$`eRq78O*ugXT(wU=Kkh?uXGune_y!Ccm3b(phUltui^9So-G$U z^3z(G8J-`POk6$9GWyuND#s&ITjhS Date: Mon, 14 Jul 2025 02:18:19 -0400 Subject: [PATCH 16/37] more textures --- .../environment/crux-floor-7-autotile.png | Bin 1149 -> 1254 bytes .../blocks/environment/crux-floor-7-mid-2.png | Bin 0 -> 253 bytes .../blocks/environment/crux-floor-7-mid-3.png | Bin 0 -> 298 bytes .../blocks/environment/crux-floor-7-mid-4.png | Bin 0 -> 283 bytes .../blocks/environment/crux-floor-7-mid-5.png | Bin 0 -> 304 bytes .../blocks/environment/crux-floor-7-mid-6.png | Bin 0 -> 294 bytes .../blocks/environment/crux-floor-7-mid-7.png | Bin 0 -> 253 bytes .../blocks/environment/crux-floor-7-mid-8.png | Bin 0 -> 253 bytes .../blocks/environment/crux-floor-7-mid-9.png | Bin 0 -> 274 bytes core/src/mindustry/content/Blocks.java | 1 + .../world/blocks/environment/Floor.java | 21 +++++++++++++++--- 11 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-2.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-3.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-4.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-5.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-6.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-7.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-8.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-9.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png index eba9b8cb2b083ffd3820a9476e4ab0174f9021a5..53c313633839a8d470dd39b74af635c0f6d0b548 100644 GIT binary patch delta 1221 zcmey%@r-kVVf_M67srr_IdA7W2I&}bw9O5FFZ1|Tk!96?<`wM)dW*DIyJcT;Xkd8w zf7-1Uo0MHnXOAC6*i|0sX-Uk0D@{c?Fmk9{(yXPi-)|Lbms&qphU zN%qIA&E|YuS}efHaB}&_u8AozC%3+7T@ZS5`Mjm~K5zK&zjE)Udz?GY)TF(Wi70Q- zIr%(p^1=G4yH&q2&6@1RAg6CxKlP9M1TO~uE~9ku|EmKzAAGC{vz_ez?K@NL`}C`S zvp0UQ*KLSCZajIxn|x+FuDaC!QEUFpwq;V8yrcZB24~2J%|F(6y|ixF*0U-vUhwnu z17|p+661SILKz~ucQR~A4JrMdHG^w`Qc23%+zx-Ke&Rq`D8nfS$!Jc6s<{i4qB$8( z-1K75V1AmT+R)DOn&qlTrCq}{yQ;YfqGJCp&*NXPwLeb%!?9EKuRb$w`KJAwb5&Cv zgY)mM1@Z@O?3213%ILuMi?QeJ>PE2WgPMls`MozhSuErko-^O@c{J_C-yfmBe_kxF zXX5^^!92UUb-^=;d%?^dHcUp>UP^xdytU;Ub3n@a%ZtB%-WqW>ek-5D#I1hMf4x8O zNlRguU;nrHy-S%o)?HrwH=X4*!`Vo!h8I@0x9Z)d-Dh0%`b)8i z*x?(95w+$QV+_lNRr&GWTk3Te|E%}Eu}d&~c;Iam1?sNSk)iD1v*^Ja*->Yo2S zYvY&rr+x?T@jS|#w&3C=yPw9=p?54hTU)M3% z-Mi;Ix1^zqQ#AP9*3F?;GR|E7eEDg1N=ap{>BLIWFO8 z^^^ZMoBf+o|4G*2H=|Xup!Hb^ndocY3N8xAjna&h3v+LTGPoQ#t{fJoKe1l%KI4IV z3Hl2x1ssYM8lJ)P9y?P8AIk+9js=#BJ~M7GK5;nv<{atz&iZe%3@4vI7SujDV^Ve` zlf$Q{5yx`Ubk^}|GN{zcb>GN5_TWan-}aV;vTw|d|5k`B)J^o*C*v)6=1Bdq|99OP zCfT=#=A=EY|FZkyj76mkD)X0}3cp^Lzzs2U{r`-lx&W1{%KpB3xAsX#&*i`H@%P`T z4dNGM{_JmfHe)}t%Y6O@meUFM89%&v@>p=S$a7`~7L%)d8-?ccGYIx zZC{mtmG$4Yi7rW+uWW4WWB1oNM%A6a$8e^V!Gn)+f((;_WqlM|e0=<|w@*@P_Ut|V zyyw>b)VCi*8J=%nxGns2jc&3tW5eg)0XNsC&s(ufiov2@zWQzbc6a%Ub~&O=S;Bw* z{&{oz=E;gZF{_fR&atej-?w&aH)F%++X3tcr~UQbcK?=h=G&{$4CnIQGbhVEzg`zU zYx7RNhR>&aw)v*~yJl;`%5ZMI@hLam&)a%<#hVsQzV@zlYvrA<+YKigJ5HImpzEDt z32T7mezRk-`;R=$I=Q*wi3f9i!h6M|vF|(na22Gm-*tX}Y#l?zo|v%ro!MUzjt@Hl}?0{Nv`YYDfD6j9>EtID}rwF65gabID=hJwYzV zq`lH#m@n{O*#G0!b7}Yb^Os+;|7fdYn0QYVq2LPRBxfm&Yr7p4Jyw*rfF(h$xsa1| z^3C&)o4(I3e;vRhax9Nf!<#? zGjHVl6`HQ?`a@tx8Anv|`-4Yf|7SORUcBx7P3OzH2UJ(38$lvI*N$0$CDrYA+7ZQ4 zQwF%BM8i}p)s8i;mdROma<*dCOoW>3=9kmp00i_ I>zopr0N_R@rvLx| diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-2.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-2.png new file mode 100644 index 0000000000000000000000000000000000000000..b2528814b01a94d9c9cba3ea9dcc2fd85f8b84bf GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VA$^I z;usRq`gWSNP=f-Giz0ic`^9VCH>&b>a+ryo+o9O-hihAshump}gEvZV@2%WoFk2$_ z+`*qR^OD5+&Ypbe>AhmFqto#=p^JA8@$}oasw>y*Hdi>9G3V6n#}>63f}Xo_ENwg+ zLq5m+E9Uf;&e(XKEoybW@P>Vty^DFE$MdW6-F%W67#J8lUHx3v IIVCg!07@rlivR!s literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-3.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-3.png new file mode 100644 index 0000000000000000000000000000000000000000..235d30cb7c412548a5ea477754eec009d29d9778 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V0hx` z;usRq`gWQv-(dxw)`PDsPXylDI{n10;`Z((-dYQf9oxTzr&gG$-ljX@QBA$g_mT`v zRnIL~yUs;dOvusc-T2`EYmcA6hUCLc8+R@h`EtY5M&;4%tqiQm$-48ef8F|>$uMyG z*+a}*7npAUwA@=F_rTh@LOY`N>mRmm2Kacg+9yu|HyLg&ZL$p_p|&#&k1GB7YOc)I$ztaD0e F0szSQgrxug literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-4.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-4.png new file mode 100644 index 0000000000000000000000000000000000000000..d7650d87891a8fb3d68520030c947659370cf283 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V7Th( z;usRq`Zmm3tVMx`$C5)XHTS#Fw(56Zm2O3RFj186h_DdlH#%dZVD-|t-rU0ADUZ~j z>r>}^{}8x&e4$6E_MGMqa3i~_F`9pZ`^qTXxJY(dw*Wu6j lsaSd7P<@zm-w%Pe|DK)Bvb}!5i-CcG!PC{xWt~$(69Dd*ZJ+=E literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-5.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-5.png new file mode 100644 index 0000000000000000000000000000000000000000..54a79297d9118aab694b4a2d004abca35df98e41 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V0h)} z;usRq`ZnBCs6~ONWy<>l%g@9-7mlmlUUS5hN?dkvzkU7J@@(r> z%fkmB+FGr9$ef;-*W1RwwCNfz)3)3QMfaFf@pFH_by&&SX)(P%TkoMm%nHG09}bJN zWi1j->U|=xEr%)EI&*=!i&+iVmA1V{G`c7B7zG7W?VE?kpF@+2YT8uV3ACo`HdZ!PC{x JWt~$(69C!We;oh- literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-6.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-6.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab458be622b1b3ec3be54101c36d68114df72f0 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V0hr^ z;usRq`Zmmwk6Dpp%aZp8mT$TK??3C^{w?j>ItvBa#C`a!m-jXq&tiR6wA()JY4@oZ z0h{f?kRETDz&WUUD z;5U@MnAO6?@sW9^QiA;i#Y1n|m0UCG8h*8A2uf92{yh-?t?@Gd7KyXPBJF<~OwS7z x>BfI$eqrN&LRWB|(HzO`*XHdObmgvLE}1(!<($VQIR*v>22WQ%mvv4FO#lUocAEeI literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-7.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-7.png new file mode 100644 index 0000000000000000000000000000000000000000..b2528814b01a94d9c9cba3ea9dcc2fd85f8b84bf GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VA$^I z;usRq`gWSNP=f-Giz0ic`^9VCH>&b>a+ryo+o9O-hihAshump}gEvZV@2%WoFk2$_ z+`*qR^OD5+&Ypbe>AhmFqto#=p^JA8@$}oasw>y*Hdi>9G3V6n#}>63f}Xo_ENwg+ zLq5m+E9Uf;&e(XKEoybW@P>Vty^DFE$MdW6-F%W67#J8lUHx3v IIVCg!07@rlivR!s literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-8.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-8.png new file mode 100644 index 0000000000000000000000000000000000000000..b2528814b01a94d9c9cba3ea9dcc2fd85f8b84bf GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VA$^I z;usRq`gWSNP=f-Giz0ic`^9VCH>&b>a+ryo+o9O-hihAshump}gEvZV@2%WoFk2$_ z+`*qR^OD5+&Ypbe>AhmFqto#=p^JA8@$}oasw>y*Hdi>9G3V6n#}>63f}Xo_ENwg+ zLq5m+E9Uf;&e(XKEoybW@P>Vty^DFE$MdW6-F%W67#J8lUHx3v IIVCg!07@rlivR!s literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-9.png b/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-9.png new file mode 100644 index 0000000000000000000000000000000000000000..1c1918d0871397b6d773df5e61d06da456030983 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U^wIH z;usRq`gWS5P_qJ$Yv!@ymc?6c-}}!}HF4L5b14R#oL;YdP6~bc>Cf`F|M}~`p7&36 zoDBNBX~SdPstr0hZ!<4CuU%-aP;mR0Y1Em$zj}7Ob>KaeoOkv8JYiW4>F6Has$T~b ze7~%^^tgbd+NmI0o?+4HQr`1o)x3+(sPa!xTcn_HYfno<{EXm^-*=lBKh!e_+AFNQ zVk3|^?}c_pi$tXZYsb2Y>{o0i2>Q?E^vplS9CCvx@bc=)2H^^YHC1N(8E#@6>+k(l d+$B}OntZl4rRu;7H3kL-22WQ%mvv4FO#lyUaTfpp literal 0 HcmV?d00001 diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 7c68a43226..aeb94adadb 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -854,6 +854,7 @@ public class Blocks{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; + autotileMidVariants = 9; }}; coloredFloor = new ColoredFloor("colored-floor"){{ diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index e14a517f5b..da9b0154f3 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -80,13 +80,15 @@ public class Floor extends Block{ public int tilingVariants = 0; /** If true, this floor uses autotiling; variants are not supported. See https://github.com/GglLfr/tile-gen*/ public boolean autotile = false; + /** If >1, the middle region of the autotile has random variants. */ + public int autotileMidVariants = 1; /** If true (default), this floor will draw edges of other floors on itself. */ public boolean drawEdgeIn = true; /** If true (default), this floor will draw its edges onto other floors. */ public boolean drawEdgeOut = true; protected TextureRegion[][][] tilingRegions; - protected TextureRegion[] autotileRegions; + protected TextureRegion[] autotileRegions, autotileMidRegions; protected int tilingSize; protected TextureRegion[][] edges; protected Seq blenders = new Seq<>(); @@ -146,6 +148,12 @@ public class Floor extends Block{ if(autotile){ autotileRegions = TileBitmask.load(name); + if(autotileMidVariants > 1){ + autotileMidRegions = new TextureRegion[autotileMidVariants]; + for(int i = 0; i < autotileMidVariants; i++){ + autotileMidRegions[i] = Core.atlas.find((i == 0 ? name + "-13" : name + "-mid-" + (i + 1))); + } + } } if(Core.atlas.has(name + "-edge")){ @@ -234,7 +242,10 @@ public class Floor extends Block{ } } - Draw.rect(autotileRegions[TileBitmask.values[bits]], tile.worldx(), tile.worldy()); + int bit = TileBitmask.values[bits]; + TextureRegion region = bit == 13 && autotileMidVariants > 1 ? autotileMidRegions[variant(tile.x, tile.y, autotileMidRegions.length)] : autotileRegions[bit]; + + Draw.rect(region, tile.worldx(), tile.worldy()); }else{ Draw.rect(variantRegions[variant(tile.x, tile.y)], tile.worldx(), tile.worldy()); } @@ -251,7 +262,11 @@ public class Floor extends Block{ } public int variant(int x, int y){ - return Mathf.randomSeed(Point2.pack(x, y), 0, Math.max(0, variantRegions.length - 1)); + return variant(x, y, variantRegions.length); + } + + public int variant(int x, int y, int max){ + return Mathf.randomSeed(Point2.pack(x, y), 0, Math.max(0, max - 1)); } public void drawOverlay(Tile tile){ From fbd9a7c40a74e5623bc7e1dda9ee0d1d5862276e Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 14 Jul 2025 23:49:09 -0400 Subject: [PATCH 17/37] More floor stuff --- .../blocks/environment/crux-floor-8-autotile.png | Bin 0 -> 1085 bytes .../blocks/environment/crux-floor-9-autotile.png | Bin 0 -> 1698 bytes .../blocks/environment/crux-floor-generic.png | Bin 0 -> 1041 bytes .../blocks/environment/crux-floor-generic2.png | Bin 0 -> 779 bytes core/assets/icons/icons.properties | 2 ++ core/src/mindustry/content/Blocks.java | 14 +++++++++++++- .../world/blocks/environment/Floor.java | 2 +- .../mindustry/world/meta/BuildVisibility.java | 10 +++++----- 8 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-9-autotile.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-generic.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..f3bbc7bbc32af3c3d1c9e6ae44959b7e597bc630 GIT binary patch literal 1085 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 VlWfuG!oa}5;OXk;vd$@?2>@-qXqW&1 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-generic.png b/core/assets-raw/sprites/blocks/environment/crux-floor-generic.png new file mode 100644 index 0000000000000000000000000000000000000000..08b4c222d0bc0bd35c5d2845267016402bbc6252 GIT binary patch literal 1041 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&zxQX)jA8<&2<>TeCH}m^VX8y+ADWCXmp5o!&q!T%5{X^^Jw|T$q z{roaQ%>LTx`ThI%@7`9LaCqnIIjR57p1;1`x_oXV^Q(yG_jML>mg;=YpLT)e#?$*T z|Cu>+HlC<|ntjOfdF+ficKx4AzOuZz&p)|O`joxt?;F2*-`m%!8U4t7@}zY3|0%^s zrOBoD;i-u1OCcxzoi!{6TvJ%nHROkA+P{ra>A zPv4gQm(E)7{7&g~)~;ec&Ac7w(m3uPI%96J@A}uD{ZHjy9WIZ1&-0-A;nq%`f3{nV zJLhr+{pPsGw9IUw*V&w)Ye|~5Dx3$J3g)=)c38xk@ZoW#3g@IWh6+0Y2N@OtcE%%) z42467sUFo3d;8kkC!Ifj{@RwOIBSU{1Lv{IB?rrc^B6r0&aBJ5TeW*-*}I4!l`mWc zzih;^-CFG?D{_8&-=1W8EN-&W!_&84|0{pduR1I2>7CN)+J;jeUpP8#_TSRK7k)Nv zZ`e4Kq3z}RBP*F_&i?z=N8nXr32y_-<)1%)l|5fKyQapIv#leFMaj{sHf@^F9J~I- zUl-qJRdBS~9vSITQ0udzu0W6@H8S74T>Gb`zD|6t9oM{xcV;edt7VxnbE#(o1DlR# z)6_`uM-lbu7p}+u6k{{cpZ3%I+U1E>*M6FNXE@28{-fXRpt9kp*8l(aSQQ#|#eUx3 z%l#s}ecJp8Tjt>XtU6Qcb86o|XV|W0^yB4|lrW|LH+ceFXNf#Z%Xv|Hoi_=pVzQ2>bGb{}{LvGKCZx7`-Po{AKLfPFVdQ&MBb@0164cSpWb4 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png b/core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png new file mode 100644 index 0000000000000000000000000000000000000000..2c113a2cd6ab9d9c88426cf23013caa1afc9ded1 GIT binary patch literal 779 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z;x8p z#WAE}&f7b_d5;_f91@Q|;@~KIqG5b{=YP%*d`Dy_u@+6SH!mx{ef4nl{X8YZ)T#4j zgeS!R`}6nvw<@dBu0pvsy`ukr-xj?+cUYi|q2%K4_t6#{yH5Q5t}D~>=-d7Jf9--t zx^C3}|I6+skp24a`(=EKUhmQ`U+%Wi=j7bl-oNMP{(sE%;itl}h4cPA^(qhB^?&F3 znLH1EJ7(;hCAh}aUh=@diW73{c25$HNdDjd%%APS$@S{$O|yRcpY@Mp{PKr~;T*$* zp-8AP?}%M@TkfQAwe4K7{mY*H3;sMgoIzP*dhsWB({KMX{vD2Iber(LY-ic?M2&y; z*XG#2mOH>PO}bo6^x&PJyG{9>${)X5R42RS*>AlBWz%&m*=Nifc(+P4GUlw=%8_=T zdBwa-)lJho=kHHFW8R>kYF=9G|7Fh4-G4s@l$5V3n)v(u;(GOquJ8BfKU8?3^!@)w zy#pLcu5bUJzU`pgA-eIud_B8CQ$+Op|JS!S?%(Tg+LfC1=kETL|HaSM_X`;DeSM-I z{#f|Hq`&8D&mPuqsrdByYEQ!2pC=i<9e4g#aChpQ15&@w|8we4-#>2-N7g%g)BFC+ z4|y2Yy%&<#fAzDHwZWLdf*C@*-tBeY@bdqY+6;3T5B#iY;Qdjat^?1RSvvQvlzYCPdAG*N?Copj$1*T5FnGH9 KxvX 1){ autotileMidRegions = new TextureRegion[autotileMidVariants]; for(int i = 0; i < autotileMidVariants; i++){ - autotileMidRegions[i] = Core.atlas.find((i == 0 ? name + "-13" : name + "-mid-" + (i + 1))); + autotileMidRegions[i] = Core.atlas.find(i == 0 ? name + "-13" : name + "-mid-" + (i + 1)); } } } diff --git a/core/src/mindustry/world/meta/BuildVisibility.java b/core/src/mindustry/world/meta/BuildVisibility.java index 8b7042d6b0..c4809d2e62 100644 --- a/core/src/mindustry/world/meta/BuildVisibility.java +++ b/core/src/mindustry/world/meta/BuildVisibility.java @@ -11,15 +11,15 @@ public class BuildVisibility{ shown = new BuildVisibility(() -> true), debugOnly = new BuildVisibility(() -> false), editorOnly = new BuildVisibility(() -> Vars.state.rules.editor), - coreZoneOnly = new BuildVisibility(() -> Vars.indexer.isBlockPresent(Blocks.coreZone)), + coreZoneOnly = new BuildVisibility(() -> Vars.indexer.isBlockPresent(Blocks.coreZone) || !Vars.state.isGame()), worldProcessorOnly = new BuildVisibility(() -> Vars.state.rules.editor || Vars.state.rules.allowEditWorldProcessors), sandboxOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.infiniteResources), - campaignOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.isCampaign()), + campaignOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.isCampaign() || !Vars.state.isGame()), legacyLaunchPadOnly = new BuildVisibility(() -> (Vars.state == null || Vars.state.isCampaign() && Vars.state.getPlanet().campaignRules.legacyLaunchPads) && Blocks.advancedLaunchPad != null && Blocks.advancedLaunchPad.unlocked()), - notLegacyLaunchPadOnly = new BuildVisibility(() -> (Vars.state == null || Vars.state.rules.infiniteResources || Vars.state.isCampaign() && !Vars.state.getPlanet().campaignRules.legacyLaunchPads)), - lightingOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.lighting || Vars.state.isCampaign()), + notLegacyLaunchPadOnly = new BuildVisibility(() -> (Vars.state == null || !Vars.state.isGame() || Vars.state.rules.infiniteResources || Vars.state.isCampaign() && !Vars.state.getPlanet().campaignRules.legacyLaunchPads)), + lightingOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.lighting || Vars.state.isCampaign() || !Vars.state.isGame()), ammoOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.unitAmmo), - fogOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.fog || Vars.state.rules.editor); + fogOnly = new BuildVisibility(() -> Vars.state == null || Vars.state.rules.fog || Vars.state.rules.editor || !Vars.state.isGame()); private final Boolp visible; From ee1cbf5b0110bfb9df6d42832a29f1aaa3a1b76d Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 15 Jul 2025 01:29:38 -0400 Subject: [PATCH 18/37] another floor --- .../environment/crux-floor-10-autotile.png | Bin 0 -> 1047 bytes .../crux-floor-6-autotile-old.aseprite | Bin 1155 -> 0 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 8 +++++++- 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-10-autotile.png delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile-old.aseprite diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-10-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-10-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c0d9b491f46e4cb3e4c750c22ac74d0d47e4ba GIT binary patch literal 1047 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&zPoIorvL-vmHK>LMuiXUVvYzsl&K%i$oyqQJ)_@ci{P=I!tA_jNv5^5@sb%U}1I|BwC`p3czq{`lm> z9e?s~Mu;#R?N9dCQ~ta^?e#(ijXIlYbJCvFpM3Vr{J{S|b=A^U?|xQoot5W1y)gf1 z;@5nk0~td9Y@}!Mbiem5P}Dk}+k5y`eT8I(?ty#dAKq@ytSrl5`@o~2EV=nd-z?5= zT?I$%r5ztBFcbcbd8#$KA<_&vh^gqv*d zs!!I;XBa?Ys8(GLV{rd^Y~|%32KR5rR$lgFnAz&YGCxzbL7A(Cfd%; z%di$v`r*A=GNJq8y9kNnDh;QYQc91z9iO0ifakyF+lLoDUtCxet9wA_f2KX-)W1LH zCcW@`W!_+3DA@U4z&ZU=IHRo44aK%~K3lmODv+G8ytKOF%Ju4YiCvd=+1e~Rzs{Lw zuBWg=`@cVYh9&7;-#)zhSF_so)?wildIwg--a0J2QtyCd=2cmnqM+wLt788c$?Mj+ z$fPg4%JbkayLW8O85eEFm`U6&AMG#uF-%|L6!_=(7Lfz0I}$|dXKrI^NOnLEgY;eR z9?bl6j=>ld19LKO9d>^c{>x5@?dG?F?z@}s`3KyRTX%1MyzM`q|7&j_wk_KsozN4! zy?y@P3c(Fr0_=<(%?w8z5r)oLSlh6*Y|X^-y(@n0+n(CH_{;wG>U#&b-(U7L^0MCo z*G}1Y935X`P4lv4!u~&7n{f5pYrV&PeUBgdGpr5y7*SM}lKulncLO- zP1Y9dL{0OS3W)P>E|ffAtZ?-=qf&a)UL~22=iMeCr&);o1@;cf_rGu3A@6YEd)(|h z`~p1RnJr}IwCX*6R@dP9u#O>dhrENtJNAZa8w6GOn4sbJlfmHbU+ZalUkex*7#KWV L{an^LB{Ts5)dbZ9 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile-old.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile-old.aseprite deleted file mode 100644 index e3e57b82a49b5a0cc300e997f065e52fa66c56e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1155 zcmZo>VPJT$l#!u!?S*WGMo7{AZwq2 z`IJ2GO#L8l6(bu(#sZr+anf8_0ufQeZ~1`#;D<3_gjKsYMEgA zr>|c}vn}|&+m`?C{kN4b{^gx_{=WW0{l8y#S?=zd)%8B^V*RrHTMzb_7c^Ce{+Il> zn^&vc;^^K@^-K3}ceE<0zcrul?)-1doxd;t`|`ry%z8|r|NHY^JnVcY`|JI)_?^rz z?`^GLKmT3*ceYD^U$O1_-!cE){VL{{`*t}ptMe7^s(-zI^ZxGtn)mB> z{m(i)@vnBC#a{cD`8V@R{$I5AduM+;{@~=lCH1%LcmL%xe{-k)ivPF#()R_2*Zp<> zlk$J}JK4M&8~=ONhyK6!_NDZTe_Qr1`v2nF6JA2zTmLR2^_ke_`~|-+|GW4uG{0e2 z)ZD?uLc>|@&6p})Vt*s^`ZCuzsrB!e#c<(Z@%~IAN_v$Z_E65{=Z-T+x^?! zJmc@@-F5rx>i@62f4_b?)H}=nhL_(d4X+ITbs4Lt@Ba6x7q#9s|HAxlyZ8Uz{lED8 z{-X6a64Sq54wea`$U$x9Rza{^^2h*qi z?XA1daC_gP|108MVBlQqzyFt)JAW^)mfN-e_U8+K@6Ky~7yt14_xPRr|64sYpRt6z zq_z6bRP!$dUDc`ov+A$%t}eTAaqp`CI`v0+{g*!49sXth+v#;L{;dVMr_SyFZV

Date: Tue, 15 Jul 2025 11:45:56 -0400 Subject: [PATCH 19/37] Colored wall block --- .../environment/colored-wall-autotile.png | Bin 0 -> 760 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 16 +++- core/src/mindustry/world/Block.java | 10 ++- core/src/mindustry/world/Tile.java | 4 +- .../world/blocks/ConstructBlock.java | 4 +- .../blocks/environment/ColoredFloor.java | 3 +- .../world/blocks/environment/ColoredWall.java | 74 ++++++++++++++++++ .../world/blocks/environment/Floor.java | 3 - .../world/blocks/environment/RemoveOre.java | 2 +- .../world/blocks/environment/RemoveWall.java | 2 +- .../world/blocks/environment/StaticWall.java | 7 +- 12 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/colored-wall-autotile.png create mode 100644 core/src/mindustry/world/blocks/environment/ColoredWall.java diff --git a/core/assets-raw/sprites/blocks/environment/colored-wall-autotile.png b/core/assets-raw/sprites/blocks/environment/colored-wall-autotile.png new file mode 100644 index 0000000000000000000000000000000000000000..8af8c962832efbb8f69ae3c950687dc317a6d441 GIT binary patch literal 760 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z_iKJ z#WAE}&f7a1{SF0)G(5cZL8wPX@5~z;8|&3PlQx`8e&OKd@buERd*AMS_)(BGW?h9gb7r6TyZ!gwm6men64@QZ_x|73*1VwmPJQ%YM~%GyZ{Lc$ z31}z%fBQaP!g0;c@B1rC1bi>wxjR?tsDWkqH`QP~i&%W@Xmz%-WKPe2e-)4O&h_j8_>lG0%w16_jvj zn5FchR(QpxMft0C|Li_nHnp^TRn5fT`HS`4OD_J-&$i&$b>eS)K2xtk*p+|p@3Bfa zuIc#uzfwAbW#hAZ|M%xJ|Nnh^V<1oPqxb(Tf4{f3|JgVpZ-sjO4x#^yXKvQtzi#u_ zp+miX&m=(~Q+vq+X}hItW5g}hHyrurUaxRua{Rd&9A5A2P4CyU9mE+yKWiE!f7CD- z%;#r#_L=cOja|dK8oP!=_HoZYGin7Sv#=R#zNKW)z+me7;4@>B%l(k@&-DzCbT+mx U(k;|vU|?YIboFyt=akR{06An##sB~S literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 0904a6a2a9..4d5a8d6afb 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -611,3 +611,4 @@ 63071=crux-floor-8|block-crux-floor-8-ui 63070=crux-floor-9|block-crux-floor-9-ui 63069=crux-floor-10|block-crux-floor-10-ui +63068=colored-wall|block-colored-wall-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index a327d60fd7..12390fe663 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -58,8 +58,14 @@ public class Blocks{ //boulders shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, carbonBoulder, ferricBoulder, beryllicBoulder, yellowStoneBoulder, arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, + metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, cruxFloor7, cruxFloor8, cruxFloor9, cruxFloor10, coloredFloor, + //new metal floors + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, cruxFloor7, cruxFloor8, cruxFloor9, cruxFloor10, + + //colored + coloredFloor, coloredWall, + pebbles, tendrils, //ores @@ -883,6 +889,14 @@ public class Blocks{ 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) .each(b -> b.asFloor().wall = darkMetal); diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index c4989411b4..3884ad8041 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -566,6 +566,11 @@ public class Block extends UnlockableContent implements Senseable{ return forceDark; } + /** If true, the 'map edge' darkness will be applied to this block. */ + public boolean isDarkened(Tile tile){ + return solid && ((!synthetic() && fillsTile) || checkForceDark(tile)); + } + @Override public void setStats(){ super.setStats(); @@ -940,6 +945,9 @@ public class Block extends UnlockableContent implements Senseable{ return (envEnabled & env) != 0 && (envDisabled & env) == 0 && (envRequired == 0 || (envRequired & env) == envRequired); } + /** Called when this block is set on the specified tile. */ + public void blockChanged(Tile tile){} + /** Called when building of this block begins. */ public void placeBegan(Tile tile, Block previous){ @@ -951,7 +959,7 @@ public class Block extends UnlockableContent implements Senseable{ } /** Called when building of this block ends. */ - public void placeEnded(Tile tile, @Nullable Unit builder){ + public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index b4bd9d3a97..0a14cc438e 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -172,7 +172,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public boolean isDarkened(){ - return block.solid && ((!block.synthetic() && block.fillsTile) || block.checkForceDark(this)); + return block.isDarkened(this); } public Floor floor(){ @@ -280,6 +280,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{ changed(); changing = false; + + block.blockChanged(this); } public void setBlock(Block type, Team team){ diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 77f6288ab1..9a10dcbe3d 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -77,10 +77,8 @@ public class ConstructBlock extends Block{ if(block instanceof OverlayFloor overlay){ tile.setOverlay(overlay); - overlay.placed(tile, config); }else if(block instanceof Floor floor){ tile.setFloor(floor); - floor.placed(tile, config); }else{ tile.setBlock(block, team, rotation); } @@ -114,7 +112,7 @@ public class ConstructBlock extends Block{ if(shouldPlay()) block.placeSound.at(tile, block.placePitchChange ? calcPitch(true) : 1f); } - block.placeEnded(tile, builder); + block.placeEnded(tile, builder, config); Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 2a6b2b6a2d..7940de4f41 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -6,6 +6,7 @@ import arc.math.geom.*; import arc.util.*; import mindustry.*; import mindustry.entities.units.*; +import mindustry.gen.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -135,7 +136,7 @@ public class ColoredFloor extends Floor{ } @Override - public void placed(Tile tile, @Nullable Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ //config is assumed to be an integer RGBA color if(config instanceof Integer i){ tile.extraData = i; diff --git a/core/src/mindustry/world/blocks/environment/ColoredWall.java b/core/src/mindustry/world/blocks/environment/ColoredWall.java new file mode 100644 index 0000000000..68f568544f --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/ColoredWall.java @@ -0,0 +1,74 @@ +package mindustry.world.blocks.environment; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.util.*; +import mindustry.entities.units.*; +import mindustry.gen.*; +import mindustry.world.*; + +public class ColoredWall extends StaticWall{ + /** If the alpha value of the color is set to this value, different colors are ignored and no border is drawn. */ + public static final int flagIgnoreDifferentColor = 1; + /** If the alpha value of the color is set to this value, the wall will have darkness applied, as other walls do. */ + public static final int flagApplyDarkness = 2; + + public Color defaultColor = Color.white; + protected int defaultColorRgba; + + public ColoredWall(String name){ + super(name); + saveData = true; + } + + @Override + public void init(){ + super.init(); + 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 + Draw.color(tile.extraData | 0xff); + super.drawBase(tile); + Draw.color(); + } + + @Override + public void blockChanged(Tile tile){ + //reset to white + tile.extraData = defaultColorRgba; + } + + @Override + public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ + //config is assumed to be an integer RGBA color + if(config instanceof Integer i){ + tile.extraData = i; + } + } + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + if(plan.config instanceof Integer i){ + Draw.tint(Tmp.c1.set(i | 0xff)); + } + drawDefaultPlanRegion(plan, list); + } + + @Override + public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ + return other != null && other.block() == this && ((tile.extraData & flagIgnoreDifferentColor) != 0 || tile.extraData == other.extraData); + } + + @Override + public boolean isDarkened(Tile tile){ + return (tile.extraData & flagApplyDarkness) != 0; + } + + @Override + public int minimapColor(Tile tile){ + return tile.extraData | 0xff; + } +} diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 4bae99e420..d72565bc53 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -290,9 +290,6 @@ public class Floor extends Block{ /** Called when this floor is set on the specified tile. */ public void floorChanged(Tile tile){} - /** Called when this floor or overlay is placed on a tile. The config may be null. */ - public void placed(Tile tile, @Nullable Object config){} - /** @return whether to index this floor by flag */ public boolean shouldIndex(Tile tile){ return true; diff --git a/core/src/mindustry/world/blocks/environment/RemoveOre.java b/core/src/mindustry/world/blocks/environment/RemoveOre.java index b50d019c4f..88904f8aaa 100644 --- a/core/src/mindustry/world/blocks/environment/RemoveOre.java +++ b/core/src/mindustry/world/blocks/environment/RemoveOre.java @@ -44,7 +44,7 @@ public class RemoveOre extends OverlayFloor{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder){ + public void placeEnded(Tile tile, @Nullable Unit builder, Object config){ tile.setOverlay(Blocks.air); } diff --git a/core/src/mindustry/world/blocks/environment/RemoveWall.java b/core/src/mindustry/world/blocks/environment/RemoveWall.java index 0359ee7052..69bd0bcb34 100644 --- a/core/src/mindustry/world/blocks/environment/RemoveWall.java +++ b/core/src/mindustry/world/blocks/environment/RemoveWall.java @@ -43,7 +43,7 @@ public class RemoveWall extends Block{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder){ + public void placeEnded(Tile tile, @Nullable Unit builder, Object config){ tile.setBlock(Blocks.air); if(tile.overlay().wallOre){ tile.setOverlay(Blocks.air); diff --git a/core/src/mindustry/world/blocks/environment/StaticWall.java b/core/src/mindustry/world/blocks/environment/StaticWall.java index a287b2a419..fd48bf0c58 100644 --- a/core/src/mindustry/world/blocks/environment/StaticWall.java +++ b/core/src/mindustry/world/blocks/environment/StaticWall.java @@ -4,6 +4,7 @@ import arc.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; +import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.graphics.*; @@ -40,7 +41,7 @@ public class StaticWall extends Prop{ for(int i = 0; i < 8; i++){ Tile other = tile.nearby(Geometry.d8[i]); - if(other != null && other.block() == this){ + if(checkAutotileSame(tile, other)){ bits |= (1 << i); } } @@ -65,6 +66,10 @@ public class StaticWall extends Prop{ } } + public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ + return other != null && other.block() == this; + } + @Override public void load(){ super.load(); From cb7e027b2bd8922f42ecaf18b31a8fd19375d091 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 15 Jul 2025 14:45:50 -0400 Subject: [PATCH 20/37] Yet another floor --- .../environment/crux-floor-11-autotile1.png | Bin 0 -> 1375 bytes .../environment/crux-floor-11-autotile2.png | Bin 0 -> 1520 bytes .../environment/crux-floor-11-autotile3.png | Bin 0 -> 1457 bytes .../blocks/environment/crux-floor-11.aseprite | Bin 0 -> 41712 bytes .../environment/crux-floor-12-autotile1.png | Bin 0 -> 9554 bytes .../environment/crux-floor-12-autotile2.png | Bin 0 -> 7325 bytes .../environment/crux-floor-12-autotile3.png | Bin 0 -> 7280 bytes .../environment/crux-floor-12-autotile4.png | Bin 0 -> 7325 bytes core/assets/icons/icons.properties | 2 + core/src/mindustry/content/Blocks.java | 22 +++++++- .../mindustry/world/blocks/TileBitmask.java | 11 ++++ .../world/blocks/environment/Floor.java | 10 +++- tools/src/mindustry/tools/Generators.java | 50 ++++++++++-------- 13 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile1.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile2.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile3.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile1.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile2.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile3.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile4.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile1.png b/core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile1.png new file mode 100644 index 0000000000000000000000000000000000000000..3a5f16377bf0e0ff08d8841aed8d37838b2990cc GIT binary patch literal 1375 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 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..545f8a629a45a1887a6f35050411d5f9e0c21414 GIT binary patch literal 41712 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 F695_r9x?y` literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile3.png b/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile3.png new file mode 100644 index 0000000000000000000000000000000000000000..3a83d7cf9624b7c0c82c57c95ef4703e74ee818a GIT binary patch literal 7280 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 My85}Sb4q9e0CLFO7XSbN literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile4.png b/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile4.png new file mode 100644 index 0000000000000000000000000000000000000000..e70ee57e2264a5246341d9b5858663f405c4e30b GIT binary patch literal 7325 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 F695_r9x?y` literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 4d5a8d6afb..6ec07cd35a 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -612,3 +612,5 @@ 63070=crux-floor-9|block-crux-floor-9-ui 63069=crux-floor-10|block-crux-floor-10-ui 63068=colored-wall|block-colored-wall-ui +63067=crux-floor-11|block-crux-floor-11-ui +63066=crux-floor-12|block-crux-floor-12-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 12390fe663..19ddda6744 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -60,8 +60,11 @@ public class Blocks{ arkyicBoulder, crystalCluster, vibrantCrystalCluster, crystalBlocks, crystalOrbs, crystallineBoulder, redIceBoulder, rhyoliteBoulder, redStoneBoulder, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, + //old metal floors + darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, + //new metal floors - darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, cruxFloor7, cruxFloor8, cruxFloor9, cruxFloor10, + cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, cruxFloor7, cruxFloor8, cruxFloor9, cruxFloor10, cruxFloor11, cruxFloor12, //colored coloredFloor, coloredWall, @@ -881,6 +884,23 @@ public class Blocks{ drawEdgeIn = false; }}; + cruxFloor11 = new Floor("crux-floor-11"){{ + autotile = true; + drawEdgeOut = false; + drawEdgeIn = false; + autotileVariants = 3; + }}; + + cruxFloor12 = new Floor("crux-floor-12"){{ + autotile = true; + drawEdgeOut = false; + drawEdgeIn = false; + autotileVariants = 4; + emitLight = true; + lightRadius = 30f; + lightColor = Team.crux.color.cpy().a(0.3f); + }}; + coloredFloor = new ColoredFloor("colored-floor"){{ autotile = true; drawEdgeOut = false; diff --git a/core/src/mindustry/world/blocks/TileBitmask.java b/core/src/mindustry/world/blocks/TileBitmask.java index b8ebacf6a9..b27660ffaf 100644 --- a/core/src/mindustry/world/blocks/TileBitmask.java +++ b/core/src/mindustry/world/blocks/TileBitmask.java @@ -31,4 +31,15 @@ public class TileBitmask{ } return regions; } + + public static TextureRegion[][] loadVariants(String name, int variants){ + var regions = new TextureRegion[variants][47]; + for(int v = 0; v < variants; v++){ + for(int i = 0; i < 47; i++){ + regions[v][i] = Core.atlas.find(name + "-" + (v+1) + "-" + i); + } + } + + return regions; + } } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index d72565bc53..e00c183ec7 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -82,6 +82,8 @@ public class Floor extends Block{ public boolean autotile = false; /** If >1, the middle region of the autotile has random variants. */ public int autotileMidVariants = 1; + /** Variants of the main autotile sprite. */ + public int autotileVariants = 1; /** If true (default), this floor will draw edges of other floors on itself. */ public boolean drawEdgeIn = true; /** If true (default), this floor will draw its edges onto other floors. */ @@ -89,6 +91,7 @@ public class Floor extends Block{ protected TextureRegion[][][] tilingRegions; protected TextureRegion[] autotileRegions, autotileMidRegions; + protected TextureRegion[][] autotileVariantRegions; protected int tilingSize; protected TextureRegion[][] edges; protected Seq blenders = new Seq<>(); @@ -148,6 +151,9 @@ public class Floor extends Block{ if(autotile){ autotileRegions = TileBitmask.load(name); + if(autotileVariants > 1){ + autotileVariantRegions = TileBitmask.loadVariants(name, autotileVariants); + } if(autotileMidVariants > 1){ autotileMidRegions = new TextureRegion[autotileMidVariants]; for(int i = 0; i < autotileMidVariants; i++){ @@ -235,6 +241,8 @@ public class Floor extends Block{ }else if(autotile){ int bits = 0; + TextureRegion[] regions = autotileVariants > 1 ? autotileVariantRegions[variant(tile.x, tile.y, autotileVariantRegions.length)] : autotileRegions; + for(int i = 0; i < 8; i++){ Tile other = tile.nearby(Geometry.d8[i]); if(checkAutotileSame(tile, other)){ @@ -243,7 +251,7 @@ public class Floor extends Block{ } int bit = TileBitmask.values[bits]; - TextureRegion region = bit == 13 && autotileMidVariants > 1 ? autotileMidRegions[variant(tile.x, tile.y, autotileMidRegions.length)] : autotileRegions[bit]; + TextureRegion region = bit == 13 && autotileMidVariants > 1 ? autotileMidRegions[variant(tile.x, tile.y, autotileMidRegions.length)] : regions[bit]; Draw.rect(region, tile.worldx(), tile.worldy()); }else{ diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 4c5a847e6d..b092275e12 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -71,32 +71,36 @@ public class Generators{ generate("autotiles", () -> { for(Block block : content.blocks().select(b -> (b.isFloor() && b.asFloor().autotile) || (b instanceof StaticWall && ((StaticWall)b).autotile))){ - Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name + "-autotile.png"), iconPath = basePath.parent().child(block.name + ".png"); + int variants = block instanceof Floor f && f.autotileVariants > 1 ? f.autotileVariants : 1; + for(int v = 0; v < variants; v++){ + Fi basePath = new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name + "-autotile" + (variants <= 1 ? "" : "" + (v+1)) + ".png"), iconPath = basePath.parent().child(block.name + ".png"); - if(basePath.exists()){ - //theoretically this might not finish in time, but I doubt that will ever happen - mainExecutor.submit(() -> { - try{ - ImageTileGenerator.generate(basePath, block.name, new Fi("../../../assets-raw/sprites_out/blocks/environment/" + block.name)); - }catch(Throwable e){ - Log.err("Failed to autotile: " + block.name, e); - }finally{ - //the raw autotile source image must never be included, it isn't useful - basePath.delete(); + if(basePath.exists()){ + int variant = v; + //theoretically this might not finish in time, but I doubt that will ever happen + mainExecutor.submit(() -> { + try{ + ImageTileGenerator.generate(basePath, block.name + (variants <= 1 ? "" : "-" + (variant+1)), new Fi("../../../assets-raw/sprites_out/blocks/environment/" + (block.name + (variants <= 1 ? "" : "-" + (variant+1))))); + }catch(Throwable e){ + Log.err("Failed to autotile: " + block.name, e); + }finally{ + //the raw autotile source image must never be included, it isn't useful + basePath.delete(); + } + }); + + if(!iconPath.exists() && v == 0){ + //save the bottom right region as the "main" sprite for previews + Pixmap out = new Pixmap(basePath); + Pixmap cropped = out.crop(32, 32, 32, 32); + iconPath.writePng(cropped); + iconPath.parent().parent().parent().child("editor").child("editor-" + block.name + ".png").writePng(cropped); + out.dispose(); + gens.put(block, cropped); } - }); - - if(!iconPath.exists()){ - //save the bottom right region as the "main" sprite for previews - Pixmap out = new Pixmap(basePath); - Pixmap cropped = out.crop(32, 32, 32, 32); - iconPath.writePng(cropped); - iconPath.parent().parent().parent().child("editor").child("editor-" + block.name + ".png").writePng(cropped); - out.dispose(); - gens.put(block, cropped); + }else{ + Log.warn("Autotile floor '@' not found: @", block.name, basePath.absolutePath()); } - }else{ - Log.warn("Autotile floor '@' not found: @", block.name, basePath.absolutePath()); } } }); From 4c8f956fefa81bc5ace50a57389296c634670846 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 15 Jul 2025 14:59:58 -0400 Subject: [PATCH 21/37] Fixed colored wall data reset --- core/src/mindustry/io/SaveVersion.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index b6d55a6814..d05c91f501 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -322,11 +322,14 @@ public abstract class SaveVersion extends SaveFileReader{ //new data format (bit 3): 7 bytes (3x block-specific bytes + 1x 4-byte extra data int) boolean hadDataOld = (packedCheck & 2) != 0, hadDataNew = (packedCheck & 4) != 0; + byte data = 0, floorData = 0, overlayData = 0; + int extraData = 0; + if(hadDataNew){ - tile.data = stream.readByte(); - tile.floorData = stream.readByte(); - tile.overlayData = stream.readByte(); - tile.extraData = stream.readInt(); + data = stream.readByte(); + floorData = stream.readByte(); + overlayData = stream.readByte(); + extraData = stream.readInt(); } if(hadEntity){ @@ -338,6 +341,14 @@ public abstract class SaveVersion extends SaveFileReader{ tile.setBlock(block); } + //must be assigned after setBlock, because that can reset data + if(hadDataNew){ + tile.data = data; + tile.floorData = floorData; + tile.overlayData = overlayData; + tile.extraData = extraData; + } + if(hadEntity){ if(isCenter){ //only read entity for center blocks if(block.hasBuilding()){ @@ -357,8 +368,8 @@ public abstract class SaveVersion extends SaveFileReader{ context.onReadBuilding(); } }else if(hadDataOld || hadDataNew){ //never read consecutive blocks if there's any kind of data - tile.setBlock(block); if(hadDataOld){ + tile.setBlock(block); //the old data format was only read in the case where there is no building, and only contained a single byte tile.data = stream.readByte(); } From 24cfb000de8021625d4617842d5b4c13707034d0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Jul 2025 16:09:45 -0400 Subject: [PATCH 22/37] 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; From 64471cf8175835ddaaafdf99fe64926653ec35e5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Jul 2025 16:52:19 -0400 Subject: [PATCH 23/37] Block color pick fix --- .../environment/crux-floor-4-autotile.png | Bin 1147 -> 1161 bytes .../blocks/environment/crux-floor-4-mid-2.png | Bin 0 -> 261 bytes core/src/mindustry/content/Blocks.java | 1 + .../ui/fragments/PlacementFragment.java | 8 ++++---- 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-4-mid-2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png index 26d4509d07d8305c2cc435a6ff022076ce192ce2..ed83b0e931e642a8bddc998c48c8c5a18c78ffa4 100644 GIT binary patch delta 1127 zcmey((aAZ%u-@6z#WAE}&fB@ZMYj!jT0?#NCU}-zQM|Qoa_;$i-vqAd&Ag*{^NQrv zg*iejKN%j@?*7v=kH>bRg36)$^XAp>)z|c8Ih+}*p7Q7U_UYGOZdtcMxP#B?-{#iI z9ehS0N@2&3^S9+Qm~=XR+<)rV^kt#S&DWCu=lq-V*I$TDN}=Au#Gzo{6NYL7^A*qk zeRO;qG3m$j7vjAP-d?NZ+pb(R{&zH(!M9;)_@C8946_)#`+tP1H<~btz5OAs-Z))7 z@YC+-KY#x|e|3NV|34G|)~<_cyCy$V<+IG2h`Tc&{V9HlH;^sAC^TMlH9)vIfmb~X+^UI7^?1(0u#tZvBG4}P<7=d*3g?CYyc7cPBY z#Nx1ja>upnDKi+imCrvmH=>$n%f8TAJONTIcmDV8;mD{xZ4%0~-L#Z*E#sGU`Hjys z7d-8p=~jDp^FG#)d8`YvUp==L{CXhG^W@vZO4C<2$lQDHBGPWiFwv2j1#0(3#y#un z_bwLwuQ>HUT)_U={X6*z?xiT!S6VIKXum&Y@^Ot?mbJgMEE}$LZvXaNJ~qBvtTv;W z(k(&t$rA(Dik66R(oP zudsw>js^QzZzw4JC^^6;s8FlD!I4GUWx|OI3H?zcr?_D<-#Ppe>?kk_YdnkJ1nY&?M z-R<~K)RuMHy=L&z(R92oGU?T2hOYVw6Gq+zJ?6p(q+MhLOPV4U$EPrSu`;)^eSBUM z99XTk`^u%}Z|oCfijS;&u=qX4y+i*P zxNgl$tY=WoUBAJ;As{}xe&3YSpY0OXYX4?da9rPaL;e7RoUa43#^bXrHM)D4U#Lv{ z%gD#}n|VSWB;pSLV`$#^EzQ8ap>e_Y*bVj#jB92#urVZ@WYJ-1ba)<_{+Itt4Nu?d Ub+ZpMFfcH9y85}Sb4q9e02luZO#lD@ delta 1113 zcmeC={LL}Ju-??u#WAE}&fB?;MYj!jTw{IvCU};8QoOb9cJBFm-vmDD&AhYlu8HK; ziMf-QelkAX8!OYlkEeFBg36)!`)dDxd~R``{lbS5E7>U@=f};D=ks4a`3=ja#eM&u zJXG1VxCcZzi2u+0$*y)`QOEzgw>%x>y(aCQ_c8wR{IL6+nFs0_P99`9`EvquOw*kO z^L`&^-<-Vl$bOgo87vm(Hot6dw5mF`zk=%kOH|d-{aWlG`pAAO&Lb>QYaYkXVVO7I z=lKU$jH*wWwC7u7^w+b~8g*6Acr)7lIh~*{Tdd2F^>@XL zYm8M_HdfC*5M;098+^dD-b>FZ_d}N6nkajz5T?nOZJ55S@`=o@y7ax{rwBvx2BXDC z7*4Y*W>1T%zWBXGhkb|WgL{$NqV98FQVFOPyz)zKf)C^I$~yjiNh?BMS38+8U8&o> z#<*bXKJg{18y?%-UvvC@JX%#eKcnnlH|M46o9K zuKt?FV|?J#?evenYi!%1?rYEH36N^p`n`7#M^^3moK-A(*{^hScoRx$`E%wmZM$Q* zdBuA7Yu_7A?qw+Tz1v)OWwxtgIAa1kn+G2Z`E6!gw7!0Evgm)ssR!Z~?2oN4mVJ;r z+4b~Y%kIBF}zt5Z7|>#zL&eD&8nLv5C=EY2Wf-!o?NEx0#- z{k886H#rupnY!A0*BADN4G9fT;OK(9g2oqihxz{)=6wmhAg{1tpXe9%f(7zZ)0ivv zaAf`M$ayEWZ|bz2w^#o=@tZMw{$AJlRtmF`t$miTB>~InR(nY zo3{R9U=vs%$2l#4L+GLE`CYr~YbJ!R1E=^*i&Gs||0cIjKGA3N@4csj+J!}3|La#X z_$+W0{LjCdLI37UxsPG2HUaDmJQM0=cqYtw~cp((^a-7MbEB>mKZV&k^TT&%pfl#0B{S z9@bi4*fXwdzcv5PEyY0jfWwvFdN24NFyyNpU|_PD+2AyRqjcWaW&gzmZgUzl{N7!~ Qz`(%Z>FVdQ&MBb@02eqD{{R30 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-4-mid-2.png b/core/assets-raw/sprites/blocks/environment/crux-floor-4-mid-2.png new file mode 100644 index 0000000000000000000000000000000000000000..cc66f1c5f6b01fbaa432780006b79c3b2eea876b GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VA${J z;usRq`gZz8J_iGVw*D`IEo;*ZAC<0|7j6DXHey27dO^?kSv%?{Nx!qJza5{Nd-?5w zC5yBe85UgoweD%mVP_!*#(=zq(p8%hHyg&ieR!bM$Kt6jqno62S^RIwyUZIEH`Iln zz0F*pCOTDE&*g*2jY7|*xsiqJIUP48ZcLlX^T?Ea#as_L7bXP;9nT+<4Z=#&$6xN7 zlH@%3Im1?A{)P*;gPbb(3Y=Hy_a;03d3D?+ur4b$vHaWbP0l+XkKMIL16 literal 0 HcmV?d00001 diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index cf8a61d3b3..2399dedf31 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -841,6 +841,7 @@ public class Blocks{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; + autotileMidVariants = 2; }}; cruxFloor5 = new Floor("crux-floor-5"){{ diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index c64becb38d..2b1a0ef25c 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -138,10 +138,6 @@ public class PlacementFragment{ 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())){ tryBlock = req.block; @@ -157,6 +153,10 @@ public class PlacementFragment{ tile.floor() != Blocks.air ? tile.floor() : null; } + if(tryBlock != null && tryBlock.showColorEdit && tryConfig == null){ + tryConfig = tile.extraData; + } + if(tryBlock != null && ((tryBlock.isVisible() && unlocked(tryBlock)) || state.rules.editor)){ input.block = tryBlock; tryBlock.lastConfig = tryConfig; From 9b5ce972e954d77cd5c079bc96634814549b0bb8 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Jul 2025 20:32:11 -0400 Subject: [PATCH 24/37] Collapser color edit fix --- core/src/mindustry/ui/fragments/HudFragment.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index e7d68e8fb6..704fb279d7 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -95,7 +95,7 @@ public class HudFragment{ control.input.block.lastConfig = col.rgba8888(); } })).left().width(250f).pad(3f).row(); - }, () -> control.input.block != null && control.input.block.showColorEdit).growX().row(); + }, () -> control.input.block != null && control.input.block.showColorEdit).with(c -> c.setEnforceMinSize(true)).growX().row(); cont.add(pane).expandY().top().left(); rebuildBlockSelection(blockSelection, ""); diff --git a/gradle.properties b/gradle.properties index 4626577d07..65165c4661 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=f18ba925db +archash=e3a5a3a832 From 78c604946e9a3dce3e292f60f6e3f82943b47029 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Jul 2025 23:31:45 -0400 Subject: [PATCH 25/37] Bundle entries --- core/assets/bundles/bundle.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 24dc105d5b..29e9f835f7 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1680,6 +1680,8 @@ block.metal-floor-3.name = Metal Floor 3 block.metal-floor-4.name = Metal Floor 4 block.metal-floor-5.name = Metal Floor 5 block.metal-floor-damaged.name = Damaged Metal Floor +block.colored-floor.name = Colored Floor +block.colored-wall.name = Colored Wall block.dark-panel-1.name = Dark Panel 1 block.dark-panel-2.name = Dark Panel 2 block.dark-panel-3.name = Dark Panel 3 From 4abc2aba8cc6e6401e007eeab91e4e3c6ee81125 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Jul 2025 13:57:07 -0400 Subject: [PATCH 26/37] Character overlay block --- .../character-overlay/character-overlay.png | Bin 0 -> 173 bytes .../character-overlay/character-overlay0.png | Bin 0 -> 173 bytes .../character-overlay/character-overlay1.png | Bin 0 -> 225 bytes .../character-overlay/character-overlay10.png | Bin 0 -> 202 bytes .../character-overlay/character-overlay11.png | Bin 0 -> 101 bytes .../character-overlay/character-overlay12.png | Bin 0 -> 175 bytes .../character-overlay/character-overlay13.png | Bin 0 -> 227 bytes .../character-overlay/character-overlay14.png | Bin 0 -> 205 bytes .../character-overlay/character-overlay15.png | Bin 0 -> 174 bytes .../character-overlay/character-overlay16.png | Bin 0 -> 298 bytes .../character-overlay/character-overlay17.png | Bin 0 -> 201 bytes .../character-overlay/character-overlay18.png | Bin 0 -> 186 bytes .../character-overlay/character-overlay19.png | Bin 0 -> 102 bytes .../character-overlay/character-overlay2.png | Bin 0 -> 174 bytes .../character-overlay/character-overlay20.png | Bin 0 -> 165 bytes .../character-overlay/character-overlay21.png | Bin 0 -> 237 bytes .../character-overlay/character-overlay22.png | Bin 0 -> 167 bytes .../character-overlay/character-overlay23.png | Bin 0 -> 249 bytes .../character-overlay/character-overlay24.png | Bin 0 -> 243 bytes .../character-overlay/character-overlay25.png | Bin 0 -> 194 bytes .../character-overlay/character-overlay26.png | Bin 0 -> 105 bytes .../character-overlay/character-overlay27.png | Bin 0 -> 191 bytes .../character-overlay/character-overlay28.png | Bin 0 -> 267 bytes .../character-overlay/character-overlay29.png | Bin 0 -> 234 bytes .../character-overlay/character-overlay3.png | Bin 0 -> 172 bytes .../character-overlay/character-overlay30.png | Bin 0 -> 145 bytes .../character-overlay/character-overlay31.png | Bin 0 -> 178 bytes .../character-overlay/character-overlay32.png | Bin 0 -> 161 bytes .../character-overlay/character-overlay33.png | Bin 0 -> 362 bytes .../character-overlay/character-overlay34.png | Bin 0 -> 187 bytes .../character-overlay/character-overlay35.png | Bin 0 -> 208 bytes .../character-overlay/character-overlay36.png | Bin 0 -> 85 bytes .../character-overlay/character-overlay37.png | Bin 0 -> 83 bytes .../character-overlay/character-overlay38.png | Bin 0 -> 170 bytes .../character-overlay/character-overlay39.png | Bin 0 -> 72 bytes .../character-overlay/character-overlay4.png | Bin 0 -> 107 bytes .../character-overlay/character-overlay40.png | Bin 0 -> 84 bytes .../character-overlay/character-overlay41.png | Bin 0 -> 100 bytes .../character-overlay/character-overlay42.png | Bin 0 -> 84 bytes .../character-overlay/character-overlay43.png | Bin 0 -> 156 bytes .../character-overlay/character-overlay44.png | Bin 0 -> 159 bytes .../character-overlay/character-overlay45.png | Bin 0 -> 92 bytes .../character-overlay/character-overlay46.png | Bin 0 -> 93 bytes .../character-overlay/character-overlay47.png | Bin 0 -> 167 bytes .../character-overlay/character-overlay48.png | Bin 0 -> 173 bytes .../character-overlay/character-overlay49.png | Bin 0 -> 208 bytes .../character-overlay/character-overlay5.png | Bin 0 -> 106 bytes .../character-overlay/character-overlay50.png | Bin 0 -> 200 bytes .../character-overlay/character-overlay51.png | Bin 0 -> 74 bytes .../character-overlay/character-overlay52.png | Bin 0 -> 153 bytes .../character-overlay/character-overlay53.png | Bin 0 -> 179 bytes .../character-overlay/character-overlay54.png | Bin 0 -> 156 bytes .../character-overlay/character-overlay55.png | Bin 0 -> 125 bytes .../character-overlay/character-overlay56.png | Bin 0 -> 75 bytes .../character-overlay/character-overlay57.png | Bin 0 -> 311 bytes .../character-overlay/character-overlay58.png | Bin 0 -> 99 bytes .../character-overlay/character-overlay59.png | Bin 0 -> 89 bytes .../character-overlay/character-overlay6.png | Bin 0 -> 183 bytes .../character-overlay/character-overlay60.png | Bin 0 -> 118 bytes .../character-overlay/character-overlay61.png | Bin 0 -> 77 bytes .../character-overlay/character-overlay62.png | Bin 0 -> 262 bytes .../character-overlay/character-overlay63.png | Bin 0 -> 192 bytes .../character-overlay/character-overlay7.png | Bin 0 -> 105 bytes .../character-overlay/character-overlay8.png | Bin 0 -> 105 bytes .../character-overlay/character-overlay9.png | Bin 0 -> 161 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 5 ++ core/src/mindustry/world/Block.java | 2 +- .../world/blocks/ConstructBlock.java | 2 +- .../blocks/environment/CharacterOverlay.java | 54 ++++++++++++++++++ .../blocks/environment/ColoredFloor.java | 2 +- .../world/blocks/environment/ColoredWall.java | 2 +- .../world/blocks/environment/RemoveOre.java | 2 +- .../world/blocks/environment/RemoveWall.java | 2 +- 74 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay0.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay1.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay10.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay11.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay12.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay13.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay14.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay15.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay16.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay17.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay18.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay19.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay2.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay20.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay21.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay22.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay23.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay24.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay25.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay26.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay27.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay28.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay29.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay3.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay30.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay31.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay32.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay33.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay34.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay35.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay36.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay37.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay38.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay39.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay4.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay40.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay41.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay42.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay43.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay44.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay45.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay46.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay47.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay48.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay49.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay5.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay50.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay51.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay52.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay53.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay54.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay55.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay56.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay57.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay58.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay59.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay6.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay60.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay61.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay62.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay63.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay7.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay8.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay9.png create mode 100644 core/src/mindustry/world/blocks/environment/CharacterOverlay.java diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..5a9c7dbf458765f738ff0b63647282a8deed529a GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+N<3X0Ln`LHy&TBZpup4c z(AKl$fA*@o38@wrI(f1=uh!joy^md1L1{x|UuVUB-S?}$6`#>ejGdC~D7ZMO)2=sA zQQClc^#zt+oDxqHmCDo_Urt|pW1e6Bk>?W~%p0b@NG%XqZ1~~$f+{wtA9Wvox92Zt b^tGN@5wic7mg^Y?1_lOCS3j3^P6ejGdC~D7ZMO)2=sA zQQClc^#zt+oDxqHmCDo_Urt|pW1e6Bk>?W~%p0b@NG%XqZ1~~$f+{wtA9Wvox92Zt b^tGN@5wic7mg^Y?1_lOCS3j3^P6Z_Cz;;WwCk z6STjuMK4m%={=SqI4h=nLh1?8D{F3KFuy8|D_B;4k@L#xn;Ne+*D>DveBV*uBG@XU^_~N_ h3FFp_;Resx{N8PDXUyQ8#=yY9;OXk;vd$@?2>{mWTPgqm literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay10.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay10.png new file mode 100644 index 0000000000000000000000000000000000000000..141d0fb7069b1c8a3692619c10735decdba8e610 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+CVIL!hE&W+{?RXQFro9K zlttFV6|FBK=FSt7V*F@d6`A3FKxb9d3)h}hhYQ}k+{&F>*2pfIH=*?k6Yu|pd`sF} zOaD)FYPlvh?XP<`Q&dz1+g+omXbz^CU$zOb1ii>r@pdj#rA%>r055L)sO|=3tBGc9|FfcH9y85}Sb4q9e E0K7LFXaE2J literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay12.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay12.png new file mode 100644 index 0000000000000000000000000000000000000000..1f8832639e252e7f4685597cc5eeda4f02eafc4b GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+$~;{hLn`LHy<*7KV8FwA zVUDBAk>B!;0ql-PtFKzHxO8`V7XFg|7xrnI+LSM6?zDM(Y3HryRc6+R+_6^tQ^Ta* z+qJDq2^tLb?C!_UXfmDJzWu=Seb;XJa97;juJ}34_x#}imOY27PsukuTCkLXk%@&v eK;gi2nO`DO+jtZc?HCvs7(8A5T-G@yGywn)xj;ey literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay13.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay13.png new file mode 100644 index 0000000000000000000000000000000000000000..e68bca7993cc75dcc122f586d355171ea14c1fe3 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+R(ZNOhE&Yidohu#*+7K( z!Mx;-y{nrx@$&C_c`iWwMuLXfzHhpXe>Q!cEOBY)k@Dt+?I-R2ob={Znk?nANGj%v zLQ#0LM@Vx{RJp)O-{0Z_nR^dPSJs*28cNvdr^-L&+V;f9>v!gAhc8~|a+j}VTYGs| z!?es;hZ2?N`!DZmeBtvh<$pQnjS1FYTEhfnuPFQqX?DGQts!GQ+u6%i4a+iZ9kv8F gzi{S_JJ+E7W>JJ{eLVMP1_lNOPgg&ebxsLQ0B_`8-v9sr literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay14.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay14.png new file mode 100644 index 0000000000000000000000000000000000000000..843026085b3d2c4a47a36cd4b665a8e7f18f5f41 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+rg*wIhE&XXd(E4#L4k+m z!n%%+|E{y_aTHCS+?2%X9qw~UH~(NhgW$p$PiJ)e-yEBr`g;0|;6tl2I$2$Nge#e!*+d#qRv3hhB{}^Y7^KhFeX$Q(&eY0fBn%Q=9jW#R!7;ky?el?Rt7{}Gt-3$y244$rj JF6*2UngA`FP)h&+ literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay15.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay15.png new file mode 100644 index 0000000000000000000000000000000000000000..eff3d5a3e675bd91b2cc2080ae32f46621b9a430 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+N^hRK|z4! zg01WS|MR2j6Rg`09pKt3>r$4mZr|ZU>n6R~lpVhIiKz32j;Q7n(-!jxblz&^jMETy zVUqTVUl1Zz+~xDZW#xm{v-$Y!of8(a|FI3umwKglv~y8x_ie#>uO6BI&5SZXn=D&W dQ1gKyD_;52tqH#;F)%PNc)I$ztaD0e0sxdcL(l*K literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay16.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay16.png new file mode 100644 index 0000000000000000000000000000000000000000..aa28a073ff6d0f1586fb74ae8546d43f226f1da5 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+K6<)1hE&YCdu=1%Aq4@3 z05<1eqI&;k9kj4`^(g7meA8pAR_mQGUFxW@_wfRrxFToi2fQ-uPT9J9a(wJc>+bk^ z)z`{TZrz~qD!ISuhRQAzu?40ZKyY5X)UUu`mpNdWH<$B924}b6OxOpS!;G~5*5ucgv-3|+R+5 z8}G%WpTy6(W4vFA`JhwJ2U$oKO-(=sK`&o`pU4;`F7#J8lUHx3vIVCg! E0Kz1FyZ`_I literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay17.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay17.png new file mode 100644 index 0000000000000000000000000000000000000000..223dd714f767d89e85aa92f53eca9210936aaa80 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+CV09yhE&XXd)1q(!GMS5 z!kQz^T?;DM^>bF6cl0K_bTT~wDa!xEJCbdHUXO`t}_?q~dA^=(Z%%@=QE!Q=@}|zz;^9NiMYlr}CcXvIuJ-dH5Q?|-CR-U6mJ_ZL_mQP%7_VW{;Kl@Yp4S$YISoFC0QhpG>*M*xe dg8cuoAA9s!NL=ED3IhWJgQu&X%Q~loCIFh(LCOFC literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay20.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay20.png new file mode 100644 index 0000000000000000000000000000000000000000..a1979e512c999364b84d243b8849fffec736a69c GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+ay(reLn`LHz2wMsK!Jzl zz?`NZ|MR1MGiN&-+$OZbP5*A|-cDu1DPJxmT;*nDV&M=_aA>G!uVi>E`Qgl0`Hcq5 zv)moNx*p>!| zZRd~7O=~(7e(ZnOq#*ZaUThY((z+!lm!#%PzF0d`e3>Wr@zowSYZfx{W;ifQeb|2> zo$1X)=087zH4~l&9%hPXDhXpyU2lG6YB>La8yfs>t#SXX?4p*uG`n;4$VQ_Bo-1tU zyWW24aX@O}Gj-Xw)-8{sZl;u{F7cV=cKWV;DTBb>%N~h+AKH(e2bce`ayx5AToUFZO#>d~A`pkc!6y1;-|q%LmzdUpV}o z|A4pkc0jn$mkVDC&*eMj>aA!zbk;KAqu?4Qn~Ms+u4l8ASN?n9xq&SvUO~8qvGAkR Wt~JZMPBAbrFnGH9xvX zw%x}fd$uQ&+&IK{Ml)8!Bul7^TF~@f@?1JO!<3b-lm7b zwl)h2S7|0|vZONHxIVS$sEy)&mIeJQ!#H(V7VOO8`>=lDP8OE4smo2f`~AKu%s(Kt z`$tDpO>WHHD^8z81U6lrtA3JkU2TKLnF{ti2@3}E&!R=|Z_k{`z`(%Z>FVdQ&MBb@ E0Q{tALI3~& literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay24.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay24.png new file mode 100644 index 0000000000000000000000000000000000000000..7950a087436f4a8ceaef93483ac7828ecb1a1363 GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0y~yV31~DV36TpV_;yIaPi1n1_p**o-U3d6?2k*^vfGe zX#6N;mUVMQ>f&jM3}!;QNsEtcig(CyTH@*!@HHixjd?R?gvne9=Z>vBEOE>mC1$BA zIsBOv!R#RAHz`4pV~O+Eqmx&>S2@#a=&^y!y$$@eJ40 z?J6l^pbP0l+XkK1Q%QM literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay25.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay25.png new file mode 100644 index 0000000000000000000000000000000000000000..a3c57307a604877110723f7d9c2d568a5a6ba3e6 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+Iz3$+Ln`LHy_Cz=UDt$bS8BZZ23HP6q1#siA0*h{J@}^h3dsdk#T}xgdutG9al(je^ x_x=0XYfrIn4lg{Y$M#6f&7YC`N9_le4%>*u6BQmhFfcGMc)I$ztaD0e0su?kL@EFP literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay26.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay26.png new file mode 100644 index 0000000000000000000000000000000000000000..222f1101b69d81eff0312e7b3a9d2543aee18566 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+3_M*NLn`JZ|M0gx;J}k6 zv9;jJA;m;R&5A3B0=eCFWkCFiS&Fd-SF|n`gdgQu&X%Q~lo FCIEtaA0Ge! literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay27.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay27.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad359a4016c6e8e26adf7a606b3a9de99a58671 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T++B{txLn`LHy<*GNV8GM% zkWWeO;P3mVrGIR6Hc+%i9SN_g}ufF#lxYX0bAM>#U1Mk_-}7n;lc&Nfu}`{3ZKY)uCNPsJD5ERTI(IPkNjg`U|{fc^>bP0l+XkK-e*f{ literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay28.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay28.png new file mode 100644 index 0000000000000000000000000000000000000000..66247afac4830bb69a3f6ab3cf06d55918f2c984 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0y~yV31{CV36TpV_;yIdw$C*1_p*po-U3d6?2YGv*tSF zAmZAt;CRI8$f0YtFO*`M_eyWrzP;4{-9ga#FnGH9xvX<0 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay29.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay29.png new file mode 100644 index 0000000000000000000000000000000000000000..59d18b41b0cbe99a3b4c1135a140e4478183fada GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+HhQ`^hE&XXdwC)Ep#Xv7 z9}SOeNHDs2X7%ZRFV(tJ6I~5B4kaW`Yh@MOd-t%_y}xjjv!cfF#=PhRE0}Xfg8gTO5I4eB)z-n_bX8i-X?)USJ%GNV!GrZoZ z^C>|>hw;tHTqOyfd5mw4=CblI`7?ZbR>q*#^%cc*u zCpP^rSvAk@PrHiRt}E>t(=Og};yLXg!QkpX`7z6ZQ|}lU7#KWV{an^LB{Ts5Dr7bb literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay31.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay31.png new file mode 100644 index 0000000000000000000000000000000000000000..e089f729bc4bab862a3076734a20a74772568301 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+Dm`5sLn`LHy=KVOV8FwA zfltY{>AU^(@C#Qzn)5XZwK{q36Z`e>e7=X*WCoSXp;ZbRA!nK%M(_q1ux8F^GVyWD zih7_I`{B;BciSAyUu<7ct!8oXd~Jm@`Z=7MUwpAGMYAEz{hY>_iz-FjQJ hZ{OOI7dImqwCxv0{W84uf`Ng7!PC{xWt~$(696*mMr!~7 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay32.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay32.png new file mode 100644 index 0000000000000000000000000000000000000000..d4ec76b6b0f9105bb87a8387d505044903ff5a52 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+GCW-zLn`LHy==&Jz<|d& zaPscfOVQ@)*~TUlG}q?b6xi_KeEy_62Pd-#-(mWqaj^E_rPcQyIII&*VO4bDUM0w~ zL?K>5cIGvw3HN?VDG8pq^J$4r3+F$lH3~f$4#G_h?97f1Qd1U4|6ow@d1eu(TC#$H Pfq}u()z4*}Q$iB}UmZBO literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay33.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay33.png new file mode 100644 index 0000000000000000000000000000000000000000..52ac59e9f137e8fcad8c7c281311e4b461fbe3c0 GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0y~yV31>AV36TpV_;w?`@z4Gfq~J`)5S5QV$R-chJ1{U zB5V(OJ35@EC@m6fb<>ub>-OaJzEQ~v)a z@9&*apLs*lo#UZI)U>^w|Bbi5d0((-MyP~Ep2+5jzBd!}M2aW)zBVxLvOJk4;Ky~e zVpC+pcFsjJ_zvVIWvJ`ab9!qZsY_ot=c8W22gTXl4Bt6+EIm}3R3RjEc3=Gp-Re1^ z;<_9*eI`ByoszNI)83ypO>4<^G$_5c|JY?2d7G3bMOW!Li7txD(s$C^6f0%hv|r0@ zNYLD3ylIQW0cY8FLfo?y6JJcZ@w(XBaXn-6bPkOzjt7`qVv{~d2(Azr&q@cQY>dkZ}u%zwVFuCe%$@zGDUMms;~UtuYJ5Zs*D^7u%v#uv_nmAY#L Uu6!3_U|?YIboFyt=akR{03`>PLjV8( literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay34.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay34.png new file mode 100644 index 0000000000000000000000000000000000000000..dbfe5c1a0d368e12cb6d2aa3d5d31451d98f1c59 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+nmk<`Ln`LHz2?Z(pdirt zFtVkjUw-ig_WsSJ7`1e-2^qpY6G|IgN!qr&39aR=;d&R$ujOV%YmDY7Z?~A O7(8A5T-G@yGywp;<4r#R literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay36.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay36.png new file mode 100644 index 0000000000000000000000000000000000000000..824b5ecbd57ddc5c1645c66c9e2488858c2c664a GIT binary patch literal 85 zcmeAS@N?(olHy`uVBq!ia0y~yU=U?sVBq6mV_;x7z!rXvfq_BB)5S5QVovgpetClj q2P;f_rL3}EtXR0XE$C%6p^fq_BF)5S5QVovgpes+T% nuRa~mIWvq-Hh$pZRbf2k{6j@VV7?p!0|SGntDnm{r-UW|@~;(9 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay38.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay38.png new file mode 100644 index 0000000000000000000000000000000000000000..c53246b16f015188b6afc164860c06097735e475 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+3O!vMLn`LHy&BEcpdjFu z*xB)I|Gry};^hXtO%p}GUYaxgS^MWdiXChlZ!am0vJm4r7=1-*&jOZ+g(5o^tIPshY7+HidTMg|5322WQ%mvv4FO#tHfLdF09 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay39.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay39.png new file mode 100644 index 0000000000000000000000000000000000000000..137b74e5c3c5286c49cc1533a896247d2e882b95 GIT binary patch literal 72 zcmeAS@N?(olHy`uVBq!ia0y~yU|wjhB3 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay40.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay40.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f0afde33a5416cdcc2405c780de484d7d41241 GIT binary patch literal 84 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8VBq6mV_;zTnfPof0|SG!r;B4q#hm0H|NqzD ptyf|^ydufu=!=RF!@w@arw`nG7FRX0FfcGMc)I$ztaD0e0sxth8T0@E literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay41.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay41.png new file mode 100644 index 0000000000000000000000000000000000000000..42c5f79fba7a1c23ecede1b655c0e503d67f6ae7 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8V36TpV_;y|Uhm4vz`&sG>EaktF(>)Q|Nr*P zQpY$ii1ulzN%d>Fg~zn(=UhBo8DhBUk>ji%?7Nc~(v~}Chv)6t%D}+D;OXk;vd$@? F2>{_g9w`6- literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay42.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay42.png new file mode 100644 index 0000000000000000000000000000000000000000..82a60429967798d278c7155b49b98669312a21a3 GIT binary patch literal 84 zcmeAS@N?(olHy`uVBq!ia0y~yU|?rpV36TpV_;xd>%6p^fq_BV)5S5QVovgpes%*M oOV2qKAw>+TAKh+Vn8?D=skyq)f4@sT0|Nttr>mdKI;Vst00sRPGynhq literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay43.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay43.png new file mode 100644 index 0000000000000000000000000000000000000000..647e892e9b1344e11d400619ec5115efd85999b5 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8V36TpV_;y|Uhm4vz`&5~>EaktG3V_SN3H`3 zJS+$1)Rfh)iNDb`^@7=~oW54JqS>xT1sE09>+RLfk<~G|(abO7c$6pPjKk5K)*TOb zJ*$Xr5jBda`%^gQ*SjkUceU;Rq{_J`nk9raibv?pj6IN0UOQJOra-XbMN$j{0|SGn LtDnm{r-UW|`S&-9 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay44.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay44.png new file mode 100644 index 0000000000000000000000000000000000000000..34ca5e76d7b26cbb64335f9f1a913ea6776a454a GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8V36TpV_;y|Uhm4vz`&5^>EaktG3V{&jeHFT z94rCLj;;UJy>@?rQ@dN!v}BWwCv)G6aWN&h*R(Iod?HtQu)kH5ua##vQ*(Ob(ZvA= z^Gs$xOWC+IbiD$up;=pI!BeKH;sVYG`(8^h QFfcH9y85}Sb4q9e0KWA-)c^nh literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay45.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay45.png new file mode 100644 index 0000000000000000000000000000000000000000..92d3445a059b962f159a6a7014114fad5661c868 GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8V36TpV_;y|Uhm4vz`&sF>EaktF(>(lzs-td wiBO-WB(@ZrRTUwIu_DUN3nvA?SR%o|b-QP}QQ4n83=9kmp00i_>zopr0JduxVgLXD literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay46.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay46.png new file mode 100644 index 0000000000000000000000000000000000000000..f317416479f7b41f53cb0eb2983b8d9a55ed661d GIT binary patch literal 93 zcmeAS@N?(olHy`uVBq!ia0y~yVBlt8V36TpV_;y|Uhm4vz`&s5>EaktF(>)Q|Nr%O y>y;P}uShaE`l2G_l7_J5PO#e_Ve1n03fx*+&&t;ucLK6UTs2y_v literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay47.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay47.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1e8c3e4d7b98303e0d7ff99165f4bb40722099 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9U=ZS9V_;xtnb!j1X+y=bEecE{^UCQwP6ek65=*o|9sw8QvML@Cf$$?IjTVm9tJxe z51DoIVJzdp+4mzO#C$F^?@VZn^VzxO{D-8k43{r7pSAXPj?v{+{8?=_&)2!rx!_2m c$4>@>|LePts@_p!U|?YIboFyt=akR{0Egf~zyJUM literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay49.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay49.png new file mode 100644 index 0000000000000000000000000000000000000000..1ac7f7e4393a4713cfb134109b4d7867477896d4 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vO!stg45^rNc8WJwgMona zZjtF6BIwtM(*nlSImj~`8XFWuOttAt2hHd|iu_wmyAmM46yG7c{B_!_uW z(sQxC=DYcIUiB~k6)z28(BhcsowaNEMQzopr0D4qX6#xJL literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay5.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay5.png new file mode 100644 index 0000000000000000000000000000000000000000..8a81bdb30612df97ee4af0e2f1a64222fc69a538 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+3_V>OLn`JZ|L{*gV3752 zMXU2YC$_A|f!yx8GQY$oal7ftY%P$8w)kWGZ$;~3v7`is?D~7_zT8P~Vqjok@O1Ta JS?83{1OU)_A({XH literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay50.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay50.png new file mode 100644 index 0000000000000000000000000000000000000000..3503ef30132e4bcc34d1d0cf07e77a8c55bd49f5 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=v^n1EEhE&YCI>nl=K|#Pp zv)BBx#NMS+z2(7Mj^Df?pindYkZ0WQwl_>pH+LRjs=B~1v8%wN+dFB=Nma{B37qX$ z&O|z|TIE@qp=KgIYvPkhv$iC#NLTDwvThQm%$y+EZQD(Txl1_lNOPgg&ebxsLQ E0IJ(gasU7T literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay51.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay51.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0ceb258085ae8357b48705b7ee0f39ed25db4a GIT binary patch literal 74 zcmeAS@N?(olHy`uVBq!ia0y~yU|?flU=ZQ}krmzRk1{YY2zt6WhE&W+{?X5D(Bs9! b%gNwlu`WTrZtpAx1_lOCS3j3^P6k_ba4!+nDh4XMqUO* z9_PSi3I84a)`;~f2{|3y6f3MLtG|Dds|$0rY>OPr?N|#Lj_m(6VY#x~vR=;(U9A8@ z){3##im|sBhTL8l;;nIA=+xGhqTa^T-p1?s-xV5!l|z!M&XpX}VPIfj@O1TaS?83{ F1OWZlGM)ec literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay53.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay53.png new file mode 100644 index 0000000000000000000000000000000000000000..2fcf13e3cc1055731b848f45097ad1defea17149 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0y~yV31{CV36TpV_;yIdw$C*1_p*IPZ!6KiaBqu9pr2< z;Awq0Pv!vQoq97z^9eWPm{hr@Uiu^Ywz*uprk!P$g3`f~uDeGJEiwXG&IIy=h_H&f zI=X(Ga>2B0+UsfdnWjl0ba4!+nDh4XX-)bP0l+XkKX@n=3 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay56.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay56.png new file mode 100644 index 0000000000000000000000000000000000000000..be3cc1d7effce3a30b37a373f52dbae6c50dc459 GIT binary patch literal 75 zcmeAS@N?(olHy`uVBq!ia0y~yU=U?sU|{E9V_;x-&dCO%ggjjwLn`JZ|L|u%V375K d!%T$X!cEW1#vj<585kHCJYD@<);T3K0RR}D5%B;3 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay57.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay57.png new file mode 100644 index 0000000000000000000000000000000000000000..32d3d680172a3681389d8a5fcf6b05b0ccd665e1 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0y~yV31~DV36TpV_;yIaPi1n1_p+Io-U3d6?3j$-N@VI zAkmhX#3L$dx^|;^A`_R{f<$Jmv%XffPvhg(-4c7Byngq4 zes|G>Ej5+~w;1cYW%sqFrZn*CEM)fC$nniNIEQ`r##{MKxhnh@ymy}q(wT6_QT_iL z-GenJdEeN7<9l(T`_|FPF^nNRU!Oayd&0D!D2J`}+9cx!t-CTzYgKp~UagE|Sb5(LXM{ThqGU SG?amXfx*+&&t;ucLK6T*Jbs%1 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay58.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay58.png new file mode 100644 index 0000000000000000000000000000000000000000..a02b65e74d3b1c6cd2c29b846611f229a6e62781 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vXnDFghE&W+{_+36J+oX7 z|AQ;-=MMxryEiQiVPD+VSK{36_ekEfghPUhVL^_RwNAyF^$ZLQ44$rjF6*2UngI8q B9Z>)P literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay59.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay59.png new file mode 100644 index 0000000000000000000000000000000000000000..03277509b879264fd68a6aee04f37ebf704c70a3 GIT binary patch literal 89 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vD0sR!hE&W+{^8Gjz#!`d shxwFO6<01y%+t7faK%F9n*j`6*S)zer7wHUz`(%Z>FVdQ&MBb@0PQv#^8f$< literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay6.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay6.png new file mode 100644 index 0000000000000000000000000000000000000000..db2fc20ced98d8f6ee0513a2d4fc7f8dc5e8bcb5 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+>O5T>Ln`LHz2?Z(pdi2+ z5PtEHaLNDX(#D*(SwTq-Z4MHD=5yKq`6?`1(A2?ldFvOE0G(|LhTLH~iW|k2Bye3a zVC5HEreJDYF#Y$bwsko>}M^ zyTpftMPDbbExh7XBX&u&C(0u0;e`zaKhpmMa=YuwtkreXmDxI>h`YW1*z(n_3_`C9 WwSq&vL>L$t7(8A5T-G@yGywn$btgUm literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay61.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay61.png new file mode 100644 index 0000000000000000000000000000000000000000..6b0330786579a4d63329f32dbc45fa12927e0bec GIT binary patch literal 77 zcmeAS@N?(olHy`uVBq!ia0y~yV31*8U|{E9V_;yAmeD=Kz`!8l>EaktF(>(lfBFG~ htcNRFo9{U>9P8wjGkw2JmVtqR!PC{xWt~$(698+86bJwS literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay62.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay62.png new file mode 100644 index 0000000000000000000000000000000000000000..aca39f727a0a795e697bc118e7bdf385ceba0e86 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+&U(5yhE&W+{^6f~z#!}4 zidN@)hin5(Lk=q>nK61lU6HFOE%5(n^25}uXpTdsEHx|JU5z6dmd)hssDBjrz2%lz zQ-KuY)^k_32#EBr=UnmEL6_UI;fJnZmSfh86^Reom9Eq_TJ>nzsj$>B7~ZefQj@BA zU@p*|u(3x#?Y5JokUI+Um-{ Pz`)??>gTe~DWM4fZ_Hr* literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay63.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay63.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ffcc3936927711a54973e61876f3801f6c37b4 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0y~yV31*8VBq6mV_;yg5w2ljU|?wXba4!+n6vguAYX$5 z2V27Y8LwyUtt?+HJz+~!w}?RM@B1n9jnW*B91!v@%L!lg<%3DLJPYgQMQRf^oNb5< z5PfshB!p$}jFzqhxdT}m84uQYnXB13F!xVdnliUUQY5e}AXzVE~^b2@*|m1oMk7#J8BJYD@<);T3K F0RY^6A@%?O literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay9.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay9.png new file mode 100644 index 0000000000000000000000000000000000000000..32a44217033aeaa0254b5ec6a56b458f786b9d55 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+GCW-zLn`LHy>yZ5fC2|= z!2Cu3|NCE8&*5a%Jr-fs`hx3wVBd-oD{)4a9V{7w4GiM!x@=543?)P&W-tc($s9;} z8Q8pkdc&I+g?E2GZ0x)$cT4DLQo#S%_3ZPHR$XA)o9O>w`Soi_lejyglpjhR$=}Vu Pz`)??>gTe~DWM4f@w__^ literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 6ec07cd35a..ae1535fa97 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -614,3 +614,4 @@ 63068=colored-wall|block-colored-wall-ui 63067=crux-floor-11|block-crux-floor-11-ui 63066=crux-floor-12|block-crux-floor-12-ui +63065=character-overlay|block-character-overlay-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 2399dedf31..91ec7fcd03 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -68,6 +68,7 @@ public class Blocks{ //colored coloredFloor, coloredWall, + characterOverlay, pebbles, tendrils, @@ -912,6 +913,10 @@ public class Blocks{ autotile = true; }}; + characterOverlay = new CharacterOverlay("character-overlay"){{ + color = Pal.metalGrayDark; + }}; + Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6) .each(b -> b.asFloor().wall = darkMetal); diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 3692214102..dbc4a6945d 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -961,7 +961,7 @@ public class Block extends UnlockableContent implements Senseable{ } /** Called when building of this block ends. */ - public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, @Nullable Object config){ } diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 9a10dcbe3d..fab1ac1171 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -112,7 +112,7 @@ public class ConstructBlock extends Block{ if(shouldPlay()) block.placeSound.at(tile, block.placePitchChange ? calcPitch(true) : 1f); } - block.placeEnded(tile, builder, config); + block.placeEnded(tile, builder, rotation, config); Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); } diff --git a/core/src/mindustry/world/blocks/environment/CharacterOverlay.java b/core/src/mindustry/world/blocks/environment/CharacterOverlay.java new file mode 100644 index 0000000000..c57bd0de36 --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/CharacterOverlay.java @@ -0,0 +1,54 @@ +package mindustry.world.blocks.environment; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; +import mindustry.world.*; + +public class CharacterOverlay extends OverlayFloor{ + /** This is a reduced character set! It is not ASCII! */ + public static final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\"!?.,;:()[]{}<>|/@\\^-%+=#_&~"; + + public @Load(value = "character-overlay#", length = 64) TextureRegion[] letterRegions; + public Color color = Color.white; + + public CharacterOverlay(String name){ + super(name); + saveData = true; + variants = 0; + rotate = true; + drawArrow = false; + } + + @Override + public void drawBase(Tile tile){ + Draw.color(color); + int letterChar = CharOverlayData.character(tile.overlayData); + Draw.rect(letterRegions[letterChar], tile.worldx(), tile.worldy(), CharOverlayData.rotation(tile.overlayData) * 90f); + Draw.color(); + } + + @Override + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, @Nullable Object config){ + byte data = 0; + if(config instanceof Integer i){ + data = i.byteValue(); + } + tile.overlayData = CharOverlayData.get(data, (byte)rotation); + } + + public static byte charToData(char c){ + int index = chars.indexOf(Character.toUpperCase(c)); + return index == -1 ? 0 : (byte)index; + } + + @Struct + class CharOverlayDataStruct{ + @StructField(6) + byte character; + @StructField(2) + byte rotation; + } +} diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index e850405e72..0b8dff8bba 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -140,7 +140,7 @@ public class ColoredFloor extends Floor{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, @Nullable Object config){ //config is assumed to be an integer RGBA color if(config instanceof Integer i){ tile.extraData = i; diff --git a/core/src/mindustry/world/blocks/environment/ColoredWall.java b/core/src/mindustry/world/blocks/environment/ColoredWall.java index 1d48e25ec3..268daa4306 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredWall.java +++ b/core/src/mindustry/world/blocks/environment/ColoredWall.java @@ -46,7 +46,7 @@ public class ColoredWall extends StaticWall{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder, @Nullable Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, @Nullable Object config){ //config is assumed to be an integer RGBA color if(config instanceof Integer i){ tile.extraData = i; diff --git a/core/src/mindustry/world/blocks/environment/RemoveOre.java b/core/src/mindustry/world/blocks/environment/RemoveOre.java index 88904f8aaa..d0a0229a6f 100644 --- a/core/src/mindustry/world/blocks/environment/RemoveOre.java +++ b/core/src/mindustry/world/blocks/environment/RemoveOre.java @@ -44,7 +44,7 @@ public class RemoveOre extends OverlayFloor{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder, Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, Object config){ tile.setOverlay(Blocks.air); } diff --git a/core/src/mindustry/world/blocks/environment/RemoveWall.java b/core/src/mindustry/world/blocks/environment/RemoveWall.java index 69bd0bcb34..df3a8eec7d 100644 --- a/core/src/mindustry/world/blocks/environment/RemoveWall.java +++ b/core/src/mindustry/world/blocks/environment/RemoveWall.java @@ -43,7 +43,7 @@ public class RemoveWall extends Block{ } @Override - public void placeEnded(Tile tile, @Nullable Unit builder, Object config){ + public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, Object config){ tile.setBlock(Blocks.air); if(tile.overlay().wallOre){ tile.setOverlay(Blocks.air); From fba935c52787ba5f37f9ac769f6f064d404245c2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Jul 2025 18:14:32 -0400 Subject: [PATCH 27/37] Char tile picker support --- .../mindustry/ui/fragments/HudFragment.java | 28 ++++++------ .../ui/fragments/PlacementFragment.java | 5 ++- core/src/mindustry/world/Block.java | 20 ++++++++- core/src/mindustry/world/Build.java | 4 +- .../blocks/environment/CharacterOverlay.java | 43 ++++++++++++++++++- .../blocks/environment/ColoredFloor.java | 34 ++++++++++++++- .../world/blocks/environment/ColoredWall.java | 13 +++++- 7 files changed, 123 insertions(+), 24 deletions(-) diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 704fb279d7..969a4e7d9f 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -72,6 +72,9 @@ public class HudFragment{ } }); + Table[] configTable = {null}; + Block[] lastBlock = {null}; + cont.table(search -> { search.image(Icon.zoom).padRight(8); search.field("", text -> rebuildBlockSelection(blockSelection, text)).growX() @@ -79,23 +82,18 @@ public class HudFragment{ }).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 -> { + configTable[0] = t; + }, () -> control.input.block != null && control.input.block.editorConfigurable).with(c -> c.setEnforceMinSize(true)).update(col -> { + + if(lastBlock[0] != control.input.block){ + configTable[0].clear(); if(control.input.block != null){ - control.input.block.lastConfig = col.rgba8888(); + control.input.block.buildEditorConfig(configTable[0]); + col.invalidateHierarchy(); } - })).left().width(250f).pad(3f).row(); - }, () -> control.input.block != null && control.input.block.showColorEdit).with(c -> c.setEnforceMinSize(true)).growX().row(); + lastBlock[0] = control.input.block; + } + }).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 2b1a0ef25c..b6b4ad7846 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -153,8 +153,8 @@ public class PlacementFragment{ tile.floor() != Blocks.air ? tile.floor() : null; } - if(tryBlock != null && tryBlock.showColorEdit && tryConfig == null){ - tryConfig = tile.extraData; + if(tryBlock != null && build == null && tryConfig == null){ + tryConfig = tryBlock.getConfig(tile); } if(tryBlock != null && ((tryBlock.isVisible() && unlocked(tryBlock)) || state.rules.editor)){ @@ -163,6 +163,7 @@ public class PlacementFragment{ if(tryBlock.isVisible()){ currentCategory = input.block.category; } + tryBlock.onPicked(tile); return true; } } diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index dbc4a6945d..33ada2e966 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -80,8 +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; + /** if true, {@link #buildEditorConfig(Table)} will be called for configuring this block in the editor. */ + public boolean editorConfigurable; /** 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 */ @@ -701,6 +701,10 @@ public class Block extends UnlockableContent implements Senseable{ return liquidFilter[liq.id]; } + public boolean canReplace(Tile tile, Block other){ + return canReplace(other); + } + public boolean canReplace(Block other){ if(other.alwaysReplace) return true; if(other.privileged) return false; @@ -947,6 +951,18 @@ public class Block extends UnlockableContent implements Senseable{ return (envEnabled & env) != 0 && (envDisabled & env) == 0 && (envRequired == 0 || (envRequired & env) == envRequired); } + /** Called to set up configuration UI in the editor. {@link #editorConfigurable} must be true. + * Config value should be assigned to lastConfig.*/ + public void buildEditorConfig(Table table){} + + /** Called when the block is picked (middle click). Clientside only! */ + public void onPicked(Tile tile){} + + /** @return the config value returned when this block is picked on a certain tile. This is only called for non-buildings. */ + public Object getConfig(Tile tile){ + return null; + } + /** Called when this block is set on the specified tile. */ public void blockChanged(Tile tile){} diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 6948e6910e..402684dde6 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -216,7 +216,7 @@ public class Build{ //floors have different checks if(type.isFloor()){ - return type.isOverlay() ? tile.overlay() != type : tile.floor() != type; + return type.isOverlay() ? type.canReplace(tile, tile.overlay()) : type.canReplace(tile, tile.floor()); } //campaign darkness check @@ -247,7 +247,7 @@ public class Build{ !check.floor().placeableOn && !type.ignoreBuildDarkness || //solid floor //when you have a payload, you cannot place blocks on things, even if normal placement rules allow it. this is a hack that assumes checkVisible = true means it's coming from a payload (!checkVisible && checkCoreRadius && !check.block().alwaysReplace) || //replacing a block that should be replaced (e.g. payload placement) - !(((type.canReplace(check.block()) || (check.build != null && check.build.canBeReplaced(type)) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type + !(((type.canReplace(check, check.block()) || (check.build != null && check.build.canBeReplaced(type)) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type (check.build instanceof ConstructBuild build && build.current == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement (type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found diff --git a/core/src/mindustry/world/blocks/environment/CharacterOverlay.java b/core/src/mindustry/world/blocks/environment/CharacterOverlay.java index c57bd0de36..d95afed719 100644 --- a/core/src/mindustry/world/blocks/environment/CharacterOverlay.java +++ b/core/src/mindustry/world/blocks/environment/CharacterOverlay.java @@ -2,13 +2,16 @@ package mindustry.world.blocks.environment; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.scene.ui.layout.*; import arc.util.*; +import mindustry.*; import mindustry.annotations.Annotations.*; +import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.world.*; public class CharacterOverlay extends OverlayFloor{ - /** This is a reduced character set! It is not ASCII! */ + /** This is a special reduced character set that fits in 6 bits! It is not ASCII! */ public static final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\"!?.,;:()[]{}<>|/@\\^-%+=#_&~"; public @Load(value = "character-overlay#", length = 64) TextureRegion[] letterRegions; @@ -20,6 +23,8 @@ public class CharacterOverlay extends OverlayFloor{ variants = 0; rotate = true; drawArrow = false; + saveConfig = true; + editorConfigurable = true; } @Override @@ -30,6 +35,42 @@ public class CharacterOverlay extends OverlayFloor{ Draw.color(); } + @Override + public Object getConfig(Tile tile){ + return (int)tile.overlayData; + } + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + byte data = 0; + + if(plan.config instanceof Integer i){ + data = i.byteValue(); + } + + int letterChar = CharOverlayData.character(data); + + TextureRegion reg = letterRegions[letterChar]; + Draw.tint(color); + Draw.rect(reg, plan.drawx(), plan.drawy(), plan.rotation * 90); + Draw.tint(Color.white); + } + + @Override + public void onPicked(Tile tile){ + Vars.control.input.rotation = CharOverlayData.rotation(tile.overlayData); + } + + @Override + public void buildEditorConfig(Table table){ + char value = chars.charAt(lastConfig instanceof Integer i ? CharOverlayData.character(i.byteValue()) : 0); + table.field(value + "", val -> { + if(val.length() == 1){ + lastConfig = (int)charToData(val.charAt(0)); + } + }).valid(t -> t.length() == 1 && chars.indexOf(Character.toUpperCase(t.charAt(0))) != -1).maxTextLength(1); + } + @Override public void placeEnded(Tile tile, @Nullable Unit builder, int rotation, @Nullable Object config){ byte data = 0; diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 0b8dff8bba..0a9ca1fe27 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -3,13 +3,17 @@ package mindustry.world.blocks.environment; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.geom.*; +import arc.scene.ui.layout.*; import arc.util.*; import mindustry.*; import mindustry.entities.units.*; import mindustry.gen.*; +import mindustry.ui.*; import mindustry.world.*; import mindustry.world.blocks.*; +import static mindustry.Vars.*; + public class ColoredFloor extends Floor{ /** If the alpha value of the color is set to this value, different colors are ignored and no border is drawn. */ public static final int flagIgnoreDifferentColor = 1; @@ -24,7 +28,7 @@ public class ColoredFloor extends Floor{ public ColoredFloor(String name){ super(name); saveData = true; - showColorEdit = true; + editorConfigurable = true; saveConfig = true; } @@ -34,6 +38,34 @@ public class ColoredFloor extends Floor{ lastConfig = defaultColorRgba = defaultColor.rgba(); } + @Override + public void buildEditorConfig(Table table){ + showColorEdit(table, this); + } + + public static void showColorEdit(Table t, Block block){ + t.button(b -> { + b.margin(4f); + b.left(); + b.table(Tex.pane, in -> { + in.image(Tex.whiteui).update(i -> { + if(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( + block.lastConfig instanceof Integer col ? new Color(col | 0xff) : new Color(Color.white), false, + col -> block.lastConfig = col.rgba8888())).left().width(250f).pad(3f).row(); + } + + @Override + public Object getConfig(Tile tile){ + return tile.extraData; + } + @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 diff --git a/core/src/mindustry/world/blocks/environment/ColoredWall.java b/core/src/mindustry/world/blocks/environment/ColoredWall.java index 268daa4306..4f6fcc23e3 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredWall.java +++ b/core/src/mindustry/world/blocks/environment/ColoredWall.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.environment; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.scene.ui.layout.*; import arc.util.*; import mindustry.entities.units.*; import mindustry.gen.*; @@ -19,7 +20,7 @@ public class ColoredWall extends StaticWall{ public ColoredWall(String name){ super(name); saveData = true; - showColorEdit = true; + editorConfigurable = true; saveConfig = true; } @@ -29,6 +30,16 @@ public class ColoredWall extends StaticWall{ lastConfig = defaultColorRgba = defaultColor.rgba(); } + @Override + public Object getConfig(Tile tile){ + return tile.extraData; + } + + @Override + public void buildEditorConfig(Table table){ + ColoredFloor.showColorEdit(table, this); + } + @Override public void drawBase(Tile tile){ //make sure to mask out the alpha channel - it's generally undesirable, and leads to invisible blocks when thtoe data is not initialized From 7ed243a8087a3852633668d7c53063a8bacb7d40 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Jul 2025 18:16:06 -0400 Subject: [PATCH 28/37] let's not do that --- core/src/mindustry/world/Block.java | 4 ---- core/src/mindustry/world/Build.java | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 33ada2e966..ae73e23450 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -701,10 +701,6 @@ public class Block extends UnlockableContent implements Senseable{ return liquidFilter[liq.id]; } - public boolean canReplace(Tile tile, Block other){ - return canReplace(other); - } - public boolean canReplace(Block other){ if(other.alwaysReplace) return true; if(other.privileged) return false; diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 402684dde6..6948e6910e 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -216,7 +216,7 @@ public class Build{ //floors have different checks if(type.isFloor()){ - return type.isOverlay() ? type.canReplace(tile, tile.overlay()) : type.canReplace(tile, tile.floor()); + return type.isOverlay() ? tile.overlay() != type : tile.floor() != type; } //campaign darkness check @@ -247,7 +247,7 @@ public class Build{ !check.floor().placeableOn && !type.ignoreBuildDarkness || //solid floor //when you have a payload, you cannot place blocks on things, even if normal placement rules allow it. this is a hack that assumes checkVisible = true means it's coming from a payload (!checkVisible && checkCoreRadius && !check.block().alwaysReplace) || //replacing a block that should be replaced (e.g. payload placement) - !(((type.canReplace(check, check.block()) || (check.build != null && check.build.canBeReplaced(type)) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type + !(((type.canReplace(check.block()) || (check.build != null && check.build.canBeReplaced(type)) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type (check.build instanceof ConstructBuild build && build.current == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement (type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found From 2e41e58b59e85b5652d9af7a77c3d379dda2ede7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Jul 2025 18:23:00 -0400 Subject: [PATCH 29/37] Color variant for character --- .../character-overlay-white.png | Bin 0 -> 173 bytes .../character-overlay/character-overlay.png | Bin 173 -> 246 bytes .../character-overlay/character-overlay.png~ | Bin 0 -> 173 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/content/Blocks.java | 9 +++++++-- 5 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay-white.png create mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png~ diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay-white.png b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay-white.png new file mode 100644 index 0000000000000000000000000000000000000000..5a9c7dbf458765f738ff0b63647282a8deed529a GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+N<3X0Ln`LHy&TBZpup4c z(AKl$fA*@o38@wrI(f1=uh!joy^md1L1{x|UuVUB-S?}$6`#>ejGdC~D7ZMO)2=sA zQQClc^#zt+oDxqHmCDo_Urt|pW1e6Bk>?W~%p0b@NG%XqZ1~~$f+{wtA9Wvox92Zt b^tGN@5wic7mg^Y?1_lOCS3j3^P6_>FObNH14=B5Da8#5NfEnAv;VwxR$q{a~kdxaw|E|;FMCAkGF8CnbMKc23j$bGcohcu_% z57x8QDbYW=dlG)TcD9DFFBS`u-5@aGzrECw#bSMF+$9G*mhJrS{ejGdC~D7ZMO)2=sA zQQClc^#zt+oDxqHmCDo_Urt|pW1e6Bk>?W~%p0b@NG%XqZ1~~$f+{wtA9Wvox92Zt b^tGN@5wic7mg^Y?1_lOCS3j3^P6 b.asFloor().wall = darkMetal); From c32f7473e8d4874b3aa21867e99bc71fb21c4763 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Jul 2025 18:53:58 -0400 Subject: [PATCH 30/37] Fixed sprites in wrong atlas --- .../character-overlay/character-overlay.png~ | Bin 173 -> 0 bytes .../environment/crux-floor-1-flat-autotile.png | Bin 1521 -> 0 bytes .../blocks/environment/crux-floor-11.aseprite | Bin 41712 -> 0 bytes .../environment/crux-floor-4-autotile.aseprite | Bin 2176 -> 0 bytes .../environment/crux-floor-5-autotile.aseprite | Bin 3435 -> 0 bytes .../environment/crux-floor-6-autotile.aseprite | Bin 23551 -> 0 bytes .../environment/crux-floor-7-autotile.aseprite | Bin 5685 -> 0 bytes .../blocks/environment/crux-floor-generic.png | Bin 1041 -> 0 bytes .../blocks/environment/crux-floor-generic2.png | Bin 779 -> 0 bytes .../sprites/blocks/environment/pipes.png | Bin 296 -> 0 bytes .../sprites/blocks/environment/plating.png | Bin 1154 -> 0 bytes tools/src/mindustry/tools/Generators.java | 4 ++-- tools/src/mindustry/tools/ImagePacker.java | 17 ++++++++++++++++- 13 files changed, 18 insertions(+), 3 deletions(-) delete mode 100644 core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png~ delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-1-flat-autotile.png delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.aseprite delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.aseprite delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.aseprite delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.aseprite delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-generic.png delete mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png delete mode 100644 core/assets-raw/sprites/blocks/environment/pipes.png delete mode 100644 core/assets-raw/sprites/blocks/environment/plating.png diff --git a/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png~ b/core/assets-raw/sprites/blocks/environment/character-overlay/character-overlay.png~ deleted file mode 100644 index 5a9c7dbf458765f738ff0b63647282a8deed529a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmeAS@N?(olHy`uVBq!ia0y~yV2}Y}4mJh`h9chkQy3T+N<3X0Ln`LHy&TBZpup4c z(AKl$fA*@o38@wrI(f1=uh!joy^md1L1{x|UuVUB-S?}$6`#>ejGdC~D7ZMO)2=sA zQQClc^#zt+oDxqHmCDo_Urt|pW1e6Bk>?W~%p0b@NG%XqZ1~~$f+{wtA9Wvox92Zt b^tGN@5wic7mg^Y?1_lOCS3j3^P6k44ofy`glX=O&z`EMg z#WAE}&fB@ZdAAJ&TBj~>*SIxzv)(SBqW{cWY+d$vPq5yiE!w5*b@<`qKlKic+cx|) zF+MNidh+n@`Sx=E^<1OgZRKBZVJXjqIYtgerx;FZGOIl2{@NP9zkYTR1OIgI@6~bZ zu4^7|dh+)x@2|@K^Zx(;`*qG=$sZGwz9wPNieLl<#`xq{uwj+Bj%e=iC&3|5Dik>aJ;L)48!gECDFY>&Y9?M$L z-Mk;%N&m#vtrpI+9$qHo6xhlHRR8m)&&!v1bnm; z>QNH>f5Gd4nWg^q*X{NiYi1^d&CyLeZofz5&aXBXvx8#q)g;UgTzs0OBJ6Rr^U8uF z?_Z@&*v7eKrr>^UW}Q@~ia+moHca7Muw3SZ%7&w7mUz#0&^{-oA?)DRu=j~ejQWMH z&8$w-|2UkGT>C_aN!juJbNd**H%~H;-fR;7Kka34Lx=J~xj6SGJ?4VccgIA^f3>{B$9P5PF&UBFK(|av)!1LU_>T6HjjT)Z>hg5$#cD_z2W6Ito%KI&^ z&C_{RtCV5#fBVP(KfhLgFV*69T>B_OmeanNOyj7X9ujk)GjtQ!qGr#)#GfGaH5DBt=Udx$ZPdpQzsH9wb zzl*D5R?C@Rcc(WBPM#1se=DDWE~n5h51%jWA0k+CYgN>KF<0m`ZL5DJ8573cktOdP zbA^8^-FZ;?KH}S#?{@Vnekvz^Y+vzKCM#FPL1g}KxwGfP?pj{y;{4Wk_|>_EtNt>k zy;+fYlqFi{jf~dUn`&izSIrIz&bqt5-{GkJmgEy<%X@CC6sq~p53NPgDy zfPUr1Z!Z?ylV{kwcv+}$#(SBnmd<|+9&2VDF#7P1;Z}-yW9L7HTT?in9nY_O9-yt( zvCDZ?_grV)*#~~_>&PqP+q%h5Ah$gv+`2tVlJnaKE1?~?Ekh2mh&{?#cu)Sop}tvh zJ_g)h|1pS_UD=Ywv~sR4o(V42$RWD4V?U^Xyk$>{^fpD*YC z?{?4s`o8)0-tx7~xzWr^{=MWVi2kD*$h}pt_Q_$B?WPW|CLL zyJBw3CG!jN3f@9SujkKWGE!08Y?sL=V9PlZls8Uzo>+6gR8+u}bLQ9g)6b=!QBqUf zY?m#o5GADYW#WqO><{Ex%0S6!!I#-=4u4E4`QIvKybgAJR-aYR(C<3o+VX!v-^I-T zGTMkZde4vkBWnJaQAga-yMD_L?W^(&X1Ljk&OsEZ%Xucusb4UWoz4HrpFIo=3=E#G KelF{r5}E+tWx0s} diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-11.aseprite deleted file mode 100644 index 545f8a629a45a1887a6f35050411d5f9e0c21414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41712 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 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.aseprite b/core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.aseprite deleted file mode 100644 index 5e8b65ea4577cf5bc8b247f5a9387a852fafd74f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23551 zcmew#&A{+rDI-GzLj!{X10w?iLka^jU}0bc2{I@!C?E?{ja?tj!0_uM7uZ%V1_lN( z1_lOp1+bM!c7Q}#K(1r?5)q-TX?&>BC@wBtmVtqRMS&Sf-G2rK237{2#LCnnd9b7~ zTvC7mB*_kuR4{}{BlHR|sDNySN*iNJw<1X!g)lQPutEdmKNHLjP#9Lsc{|H6Pu5W2 z=(*$_Ul`|@nSc0u{()U)kX8NGOCDEVZA_3XnC9=;@Sy(RufNZOU0hsTp2)w?mp5X# zd;e|ai+_3Noxhh?%k8Rf{r~&*YR+AyrlR-vF8c3NpWQ5(|A6KDs(;3R%B4fz6?9dn z{`acSZ!UT9Z;QR`F8jCs?eF}5Utak8@;@v>^YdOj?0hHt>;1F%oy;%qZLMEF|6Toe zwo89svF-ZbG5_8DD(08_b~V1Uf3^H~{9T7#(RmAgU#|OJUjP04-ThbZ|9<}%O1=w!41Y{lA<4zMKEH{D02=-|4@r^A+x@f4zV6{_g*p_v?54&pJHuuXdir zUi+8%H}gyWU$pjnXMa2X;N-t0^|$PI|K&4(bEp1_|F`_o_XUU7{dND7@_+X`*}NMY z|9jPk{=fJ3rSyw`TlO#d|Ki&d-je!T^ZD-1|F+!u`|`gpFZ|7{w?YwG|1Kl-nb_w1 z1-~!KhCXuKyH%@4{itcT@ka{u^q(=2oKn_f`Kk{}DB}ncDR}?qdD6_+JZu zZ~s-xoby}q?|U$P>fheF`wX}DE&9JA9+bYo_+0D1|Cg6T($@alpD+BqJFop+{KN0x z<9F`=Z}rf8#**sL|C0Z9^JXN-sk1#zL&?<=Ren; zZ~d@1-qUgEzMsJ&zQS2uioa{TW*L2+a3y`skDlt?tFJ76_or1p)m%F(^vbdoD^}cH zyvQbdYWeI>*N&btTekNs-~6s`*Bjq&3HnynulA31x!$z$g>ir8Zrkp0Q+E6JbFX*r z&A+F){p-2t1sM|;U2geN&3OKc_1@1`OZ~R#HR=RS>aO(Wc_-@>_+$Hz+VyVt#2zc< zdfv`k=|B6!diVMMhw2vw-2Gu)yJo@dyXN`(wtRk{|MsQ5|HU9zZIM`oElzdT@3+nS zxA}^B_f_-dtLm#=)VA4gTcV=(`o&B8=z@5)i1lAG zT5T5JpQ~FVZu!|iYM*V>N2gN)^RzRAyUOC7Y!7&SHmlv|yTM2Ix5$t6fi~B*qy(Z) z=U4u)w(0JX4n6kri~23!-+8ZI?XF8te}BEaJeb7S}3-?4J_ zcebzZCR}-%^km^F%j;i`|GOMoYbWn+BW`*7qieK&*cVmTaISaGUE4Hvxn*?!Vfz<; zYPYy|{Dsf`FWECIUR%xcp4+M~!GBThme}pQR?Zt9vM;`So7%T7Tw}j7C0_Rby|=66 z%HOy{p$Yd zym`joPrthDcy{;d?_pQ>)rUR3xA?=or4=>te}6N3{JVG5_};_VeGj8gEzr^2td+m= z@zX0acU@+?h{r}E=|FwHx-wV_~f2jYv zp=oAxiG4I<-YWUG0XypY%kt-6{rP0uOj-S!t-0U4<83Ry#c!K;=bsiRT*rZHn!8-LKAim}J@i=Ksi3#N%}=rB zzgqZWyOaMX>GKutKi-)oFZ@1x%F@$5$E(>(m!7+F_ru$&CbNrXwzH#v90&Q#v}m+O9A*_L$t^On!M z4y`d?pQ*cV_tMg52X&3p_UV@d{QY)stNPh0?}r~}9b0tcXSH(wyZ9BqY-%3Av9u3M zwe{HVvw;0-wLQ~&>07(&{p!PJ*t5QWI8*k&vvugt-z?v+xBRG{f6QU;;oUWdw@+F4 zyHU$n^}T#>_$!~gnasJ3{JD#Jx0q&>ug?3vJAujU1Dm!1v$bTock14^Q}!lbnXy{( ze|A**zxfN_{F(bR)$TXbHI8EpweFuo{$^$`{A+q^@6M%f4=)t<|M%n7vqS3P^8+jv zt=w6VvSR0lkIRJp|9Lzt^mz4&tyD7a^$+3u+C1}vKUIWXd@o@yc;x;0Ro}m@`u_jH ziAwvoyS^=XWW7arkGZzo?DQ?Q2^r56>mEzK|DboD<*&n3*O{7?_UXrhkI!d$Y+fQC zZj&LMyJW53ZhJ;<14e0sN7V+GAD=t3bM*m{oVPX7ir;g7Jb&>1jjELe`-`8hZ}}s% zXPCcmp5lH#%!V)D=HU{5_SsSYw!zhFYy9zvmupDEGZ@{I_9K)|0b4>e|6c z^=I?4yUK!Z|4Dy+V7u?)4ec`r_;?OpI*Dk}vj^H_fYmP-~%_fA@GyPo{M4nw;$q?KN&Ri_U12 zm1t6((X{qOSk&E8GyZ>-Ke!E#&pEWSeY3`Mp>G{$B+tx#u<7EbE4g+bU+mIUmy6Xt za{t%%mAdY^v1~DsCUa9bWL8hC72h-4<=oU6@?TH9uI?%i_Pck&>dx{0V_RoG|G=WW zfysCSv-1X);0>(FGqY=VrXRBBuaAuGdhz=Pvw?nr+S8gt^V+`l{^J)*V35E3F0Ehd zmxBWLUH+^EUndsvCBK_|`}?cYx1UGf%y_sQC~k{`-% z&1>8ru=|a2WVG3${s%dyY7WjiILH0}^@tnW{?B#a_{sjF{A|saMN>=ZcML!`@?!l>;A*jZI80PkiY0!*!QsKNZib?lPX*O?Y}nh zcj&}T^73zvw`@QBS!?~-*D32*LD|88#oK^2`eyXelY7(teEx9$?DgmNTA%l5Hz!Z| zeq?I(7aL>e^TzH%&nwgCUaq$O7Jm73_3t^=+Pdu4e3P%;Fnm1M=6rMY-)BFwexyH{ zzhQla%-$t-&L-kF!h0lm_I%r2J$vP*`C;$#bml*`JTANLqfTkWxu9Qj{3@9b?z2jZ zH(s_!`PRA(jLI7>rE9jzN<6!9J@mLe`~MTgF5&OZx138zJ1&1QxnNnU4bO|eDc&ac zSEkJ|jJpxt@$X6Pw`r1J%_+#4Y&{3Mj1Ks{_7j$y}pziN%B-3#vv^W&<6KIUGW zo@D+bnYZfJ^CN6caW(c&1MW>|uHW$PR8(H7-K#yU<@^8Mld0x7qan_7FzB^cuf5l% zduq!6B7a2NF8m>3BY~ye4If3USKNVb&ymZd+OnW%{j`LOrY!+9%zxqw^>ifJI zw$I})-*Btw|9(_$^YkK({-U!tvSkfR1?JAQ+}_9eo>#Ou_vp=^8;Z;7n0O8f`E2E% zw6WLaRp#f1^LzKlCV$YLv@?x&TY669jU_YwUkKfNkN3pBO>6Xx9`~l7>FyEi{k`Vg z{Z;Sf585gGld%5C>#?QvQ_SAwwK6?#KMI~Q{2_jSSxq$i=J4x#+>g!po-X)y`>sv= zkhFPJ?U+pUs{Px3XV>ukG5%QoOe$x8`h#W$xf`D?xLscHFWY5xD53A+pAGXjE-HNg zW+(UVZLf;|FZnC~?9AWeD)-svWzXmSYIpzR-ed7o-FN=-QGR@G-tIRx#%_E1Rkqx} zI{lB^Z70#Tgq45gdw6Y3j$fDjKkKKpnc_KN?vKWYp0oUC&bfF)bz|VvudRIXoBMfQ zvd>gM%D01ezk2AsqL06=jL+To{4?jANc^U!HOoJSKMjbBNMCuqa;^RK*S}_b^2_;e zoxqxwz}|N3e9k>5OMBN})>j4p&-yui&Hna{jPtwq3+_|@p}62N|F@}J&%c({FFt=d z&Hw1nW%K6>2n6Q#<|BE-zpDhGO!!4U3QbE^zvtE4!iHhNmon zV_MR0zvuarW&iv9x%-zj_j++})aMVOiSt)q>t&wZwAVGY{;}ly4ci`UKV&Dg-|X1L zH_B_{%Zr&Z;|n)>&O7kF3ETRm z>eJV~oKX9;b<;7M15(R>zWOJoU4C|Y`Omh!La8TWvTAEq9W{7i!6?~0f4UV<`zwdr zsrAMRW$Cxm9{yGMJN0YSuQ^|Jy}K4}DD(W7A6)BKyZ-lHt$t&<=heTaSNHMFo$Y(S zdTx2C>=~=#jcau8E|rj9%@M!)UBaD}MsBnBAHJScH!-2k{&{qX^lafDQoHl5YwDN3 z{p_1peiwQIMX?au4FU!j(M?c#&EJO9S*_gDVD>rs4f zJxjdxJ=15VAGY4e@0EC;`RDuMR~vS-?R>w^_`PA~|B8?D@5{`e+?!DC{O0? z^X~Mw*jdhArJe6DtN#5$Tv+Yn7b{o2TiW0HP2Rake*ND)uY>n!J>vPDc?nXlD5b?r$jx`}oVMB(&e+TZd{={|2j5AFcLZSNR@j zv48o*>g}CJc}h}Wy#97=k^ZR_#@V7XZ$|{Ynb>^n`;y-mA8xy;-_`f4pr!8LhKs)E z>jIB+NXk!kJXMh7bldx+rNFDD>u+sn`oWn#`-FBm z*S~wtmKLl!Q8V)h>$@rc{!RHIA?LHO3{+Zo6 z?se=>-QH^}^0&STjhv$S(>(0x6Z;eC_2&P2<~ImNysTTlVe-~vUz2^4+t{qga-#ru1|mflqSsroK$UfP+iGv5ubnR)8GXpmM8`?k^~Iqpx- zkG6cx=1nT>-k#6nJk~j@)k`1G|2yH!@8vG_CUc(I%;c;;zTZIme?o4e|JBR&W}jt# zI`z!=KmPg1P1Z7l^UIAF*Wb-+zcYuqe}n$wduOh1aXft|A@5k!lKR;*i!0j8UBCSX z883c9IqqF+msQH=_1te)+Fvs4RO6GhUmkr>$R{;_=9~PF+pO=6A zW>MD5YHh%B+Cu)-t_Sm*>sP+nonKq?;qHF-KbBu_1xe0MuRW3dInjOot6rRxnZAQXWi7T zkLUN-uQUov?~n-;TD*1rp5-5twj?F1H_Z?=f6rK`DSu>QU--lt_Ple9yUY7~gFh!d zej|7P^xlFU$E_W?3D1*qrfu zsoy)!+25UlgPBfRGyBzbmvS2IKh=L&uH8yvpW+>RR&Ck!i$D#tk^=w9_tj+oT`clH zyI=A9lVj--xbG%ys350H}?Eu=C@|bv-daCoD7Y5ZQr_F zzT9^E{mlpb690`$~_v;SE8FWDc$ z?6J@0@7QMkM^A0a{nnHDB6r`L{Nt2Fa9C7yii#2PXEFko$O2QtDfFFhqpp+kocXlQ=9s5xfB5g! z5B~3#db;oS=HoshJNv_9mYn^5al-G9qU^T!ipoEW@A@;h(k?Cj`h?#t)2cO3=$m}! zUUQLmr}+~*x1#wUDtkAb*n98od8P8l^%K3{MSlDI_2gnxuboFOy?f64zM$@$#6G?M z3gIs-o*J%Bm$S6KucH@gzyG>w{ymN7d_Fe&t@r4Q{#M^9)g4q9bnZx4|M#VjCv4v! zSE1DTexEP+`T)P8WT*$LSXt9kD4j5jcg{I^x)WOYRC|J+lasrBdQx9@o*qrC6Rch%ovYQIA6 zsaOBHVeFdu>8|yG*cbfC&Ectc6~FK2-+Y{vTk+pMy~gi{7Z<#DxKn$fFni7G^rvq$ zmH(_c^;_opdF`^bAJ6Fvf0`%wu=dE~zdGMFJLB*6FZm-c?CH+sUPpgit}6H3`{u`=8`ejhp6?7=y0`w(UF|17qIT|S=Y22!cbLh0A=Y-c{%9FKjO#r+%4pIq&>r zz5m9s|CV}|_D5*%>95%H^xyZg*XI9cIX|+FUtWD=POa^~IIhFBdRb$|-4Tayrp+yl-|a|@18zSvJc*R_ip*?1NQxQ`ma|XSU)SKX#LxJ zKMN1qIenA6U-hZ)v83+zPd3r#E9<=5D(!gxx76NEp8D&gq~Pz97M0hF=jC_4WDeYv zck+C7*4IkAhjMve%D&#Y?t0`<+s5;U>_5pIw@fPg?r-^f(f^w=HxA6Xu|?vHvnBhd zcdtwMx{BU)7T9wHX4u{rcw&9x(CmDb_eZy^sErM&-)z+~q4wGSFP3`GWJ15nEZ?`3 z=enGk!P+(2XHMHM+0OZ9eeLz^>itpjGhTm<>@!|6wYFfL;M_=#&tdk@8*II=7WG~J z$$w$`hV2GMhShI)kI8+W=`DT7jxGM{*#L|Cj?au!EWaP>`Ecj)m*VjJCr97fBs>yt zs{XR5$jz#b|KQxp+ehEY9pSureR;Oo!dH3&HQUn&AsnqG2fCaw`Cl@AF!OUm8 z%2zYfmp%6uzWc&{s-?Yp8~3%=2YV_e9sM)m+WBPet5(9flcV*kS1pm*nCJ7PsJZ_9 zTr0gRXLjZXY`ZGWW?8}XX7k7LoQBUwpC?Scp}61uj^I;;>SKG4KFX5po;B<1k4ukl zCB)T;|2rdkLv`;Q=Br<}RCgLW-#;SNx^K$XV=vj?7u&hkXJtH7Ts+&j=vnMV{{2pp zQ&g*NZLvz4UHwphOXIc!$-$QYyY4@?n^-3Qq*i$P&96IdENtJ}Cn8<(^~RB=Bm3ts zeSU}G|GMLv!72W79sM?Mj6avZZMgJ&npeytzBipw-?Hu~yBA!o@-dY=5ZzJuS1!5r zbMv*6;@0)&>x7~Ww(06WcUTk4Ce5`?<=5&P?(>?qU*`X2*niNyWB+&7qOkX$dbhE! zG}7>XW0YAjx%y!uX!xo5+SS!|{r=87?@P+c*Vc5u%inc({iSr4&+;An&t|>3FZqu3 z*uQu)G4m__)fXXU1649 zd13Oh`cm72)`!Z??+3A^cFLOZ<`?PTahtnx_ru#?Sw1uVR(TV1>HW9ccJB3$C2M_; z-!VSN^DMleOlUvfwX0h`Zn&EyuB!H8 zsVM(?&ug7n(of5NCE;INZiM`-7C&FnUVikNorazGbkCWgmEN-Y%glOdg`o{j|v!!@}n#=ZPJrCjf*)d8#!tXTHd3^GY$@#+i_qo@(Mi2Sb z8`g*Zmt5mMM|0_Y#eV&V#xAlNv*+aW{XZi1GuQV0iQOM!9VH(nm%3Tq+tv4+>z=sx zzh1>#Oa2=EDVzPT%zVa%{ApG(i)v?|v3Nc4b5Zb>Kl3cU^}G>3J*U3&;QsR659-A~ z&%6-(^}+iS`+Rc_bsu@3)7sOn&GNtZMM+e*LsfT{z=w_w=0&NaevNze`(tNWzR3~ z`k+6x)+mZ)KVQ0x-iHs*-?N_kaj1R0#-7QacvX%Xn4H|6XRqNkTj4c(?*I5NPwvEc z^7H(w~=^A_V=2Xk7Y0Am(0$dT7D*O{mqx%2PH1lUYcW}libwA-%gW*=cm0l|9x+Y)rZpGaa+r7|I~T$xH45PP`sQ+WQkqw(ho6Kv;Nfn zQ7&9Bem|==sprR%%8S>eb#YtNM#&yR1vn{0c2y43GoI&bG~_-)l5 z|5#@Frn^D&%^uFL{$pJ#Ik`AyW!F81`LY-LO~06JyBl@f`n`$e>GEktFJ2{mc>m#p zy}DC=v0vQY-owUz{vGG4)^4ko*!yF`pS@uvpQg{KSo5z~_1mA2biRV)=^{5PzH}~G zzV%n;?RUi{?>FVyn0>QktY59p|2RLXEL?cA^ova2H6OD&P2;Ay`oBK0XIAWkyxhqh z+x!!z-|UF>&WU~Qesuovi5n-f{PIYtRQ&k6>30euPOO{XKO zr{tC2|9XjigTKzy82-PT{wkDsB9~ z=2|W9?;YEYFW-DPt9tjw|4PkQjriu?_;?4R0FK^73KWx_9D;2%yLh~-1txL zhqmXN&;Am^yY!BIPuzXtaIa(eORI?+JDtrxpR(<{&uV9|pQ%`X-dD|uhu0t3e*9PL z9p%scy}R$vI{f}o_3YR0yBxpcb>^?!>+cFXpNDgNyT%rG_Px@%_o>tS&WF7f zvEMNLKyn~&{Z`?vHhbI_ZLd!IKS zy8g0JTKj!jVe$oegSxO{xuQR7=JDOis;%LAyFRksL-x9s(FTbRzBkWjopY9ZZ&DYw z-=r=~_I!4v_^tn5K3g8&FY$P>;D?Z0gZ+EseFK{x$`(o4>Z@mLXx^Be>_8NCoukHjyHZ*r@sHZ*2$Nq z_s?xNe4YKaZtWxIJ&~XF_Z_!Bc6{CMz~k$UCha%Bmi_T@?+10Wy3baaUi%4#-{x7ru`8=R-dyIdf8TxO?KK~s zOP`u#tzP%+hvDrS;mmiOYY+C{Jve9gZ($x$}6OO+MZ^qO0&c;7wC?ezxT_tt;Q%_RQ!tdS6p0tQ`7SZ5ewZw|w>+=R)q< z>+VlBuHJK4S7iI5kL#tjCnZn*ksFY*{_~s_`A_Cu_^sMM_o@7oNBlpgJuV6Jo^x)V zNugEUKSuL5Ws%^-NBx&BdHD29Y2N8?=C)cXEK9|?XPUga=*)aYk>w__Mcl2Ar+lj@ z^b)OnGskqAg=zKiW3r)-ugFB{Tdp-@`x%tJSF`d>omb@cDev!byyN@wV_yG$v3*sO z-amT!!dmNb@&)B&!4|1RqoSwohsMMfFMPPwFkBz5G@(@_)~~H}BjrWnp&P z2^IM31i+~Rer_nNnG-qTC1JXcMccz@17n0{;BQG`^IiX^XGi7xm&#E z$n$HSbJF|oR@Mc*d;Mxc@X6kv>t58qc1m8mtv2+?zPx`D?_aCEx73UNQ!P*|`zUs1 zwc>TlR}vP-eZBVj&V6)$?Ywi(;v_mdexF}rE}6ggY~h0CX9fP>`>1}gb-!W_|I12; zXA0)uY*x=J+4FVF0eZOboeOI4V?WBzzgK5{=Z6@zEnDu~e|^mUT>kyz_aEJR|MSfDhdLcZRlief-4}**)+SE* zdHkV$=Hm@}&HBq@QnuF3pY{Jgvyf2a1z{!7Vhkn*?29q@dtyW99>4o9c?RF%FQr!X zR>pJ9miS(taI9^DY0CwPO}>|pT@g6p7UX1-Yw+&Uxsp>`TwiTzTKg&8WYPtTyfwakk6dW=>ZkhKnW5*cj(5Lb z^XGa)z03Y{HNoYRwRBf)Ss4_x^sct*&$X`e<~~oJIDOyLT&DfLd~><}btecM*r9R1 z^;fOipXj;UB5tj<`>Rw_y~o`9u59@iy|=p;=f7m#{#`G2;VG?9y(x#Di~d47ohcJH?wDb&{@|XXYD@j*``?Q$ZIhV(KvnzxrFmux;|>44?)mSfx$?{B6L()G zubuUN-_p}9=lAbjyZry&RcnG%7i+zryeV*B_4~KBf8PhbUlaCTC;b1n4xgO*oO2Ot z=G+dIy}N2%-NW*w?Yq1Gd!4mEzpA_?FPd@JTBq&q6%oAtp+CcJToBtZsqX%({=Zfa z_lISyn||o|*32)PFNn_i^4+Y$e8#tUuKw+MaYb9TuGg;Go$oMp?y5JF4n1eA3r^i! zRW|wHqW?-0j~n$W8<{*-Ut41Rw`%IT#moN-9jx7(u=k|4^i%U+cU7IrryBoHS$bPp zV*L`ng*!Rt8GWcVeaoQjd;7~zvx7xpVLQ_g)URH&(|4+)=ItNrr2d-h;yWw!*zM}Z zwtp=5KYTyAZr^PFvTt?I9MaFvUG?X4W8b{$l82jry-NsxpKgEiYIS#2S;Va((N6(i zW72*l|ChQtuUuWUPTcbLN7nV>D?d4g+9~beU%knFs`Sz~6W<^Bul(sv=q2$lf0BPW zirw1PJN;tXLhfUSKd|I?)@b`2aJ%KOKYsa3O`g=hE4ymV{#1WoT~_leA^p6#=-u6# zHP5W;w4LtHjK04t^^(l; zulJVy_^lrLK9=jfbJwx(tNY^@pLp*4=a{k0Y3n`SvR70~!gW58YF=XT0YC2g*{<^aogqGh?NrCV*k0Yxyil8(zJF_8S@^_u?XO=P_hFgrsy{xb zlxvRX+bEat&)#_9x8*na zIsI#yU)LSu$M#JBa=Yg(?0K?8UgGuHHN|Uqjkf1Jt^Kjw|E+eZ4dZEdUxf36Qd?m4#T%1>?O{&(^#zTNrX>Ds-2>8oFCe~p&b zINN^r{jhK8-rv8!q__TDd_gYq!bkfLD__~G?XcHxJ%8MU?Um%br?U5!^4;YRnJbxD z-wkpwAO8m?*@|ZOiryc27i;$Os3kDxf+jmA7jE~vcH8f!by&|&r62ciYq1?px>ilopw%POF-#zWI-II?qwDza`Vd1)OzigiMs(JsnDnEbz;Pv9? zQ{$TaKipfJ@n+urZ?iPH{XWU=|HyOxliwBokk~6TCw_aJW>fkn%%INkd!Z}yy$6DE zvit5cL6&ONLY8XGJ_uf_F`?S<5BH_---Kl6Fn{^8=o|YQ(KFIt6kjdQ*OppdHm~^J zZRgKX|8^zkoxahx^YhXzJuBZIYrB%ai+{!Qkm$I{A3q2sv+{)gyzIO7t!C?e@qG*C z*}psS^U1nr+stL+{8yU=+?%%O_uQim>EN{*yNWKQ#q4*v{g5$kMg55nwqg%{uiw)A zyuv+sy#cee0gJcseZ9Q_=dSy{o3Wnv|D!Ldv6&C|9Il(Tm$y3jncX#>U$(WKRS#wB z*q@!LPfsZOY<+v_hsp%M&(_Vas<-P-)VUJjD7R|QKI^4#jGpq^ZWGy?I5W6y&ptDY z@_*KOg{cdE-?Oax*Z6H^)0R^CV#7A`iZxGeUyv7ibC3(X>OsioU|5N^?mMe^?tfb^ zOg|)3%=ldH+@d+&H)mdhu)25ryvoP3?=N7k)et|lU+mYWZBs6M-^iX2 z_rT}W&lX$W*V2FGbq+9CwY^tcAM&NqLu{A)6AflZ%j1UMyKjGg<$Zg3^vUhV;`Xw; zK_-$DG>dhAuNEzuH}Cn{x2zw^EA$=Wy})ZV%23y8MBMv-OuO@w{dM`-lBaiaZp!Pr z{QX6r{M%(N`zp`%?3`u@O3>h?B$3JC;I$fcf93|Y>~o%Od-V4O`$gT4WDZMq?lpR? z`kCWz{cPp$ubVf`mwBV!vd#H(RsZw1M%SAVD_-8Lo%Cd$^#7*{!O#g6S z^1m5w(-IdnUvXB{&F~&c9-Du6_nytU>AyO?eA@X>a~}IWweg-iY4a4j<-zw8wygKN zaotDbEyH^*X#*zh+G#;I8WVYc?|Sv)x`Ta1--}m&*Ibj-dGUj{is#&xo_5E*^KkI$5)ciQCjS`8KyUT7KiX0a{4Lek1d4=OLr- zmU_bf^w@sBJpP5v_V4?PR)^Nzi{9Y4@UV+{@4wYW>k7XIIE6oK-pBIyrTcm9y&AuQ z-mvXIxo~-HOpd~fqw^Qby^=2b(0?s9^7Ps>$LDT)@b2^bvm4b9_Ea4d(Am1~%8$iM zUgvT>if`F>Rk-W@!K^<#8!VISkBB{;qv+pyZbDgKqTL?FL$wbJpGms@Ua_rzMP2#n zMMwY7I%;;P*hb%M=He^PwO6u_#hsp!+5Fp4fi_2_cX7Wpi{E9=^B$D85PzPhIE`6&HaDcR-m zz73z#U;Sm@z~5ni%&~?!D0ktXb@MLU@g4j2gW;>hA8-Aj{khFIS7+Z!7WVl)m*Ia{ z_&2GDM#&qE3vV2mkv#o(_U`@1t~b={{hIf7uWQbJ@rTgW8Z2MgH^<5*nj9~vtLOu- z*7zw@mV5R2KgZwpI&q)AXYS+wv#wU}%I7`De@oSe%71-j+}mSa{ch9eGb|VF<{sL= zTL0(DZLL~72ZMgwOGsDb^zonhy7j^QnRN&Dw|_q3^{3~9<-z|9(I#b{IU%XF3!SgO zQBMBl_{?)7^Si_EJ+E$e{IgHb?^C&u{qpXk({q^LXZ{Jby&`@+@>OZv>+@fC*)7}> z{Ii~O%>kY_2QK`WsT-^LeEAI-`3)zpcGau>a;%q5X5PnBuUzB*!P()s{9A3&bIj-~ zHcTHqp7AU?^RJY?K>cLiJ@dD0?|n0Yv-(EiqFSxi`rB-86u&piN;ECKv2XLw+aky9 zh5xF|w|o5g;(oXDrdekXhqufhe`6>VEt_ltg;_+zVKUy6L@-(9nV zy1t2u&wg@r&-(A%R@p^9&p0e?ExYsdt$(}LWcP12PoA50POQF}+wJteJDGM@j@92f zA$Pw$du98tmjB`rkCT5_J(oG0zm50Mf5zkgGN0eb`d4anJ-RyQJ>$c@d0&ESEUi=G zD_hqXe&2X3bJwo@s;6QvKaISXxZXw9XnK_V{47HrD?f*04|Xr*Ro-ZJVE3DRwxjQI zD#dQyU$B2uocH|A`%*IvMXu>-{>xo;e&zSl{o!8=k3FvO|6g?e;>P05FRSYxMc!rG zd@e>c+xvS)Q-A1z>#MA#%2)MOUG|@_yZh(Vrk{J~Ymh*OT^}8{7+i%ocpBz@q&Qzxu^>O5Z)7)-QVDZ@N#qDF4J>#qXQr z-kE}zZ&>dvcLy!sn5**rMqJq5$1he2ecu$^`Cn7z`^j79ciSDE&76MY`sH))&)qED z{N6go^k=r zK2BgwOIZH9wrRiXE2(gv|2|)si?(m9ymi0bBI;2`r>5$@2@#tgiu|q7H8VWvpIBUx zGigSC&cgp|j=kp>{rmq~&FNe766)*crdLcWuLyskTwRppp(k+n|MA0epB zWB)JXy1iTZd(_ACF7^h;qpcTweVx*`H~L3io5kTo_(G1zPu@I+VH2g_ruT{d{>}+r z$dLqH$WdIiHt>Dc&DFbB1b@oU@jFo;F#GS_AIAGw-4d4m-h0UJn$-1v({5Qa`+t@% z)z`k=v|K{4_T=J2-#xGQ@9z6&cJ2Dph9}c^OsRziay>GAeYw^Sjl}49;Zk77iSDzU7OElZMdeyvt z-ZP$`5KsD3V>M6VoZhD9O1rtNe_!)iA3baNf#J8&t+O?}{87)?ijA)|{mV@|_fT@4 z=uLZf*(<6$9ppX~>4$7tIHNu`$Nz6zpQlOTi654C*`_6ERi7@YpY8PH`SSNC?|yyy zmt$wr3F${`bT@8Y%T|ADg8k~r#R(VR-R^6QX_x9msyz9OBrcE!}rnvZjO{;wImSbJ^uVaNa zC)Caj`m6Q%aeU7{_40CmL!Um4&Wl!I_byi$Ms;o!4m{H}`+LKVDc2`;A=Y#F_aN4D zXr)Wv*~6ZE(oi@qC#o{P+9&BUU#EPrf!nFc)sBBYU*&*3~X`N@RD ze^YFIjlP+w74|)`y|9zrC+F5Vo}j;YUfnz?|IzA%%rEX!4JR`0e13SpLhXB=>klvNop`6c z@$Q^Iwd*>ekC; z%X>e+zxkkF`d9bu{i6k^ zzXV_Z)^`8smQTA4e)b;v>-YHm1$FzEVx8@8zhD2>Hvj6D51Xqt`P_e9zFD!-%Oyzg3x=eynf$ zuU~xX?}qgLnR-R@*X;0^{eH3H_s!aTRhyo^d!}FV()x4Fp?&KVzh~-xzo@bQ!ldt; z-9QWDezTmcz4hEwOX+*n=XjTQ$Nn!;+bMqY{B`yIYZgz1PVbs;zUA>xOW_y0zATPe zIC;wPHS;Q;ys6n-wdL2(y?T|Ok6D%{y!v@}VQudX`;%8ACjGixq_(YM%leruds@Gq zkd}P;+GcOyq&w*;^MY*8&-(p*_tN{}A`9(rR(ieNvH91}Y#00dkM)6Xl0?fS-R=J` zTB`r8F?&+Z`+M`!Zar7M_Rm$;w*APr+O^wG&#->5aQCdQeMRjjkLPvYU`gJxbN<%} z)0yjHJ_&W-S!>HD`}OIu=gYo-W~OzYb zGpDuxsVit_-^pCJdExFSe~+o1-oK3{vwy|+{T{Y6-@M=YTyed{@ecj3wlDWhU1>M< z`-ypWA7hNIKEIQFp!enX#)GSO+39}Y-@oBFE4OCNKF!u|e;*gTceqr0!4tZsgSjs3 zX>H%@=Tm1)zGc1N=XAAO%eTz_Z^?I-tJIa=pYm(JpAO@Hua(X9vEQog+%7*>Tl0U< zUhgx%ZrRB04%Rw2|JrWvSDDA3AHSz4W_`Xl?AGt)_xC#Wt)J>$edI!2(7XEfW9L7f zp75!7xybkBb3>6Ab<`F+ygU2tjn;FG?*GY)%umSaFMd9!ta@I_%lJ2!yS8s(DZ zueXBNbjV1D3(8CMP4r%DFV%l?cHwuX=L@A5)T-I-S2^<7>i4S?aS2I5@)JK_*>Ev2 zs{ZazqWmF{k+c3=ex`6f;RAo4?L^{#|6o^UW9hZ(g^JSUG=={0)D#le_1At|@ks=Qz1*XW6aItIvPd{9dql z`|9WW^aQx2kMHC7`@piV_{gGn?~A^<{@-l9snK#{Cg+UfMSNFwt-oxkacZafqrVDa zNw0tQY20@dytPNUQvX@Yx6+0G(n>iDf1jy;SsZi7a@8wKzrEhF>uhrh{3636wExby zr?zSTx4UcJ{>`dQSa&_$^4x^5Zx?sEm82P-iT*Q(`J2wv=Q7Jb%P-JR%uh^7`gX&* z$M%`*_BRE;B}%SZAO2Xw-gvUs9~bvuJ|DYxqWJdW`JM3{?=G(1aM-$PcHZ-I zd;TVs_djaM$w~O>b2CP`7P6>=eZ%vNyS^(QbC$@g`FvPt@~cw^4#wPed3vUn#JD-q34#r@b`@@xb)&#&z#DzFNe5>}3S zKfCV4cE4YDtUA4I8f*hk$Mse};aC^dzw#J!g?D1i{zDND|12o|wDes3#`#CYdU8*n zww#bL{a{;@Zs$L(Zxh`YzWvgid?xwA#6!=MC(gOLdC%gvj;r`y3GMa~yY(b)$9%KP zWfd28Rb74lF;nBa_2S2i``=&u>-+hyPOY24|5-n7=N$YO`yeji&HLyT&AV0v_uEcp zf1~fj&_ScEen7?`6*tz7sZTfGSzrFWgWLrI(SD0q7zi;#8AEg`CrS-PI72B<0 zc<{RGkJY=rN@#3n{&Vo}OPepke_p?-$xjY4_tN>r@!IxrQ>|UP&AIOnbf2mxeYR=h z<@mk$oPOi|W-I3e=CpmDCoBa{*B_8``E9?#Zh5hS!|v7J&5E`PoIYPEGV{XnqsvY~ z##FVpeN+6nb4S>#HD1xTekk7Zxvl#D*z|{;dkt-@{_4HT|8q>vtH#zXWzJgh`t}pc zP0r509+@9~RQ~N!&PLwm-D4%yKS1#@7zv_B3Z9v3o&`&uYAk5HuuMKi>2Jc`6UCFm%}(W?_$jn-w^xnj zpQU<>&l=r#ES~(t-SbiP?2juWKQZpjzxLPXW6ra%*VgN|aX2|JJ`}v}1;qG&9Zhxtn%frYNDzMN4t$4x5twSWAioeQMypI*{m?y>)( z&F|{%Hb1PZ_o^+|cT0Bo?iu`NpWMauUIvZpu7B4Nv-_ubCwa#81KYK^Z;L;(e4F`c z-{$jYPhC1c`33v0IMaP^Ys9{O6qsiEAphz6bDp_DcXpaAif?(Z^`-Vt^A7Qc*5~5` zZ!Y_L^~CozD*Li0R-cmi;C=UF#vjvvQuW5~*BhSi=f59ZJ1_suYp(aNYxXUFyYJk> z>lVjTpG4oftoB9wSbf}1>)e?Witl8I?q#&IUL>FWB3I{r)bZV4oGee5_f_rMWmEJW zwDx1a$%5@Ww}kEObvE_{t^Jt24Yc-SL(M%ktDmcVZNmPi3RUmBGn4twM@cO+xmv52 znQQBAeX3o#EcRNj`?l*cKca0bW$J}D?{1xO*TX+Msdu}_nvcJfs-oPVU46q;o;BO$ zhFxQ9ntGY;#?n~1E_;8iV{Sq(l_x$GJ@TIW-EEmW-#rSyK6y~zdm%RdT72K+*kiXA zo7}H8_m)3kx6!Z2_RHyC!e>k;Hte5TIX`dutZ3HyoR;4k1e3}yZ}UuU{?l~B?mKMt zhu!w~OD~*FV*fKQon8O7^6lOG^~-MT-k6-MFD!l2G)Z~4l0n$qMUOA87x{f&?C$jq z{n^zuX4Y%AZI}M7Z*)WH@rBOX^*8yt|NgX>{r$Q5#r#vW}hiPA?Ud9y!oR0{Jz&N z`jjVb&i2>tar)LDxBKQ_J+BQ8QenV9`*c`5tV zed=4*MBo1J;R9O#5p;_4qpA&G?Y#6qFJr`yJx^Ud^YhoL`7=)EY-yM;ooncN`G2w8 zuX_>apI#ULl)1HT%a2=~^^XnT>#4uKKO>~iZC~%T`R9IYbKQ9I+VgPQ6W758~_gfE7zxYY^=j2so3e3OQ_obcr>sL4b?4--tGw0?r z7wJE{u4Q**x9Q(Y+BV5GZ+6u``4Jj+fxqXgP2C>G`lQF^`5OyTJ}Mf?!X zdi6hN?_Q(7_iJYPW9>&q2ex1N`f%IE@5i~1-79XtJA2*xiX-3ee5#!?E4|hJeZcfP zmLF}8_uqUr`$Um{2A_Qyd+|HJ;PV+bXWOW|uTbvXXM9}b!|m@$lb=m_-z`>oexk z4nv-Yhu*8@FAv%a@~)>Ab9IH57pr*B>6>4F zp!Z?N(U2KG7OzRwQFJ?X@QyxY`NtXu@bZr{+XcFVXKC+jeN^b>zQzcQCyUO_!|BJRwnG@73_pW%4?c82>HNGl?ulIH=`D4}y zUjEU%y%MziW1jIhyV-Ym-xcmW{_g$f@1N$~c|S{G=lL_0``%fGO)7r9xQ?c?iA0ma`$a4zSDE% z_7%;4cVE5CdDptp;ZD8c-jgY>bI&o^<~IKL-gm!C?+@$3>Y($?M(jH`K6m}HB-qj4 z`tw_((vEt2`&ZTLFMMCT^0P`RBKM-#lx>kMAEpZ}vK2zu-go zbE9)l%>K1W|91h^2xI5Pq!^D-6HfmY<`{K zKJEwcjn#tt)PJw{+CQJGaN^ZpwP}_A?LV!zuDvP@S`xy{z{0@7fH z=vC3<(d_J%XGE-YogEyPXiYjM)pc-@!9KeMilNy~zCK)Cxu%o&)?UmIUYwDYyOJwI z+pIU@_d#|oDR!kBYN=PF6mMOza?Pk+ARiF2A%yXw*~@?5|7}Y@|L~sm^E=ml^na`U zKQp)ZdtCPV|F^2=|BZTH^UU~fea^`(=a)@Xj1I14n|ybxhWCThhh?H<+8PcYoWP*F zWcBR7y{qC=-}pTap8Yy--U6Pbrvf+Dee!f$eb~U@PGZYp4+EtgW<6V+SA8wE|1)iE zwCRP}+oHE^wcN7&LfDyiUZvui-VuEZHUHVZKm6&{@nd42dJatEYv0KCShlZd21DPY zSq8@vO)A^k>drM@n164X$^QAwM=QQnMQdGo`?c@DG{YNe(fwsJSo)sL+FmVE8Feu> zSC;#y{M1MPJq+e$%YK;PX}|xp+t%~?Rz4*&UKyNyDAFD*>&LvjD0kQ4>9T6pJ>EYf zt@zJ#ES2v&Z} zzB$vh{=EK~@BVB_!+*&ab5DNH{9`5<->b9yK3D0EsU@qVk6YKAeJImj$@f`SulR@A zj-KrMB{NZIo)WE!@n|%Gk3$;|7=%&&5|--`on&KioeevEPnj) z=82?VYcJ@psF!k#wUFb}FM3h7<6`2W4sWdZ-Y4SBsc>MOp?m6$b zTgANJ&|!6(J@Lxv+oFd5sR^3bcWvCyJ->G2jJhYkcNtH#T3B=4 z>dw;-3!M88U*_A-{OjM2!_0izvU!C&xbpP2INi0n{gB7|R;=Ni#{6d%bKVzhJS@t0 z-9o4E$I8R91-qGap5OBKEat7$b2}!Jl6JAyEOqaMP4TU|+8ce%))iN9ttpLoTwtHN zL&|=|+LiXQtkWz1-uAlZdE%GaruQ5_?lV;FC=<8a#WCM^%MyOhzpM8-CX0N{4&JzZ z_8)&Mo97o^e<*JcKX6~>-=X|ZU$ZQJZaiGd*DbrQWXGLJW#K&2C$F2m>0VB&Rn_{# z&V2p{-v2tV?`uqTlgal<&(l&$o?qEJ!|1<+bXfA`;u{*#@obMCp68R6m20fuYWQ{W zF8Th((`RZ+4*Zu$nbUp7`oc!Ry|*3oQ>%sKOCN7u`Qt%-8c(j4@UFf{uGVdI>=jSio&{XoMRPU*t}rx$DaQ|nly%@pgc%}!k_Kj_zP{xi1fYTx>H z?Ymk|1@Fz>8w0n!W0o(9wF|Qji?7w5voijwg#Y6oik5$@TWo|U7|PGgzVI>a!2h~^ z`+M`NK3uJ-F_(+y^ZXh9)x9|CY_&;Q;NLo_cV&v-h1=^te@|}j-w^w@Qaxt%{~xOl zbBAR_KYFv%=!VNK@e|9p?X-RHJzlfU_S>h~>*H^qjP8Axdt-y}>~Berk2juW|M1c8 zN2u&h*>fi4m-ejP%k+QSr+jJVi#-zlC!VM zpUpM>e^DaxvBur(`^WWuezR}v=RZ)Y`!~ApvB1|A(V2IDZ@75sP~H*ZmRs zljXC%@Qup*_|pc*HZ7^$I(a*Hn)xwO8%`QO5j|7$ib zepgz(HsAhf?dsnL>}BSa|5$r?G2i}ee;%){KJi_nXrBAK+l=S`-Ln_i<$U}5p_BJl z$bWq`|N7D&{KxI$>QDZ&RJFI=cWF;tvHe+oleR0ie;14F-}Qc_fAux4;;Hcy-?vYz zuiG-C#@_Lq@QJ%^a`(f3+wGjV>+r9yf-!FzW*~?h`K;*d zw{D-S?=CkfyP12^;`nyioB!Rl&uCu}Gikr_EArmg-h$pl#iB5U@K4*5`sd5Pc@U*s zlD~P0?C-+6c@~v?eR&O=qt5o9`Zz!I|AZ-j3hLHw4PSdcQ*PzA^*^WQJJ;DP{`Wf4 z``M5C?#E~H#cw?nV|`xgVaTVsopatt8}0vYS0~)EZ|(MX=^L;1@2t7Mku@*u(AAjL zcYnFn|4F}if6}D&rfV>hBv>P z*DlFd{y$wOviWM&;$!ww@9mhYc9iALEsbyQ-G4MK|G#&^CZWE4eCdzZ{QBFf^XK`s z{8lrYD}3vmqbAq3{CafV{%dTq@7?RA=Y#e?`>x-1I9j#(P5b2g?-M=WE#`q8WU zdDi`cx0kG5$944fi*5WbxWjY1Y+=O9e+hE`ieKsnwQrfWvd*hCB75^J`G2A>c0Uug zSLuBh`|AEJof+k!35(}75O5sP?c9nP4y>i2?gW$)R{i{F-9y5d}Z`0e`b|Ag*j&2|4Q(3|~dR}KI5 zebMQCs^PCUO1a;C@`1ZR`1-C_Yj!XEc0KyP!|m`zJQw#v;M5m=|9b!R{#$$RSfhl! z`~Pd__cL4mw+;DY9q{>nW6XZ5kZ1cBXNadqKE9s6rEb+{=gRBz-J@Ew_iO&GyxxCK z>Fo-sU*`P(XMT;|^lzo{hu{o(E9v*&SG?NxPv(c&ox_25-{k*)!Si}|eaOas-TS{j zd+nIX94;HS`|EQ^+!xC{@-X!4x*Vj_|1ILG`nBBu8Xwm7PYkSITrsQi+W&v=Z7%t3 zQ!!KC-mm-r-$ku2^ZCQ)7KG>4WQ6@Ie#vj~?fIUPFz=61QmeJzIj5_Y=q%^6XG>D%)%DtH{)N%I=4<~;-hK7kpEi5zhmTLHKUTkb^1bDqv{qw{ z`Yn&1uMeC2toq5!MjrY1AQR8$=d^ckEhuJ^i03C^U+e# z;MF_4k3P%Y;-u4ZuJr1sKcTSJF0d1Acer(~tx29j$oO7EFJg6U+K1e98S^^Dc(?>`C&P9w$30x93zmJYuPZW-$!VLdT2Q(v zw7|?v{r|qY=hyPt=WmQlX#J6S^}hJS%g3ukt^cp7Uij|2)a9&uM(q1c{=d^|y8N@2 z@1?%#{wFK$e|>9KyU(U}-@WaRubS#PZ~T1TZrNL1i%OH^ltXmE0}b zT^Q9r_kE<$<0rQ#{L-%1zcS<8dEc%77MQB7RnF=u4;H+0=DoM)`{=ImhpxiJ5K zvge;g-wPL?DmXCd#=-ADYWIc;Mo*hue{@DI$Gx+Q?|ZGU&Z^nCu%o_~Xa1{A@7Sd- zXVtuXzAP&F(jTAfqqq2fxC-7m`+l`f<-Q}vCn|+^+AY)ilKbMZ+q8qnr?vjO%itcm z*7^B^`~CJsFZ=)5s{E1u{ao$s{ELFe!+ovxaXmTyGw}1d{zt#uir42K`FiqM-29&3 z+-LXh7x>OTyP{q|wy=J`=lAau*H_7$e{S;r=bVat>vo>Me)RLk_G3S9RP5XP^Za)H zCH0q6J3eZjeSKddUhJ>*U+KTmo$p@U2fY*S+i8OV#b> z|NsB}=bxkZ-I}0`tz!$@}=%;_QdIIUoLNR^D4LazEd+;(mT;$o|xN z`&s?E+>f0@wm<&;lI`8!lGLx!MrEfz)gAs(ck7eUJK7mng3+dH=nQ!Ta)W-|xr#(!KrrV7apS6Z3uZ z_ZGfS|DO6&VSSx-Ma{Yy4X8zy91xXH!bw{)xL5{dDc{PxPJl)C+|Y3;ptaXW5g zocwi4$zt`@Uv7r~O8F}}_e^l#ulhRKih2F-&GGenXZ=~F{EGdG+dQU6;l=COAGo|u ziQ>K*6?xB;ZSKMAar2WhMf8`>usCX~x6$d(rc)1Y&(5D*{^7RJr8viXpC^`vx!ryE z>zL||0&X+ghThjqyRRQQ`gh91EbnUv)DI>ueLeZ-Fx;VM#wVKfO1;bY1hO%$fxeVMn#+`$(om zf3j)4{L^mseLuCgg-_nPTwBqz>+ioq7N_cjHa$;@*4+L4;8~v?QtaiAHeC99u;@?y zX|C7Hxqr@!-Y@#@v$LoAyes#vF86mor{g^@*04MKvghN!R3u55aLQP!{O?f$Gc z-z&fLA5V7=7Q6pWtuU7<)9U2qww{HSU$#xEV@ds9cP{I@%9riR%WwU-Q1oX$o7ScL z*1AQkvs2gKIxs`YX8BLq$)B?4-FQ{dzqfVIBtxFc+$pgia?kz0?=~y3@!mA9((1kU z&PTqLbDbAf5?=jpmCS!($IxHQ)zRJ`VtVdhyRbg=){Jl4+w+SbZngWjCMZ9&EPT~& zkI1g6$tqR1f5c7wS68vla=+!N%Nn-KS>QnY_`zQmC##OO@8jElY4`C-yPnQJ|3UHkw+YX5KV8wb zyK?;KuNe{N-+OUH!k_7}Bv;s>wBPTMm(&g?(mi|UyB8E1aAJ->hbz1+IHt^In3(uH*+ z7wd@re?5QxEmym%yj%Y-{ZOTT;rkA|n=`(8p8s#OVM_Mh8~0OB8khX;{(rT$ZjI{u z=&-wd-^KUwKKkdB{9Sy><@fp(f1gKuvU|Ppho1MJ_4W5R-P--D;<+ z7uIjs_q%x>e5mH)r0d;d?J$M>qO!iLLF{X^}ZqksQay?@{SN1pRo@mglNRlWa3 z+oFs7j?Cx(c>U4OIltzf|5$pr_-&PMXVY*AsQ7Db8^ZU7#LWgaqu5*KPcKN=Da=Z$jQLK!LmW@ zQ0<%hpLiazoz7XjiX!mpH~Yi$EcebZfoz3D2ZpUzRu{4a3OHZ9aP5kxPU%0v8%GYL zTv7Tv@pY5p`e%2tmRvvn{QK+g)%*9adH?nJo)7ZMO%>V4?99gq3ocH*nk3VAe@3sG78-H_Ew|@`5 z*QBmyv%9|f{~R{E>mX&%WvdhCe=z=cau;vSy7f6%4?O<3v#z@S!|&0+BO~yh|CGO( zQ0RIDoR%S32Qw{iTr1(p!*bC(MDV}Ol(r{x6w_zD<+0ehg7uo@2hog=&#%9?xBvhD z|J3{E?Vq{-m%MK>>FVd&ER(SFpI+|WShcUd*8Xp8{jBV@^WM*P+f=pBzxUXyuT|^r z@3a49Ykza)!sowCuA6*``Twi#SM|P)D;NHsW`A?r!sowE`tk0KJOB0eclZ78gBNeC zn&$t$_v+`ruYbRM|NC-G_SYJ?MeDB@|NZv&;`^T`{djG!FW&5=3{@Ze2?5x`q>e6jQ2*S}xB*CYo!|JSYGl*Tpo zRZv^+FLz7+sx$wd^y=roL4NqYeCM@SKlf#-tbPu%C~p1pUvGaezW*7dWu1Squk-n@ z>)$Wm|6F>u)UW)XlXIo3*3Ex&m+k!-8@;r3 z%B$^0uUmwZr1;*PowxRN;?mv4&$fS`_xbF+zh`y)j-5IeyKPf({m!-+-E~&itHP(g zHe1z|TDr#A<=Ljr{>J%5bIWRs`0HZuTj8UFLPsdC&K}HV>bk zy?*tvuNLd0k3N>FyLNQf^OIfYr@6n;-{BVXtm^#NuI#0+Rf&2Y`o`C_uXV$>zOKB^z0Ozc7wZqk zWA&Fz6BBJ-JgW5nAhV)d21NHJo~@Rza_194V%`-$VdEnJp0F!pSJ6wuAdgGuT!>@ty}xr z@$~UOZhI;|zWh)ryZ?y#;pc|+g7anMFaL4<^Xc=(`}2R4{Je2o{o~6|8=tE`y8JYG z{`?MceLGvb*B{+$w$)tw+5RKv=bGp8k2XI|-fs_5*6$BecHaNU^3%ud>;?7X_WY^; z`04-A)BnZw|HmV7NRv2jPlQ>?Pd4h`*Z6;5{Ndkp+y6iGKg92trTb=WSy!ob3=RE7J zLreZ%?71cX`;UtDzDuQ>U$g!G{`a!}&a{=8+~-SXw|Jso>J;Hl2x^tEQ&|Nqii z-(P3oR5v}_ndR;O{h#@FUN23} zsXy~LKkQG~b*<~R>#TKq?o0oS?0>zc^?7~Ut|Ob|uHE!lHYZBsfA?$Y>#x_TSG=F9 zx!wNtA7wYWowwAkUtYId!urG8HUHTkoBGX7y(#eejoRkED2@Iaf$B}k`x@*vBud_z z|Mib@m|UgIvDdOs1g+29SO2m1p=I9UstB`#R&P_b1#>^0C_Zo71@?VqSEEm`OXcR( zK1@0E_WsFj&vflFKXwQ{dp_gxb~Ty%tsh=6OR#^?dy!DNJ^O&ueUGZYFCw`=-?r&J zpZW1e+;2(sBaD`jlO9)V{(0~EN9BEb!}lKxTV+%`zbPM&O#ON4{G~@5`=V#ePmY^k zQny`X--dk+rYtt=SL?3v*Duyl%eA{|&8n4TTKvo7Q&c)cgDl53@=7Ke6>W_vh7~t1Rl9C)Cew{loqGXX~G} zvr>QX{ELfv&HTBthq*#L=h@fU;urtjcorY|;l%F;w`G(6Oh_;Py!)68&-uHWb^U*B z)URdSTT*bxE3fCdh0DIV$D4ape~JI%{InxCg!%M`NX^g3WkZG{3*q~FQs z&wo1dIKS$Ho@0Gvw&M0RPYh2|WPyat3O_n+EBjCe-!{xhMS0zZ=9iGwuT>N$L<|{{)_MQ9ko%zwz|J~F7 z>&N}u|6?^qQT6qA{l`Z~mmf~I{nv5*{r{t{zyE&(68rUcf5qQ_@q6n2>&NY>`1v1U z2oi@3i63u{%VR6%_VfI)U)<`lx(wWEV`1Q9;A244cqt4i3>9Z{&$-M@6`f&ck^ug$j_{J8x2{V!i#o_|}CQ`x<_o9*95-aUNb&;$S7^WHdZH~4XR z-}2voo2i;4Gk(@R*Y&9HO6e}oFT3CLNnP@^hPn-PD`n}MNJi~M5zsi$#AHACR<$c+U&Y!pY(e^C{KQ3>Ec=XGk-F3krk4D@)2nvVl zu2>P6FMz_~{YyLhpJLCd1LAJY|EBhBm$CNKEkDxlYEIHk+jqZ``_g=+n~(0! zzPo+FA5XXclf~BGo4bScp}+C3`CERxd%H4v&bRjoSN+kV6Upb^noFkyd0{1<+JE_P zb{RF0>`&T1uQ>BniW$_-f($qyQXRCneb+iqBv8U7aa*%Y72||WoXhY1=i-rM>{-72 z{o`!^P*2gQ=db>lPD_>i`04N0$4hf>Zv&zKm$z^K{w-nY|9k(Wrv9t`ogMP){oD0{ zFY8r*A3q=ecK*6u&3EGS^UVv6{pBmmudid)&bKdS-urhJZ_h9J+QWKvRpCG8e{7rj zCqMD#%ld14;UB;1hHUv?{r*N_{mcJcf#2;v^~L`7_J8!Z^|`kD@9TfQWc;5sU+!)E z=gW)#X4h41sXy!A|84!xmlyw;+S}gR|7`ilQuO{=IdgsS>GPZK@0ULD@BjVF<^|_Z zuY13L_0PKp_E&!Srfpwu{m%YV-;8p(+}-$j`~9y!XCHje zcIU0TnZe}yygP2of34q={?qvWgj<5&jsNt2+Rga7?#O?gI`f3P^FP|pzRw%+z5hr2 z(fr%s$cK{ODp%L9{}sCG@Aq%}Zq?_%Ukzsb*V^`P_UhH8M|q#HRaftBH2#{#Fs5v`Wz~wO; zcyJ6OXIwm(%WNpX;`n_278wTCIq`CGtA0KglluH~&im*6?@wPpzW@HeC-)!gzx}iA z{QV!^*8AUnHvf0&Tz$L#_SgIFtovQG``zicyD&NP>hDF}`k6a_|HtWNb+@1A|5-Y> remkZzr~yCE|GRW9|M#EX{aZfYwyPht4mD)S56u7P|Fdohp4J2aOLA)7 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-generic.png b/core/assets-raw/sprites/blocks/environment/crux-floor-generic.png deleted file mode 100644 index 08b4c222d0bc0bd35c5d2845267016402bbc6252..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1041 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&zxQX)jA8<&2<>TeCH}m^VX8y+ADWCXmp5o!&q!T%5{X^^Jw|T$q z{roaQ%>LTx`ThI%@7`9LaCqnIIjR57p1;1`x_oXV^Q(yG_jML>mg;=YpLT)e#?$*T z|Cu>+HlC<|ntjOfdF+ficKx4AzOuZz&p)|O`joxt?;F2*-`m%!8U4t7@}zY3|0%^s zrOBoD;i-u1OCcxzoi!{6TvJ%nHROkA+P{ra>A zPv4gQm(E)7{7&g~)~;ec&Ac7w(m3uPI%96J@A}uD{ZHjy9WIZ1&-0-A;nq%`f3{nV zJLhr+{pPsGw9IUw*V&w)Ye|~5Dx3$J3g)=)c38xk@ZoW#3g@IWh6+0Y2N@OtcE%%) z42467sUFo3d;8kkC!Ifj{@RwOIBSU{1Lv{IB?rrc^B6r0&aBJ5TeW*-*}I4!l`mWc zzih;^-CFG?D{_8&-=1W8EN-&W!_&84|0{pduR1I2>7CN)+J;jeUpP8#_TSRK7k)Nv zZ`e4Kq3z}RBP*F_&i?z=N8nXr32y_-<)1%)l|5fKyQapIv#leFMaj{sHf@^F9J~I- zUl-qJRdBS~9vSITQ0udzu0W6@H8S74T>Gb`zD|6t9oM{xcV;edt7VxnbE#(o1DlR# z)6_`uM-lbu7p}+u6k{{cpZ3%I+U1E>*M6FNXE@28{-fXRpt9kp*8l(aSQQ#|#eUx3 z%l#s}ecJp8Tjt>XtU6Qcb86o|XV|W0^yB4|lrW|LH+ceFXNf#Z%Xv|Hoi_=pVzQ2>bGb{}{LvGKCZx7`-Po{AKLfPFVdQ&MBb@0164cSpWb4 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png b/core/assets-raw/sprites/blocks/environment/crux-floor-generic2.png deleted file mode 100644 index 2c113a2cd6ab9d9c88426cf23013caa1afc9ded1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 779 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z;x8p z#WAE}&f7b_d5;_f91@Q|;@~KIqG5b{=YP%*d`Dy_u@+6SH!mx{ef4nl{X8YZ)T#4j zgeS!R`}6nvw<@dBu0pvsy`ukr-xj?+cUYi|q2%K4_t6#{yH5Q5t}D~>=-d7Jf9--t zx^C3}|I6+skp24a`(=EKUhmQ`U+%Wi=j7bl-oNMP{(sE%;itl}h4cPA^(qhB^?&F3 znLH1EJ7(;hCAh}aUh=@diW73{c25$HNdDjd%%APS$@S{$O|yRcpY@Mp{PKr~;T*$* zp-8AP?}%M@TkfQAwe4K7{mY*H3;sMgoIzP*dhsWB({KMX{vD2Iber(LY-ic?M2&y; z*XG#2mOH>PO}bo6^x&PJyG{9>${)X5R42RS*>AlBWz%&m*=Nifc(+P4GUlw=%8_=T zdBwa-)lJho=kHHFW8R>kYF=9G|7Fh4-G4s@l$5V3n)v(u;(GOquJ8BfKU8?3^!@)w zy#pLcu5bUJzU`pgA-eIud_B8CQ$+Op|JS!S?%(Tg+LfC1=kETL|HaSM_X`;DeSM-I z{#f|Hq`&8D&mPuqsrdByYEQ!2pC=i<9e4g#aChpQ15&@w|8we4-#>2-N7g%g)BFC+ z4|y2Yy%&<#fAzDHwZWLdf*C@*-tBeY@bdqY+6;3T5B#iY;Qdjat^?1RSvvQvlzYCPdAG*N?Copj$1*T5FnGH9 KxvXV0h%| z;usRq`gZzh-opw!ZN5`2PiVZ|>iy)_%%arJn8|^MlwO_`?JD@tEEf96UTK59ulTyUf4=EF&Vouv|KN^ zwoUJxNTY~SOXSyiX9PE_VlHX;&$dBip%#Owf?hZK)sIDfrlN)|HzzVI?F;8#RKXh3 zQGCwi`oUMMLWk$<)vWn!B2s!dH#S6;zxBOV=x+{>ptaM!Nt`xbn0o1RoL*7+?MWvsx?c&ooNZ0DzYHoVpj>=n#!l0uKhZ}}L=z`(%Z>FVdQ&MBb@0QhWp Ap#T5? diff --git a/core/assets-raw/sprites/blocks/environment/plating.png b/core/assets-raw/sprites/blocks/environment/plating.png deleted file mode 100644 index 534913714bea917d40a795ae91515f1cbd888ec0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1154 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z+&U+ z;uumf=WO)eJSj(kdCqlQ8oA;ek<%&~mpFJ#%y^u>;mM&z-<%c1JzugHL}?u{UgD@B zs#?bzWZ^w+=gqnE=i2^I@&0!3?z``I&zyVnW=CaBmF1dn?+!zWF9*4Q|7B-j@L9Hb z(epdK>!PpUyI;Tc*u}o9ubXTb806fWzh-fEA6oiQQX$WnR$(qE@kWu%iCVMA? z#0mC_u7;D-cd50?m0t9kw@chV>X+Nc?`?|@-=hh9|T?+E&J4G2plnS1F z|K0!SP>0x^IWBq*M|1xqa8|ymHdWO8rV^Yeux#Vxmp&!}`?haWEhy&dE(l{Vc=Bnd zj=wUKT0*bGl{ts3O3ZgXi*=ZMEGziV6zhQNYXv*JSDy@-vHAehN3&oxx25|ny&rT` zxhb4@%W9%ja67D%Lxin)Uo?wX>NHRB1&<7$@=da}F7hs6YgW=r;R9KLuX#`jX*y&F{x>8G>=6~EoSrL-p8yH4=S zojnEIT5(%;Jj&vlb-{BUZ`GVv&n8rDUKtv_>s!P*g{mo0Lae$G>!+>VT-O=t-K{ds zxFg5$$Ymjw^tzZk-?p_JT<|}>;mWh6Zj+fMCQp;u;$D>aM^54L#2FKh$?j6%KXrM< zC$UArM6{g@U&gTmJr!H8^^xDTBh;AvK$UniQ*WjO_;3uJncb+g8 zDIIw{Kc#7@QViEmnGZi6{bTT+RG9av`>6Kqgq5!ZG*=3g`^HJFS|22zv(4J*^C4HR zRRu3S_kHu6v`dYnONCjl!RGm@WwR7Gw2xf-7P`VEu2ipK;;oJ)M!MO*twOSOAN9mv1iYoGo2&q(=@+8JzcZ!oYOiK9L1k3T;hMh zI{AqG&h%+#_!sX8-f~6AqA{y{nn-!qw1}ou`-gKScYWo`)>Tw{hFP5#x|rg+xkVps*~;j>d!CuqoQMOe6WjZA9%>v|I+1@v$AW|LNq2ZWctxhJ RV_;xl@O1TaS?83{1OPYV4fg;5 diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 76f8cec5f6..18f68ec2c9 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -80,7 +80,7 @@ public class Generators{ //theoretically this might not finish in time, but I doubt that will ever happen mainExecutor.submit(() -> { try{ - ImageTileGenerator.generate(basePath, block.name + (variants <= 1 ? "" : "-" + (variant+1)), new Fi("../../../assets-raw/sprites_out/blocks/environment/" + (block.name + (variants <= 1 ? "" : "-" + (variant+1))))); + ImageTileGenerator.generate(basePath, block.name + (variants <= 1 ? "" : "-" + (variant+1)), new Fi("../../../assets-raw/sprites_out/blocks/environment")); }catch(Throwable e){ Log.err("Failed to autotile: " + block.name, e); }finally{ @@ -514,7 +514,7 @@ public class Generators{ Pixmap container = new Pixmap(base.width + 10, base.height + 10); container.draw(base, 5, 5, true); - replace("sector-" + item.name, container.outline(Pal.darkerGray, 5)); + replace("../ui/sector-" + item.name, "sector-" + item.name, container.outline(Pal.darkerGray, 5)); } }); diff --git a/tools/src/mindustry/tools/ImagePacker.java b/tools/src/mindustry/tools/ImagePacker.java index 7018acf998..5ab4153826 100644 --- a/tools/src/mindustry/tools/ImagePacker.java +++ b/tools/src/mindustry/tools/ImagePacker.java @@ -29,6 +29,8 @@ public class ImagePacker{ //makes PNG loading slightly faster ArcNativesLoader.load(); + fixSubdirectory("blocks/environment/character-overlay"); + Core.settings = new MockSettings(); Log.logger = new NoopLogHandler(); Vars.content = new ContentLoader(); @@ -200,6 +202,15 @@ public class ImagePacker{ } } + static void fixSubdirectory(String dir){ + Fi folder = Fi.get("../../../assets-raw/sprites_out/" + dir); + Fi parent = folder.parent(); + folder.walk(fi -> { + fi.moveTo(parent.child(fi.name())); + }); + folder.delete(); + } + static String texname(UnlockableContent c){ return c.getContentType() + "-" + c.name + "-ui"; } @@ -251,7 +262,11 @@ public class ImagePacker{ } static void replace(String name, Pixmap image){ - Fi.get(name + ".png").writePng(image); + replace(name, name, image); + } + + static void replace(String path, String name, Pixmap image){ + Fi.get(path + ".png").writePng(image); ((GenRegion)Core.atlas.find(name)).path.delete(); } From 72e9db57a4b833a3878b466862640e142aa83ade Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 19 Jul 2025 15:06:00 -0400 Subject: [PATCH 31/37] WIP unification and cleanup of rendering in editor --- .../blocks/environment/clear-editor.png | Bin 0 -> 91 bytes .../sprites/editor/block-border-editor.png | Bin 146 -> 0 bytes .../sprites/editor/clear-editor.png | Bin 68 -> 0 bytes core/assets-raw/sprites/editor/pack.json | 9 -- core/src/mindustry/core/Renderer.java | 5 +- core/src/mindustry/editor/EditorTile.java | 8 +- core/src/mindustry/editor/MapRenderer.java | 78 ++++++++++---- core/src/mindustry/editor/MapView.java | 2 +- .../src/mindustry/graphics/BlockRenderer.java | 102 ++++++++++-------- core/src/mindustry/graphics/CacheLayer.java | 4 +- .../src/mindustry/graphics/FloorRenderer.java | 27 +++-- .../mindustry/graphics/IndexedRenderer.java | 54 ++++------ core/src/mindustry/graphics/MultiPacker.java | 3 +- core/src/mindustry/mod/Mods.java | 2 - core/src/mindustry/world/Block.java | 34 +----- .../world/blocks/environment/Floor.java | 1 - .../world/blocks/environment/OreBlock.java | 2 - .../blocks/environment/ShallowLiquid.java | 3 +- tools/src/mindustry/tools/Generators.java | 15 +-- 19 files changed, 173 insertions(+), 176 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/clear-editor.png delete mode 100644 core/assets-raw/sprites/editor/block-border-editor.png delete mode 100644 core/assets-raw/sprites/editor/clear-editor.png delete mode 100644 core/assets-raw/sprites/editor/pack.json diff --git a/core/assets-raw/sprites/blocks/environment/clear-editor.png b/core/assets-raw/sprites/blocks/environment/clear-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..f65a75d14472e888bb30a75ec58cd7be776b9aeb GIT binary patch literal 91 zcmeAS@N?(olHy`uVBq!ia0y~yU|<4a4mJh`hN5k}Dhvz^jKx9jP7LeL$-HD>U=a0m qaSY*@nf&Mfe|u&S5M~x(U@%}~X52aZT?zvO1B0ilpUXO@geCz0gfXCh2ZPJf2aJXdDLbCs%>B*4z`)??>gTe~DWM4f3q~@; diff --git a/core/assets-raw/sprites/editor/clear-editor.png b/core/assets-raw/sprites/editor/clear-editor.png deleted file mode 100644 index 1a3a506d64fa8dd2c2b0c8908f75ed73dad8200a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0y~yU| renderer.blocks.floor.recacheTile(i % width, i / width)); + updates.clear(); + + updates.addAll(delayedUpdates); + delayedUpdates.clear(); + + renderer.blocks.floor.checkChanges(); + + boolean prev = renderer.animateWater; + renderer.animateWater = false; + + Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); + Core.camera.width = 999999f; + Core.camera.height = 999999f; + Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f)); + renderer.blocks.floor.drawFloor(); + + Tmp.m2.set(Draw.proj()); + + //this sure is awful! + Gl.disable(Gl.scissorTest); + + renderer.blocks.processShadows(); + + Gl.enable(Gl.scissorTest); + + Draw.proj(Core.camera.mat); + + Draw.shader(Shaders.darkness); + Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize); + Draw.shader(); + + Draw.proj(Tmp.m2); + + renderer.blocks.floor.beginDraw(); + renderer.blocks.floor.drawLayer(CacheLayer.walls); + renderer.animateWater = prev; + return; + } + clearEditor = Core.atlas.find("clear-editor"); updates.each(i -> render(i % width, i / width)); @@ -60,7 +105,7 @@ public class MapRenderer implements Disposable{ return; } - var texture = Core.atlas.find("clear-editor").texture; + var texture = clearEditor.texture; for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ @@ -92,10 +137,10 @@ public class MapRenderer implements Disposable{ } private TextureRegion getIcon(Block wall, int index){ - return !wall.editorIcon().found() ? + return !wall.fullIcon.found() ? clearEditor : wall.variants > 0 ? - wall.editorVariantRegions()[Mathf.randomSeed(index, 0, wall.editorVariantRegions().length - 1)] : - wall.editorIcon(); + wall.variantRegions()[Mathf.randomSeed(index, 0, wall.variantRegions().length - 1)] : + wall.fullIcon; } private void render(int wx, int wy){ @@ -104,7 +149,6 @@ public class MapRenderer implements Disposable{ IndexedRenderer mesh = chunks[x][y]; Tile tile = editor.tiles().getn(wx, wy); - Team team = tile.team(); Floor floor = tile.floor(); Floor overlay = tile.overlay(); Block wall = tile.block(); @@ -113,12 +157,11 @@ public class MapRenderer implements Disposable{ int idxWall = (wx % chunkSize) + (wy % chunkSize) * chunkSize; int idxDecal = (wx % chunkSize) + (wy % chunkSize) * chunkSize + chunkSize * chunkSize; - boolean center = tile.isCenter(); - boolean useSyntheticWall = wall.synthetic() || overlay.wallOre; + boolean useSyntheticWall = overlay.wallOre; //draw synthetic wall or floor OR standard wall if wall ore if(wall != Blocks.air && useSyntheticWall){ - region = !center ? clearEditor : getIcon(wall, idxWall); + region = getIcon(wall, idxWall); float width = region.width * region.scl(), height = region.height * region.scl(), ox = wall.offset + (tilesize - width) / 2f, oy = wall.offset + (tilesize - height) / 2f; @@ -138,7 +181,7 @@ public class MapRenderer implements Disposable{ mesh.setColor(Tmp.c1.set(tile.extraData | 0xff)); } - region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)]; + region = floor.variantRegions()[Mathf.randomSeed(idxWall, 0, floor.variantRegions().length - 1)]; mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8); } @@ -146,14 +189,7 @@ public class MapRenderer implements Disposable{ float offsetX = -((wall.size + 1) / 3) * tilesize, offsetY = -((wall.size + 1) / 3) * tilesize; //draw non-synthetic wall or ore - if((wall.update || wall.destructible) && center){ - mesh.setColor(team.color); - region = Core.atlas.find("block-border-editor"); - if(wall.size == 2){ - offsetX += tilesize; - offsetY += tilesize; - } - }else if(!useSyntheticWall && wall != Blocks.air && center){ + if(!(wall.update || wall.destructible) && !useSyntheticWall && wall != Blocks.air){ region = getIcon(wall, idxWall); if(wall == Blocks.cliff){ @@ -169,7 +205,7 @@ public class MapRenderer implements Disposable{ if(floor.isLiquid){ mesh.setColor(Tmp.c1.set(1f, 1f, 1f, floor.overlayAlpha)); } - region = overlay.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().editorVariantRegions().length - 1)]; + region = overlay.variantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().variantRegions().length - 1)]; }else{ region = clearEditor; } diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index e4f571bfb0..1932191986 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -248,7 +248,7 @@ public class MapView extends Element implements GestureListener{ Draw.color(Pal.remove); Lines.stroke(2f); Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2); - editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight); + editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight, zoom); Draw.reset(); if(grid){ diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 4949a90bc3..83e8990426 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -64,48 +64,7 @@ public class BlockRenderer{ }); Events.on(WorldLoadEvent.class, event -> { - blockTree = new BlockQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); - blockLightTree = new BlockLightQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); - floorTree = new FloorQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); - - shadowEvents.clear(); - updateFloors.clear(); - lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated - hadMapLimit = state.rules.limitMapArea; - - shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear); - shadows.resize(world.width(), world.height()); - shadows.begin(); - Core.graphics.clear(Color.white); - Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight()); - - Draw.color(blendShadowColor); - - for(Tile tile : world.tiles){ - recordIndex(tile); - - if(tile.floor().updateRender(tile)){ - updateFloors.add(new UpdateRenderState(tile, tile.floor())); - } - - if(tile.overlay().updateRender(tile)){ - updateFloors.add(new UpdateRenderState(tile, tile.overlay())); - } - - if(tile.build != null && (tile.team() == player.team() || !state.rules.fog || (tile.build.visibleFlags & (1L << player.team().id)) != 0)){ - tile.build.wasVisible = true; - } - - if(tile.block().displayShadow(tile) && (tile.build == null || tile.build.wasVisible)){ - Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); - } - } - - Draw.flush(); - Draw.color(); - shadows.end(); - - updateDarkness(); + reload(); }); //sometimes darkness gets disabled. @@ -150,6 +109,51 @@ public class BlockRenderer{ }); } + public void reload(){ + blockTree = new BlockQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); + blockLightTree = new BlockLightQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); + floorTree = new FloorQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); + + shadowEvents.clear(); + updateFloors.clear(); + lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated + hadMapLimit = state.rules.limitMapArea; + + shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear); + shadows.resize(world.width(), world.height()); + shadows.begin(); + Core.graphics.clear(Color.white); + Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight()); + + Draw.color(blendShadowColor); + + for(Tile tile : world.tiles){ + recordIndex(tile); + + if(tile.floor().updateRender(tile)){ + updateFloors.add(new UpdateRenderState(tile, tile.floor())); + } + + if(tile.overlay().updateRender(tile)){ + updateFloors.add(new UpdateRenderState(tile, tile.overlay())); + } + + if(tile.build != null && (tile.team() == player.team() || !state.rules.fog || (tile.build.visibleFlags & (1L << player.team().id)) != 0)){ + tile.build.wasVisible = true; + } + + if(tile.block().displayShadow(tile) && (tile.build == null || tile.build.wasVisible)){ + Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); + } + } + + Draw.flush(); + Draw.color(); + shadows.end(); + + updateDarkness(); + } + public void updateDarkness(){ darkEvents.clear(); dark.getTexture().setFilter(TextureFilter.linear); @@ -197,6 +201,10 @@ public class BlockRenderer{ } } + public FrameBuffer getShadowBuffer(){ + return shadows; + } + public void removeFloorIndex(Tile tile){ if(indexFloor(tile)) floorTree.remove(tile); } @@ -294,7 +302,7 @@ public class BlockRenderer{ } } - public void drawShadows(){ + public void processShadows(){ if(!shadowEvents.isEmpty()){ Draw.flush(); @@ -315,6 +323,10 @@ public class BlockRenderer{ Draw.proj(camera); } + } + + public void drawShadows(){ + processShadows(); float ww = world.width() * tilesize, wh = world.height() * tilesize; float x = camera.position.x + tilesize / 2f, y = camera.position.y + tilesize / 2f; @@ -511,6 +523,10 @@ public class BlockRenderer{ } } + public void updateShadowTile(Tile tile){ + shadowEvents.add(tile); + } + static class BlockQuadtree extends QuadTree{ public BlockQuadtree(Rect bounds){ diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index 31de034b7f..bdd4e24713 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -97,7 +97,7 @@ public class CacheLayer{ @Override public void begin(){ - if(!Core.settings.getBool("animatedwater")) return; + if(!renderer.animateWater) return; renderer.effectBuffer.begin(); Core.graphics.clear(Color.clear); @@ -106,7 +106,7 @@ public class CacheLayer{ @Override public void end(){ - if(!Core.settings.getBool("animatedwater")) return; + if(!renderer.animateWater) return; renderer.effectBuffer.end(); renderer.effectBuffer.blit(shader); diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 15e110f708..20fb0443f1 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -111,10 +111,17 @@ public class FloorRenderer{ Events.on(WorldLoadEvent.class, event -> clearTiles()); } + public IndexData getIndexData(){ + return indexData; + } + /** Queues up a cache change for a tile. Only runs in render loop. */ public void recacheTile(Tile tile){ - //recaching all layers may not be necessary - recacheSet.add(Point2.pack(tile.x / chunksize, tile.y / chunksize)); + recacheTile(tile.x, tile.y); + } + + public void recacheTile(int x, int y){ + recacheSet.add(Point2.pack(x / chunksize, y / chunksize)); } public void drawFloor(){ @@ -127,10 +134,10 @@ public class FloorRenderer{ float pad = tilesize/2f; int - minx = (int)((camera.position.x - camera.width/2f - pad) / chunkunits), - miny = (int)((camera.position.y - camera.height/2f - pad) / chunkunits), - maxx = Mathf.ceil((camera.position.x + camera.width/2f + pad) / chunkunits), - maxy = Mathf.ceil((camera.position.y + camera.height/2f + pad) / chunkunits); + minx = Math.max((int)((camera.position.x - camera.width/2f - pad) / chunkunits), 0), + miny = Math.max((int)((camera.position.y - camera.height/2f - pad) / chunkunits), 0), + maxx = Math.min(Mathf.ceil((camera.position.x + camera.width/2f + pad) / chunkunits), cache.length), + maxy = Math.min(Mathf.ceil((camera.position.y + camera.height/2f + pad) / chunkunits), cache[0].length); int layers = CacheLayer.all.length; @@ -221,10 +228,10 @@ public class FloorRenderer{ Camera camera = Core.camera; int - minx = (int)((camera.position.x - camera.width/2f - pad) / chunkunits), - miny = (int)((camera.position.y - camera.height/2f - pad) / chunkunits), - maxx = Mathf.ceil((camera.position.x + camera.width/2f + pad) / chunkunits), - maxy = Mathf.ceil((camera.position.y + camera.height/2f + pad) / chunkunits); + minx = Math.max((int)((camera.position.x - camera.width/2f - pad) / chunkunits), 0), + miny = Math.max((int)((camera.position.y - camera.height/2f - pad) / chunkunits), 0), + maxx = Math.min(Mathf.ceil((camera.position.x + camera.width/2f + pad) / chunkunits), cache.length), + maxy = Math.min(Mathf.ceil((camera.position.y + camera.height/2f + pad) / chunkunits), cache[0].length); layer.begin(); diff --git a/core/src/mindustry/graphics/IndexedRenderer.java b/core/src/mindustry/graphics/IndexedRenderer.java index 954bc13153..5b5a1e3203 100644 --- a/core/src/mindustry/graphics/IndexedRenderer.java +++ b/core/src/mindustry/graphics/IndexedRenderer.java @@ -5,6 +5,9 @@ import arc.graphics.g2d.*; import arc.graphics.gl.*; import arc.math.*; import arc.util.*; +import mindustry.*; + +import java.nio.*; public class IndexedRenderer implements Disposable{ private static final int vsize = 5; @@ -34,9 +37,10 @@ public class IndexedRenderer implements Disposable{ } """ ); - private static final float[] tmpVerts = new float[vsize * 6]; + private static final float[] tmpVerts = new float[vsize * 4]; private Mesh mesh; + private FloatBuffer buffer; private Mat projMatrix = new Mat(); private Mat transMatrix = new Mat(); @@ -57,7 +61,7 @@ public class IndexedRenderer implements Disposable{ program.setUniformMatrix4("u_projTrans", combined); - mesh.render(program, Gl.triangles, 0, mesh.getMaxVertices()); + mesh.render(program, Gl.triangles, 0, mesh.getMaxVertices() * 6 / 4); } public void setColor(Color color){ @@ -94,26 +98,19 @@ public class IndexedRenderer implements Disposable{ vertices[idx++] = u2; vertices[idx++] = v2; - //tri2 - vertices[idx++] = fx2; - vertices[idx++] = fy2; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - vertices[idx++] = fx2; vertices[idx++] = y; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; - vertices[idx++] = x; - vertices[idx++] = y; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; + int dest = index * vsize * 4; - mesh.updateVertices(index * vsize * 6, vertices); + buffer.position(dest); + buffer.put(vertices); + + //mark dirty + mesh.getVerticesBuffer(); } public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){ @@ -166,26 +163,19 @@ public class IndexedRenderer implements Disposable{ vertices[idx++] = u2; vertices[idx++] = v2; - //tri2 - vertices[idx++] = x3; - vertices[idx++] = y3; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - vertices[idx++] = x4; vertices[idx++] = y4; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; - vertices[idx++] = x1; - vertices[idx++] = y1; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; + int dest = index * vsize * 4; - mesh.updateVertices(index * vsize * 6, vertices); + buffer.position(dest); + buffer.put(vertices); + + //mark dirty + mesh.getVerticesBuffer(); } public Mat getTransformMatrix(){ @@ -199,13 +189,15 @@ public class IndexedRenderer implements Disposable{ public void resize(int sprites){ if(mesh != null) mesh.dispose(); - mesh = new Mesh(true, 6 * sprites, 0, + mesh = new Mesh(true, 4 * sprites, 0, VertexAttribute.position, VertexAttribute.color, VertexAttribute.texCoords); - //TODO why is this the only way to get it working properly? it should not need an array - mesh.setVertices(new float[6 * sprites * vsize]); + buffer = mesh.getVerticesBuffer(); + buffer.limit(buffer.capacity()); + + mesh.indices = Vars.renderer.blocks.floor.getIndexData(); } private void updateMatrix(){ diff --git a/core/src/mindustry/graphics/MultiPacker.java b/core/src/mindustry/graphics/MultiPacker.java index 42bc8d00d7..f3ebb3b5b5 100644 --- a/core/src/mindustry/graphics/MultiPacker.java +++ b/core/src/mindustry/graphics/MultiPacker.java @@ -118,8 +118,7 @@ public class MultiPacker implements Disposable{ environment(4096), ui(4096), - rubble(4096, 2048), - editor(4096, 2048); + rubble(4096, 2048); public static final PageType[] all = values(); diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index a21eed63c1..6a21fb042e 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -273,7 +273,6 @@ public class Mods implements Loadable{ ObjectMap pageTypes = ObjectMap.of( Core.atlas.find("white").texture, PageType.main, Core.atlas.find("stone1").texture, PageType.environment, - Core.atlas.find("clear-editor").texture, PageType.editor, Core.atlas.find("whiteui").texture, PageType.ui, Core.atlas.find("rubble-1-0").texture, PageType.rubble ); @@ -405,7 +404,6 @@ public class Mods implements Loadable{ String path = file.path(); return path.contains("sprites/blocks/environment") || path.contains("sprites-override/blocks/environment") ? PageType.environment : - path.contains("sprites/editor") || path.contains("sprites-override/editor") ? PageType.editor : path.contains("sprites/rubble") || path.contains("sprites-override/rubble") ? PageType.rubble : path.contains("sprites/ui") || path.contains("sprites-override/ui") ? PageType.ui : PageType.main; diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index ae73e23450..a1a07a6736 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -382,11 +382,10 @@ public class Block extends UnlockableContent implements Senseable{ protected Seq consumeBuilder = new Seq<>(); protected TextureRegion[] generatedIcons; - protected TextureRegion[] editorVariantRegions; /** Regions indexes from icons() that are rotated. If either of these is not -1, other regions won't be rotated in ConstructBlocks. */ public int regionRotated1 = -1, regionRotated2 = -1; - public TextureRegion region, editorIcon; + public TextureRegion region; public @Load("@-shadow") TextureRegion customShadowRegion; public @Load("@-team") TextureRegion teamRegion; public TextureRegion[] teamRegions, variantRegions, variantShadowRegions; @@ -864,24 +863,6 @@ public class Block extends UnlockableContent implements Senseable{ } } - /** Never use outside of the editor! */ - public TextureRegion editorIcon(){ - return editorIcon == null ? (editorIcon = Core.atlas.find(name + "-icon-editor")) : editorIcon; - } - - /** Never use outside of the editor! */ - public TextureRegion[] editorVariantRegions(){ - if(editorVariantRegions == null){ - variantRegions(); - editorVariantRegions = new TextureRegion[variantRegions.length]; - for(int i = 0; i < variantRegions.length; i++){ - AtlasRegion region = (AtlasRegion)variantRegions[i]; - editorVariantRegions[i] = Core.atlas.find("editor-" + region.name); - } - } - return editorVariantRegions; - } - /** @return special icons to outline and save with an -outline variant. Vanilla only. */ public TextureRegion[] makeIconRegions(){ return new TextureRegion[0]; @@ -1388,13 +1369,6 @@ public class Block extends UnlockableContent implements Senseable{ mapColor.set(image.get(image.width/2, image.height/2)); } - if(variants > 0){ - for(int i = 0; i < variants; i++){ - String rname = name + (i + 1); - packer.add(PageType.editor, "editor-" + rname, Core.atlas.getPixmap(rname)); - } - } - Seq toDispose = new Seq<>(); //generate paletted team regions @@ -1459,8 +1433,6 @@ public class Block extends UnlockableContent implements Senseable{ } } - PixmapRegion editorBase; - if(gen.length > 1){ Pixmap base = Core.atlas.getPixmap(gen[0]).crop(); for(int i = 1; i < gen.length; i++){ @@ -1472,15 +1444,11 @@ public class Block extends UnlockableContent implements Senseable{ } packer.add(PageType.main, "block-" + name + "-full", base); - editorBase = new PixmapRegion(base); toDispose.add(base); }else{ if(gen[0] != null) packer.add(PageType.main, "block-" + name + "-full", Core.atlas.getPixmap(gen[0])); - editorBase = gen[0] == null ? Core.atlas.getPixmap(fullIcon) : Core.atlas.getPixmap(gen[0]); } - packer.add(PageType.editor, name + "-icon-editor", editorBase); - toDispose.each(Pixmap::dispose); } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 2a15220aee..90d253ccac 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -210,7 +210,6 @@ public class Floor extends Block{ @Override public void createIcons(MultiPacker packer){ super.createIcons(packer); - packer.add(PageType.editor, "editor-" + name, Core.atlas.getPixmap(fullIcon)); if(blendGroup != this){ return; diff --git a/core/src/mindustry/world/blocks/environment/OreBlock.java b/core/src/mindustry/world/blocks/environment/OreBlock.java index f6da9d5f89..ec79b82e42 100644 --- a/core/src/mindustry/world/blocks/environment/OreBlock.java +++ b/core/src/mindustry/world/blocks/environment/OreBlock.java @@ -63,10 +63,8 @@ public class OreBlock extends OverlayFloor{ } packer.add(PageType.environment, name + (i + 1), image); - packer.add(PageType.editor, "editor-" + name + (i + 1), image); if(i == 0){ - packer.add(PageType.editor, "editor-block-" + name + "-full", image); packer.add(PageType.main, "block-" + name + "-full", image); } diff --git a/core/src/mindustry/world/blocks/environment/ShallowLiquid.java b/core/src/mindustry/world/blocks/environment/ShallowLiquid.java index 95c4a368ee..87b10a8dd6 100644 --- a/core/src/mindustry/world/blocks/environment/ShallowLiquid.java +++ b/core/src/mindustry/world/blocks/environment/ShallowLiquid.java @@ -47,9 +47,8 @@ public class ShallowLiquid extends Floor{ } } - String baseName = this.name + "" + (++index); + String baseName = this.name + (++index); packer.add(PageType.environment, baseName, res); - packer.add(PageType.editor, "editor-" + baseName, res); res.dispose(); } diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 18f68ec2c9..bb22f32e1f 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -94,7 +94,6 @@ public class Generators{ Pixmap out = new Pixmap(basePath); Pixmap cropped = out.crop(32, 32, 32, 32); iconPath.writePng(cropped); - iconPath.parent().parent().parent().child("editor").child("editor-" + block.name + ".png").writePng(cropped); out.dispose(); gens.put(block, cropped); } @@ -262,7 +261,6 @@ public class Generators{ Fi fi = Fi.get("../blocks/environment/cliffmask" + (val & 0xff) + ".png"); fi.writePng(result); - fi.copyTo(Fi.get("../editor").child("editor-" + fi.name())); }); } @@ -324,14 +322,6 @@ public class Generators{ TextureRegion[] regions = block.getGeneratedIcons(); - if(block.variants > 0 || block instanceof Floor){ - for(TextureRegion region : block.variantRegions()){ - GenRegion gen = (GenRegion)region; - if(gen.path == null) continue; - gen.path.copyTo(Fi.get("../editor/editor-" + gen.path.name())); - } - } - for(TextureRegion region : block.makeIconRegions()){ GenRegion gen = (GenRegion)region; save(get(region).outline(block.outlineColor, block.outlineRadius), gen.name + "-outline"); @@ -418,7 +408,6 @@ public class Generators{ 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); @@ -472,9 +461,8 @@ public class Generators{ } } - String name = floor.name + "" + (++index); + String name = floor.name + (++index); save(res, "../blocks/environment/" + name); - save(res, "../editor/editor-" + name); gens.put(floor, res); } @@ -828,7 +816,6 @@ public class Generators{ replace(ore.variantRegions[i], image); save(image, "../blocks/environment/" + ore.name + (i + 1)); - save(image, "../editor/editor-" + ore.name + (i + 1)); save(image, "block-" + ore.name + "-full"); save(image, "../ui/block-" + ore.name + "-ui"); From 6cd3a0a096d42fdd5fc60172d8c6070147df9605 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 20 Jul 2025 17:06:03 -0400 Subject: [PATCH 32/37] Partially implemented new building rendering --- core/src/mindustry/editor/DrawOperation.java | 6 +- .../mindustry/editor/EditorSpriteCache.java | 171 ++++++++++ core/src/mindustry/editor/EditorTile.java | 37 ++- core/src/mindustry/editor/MapEditor.java | 2 +- .../src/mindustry/editor/MapEditorDialog.java | 2 +- .../mindustry/editor/MapGenerateDialog.java | 2 +- .../mindustry/editor/MapProcessorsDialog.java | 2 +- core/src/mindustry/editor/MapRenderer.java | 300 ++++++++---------- core/src/mindustry/editor/MapView.java | 2 +- core/src/mindustry/graphics/CacheLayer.java | 4 +- .../src/mindustry/graphics/FloorRenderer.java | 20 +- .../mindustry/graphics/IndexedRenderer.java | 211 ------------ 12 files changed, 345 insertions(+), 414 deletions(-) create mode 100644 core/src/mindustry/editor/EditorSpriteCache.java delete mode 100644 core/src/mindustry/graphics/IndexedRenderer.java diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 163546bfc3..903b38a588 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -70,7 +70,7 @@ public class DrawOperation{ } } case opBlock -> { - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); Block block = content.block(to); tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); @@ -78,7 +78,7 @@ public class DrawOperation{ tile.build.enabled = true; } - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); } case opRotation -> { if(tile.build != null) tile.build.rotation = to; @@ -86,7 +86,7 @@ public class DrawOperation{ case opTeam -> tile.setTeam(Team.get(to)); } }); - editor.renderer.updatePoint(tile.x, tile.y); + editor.renderer.updateStatic(tile.x, tile.y); } @Struct diff --git a/core/src/mindustry/editor/EditorSpriteCache.java b/core/src/mindustry/editor/EditorSpriteCache.java new file mode 100644 index 0000000000..6fe1faeea1 --- /dev/null +++ b/core/src/mindustry/editor/EditorSpriteCache.java @@ -0,0 +1,171 @@ +package mindustry.editor; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.graphics.gl.*; +import arc.math.*; +import arc.struct.*; +import arc.util.*; + +public class EditorSpriteCache implements Disposable{ + //xy + color + uv + static final int vertexSize = 2 + 1 + 2; + + private @Nullable Mesh mesh; + private final Seq textures = new Seq<>(8); + private final IntSeq counts = new IntSeq(8); + + private float[] tmpVertices; + + /** Index in tmpVertices of current vertex data. */ + private int index; + + /** @param tmpVertices Temporary buffer to hold vertices while building up sprites. Should be large enough to hold all sprite data this cache will contain. */ + public EditorSpriteCache(float[] tmpVertices){ + this.tmpVertices = tmpVertices; + } + + /** @return whether anything was added to the cache. */ + public boolean isEmpty(){ + return index == 0; + } + + /** + * Builds this cache into a mesh that can be used for rendering. Use after calling {@link #draw(TextureRegion, float, float, float, float, float, float, float, float)}. + * Until this method is called, no mesh is created. + * + * @param indices The shared index data in standard quad format, as seen in SpriteBatch. + * Since this data is static, it should be the same across all caches, and be large enough to accommodate all sprites. + * */ + public void build(IndexData indices){ + if(mesh != null) mesh.dispose(); + + mesh = new Mesh(true, index / vertexSize, 0, + VertexAttribute.position, + VertexAttribute.color, + VertexAttribute.texCoords + ); + mesh.indices = indices; + mesh.setVertices(tmpVertices, 0, index); + } + + /** Adds the specified region to the cache. */ + public void draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float rotation, float colorPacked){ + if(mesh != null) throw new IllegalStateException("This cache is already built. Call #clear() before drawing new sprites."); + + // bottom left and top right corner points relative to origin + final float worldOriginX = x + originX; + final float worldOriginY = y + originY; + float fx = -originX; + float fy = -originY; + float fx2 = width - originX; + float fy2 = height - originY; + + float x1, y1, x2, y2, x3, y3, x4, y4; + + // rotate + if(rotation != 0){ + final float cos = Mathf.cosDeg(rotation); + final float sin = Mathf.sinDeg(rotation); + + x1 = cos * fx - sin * fy; + y1 = sin * fx + cos * fy; + + x2 = cos * fx - sin * fy2; + y2 = sin * fx + cos * fy2; + + x3 = cos * fx2 - sin * fy2; + y3 = sin * fx2 + cos * fy2; + + x4 = x1 + (x3 - x2); + y4 = y3 - (y2 - y1); + }else{ + x1 = fx; + y1 = fy; + + x2 = fx; + y2 = fy2; + + x3 = fx2; + y3 = fy2; + + x4 = fx2; + y4 = fy; + } + + x1 += worldOriginX; + y1 += worldOriginY; + x2 += worldOriginX; + y2 += worldOriginY; + x3 += worldOriginX; + y3 += worldOriginY; + x4 += worldOriginX; + y4 += worldOriginY; + + final float u = region.u; + final float v = region.v2; + final float u2 = region.u2; + final float v2 = region.v; + + int idx = index; + float[] verts = tmpVertices; + Texture texture = region.texture; + + verts[idx + 0] = x1; + verts[idx + 1] = y1; + verts[idx + 2] = colorPacked; + verts[idx + 3] = u; + verts[idx + 4] = v; + + verts[idx + 5] = x2; + verts[idx + 6] = y2; + verts[idx + 7] = colorPacked; + verts[idx + 8] = u; + verts[idx + 9] = v2; + + verts[idx + 10] = x3; + verts[idx + 11] = y3; + verts[idx + 12] = colorPacked; + verts[idx + 13] = u2; + verts[idx + 14] = v2; + + verts[idx + 15] = x4; + verts[idx + 16] = y4; + verts[idx + 17] = colorPacked; + verts[idx + 18] = u2; + verts[idx + 19] = v; + + int lastIndex = textures.size - 1; + if(lastIndex < 0 || textures.get(lastIndex) != texture){ + textures.add(texture); + counts.add(6); + }else{ + counts.incr(lastIndex, 6); + } + + index += vertexSize * 4; + } + + /** Renders the cached mesh. The shader must already have the correct view matrix (usually u_projectionViewMatrix) set as a uniform. */ + public void render(Shader shader){ + if(mesh == null) throw new IllegalStateException("Cache is empty, call build() first."); + + int offset = 0; + + for(int i = 0; i < textures.size; i++){ + int count = counts.items[i]; + textures.get(i).bind(); + + mesh.render(shader, Gl.triangles, offset, count); + offset += count; + } + } + + @Override + public void dispose(){ + if(mesh != null){ + mesh.dispose(); + mesh = null; + } + } +} \ No newline at end of file diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 2c662cecf6..47a5aee534 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -4,6 +4,7 @@ import arc.func.*; import mindustry.content.*; import mindustry.game.*; import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; import mindustry.world.modules.*; @@ -46,13 +47,16 @@ public class EditorTile extends Tile{ @Override public void setBlock(Block type, Team team, int rotation, Prov entityprov){ + Block prev = this.block; + Tile prevCenter = (build == null ? this : build.tile); + if(skip()){ super.setBlock(type, team, rotation, entityprov); return; } if(this.block == type && (build == null || build.rotation == rotation)){ - update(); + updateStatic(); return; } @@ -61,7 +65,7 @@ public class EditorTile extends Tile{ cen.op(DrawOperation.opRotation, (byte)build.rotation); cen.op(DrawOperation.opTeam, (byte)build.team.id); cen.op(DrawOperation.opBlock, block.id); - update(); + updateStatic(); }else{ if(build != null) op(DrawOperation.opRotation, (byte)build.rotation); if(build != null) op(DrawOperation.opTeam, (byte)build.team.id); @@ -70,7 +74,20 @@ public class EditorTile extends Tile{ super.setBlock(type, team, rotation, entityprov); - renderer.blocks.updateShadowTile(this); + if(requiresBlockUpdate(type) || requiresBlockUpdate(prev)){ + if(prev.size > 1){ + prevCenter.getLinkedTilesAs(prev, tile -> { + editor.renderer.updateBlock(tile.x, tile.y); + renderer.blocks.updateShadowTile(tile); + }); + } + getLinkedTiles(tile -> { + editor.renderer.updateBlock(tile.x, tile.y); + renderer.blocks.updateShadowTile(tile); + }); + }else{ + renderer.blocks.updateShadowTile(this); + } } @Override @@ -84,7 +101,7 @@ public class EditorTile extends Tile{ op(DrawOperation.opTeam, (byte)getTeamID()); super.setTeam(team); - getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); } @Override @@ -105,7 +122,7 @@ public class EditorTile extends Tile{ if(skip()){ super.fireChanged(); }else{ - update(); + updateStatic(); } } @@ -114,7 +131,7 @@ public class EditorTile extends Tile{ if(skip()){ super.firePreChanged(); }else{ - update(); + updateStatic(); } } @@ -159,8 +176,12 @@ public class EditorTile extends Tile{ return skip() && super.isDarkened(); } - private void update(){ - editor.renderer.updatePoint(x, y); + private boolean requiresBlockUpdate(Block block){ + return block != Blocks.air && block.cacheLayer == CacheLayer.normal; + } + + private void updateStatic(){ + editor.renderer.updateStatic(x, y); } private boolean skip(){ diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 7df7f67ea6..e663e7d8cc 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -374,7 +374,7 @@ public class MapEditor{ if(currentOp == null) currentOp = new DrawOperation(); currentOp.addOperation(data); - renderer.updatePoint(TileOp.x(data), TileOp.y(data)); + renderer.updateStatic(TileOp.x(data), TileOp.y(data)); } class Context implements WorldContext{ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 2ab5c0759f..f1755db39d 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -303,7 +303,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules); lastSavedRules = null; saved = false; - editor.renderer.updateAll(); + editor.renderer.recache(); } private void editInGame(){ diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index bb04261baf..19d435a6ac 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -185,7 +185,7 @@ public class MapGenerateDialog extends BaseDialog{ } //reset undo stack as generation... messes things up - editor.renderer.updateAll(); + editor.renderer.recache(); editor.clearOp(); } diff --git a/core/src/mindustry/editor/MapProcessorsDialog.java b/core/src/mindustry/editor/MapProcessorsDialog.java index 8867c2df13..9c687f08a8 100644 --- a/core/src/mindustry/editor/MapProcessorsDialog.java +++ b/core/src/mindustry/editor/MapProcessorsDialog.java @@ -41,7 +41,7 @@ public class MapProcessorsDialog extends BaseDialog{ foundAny = true; tile.setNet(Blocks.worldProcessor, Team.sharded, 0); if(ui.editor.isShown()){ - Vars.editor.renderer.updatePoint(x, y); + Vars.editor.renderer.updateStatic(x, y); } break outer; } diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index fa0abee70c..9e3938fedc 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -3,228 +3,178 @@ package mindustry.editor; import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; -import arc.math.*; +import arc.graphics.gl.*; +import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.graphics.*; import mindustry.world.*; -import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; public class MapRenderer implements Disposable{ - private static final int chunkSize = 62; - private IndexedRenderer[][] chunks; - private IntSet updates = new IntSet(); - private IntSet delayedUpdates = new IntSet(); - private TextureRegion clearEditor; + private static final int chunkSize = 60; + private EditorSpriteCache[][] chunks; + private IntSet recacheChunks = new IntSet(); private int width, height; + private Shader shader; + public void resize(int width, int height){ - updates.clear(); - delayedUpdates.clear(); - if(chunks != null){ - for(int x = 0; x < chunks.length; x++){ - for(int y = 0; y < chunks[0].length; y++){ - chunks[x][y].dispose(); - } - } - } + dispose(); - chunks = new IndexedRenderer[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)]; + recacheChunks.clear(); + chunks = new EditorSpriteCache[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)]; - for(int x = 0; x < chunks.length; x++){ - for(int y = 0; y < chunks[0].length; y++){ - chunks[x][y] = new IndexedRenderer(chunkSize * chunkSize * 2); - } - } this.width = width; this.height = height; - updateAll(); - renderer.blocks.floor.clearTiles(); - renderer.blocks.reload(); + recache(); } - public void draw(float tx, float ty, float tw, float th, float zoom){ + public void draw(float tx, float ty, float tw, float th){ + if(shader == null){ + shader = new Shader( + """ + attribute vec4 a_position; + attribute vec4 a_color; + attribute vec2 a_texCoord0; + uniform mat4 u_projTrans; + varying vec4 v_color; + varying vec2 v_texCoords; + void main(){ + v_color = a_color; + v_color.a = v_color.a * (255.0/254.0); + v_texCoords = a_texCoord0; + gl_Position = u_projTrans * a_position; + } + """, + + """ + varying lowp vec4 v_color; + varying vec2 v_texCoords; + uniform sampler2D u_texture; + + void main(){ + gl_FragColor = v_color * texture2D(u_texture, v_texCoords); + } + """ + ); + } + Draw.flush(); - //TODO properly integrate this later - if(true){ - updates.each(i -> renderer.blocks.floor.recacheTile(i % width, i / width)); - updates.clear(); + renderer.blocks.floor.checkChanges(); - updates.addAll(delayedUpdates); - delayedUpdates.clear(); + boolean prev = renderer.animateWater; + renderer.animateWater = false; - renderer.blocks.floor.checkChanges(); + Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); + Core.camera.width = 999999f; + Core.camera.height = 999999f; + Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f)); + renderer.blocks.floor.drawFloor(); - boolean prev = renderer.animateWater; - renderer.animateWater = false; + Tmp.m2.set(Draw.proj()); - Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); - Core.camera.width = 999999f; - Core.camera.height = 999999f; - Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f)); - renderer.blocks.floor.drawFloor(); + //scissors are always enabled because this is drawn clipped in UI, make sure they don't interfere with drawing shadow events + Gl.disable(Gl.scissorTest); - Tmp.m2.set(Draw.proj()); + renderer.blocks.processShadows(); - //this sure is awful! - Gl.disable(Gl.scissorTest); + Gl.enable(Gl.scissorTest); - renderer.blocks.processShadows(); + Draw.proj(Core.camera.mat); - Gl.enable(Gl.scissorTest); + Draw.shader(Shaders.darkness); + Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize); + Draw.shader(); - Draw.proj(Core.camera.mat); + Draw.proj(Tmp.m2); - Draw.shader(Shaders.darkness); - Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize); - Draw.shader(); + renderer.blocks.floor.beginDraw(); + renderer.blocks.floor.drawLayer(CacheLayer.walls); + renderer.animateWater = prev; - Draw.proj(Tmp.m2); + if(chunks == null) return; - renderer.blocks.floor.beginDraw(); - renderer.blocks.floor.drawLayer(CacheLayer.walls); - renderer.animateWater = prev; - return; - } + recacheChunks.each(i -> recacheChunk(Point2.x(i), Point2.y(i))); + recacheChunks.clear(); - clearEditor = Core.atlas.find("clear-editor"); - - updates.each(i -> render(i % width, i / width)); - updates.clear(); - - updates.addAll(delayedUpdates); - delayedUpdates.clear(); - - //???? - if(chunks == null){ - return; - } - - var texture = clearEditor.texture; + shader.bind(); + shader.setUniformMatrix4("u_projTrans", Core.camera.mat); for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ - IndexedRenderer mesh = chunks[x][y]; + EditorSpriteCache mesh = chunks[x][y]; - if(mesh == null){ - continue; + if(mesh == null) continue; + + mesh.render(shader); + } + } + } + + void updateStatic(int x, int y){ + renderer.blocks.floor.recacheTile(x, y); + } + + void updateBlock(int x, int y){ + recacheChunks.add(Point2.pack(x / chunkSize, y / chunkSize)); + } + + void recache(){ + renderer.blocks.floor.clearTiles(); + renderer.blocks.reload(); + + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ + recacheChunk(x, y); + } + } + } + + void recacheChunk(int cx, int cy){ + if(chunks[cx][cy] != null){ + chunks[cx][cy].dispose(); + chunks[cx][cy] = null; + } + + EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer()); + + for(int x = cx * chunkSize; x < (cx + 1) * chunkSize; x++){ + for(int y = cy * chunkSize; y < (cy + 1) * chunkSize; y++){ + Tile tile = world.tile(x, y); + + if(tile != null && tile.block() != Blocks.air && tile.block().cacheLayer == CacheLayer.normal && tile.isCenter()){ + Block block = tile.block(); + + TextureRegion region = block.fullIcon; + + float width = region.width * region.scl(), height = region.height * region.scl(); + + cache.draw(block.fullIcon, + x * tilesize + block.offset - width / 2f, + y * tilesize + block.offset - height / 2f, + width/2f, height/2f, + width, height, + tile.build == null || !block.rotate ? 0 : tile.build.rotdeg(), + Color.whiteFloatBits); } - - mesh.getTransformMatrix().setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)); - mesh.setProjectionMatrix(Draw.proj()); - - mesh.render(texture); } } - } - public void updatePoint(int x, int y){ - updates.add(x + y * width); - } - - public void updateAll(){ - clearEditor = Core.atlas.find("clear-editor"); - for(int x = 0; x < width; x++){ - for(int y = 0; y < height; y++){ - render(x, y); - } + if(!cache.isEmpty()){ + cache.build(renderer.blocks.floor.getIndexData()); + chunks[cx][cy] = cache; } } - private TextureRegion getIcon(Block wall, int index){ - return !wall.fullIcon.found() ? - clearEditor : wall.variants > 0 ? - wall.variantRegions()[Mathf.randomSeed(index, 0, wall.variantRegions().length - 1)] : - wall.fullIcon; - } - - private void render(int wx, int wy){ - int x = wx / chunkSize, y = wy / chunkSize; - if(x >= chunks.length || y >= chunks[0].length) return; - IndexedRenderer mesh = chunks[x][y]; - Tile tile = editor.tiles().getn(wx, wy); - - Floor floor = tile.floor(); - Floor overlay = tile.overlay(); - Block wall = tile.block(); - - TextureRegion region; - - int idxWall = (wx % chunkSize) + (wy % chunkSize) * chunkSize; - int idxDecal = (wx % chunkSize) + (wy % chunkSize) * chunkSize + chunkSize * chunkSize; - boolean useSyntheticWall = overlay.wallOre; - - //draw synthetic wall or floor OR standard wall if wall ore - if(wall != Blocks.air && useSyntheticWall){ - region = getIcon(wall, idxWall); - - float width = region.width * region.scl(), height = region.height * region.scl(), ox = wall.offset + (tilesize - width) / 2f, oy = wall.offset + (tilesize - height) / 2f; - - //force fit to tile - if(overlay.wallOre && !wall.synthetic()){ - width = height = tilesize; - ox = oy = 0f; - } - - mesh.draw(idxWall, region, - wx * tilesize + ox, - wy * tilesize + oy, - 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.variantRegions()[Mathf.randomSeed(idxWall, 0, floor.variantRegions().length - 1)]; - - mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8); - } - - float offsetX = -((wall.size + 1) / 3) * tilesize, offsetY = -((wall.size + 1) / 3) * tilesize; - - //draw non-synthetic wall or ore - if(!(wall.update || wall.destructible) && !useSyntheticWall && wall != Blocks.air){ - region = getIcon(wall, idxWall); - - 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; - offsetY = tilesize / 2f - region.height * region.scl() / 2f; - }else if((wall == Blocks.air || overlay.wallOre) && !overlay.isAir()){ - if(floor.isLiquid){ - mesh.setColor(Tmp.c1.set(1f, 1f, 1f, floor.overlayAlpha)); - } - region = overlay.variantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().variantRegions().length - 1)]; - }else{ - region = clearEditor; - } - - float width = region.width * region.scl(), height = region.height * region.scl(); - if(!wall.synthetic() && wall != Blocks.air && !wall.isMultiblock()){ - offsetX = offsetY = 0f; - width = height = tilesize; - } - - mesh.draw(idxDecal, region, wx * tilesize + offsetX, wy * tilesize + offsetY, width, height); - mesh.setColor(Color.white); - } - @Override public void dispose(){ - if(chunks == null){ - return; - } + if(chunks == null) return; + for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ if(chunks[x][y] != null){ diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 1932191986..e4f571bfb0 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -248,7 +248,7 @@ public class MapView extends Element implements GestureListener{ Draw.color(Pal.remove); Lines.stroke(2f); Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2); - editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight, zoom); + editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight); Draw.reset(); if(grid){ diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index bdd4e24713..fff6b5f332 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -101,7 +101,7 @@ public class CacheLayer{ renderer.effectBuffer.begin(); Core.graphics.clear(Color.clear); - renderer.blocks.floor.beginc(); + renderer.blocks.floor.beginDraw(); } @Override @@ -110,7 +110,7 @@ public class CacheLayer{ renderer.effectBuffer.end(); renderer.effectBuffer.blit(shader); - renderer.blocks.floor.beginc(); + renderer.blocks.floor.beginDraw(); } } } diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 20fb0443f1..31922c8877 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -115,6 +115,10 @@ public class FloorRenderer{ return indexData; } + public float[] getVertexBuffer(){ + return vertices; + } + /** Queues up a cache change for a tile. Only runs in render loop. */ public void recacheTile(Tile tile){ recacheTile(tile.x, tile.y); @@ -183,14 +187,6 @@ public class FloorRenderer{ underwaterDraw.clear(); } - public void beginc(){ - shader.bind(); - shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat); - - //only ever use the base environment texture - texture.bind(0); - } - public void checkChanges(){ if(recacheSet.size > 0){ //recache one chunk at a time @@ -215,7 +211,11 @@ public class FloorRenderer{ Draw.flush(); - beginc(); + shader.bind(); + shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat); + + //only ever use the base environment texture + texture.bind(0); Gl.enable(Gl.blend); } @@ -343,7 +343,7 @@ public class FloorRenderer{ (cx+1) * tilesize * chunksize + tilesize/2f, (cy+1) * tilesize * chunksize + tilesize/2f); mesh.setVertices(vertices, 0, vidx); - //all vertices are shared + //all indices are shared and identical mesh.indices = indexData; return mesh; diff --git a/core/src/mindustry/graphics/IndexedRenderer.java b/core/src/mindustry/graphics/IndexedRenderer.java deleted file mode 100644 index 5b5a1e3203..0000000000 --- a/core/src/mindustry/graphics/IndexedRenderer.java +++ /dev/null @@ -1,211 +0,0 @@ -package mindustry.graphics; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.graphics.gl.*; -import arc.math.*; -import arc.util.*; -import mindustry.*; - -import java.nio.*; - -public class IndexedRenderer implements Disposable{ - private static final int vsize = 5; - - private final static Shader program = new Shader( - """ - attribute vec4 a_position; - attribute vec4 a_color; - attribute vec2 a_texCoord0; - uniform mat4 u_projTrans; - varying vec4 v_color; - varying vec2 v_texCoords; - void main(){ - v_color = a_color; - v_color.a = v_color.a * (255.0/254.0); - v_texCoords = a_texCoord0; - gl_Position = u_projTrans * a_position; - } - """, - - """ - varying lowp vec4 v_color; - varying vec2 v_texCoords; - uniform sampler2D u_texture; - void main(){ - gl_FragColor = v_color * texture2D(u_texture, v_texCoords); - } - """ - ); - private static final float[] tmpVerts = new float[vsize * 4]; - - private Mesh mesh; - private FloatBuffer buffer; - - private Mat projMatrix = new Mat(); - private Mat transMatrix = new Mat(); - private Mat combined = new Mat(); - private float color = Color.white.toFloatBits(); - - public IndexedRenderer(int sprites){ - resize(sprites); - } - - public void render(Texture texture){ - Gl.enable(Gl.blend); - - updateMatrix(); - - program.bind(); - texture.bind(); - - program.setUniformMatrix4("u_projTrans", combined); - - mesh.render(program, Gl.triangles, 0, mesh.getMaxVertices() * 6 / 4); - } - - public void setColor(Color color){ - this.color = color.toFloatBits(); - } - - public void draw(int index, TextureRegion region, float x, float y, float w, float h){ - float fx2 = x + w; - float fy2 = y + h; - float u = region.u; - float v = region.v2; - float u2 = region.u2; - float v2 = region.v; - - float[] vertices = tmpVerts; - float color = this.color; - - int idx = 0; - vertices[idx++] = x; - vertices[idx++] = y; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; - - vertices[idx++] = x; - vertices[idx++] = fy2; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v2; - - vertices[idx++] = fx2; - vertices[idx++] = fy2; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - - vertices[idx++] = fx2; - vertices[idx++] = y; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v; - - int dest = index * vsize * 4; - - buffer.position(dest); - buffer.put(vertices); - - //mark dirty - mesh.getVerticesBuffer(); - } - - public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){ - float u = region.u; - float v = region.v2; - float u2 = region.u2; - float v2 = region.v; - - float originX = w / 2, originY = h / 2; - - float cos = Mathf.cosDeg(rotation); - float sin = Mathf.sinDeg(rotation); - - float fx = -originX; - float fy = -originY; - float fx2 = w - originX; - float fy2 = h - originY; - - float worldOriginX = x + originX; - float worldOriginY = y + originY; - - float x1 = cos * fx - sin * fy + worldOriginX; - float y1 = sin * fx + cos * fy + worldOriginY; - float x2 = cos * fx - sin * fy2 + worldOriginX; - float y2 = sin * fx + cos * fy2 + worldOriginY; - float x3 = cos * fx2 - sin * fy2 + worldOriginX; - float y3 = sin * fx2 + cos * fy2 + worldOriginY; - float x4 = x1 + (x3 - x2); - float y4 = y3 - (y2 - y1); - - float[] vertices = tmpVerts; - float color = this.color; - - int idx = 0; - vertices[idx++] = x1; - vertices[idx++] = y1; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; - - vertices[idx++] = x2; - vertices[idx++] = y2; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v2; - - vertices[idx++] = x3; - vertices[idx++] = y3; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - - vertices[idx++] = x4; - vertices[idx++] = y4; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v; - - int dest = index * vsize * 4; - - buffer.position(dest); - buffer.put(vertices); - - //mark dirty - mesh.getVerticesBuffer(); - } - - public Mat getTransformMatrix(){ - return transMatrix; - } - - public void setProjectionMatrix(Mat matrix){ - projMatrix = matrix; - } - - public void resize(int sprites){ - if(mesh != null) mesh.dispose(); - - mesh = new Mesh(true, 4 * sprites, 0, - VertexAttribute.position, - VertexAttribute.color, - VertexAttribute.texCoords); - - buffer = mesh.getVerticesBuffer(); - buffer.limit(buffer.capacity()); - - mesh.indices = Vars.renderer.blocks.floor.getIndexData(); - } - - private void updateMatrix(){ - combined.set(projMatrix).mul(transMatrix); - } - - @Override - public void dispose(){ - mesh.dispose(); - } -} From 6e44ff1de182d0c2f738181b396401e9f73fb6cd Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 20 Jul 2025 19:33:37 -0400 Subject: [PATCH 33/37] Misc map editor fixes --- core/src/mindustry/editor/DrawOperation.java | 21 +++++-- core/src/mindustry/editor/EditorTile.java | 15 ++--- core/src/mindustry/editor/MapEditor.java | 5 ++ .../src/mindustry/editor/MapEditorDialog.java | 21 ++++--- core/src/mindustry/editor/MapRenderer.java | 59 +++++++++++++++---- core/src/mindustry/editor/MapView.java | 2 +- 6 files changed, 84 insertions(+), 39 deletions(-) diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 903b38a588..a67253ce80 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -57,6 +57,15 @@ public class DrawOperation{ } void setTile(Tile tile, byte type, short to){ + if(type == opBlock || type == opTeam || type == opRotation){ + tile.getLinkedTiles(t -> { + editor.renderer.updateBlock(t); + editor.renderer.updateStatic(t.x, t.y); + }); + }else{ + editor.renderer.updateStatic(tile.x, tile.y); + } + editor.load(() -> { switch(type){ case opFloor -> { @@ -70,15 +79,11 @@ public class DrawOperation{ } } case opBlock -> { - tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); - Block block = content.block(to); tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); if(tile.build != null){ tile.build.enabled = true; } - - tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); } case opRotation -> { if(tile.build != null) tile.build.rotation = to; @@ -86,7 +91,13 @@ public class DrawOperation{ case opTeam -> tile.setTeam(Team.get(to)); } }); - editor.renderer.updateStatic(tile.x, tile.y); + + if(type == opBlock || type == opTeam || type == opRotation){ + tile.getLinkedTiles(t -> { + editor.renderer.updateBlock(t); + editor.renderer.updateStatic(t.x, t.y); + }); + } } @Struct diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 47a5aee534..3aec80c678 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -56,7 +56,6 @@ public class EditorTile extends Tile{ } if(this.block == type && (build == null || build.rotation == rotation)){ - updateStatic(); return; } @@ -76,15 +75,9 @@ public class EditorTile extends Tile{ if(requiresBlockUpdate(type) || requiresBlockUpdate(prev)){ if(prev.size > 1){ - prevCenter.getLinkedTilesAs(prev, tile -> { - editor.renderer.updateBlock(tile.x, tile.y); - renderer.blocks.updateShadowTile(tile); - }); + prevCenter.getLinkedTilesAs(prev, tile -> editor.renderer.updateBlock(tile)); } - getLinkedTiles(tile -> { - editor.renderer.updateBlock(tile.x, tile.y); - renderer.blocks.updateShadowTile(tile); - }); + getLinkedTiles(tile -> editor.renderer.updateBlock(tile)); }else{ renderer.blocks.updateShadowTile(this); } @@ -97,11 +90,11 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == team.id) return; + if(getTeamID() == team.id || !synthetic()) return; op(DrawOperation.opTeam, (byte)getTeamID()); super.setTeam(team); - getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); + getLinkedTiles(t -> editor.renderer.updateBlock(t.x, t.y)); } @Override diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index e663e7d8cc..2562a6a8df 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -148,6 +148,7 @@ public class MapEditor{ y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1); if(!hasOverlap(x, y)){ tile(x, y).setBlock(drawBlock, drawTeam, rotation); + addTileOp(TileOp.get((short)x, (short)y, (byte)DrawOperation.opTeam, (byte)drawTeam.id)); } }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; @@ -169,6 +170,10 @@ public class MapEditor{ } tile.setBlock(drawBlock, drawTeam, rotation); + + if(drawBlock.synthetic()){ + addTileOp(TileOp.get(tile.x, tile.y, (byte)DrawOperation.opTeam, (byte)drawTeam.id)); + } } }; diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index f1755db39d..47e1a979c8 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -29,6 +29,7 @@ import mindustry.ui.dialogs.*; 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.*; @@ -323,9 +324,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ "width", editor.width(), "height", editor.height() )); + state.set(State.playing); world.endMapLoad(); - player.set(world.width() * tilesize/2f, world.height() * tilesize/2f); - Core.camera.position.set(player); player.clearUnit(); for(var unit : Groups.unit){ @@ -338,14 +338,17 @@ public class MapEditorDialog extends Dialog implements Disposable{ Groups.weather.clear(); logic.play(); - if(player.team().core() == null){ - player.set(world.width() * tilesize/2f, world.height() * tilesize/2f); - var unit = (state.rules.hasEnv(Env.scorching) ? UnitTypes.evoke : UnitTypes.alpha).spawn(player.team(), player.x, player.y); - unit.spawnedByCore = true; - player.unit(unit); - } + Point2 center = view.project(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f); - player.checkSpawn(); + CoreBuild best = player.bestCore(); + + player.set(center.x * tilesize, center.y * tilesize); + var unit = (best != null ? ((CoreBlock)best.block).unitType : (state.rules.hasEnv(Env.scorching) ? UnitTypes.evoke : UnitTypes.alpha)).spawn(editor.drawTeam, player.x, player.y); + unit.spawnedByCore = true; + player.unit(unit); + player.set(unit); + + Core.camera.position.set(unit.x, unit.y); }); } diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index 9e3938fedc..a4b32967ab 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -15,6 +15,8 @@ import static mindustry.Vars.*; public class MapRenderer implements Disposable{ private static final int chunkSize = 60; + private static final Seq tmpTiles = new Seq<>(); + private EditorSpriteCache[][] chunks; private IntSet recacheChunks = new IntSet(); private int width, height; @@ -70,6 +72,7 @@ public class MapRenderer implements Disposable{ boolean prev = renderer.animateWater; renderer.animateWater = false; + Tmp.v3.set(Core.camera.position); Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); Core.camera.width = 999999f; Core.camera.height = 999999f; @@ -114,12 +117,19 @@ public class MapRenderer implements Disposable{ mesh.render(shader); } } + + Core.camera.position.set(Tmp.v3); } void updateStatic(int x, int y){ renderer.blocks.floor.recacheTile(x, y); } + void updateBlock(Tile tile){ + updateBlock(tile.x, tile.y); + renderer.blocks.updateShadowTile(tile); + } + void updateBlock(int x, int y){ recacheChunks.add(Point2.pack(x / chunkSize, y / chunkSize)); } @@ -143,28 +153,51 @@ public class MapRenderer implements Disposable{ EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer()); + TextureRegion teamRegion = Core.atlas.find("block-border"); + + tmpTiles.clear(); + for(int x = cx * chunkSize; x < (cx + 1) * chunkSize; x++){ for(int y = cy * chunkSize; y < (cy + 1) * chunkSize; y++){ Tile tile = world.tile(x, y); if(tile != null && tile.block() != Blocks.air && tile.block().cacheLayer == CacheLayer.normal && tile.isCenter()){ - Block block = tile.block(); - - TextureRegion region = block.fullIcon; - - float width = region.width * region.scl(), height = region.height * region.scl(); - - cache.draw(block.fullIcon, - x * tilesize + block.offset - width / 2f, - y * tilesize + block.offset - height / 2f, - width/2f, height/2f, - width, height, - tile.build == null || !block.rotate ? 0 : tile.build.rotdeg(), - Color.whiteFloatBits); + tmpTiles.add(tile); } } } + tmpTiles.sort(Structs.comparingBool(b -> !b.block().synthetic())); + + for(Tile tile : tmpTiles){ + int x = tile.x, y = tile.y; + Block block = tile.block(); + + TextureRegion region = block.fullIcon; + + float width = region.width * region.scl(), height = region.height * region.scl(); + + cache.draw(block.fullIcon, + x * tilesize + block.offset - width / 2f, + y * tilesize + block.offset - height / 2f, + width/2f, height/2f, + width, height, + tile.build == null || !block.rotate ? 0 : tile.build.rotdeg(), + Color.whiteFloatBits); + + if(tile.build != null){ + cache.draw(teamRegion, + x * tilesize + block.offset - width / 2f, + y * tilesize + block.offset - height / 2f, + 0f, 0f, + teamRegion.width * teamRegion.scl(), teamRegion.height * teamRegion.scl(), + 0f, + tile.build.team.color.toFloatBits()); + } + } + + tmpTiles.clear(); + if(!cache.isEmpty()){ cache.build(renderer.blocks.floor.getIndexData()); chunks[cx][cy] = cache; diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index e4f571bfb0..55c40faee4 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -204,7 +204,7 @@ public class MapView extends Element implements GestureListener{ zoom = Mathf.clamp(zoom, 0.2f, 20f); } - Point2 project(float x, float y){ + public Point2 project(float x, float y){ float ratio = 1f / ((float)editor.width() / editor.height()); float size = Math.min(width, height); float sclwidth = size * zoom; From fab3c08ddb977d49727bc35716108d806a89a3a1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 20 Jul 2025 20:05:32 -0400 Subject: [PATCH 34/37] Mobile improvements --- core/src/mindustry/editor/MapEditorDialog.java | 4 +++- core/src/mindustry/editor/MapRenderer.java | 13 +++++++++---- core/src/mindustry/editor/MapView.java | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 47e1a979c8..5e617806f4 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -834,7 +834,9 @@ public class MapEditorDialog extends Dialog implements Disposable{ if(i == 0) editor.drawBlock = block; - if(++i % 6 == 0){ + int cols = mobile ? 4 : 6; + + if(++i % cols == 0){ blockSelection.row(); } } diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index a4b32967ab..311e4c8876 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -67,7 +67,10 @@ public class MapRenderer implements Disposable{ Draw.flush(); - renderer.blocks.floor.checkChanges(); + //don't process terrain updates every frame (helps with lag on low end devices) + boolean doUpdate = Core.graphics.getFrameId() % 2 == 0; + + if(doUpdate) renderer.blocks.floor.checkChanges(); boolean prev = renderer.animateWater; renderer.animateWater = false; @@ -84,7 +87,7 @@ public class MapRenderer implements Disposable{ //scissors are always enabled because this is drawn clipped in UI, make sure they don't interfere with drawing shadow events Gl.disable(Gl.scissorTest); - renderer.blocks.processShadows(); + if(doUpdate) renderer.blocks.processShadows(); Gl.enable(Gl.scissorTest); @@ -102,8 +105,10 @@ public class MapRenderer implements Disposable{ if(chunks == null) return; - recacheChunks.each(i -> recacheChunk(Point2.x(i), Point2.y(i))); - recacheChunks.clear(); + if(doUpdate){ + recacheChunks.each(i -> recacheChunk(Point2.x(i), Point2.y(i))); + recacheChunks.clear(); + } shader.bind(); shader.setUniformMatrix4("u_projTrans", Core.camera.mat); diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 55c40faee4..e030350238 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -11,6 +11,7 @@ import arc.scene.*; import arc.scene.event.*; import arc.scene.ui.layout.*; import arc.util.*; +import mindustry.*; import mindustry.graphics.*; import mindustry.input.*; import mindustry.ui.*; @@ -18,7 +19,7 @@ import mindustry.ui.*; import static mindustry.Vars.*; public class MapView extends Element implements GestureListener{ - EditorTool tool = EditorTool.pencil; + EditorTool tool = Vars.mobile ? EditorTool.zoom : EditorTool.pencil; private float offsetx, offsety; private float zoom = 1f; private boolean grid = false; From f0820572cedfb54e9b06006278e266bafd7e0c54 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 21 Jul 2025 02:17:07 -0400 Subject: [PATCH 35/37] Cleanup --- core/assets/bundles/bundle.properties | 4 +++- core/src/mindustry/editor/DrawOperation.java | 2 +- core/src/mindustry/editor/EditorSpriteCache.java | 2 +- core/src/mindustry/editor/MapEditor.java | 6 +++--- core/src/mindustry/editor/MapRenderer.java | 4 ++++ core/src/mindustry/world/blocks/environment/Cliff.java | 1 - 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 29e9f835f7..a7164a71db 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1680,8 +1680,10 @@ block.metal-floor-3.name = Metal Floor 3 block.metal-floor-4.name = Metal Floor 4 block.metal-floor-5.name = Metal Floor 5 block.metal-floor-damaged.name = Damaged Metal Floor -block.colored-floor.name = Colored Floor +block.colored-floor.name = Colored Floor block.colored-wall.name = Colored Wall +block.character-overlay.name = Character Overlay +block.character-overlay-white.name = Character Overlay (White) block.dark-panel-1.name = Dark Panel 1 block.dark-panel-2.name = Dark Panel 2 block.dark-panel-3.name = Dark Panel 3 diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index a67253ce80..6fbf9b996d 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -10,7 +10,7 @@ import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; public class DrawOperation{ - static final int + static final byte opFloor = 0, opBlock = 1, opRotation = 2, diff --git a/core/src/mindustry/editor/EditorSpriteCache.java b/core/src/mindustry/editor/EditorSpriteCache.java index 6fe1faeea1..26cfc652ec 100644 --- a/core/src/mindustry/editor/EditorSpriteCache.java +++ b/core/src/mindustry/editor/EditorSpriteCache.java @@ -146,7 +146,7 @@ public class EditorSpriteCache implements Disposable{ index += vertexSize * 4; } - /** Renders the cached mesh. The shader must already have the correct view matrix (usually u_projectionViewMatrix) set as a uniform. */ + /** Renders the cached mesh. The shader must already have the correct view matrix set as a uniform. */ public void render(Shader shader){ if(mesh == null) throw new IllegalStateException("Cache is empty, call build() first."); diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 2562a6a8df..bb5ff4b102 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -148,7 +148,7 @@ public class MapEditor{ y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1); if(!hasOverlap(x, y)){ tile(x, y).setBlock(drawBlock, drawTeam, rotation); - addTileOp(TileOp.get((short)x, (short)y, (byte)DrawOperation.opTeam, (byte)drawTeam.id)); + addTileOp(TileOp.get((short)x, (short)y, DrawOperation.opTeam, (byte)drawTeam.id)); } }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; @@ -166,13 +166,13 @@ public class MapEditor{ } }else if(!(tile.block().isMultiblock() && !drawBlock.isMultiblock())){ if(drawBlock.rotate && tile.build != null && tile.build.rotation != rotation){ - addTileOp(TileOp.get(tile.x, tile.y, (byte)DrawOperation.opRotation, (byte)rotation)); + addTileOp(TileOp.get(tile.x, tile.y, DrawOperation.opRotation, (byte)rotation)); } tile.setBlock(drawBlock, drawTeam, rotation); if(drawBlock.synthetic()){ - addTileOp(TileOp.get(tile.x, tile.y, (byte)DrawOperation.opTeam, (byte)drawTeam.id)); + addTileOp(TileOp.get(tile.x, tile.y, DrawOperation.opTeam, (byte)drawTeam.id)); } } }; diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index 311e4c8876..f943117b36 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -128,6 +128,10 @@ public class MapRenderer implements Disposable{ void updateStatic(int x, int y){ renderer.blocks.floor.recacheTile(x, y); + if(x > 0) renderer.blocks.floor.recacheTile(x - 1, y); + if(y > 0) renderer.blocks.floor.recacheTile(x, y - 1); + if(x < world.width() - 1) renderer.blocks.floor.recacheTile(x + 1, y); + if(y < world.height() - 1) renderer.blocks.floor.recacheTile(x, y + 1); } void updateBlock(Tile tile){ diff --git a/core/src/mindustry/world/blocks/environment/Cliff.java b/core/src/mindustry/world/blocks/environment/Cliff.java index d3a0c99771..49dba95d7c 100644 --- a/core/src/mindustry/world/blocks/environment/Cliff.java +++ b/core/src/mindustry/world/blocks/environment/Cliff.java @@ -9,7 +9,6 @@ import mindustry.world.*; public class Cliff extends Block{ public float size = 11f; public @Load(value = "cliffmask#", length = 256) TextureRegion[] cliffs; - public @Load(value = "editor-cliffmask#", length = 256) TextureRegion[] editorCliffs; public Cliff(String name){ super(name); From f6745a6b802742700fd594245a06abd80e94b4b4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 21 Jul 2025 02:29:10 -0400 Subject: [PATCH 36/37] Reordered floors --- .../blocks/environment/crux-floor-1.png | Bin 121 -> 251 bytes .../blocks/environment/crux-floor-11.png | Bin 0 -> 198 bytes .../blocks/environment/crux-floor-12.png | Bin 0 -> 548 bytes .../environment/crux-floor-4-autotile.png | Bin 1161 -> 1085 bytes .../environment/crux-floor-8-autotile.png | Bin 1085 -> 1161 bytes ...oor-4-mid-2.png => crux-floor-8-mid-2.png} | Bin core/assets/bundles/bundle.properties | 2 +- core/src/mindustry/content/Blocks.java | 3 +-- 8 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-11.png create mode 100644 core/assets-raw/sprites/blocks/environment/crux-floor-12.png rename core/assets-raw/sprites/blocks/environment/{crux-floor-4-mid-2.png => crux-floor-8-mid-2.png} (100%) diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1.png b/core/assets-raw/sprites/blocks/environment/crux-floor-1.png index 66f26a95bfd636d9f5418b162307ac982af3710e..d20970e1fa147754b5c2f49a86f9b12f631626e8 100644 GIT binary patch delta 209 zcmb>Y%{alZeygX8V@O2n(d*uP2NXD10!}-=IeX{Zov%u7*LALxcaVs7Ztb({e0^r;ZogT+v!rCxxEvIwG32vwKj=(g-XoyYz}{pMxY;Ej=-FMakAIsq zTrM*UcEk%W61*#-Ab40}k-%lk1_vGXiRMkFoVJ2*0^hU>-1TOaG2bN#DCHcRoi)UJQW6a&__T6*OS~8#jheU}*4k zaSVxQeS38yXM=%&+r!{ImWz7Vl3xBhJmcI0zFS=q7TupC=Wy@ow?AU?d5a8FovtMR z0eyyBytZ5i#1Al9Eo))=z{<2B`V7%w) z;usRqdUm>f_mu>JWA(=GkL=w#sX=DZhV}%-X}2Od4k^|N*-wr?bm-WzYfc}eIUb2_ z(mV7pR&kAIn$9HC)46>qw@H238=-#;^5t<$FJhs6nvvzh7 z4@0?0K2J_qL|jAo_x$Iq6HZ2mO5DmfVlbHWcf!pHJ*mc0hpKqj9p1qJ@>rs^2j7vQK3{%`uBZU|~Q&sL-ZBuIj3wcl-i(KQ`Rz zytT0KUd?_7(IZnXSF289W0>*ghuMxOM*bCxS&J*I_aE`m>dWyMdr7n|1`ZFnuhGnr$?A(zBSQN>fYxhUD}tX{p=MYx``Y<|<~N!MDgIC@-{ z?*Dco>!bFKTOu-VCR^<4zRb!i@cx~v{FJSNIgHc3E)=MW-5$&SDQ*4!KNdCz#5Qft zYT?RZHYh*O{h@N>3GNTtt8H&o+;{%J?9KnSn~eV${MvV%d!Ukfh=GBD!PC{xWt~$( F699w}>-7Kt literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png index ed83b0e931e642a8bddc998c48c8c5a18c78ffa4..f3bbc7bbc32af3c3d1c9e6ae44959b7e597bc630 100644 GIT binary patch literal 1085 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&!2I3Q z#WAE}&f7Vsb8kC{xT;P~kT9I!yX~Dr=#J(uLQBN;?{=I%q1M2xtgA8mhJdN@pB{_i z`4#8i=rr5;zmE-ga>C~K^yAAfuiH@frha3KI>?@`q|k7`RC<% z9o8#7c>QBC#$tS;7P{$ zYe3Tbtr)V!9v+GRe1G?~2l1i}x0J3p2Ygm;eejCmir7NArdjf;EUQ@-Y~%PUaODq& zqQ#2t0Di}_;otuYECdPFr2e-+Wz5l&g`#_i1@oc|Hlk0ufoJ@|ax+wxW z|BN!cLGEZ_uy3g3_`uBa;4wRg0gI`;y+ecIil09iA3SDn=$B`(t7G`F_s0*$Ge2=- ztIt>Y?>}JYIM6S`^oK#IZi>JIc7adIq!>*FBXGG8m(dCznfL71{qKBTWTBjs|G(F- z??2f(@9+7Ko9h^yHrUx;|I>eU@qg8S|DJw)`Q@YY+4?0@!p^?rt*fsyws$x?yYc?~ z`7tb3W(Q}^-^*Q)-DJGKLi)uOmh^uw>>9j<=lq;3?a1d_@a+68&O24YbAC40HheC% zxu?4RYR;x9VP~J6*8Qw+UcL+|1*;qsRFZ&f&%vX39SV8{&W& tR}6Iwe;9r+{?kAH{PA6s*#6HjACL>Oc=L+n z)rC1iEI%0@*6#k(Gmpo1qJqky`}5}2@734zWjUM~tDf@b`S$78Uv62qLAZm@>fh$p z$sK$~AWC7!kMpX7(cNe#`!cdQk^rXPGKYb?&NWnXy6 zYX;j_H}?82SovP?qDVpSr26gv={>W!yRUs`({4N{*w3(6EBMx|XP~ zxs8jzu4Ra2)zQ4W=D2+1eI^|i)^;`yK3)MCDX?#ktZvBG4}P<7=d*3g>g}sc7cPBY z#Nx1ja>upnDKi+imCrvmH=>$n%f8TAJONTIcmDV8;mD{xZ4%0~-L#Z*E#sGU`Hjys z7d-8p=~jDp^FG#)d8`YvUp==L{CXhG^W@vZO4C<2$lQDHBGPWiFwv2j1#0(3#y#un z_bwLwuQ>HUT)_U={X6*z?xoZ#R$49JXum&Y@^Ot?mbJgMEE}$LZvXaNJ~qBvtTv;W z(k(&t$rA(Dik66R(oP zudsw>js^QzZzw4JC^^6;s8FlD!I4GUWx|OI3H?zcr?_D<-#Ppe>?kk_YdnkJ1nY&?M z-R<~K)RuMHy=L&z(R92oGU?T2hWf4w6Gq+zJ?6p(q+MhLOPV4U$EPrSu`;)^eSBUM z99XTk`^u%}Z|oCfijS;&u=qX4y+i*P zxNgl$tY=WoUBAJ;As{}xe&3YSpA+rYYX4?da9rPaL;e7RoUa43#^bXrHM)D4U#Lv{ z%gD#}n|VSWB;pSLV`$#^EzQ8ap>e_Y*bVj#jB92#urVZ@WYJ-1ba)<_{+Itt4Nu?d Ub+ZpMFfcH9y85}Sb4q9e02gKq6951J diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png b/core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png index f3bbc7bbc32af3c3d1c9e6ae44959b7e597bc630..ed83b0e931e642a8bddc998c48c8c5a18c78ffa4 100644 GIT binary patch delta 1128 zcmdnX(aAZ%pq|Cq)5S5QV$R#SzD2hUcv?e!`zCmnT~WNXZgTGVd*1}E>CL>Oc=L+n z)rC1iEI%0@*6#k(Gmpo1qJqky`}5}2@734zWjUM~tDf@b`S$78Uv62qLAZm@>fh$p z$sK$~AWC7!kMpX7(cNe#`!cdQk^rXPGKYb?&NWnXy6 zYX;j_H}?82SovP?qDVpSr26gv={>W!yRUs`({4N{*w3(6EBMx|XP~ zxs8jzu4Ra2)zQ4W=D2+1eI^|i)^;`yK3)MCDX?#ktZvBG4}P<7=d*3g>g}sc7cPBY z#Nx1ja>upnDKi+imCrvmH=>$n%f8TAJONTIcmDV8;mD{xZ4%0~-L#Z*E#sGU`Hjys z7d-8p=~jDp^FG#)d8`YvUp==L{CXhG^W@vZO4C<2$lQDHBGPWiFwv2j1#0(3#y#un z_bwLwuQ>HUT)_U={X6*z?xoZ#R$49JXum&Y@^Ot?mbJgMEE}$LZvXaNJ~qBvtTv;W z(k(&t$rA(Dik66R(oP zudsw>js^QzZzw4JC^^6;s8FlD!I4GUWx|OI3H?zcr?_D<-#Ppe>?kk_YdnkJ1nY&?M z-R<~K)RuMHy=L&z(R92oGU?T2hWf4w6Gq+zJ?6p(q+MhLOPV4U$EPrSu`;)^eSBUM z99XTk`^u%}Z|oCfijS;&u=qX4y+i*P zxNgl$tY=WoUBAJ;As{}xe&3YSpA+rYYX4?da9rPaL;e7RoUa43#^bXrHM)D4U#Lv{ z%gD#}n|VSWB;pSLV`$#^EzQ8ap>e_Y*bVj#jB92#urVZ@WYJ-1ba)<_{+Itt4Nu?d Ub+ZpMFfcH9y85}Sb4q9e02gKq6951J literal 1085 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&!2I3Q z#WAE}&f7Vsb8kC{xT;P~kT9I!yX~Dr=#J(uLQBN;?{=I%q1M2xtgA8mhJdN@pB{_i z`4#8i=rr5;zmE-ga>C~K^yAAfuiH@frha3KI>?@`q|k7`RC<% z9o8#7c>QBC#$tS;7P{$ zYe3Tbtr)V!9v+GRe1G?~2l1i}x0J3p2Ygm;eejCmir7NArdjf;EUQ@-Y~%PUaODq& zqQ#2t0Di}_;otuYECdPFr2e-+Wz5l&g`#_i1@oc|Hlk0ufoJ@|ax+wxW z|BN!cLGEZ_uy3g3_`uBa;4wRg0gI`;y+ecIil09iA3SDn=$B`(t7G`F_s0*$Ge2=- ztIt>Y?>}JYIM6S`^oK#IZi>JIc7adIq!>*FBXGG8m(dCznfL71{qKBTWTBjs|G(F- z??2f(@9+7Ko9h^yHrUx;|I>eU@qg8S|DJw)`Q@YY+4?0@!p^?rt*fsyws$x?yYc?~ z`7tb3W(Q}^-^*Q)-DJGKLi)uOmh^uw>>9j<=lq;3?a1d_@a+68&O24YbAC40HheC% zxu?4RYR;x9VP~J6*8Qw+UcL+|1*;qsRFZ&f&%vX39SV8{&W& tR}6Iwe;9r+{?kAH{PA6s*#6HjA Date: Mon, 21 Jul 2025 02:42:25 -0400 Subject: [PATCH 37/37] Proper naming for metal floors --- ...utotile.png => metal-tiles-1-autotile.png} | Bin .../{crux-floor-1.png => metal-tiles-1.png} | Bin ...totile.png => metal-tiles-10-autotile.png} | Bin ...tile1.png => metal-tiles-11-autotile1.png} | Bin ...tile2.png => metal-tiles-11-autotile2.png} | Bin ...tile3.png => metal-tiles-11-autotile3.png} | Bin .../{crux-floor-11.png => metal-tiles-11.png} | Bin ...tile1.png => metal-tiles-12-autotile1.png} | Bin ...tile2.png => metal-tiles-12-autotile2.png} | Bin ...tile3.png => metal-tiles-12-autotile3.png} | Bin ...tile4.png => metal-tiles-12-autotile4.png} | Bin .../{crux-floor-12.png => metal-tiles-12.png} | Bin ...utotile.png => metal-tiles-2-autotile.png} | Bin ...utotile.png => metal-tiles-3-autotile.png} | Bin ...utotile.png => metal-tiles-4-autotile.png} | Bin ...utotile.png => metal-tiles-5-autotile.png} | Bin ...utotile.png => metal-tiles-6-autotile.png} | Bin ...utotile.png => metal-tiles-7-autotile.png} | Bin ...or-7-mid-2.png => metal-tiles-7-mid-2.png} | Bin ...or-7-mid-3.png => metal-tiles-7-mid-3.png} | Bin ...or-7-mid-4.png => metal-tiles-7-mid-4.png} | Bin ...or-7-mid-5.png => metal-tiles-7-mid-5.png} | Bin ...or-7-mid-6.png => metal-tiles-7-mid-6.png} | Bin ...or-7-mid-7.png => metal-tiles-7-mid-7.png} | Bin ...or-7-mid-8.png => metal-tiles-7-mid-8.png} | Bin ...or-7-mid-9.png => metal-tiles-7-mid-9.png} | Bin ...utotile.png => metal-tiles-8-autotile.png} | Bin ...or-8-mid-2.png => metal-tiles-8-mid-2.png} | Bin ...utotile.png => metal-tiles-9-autotile.png} | Bin core/assets/bundles/bundle.properties | 12 ++++++++ core/assets/icons/icons.properties | 24 ++++++++-------- core/src/mindustry/content/Blocks.java | 26 +++++++++--------- 32 files changed, 37 insertions(+), 25 deletions(-) rename core/assets-raw/sprites/blocks/environment/{crux-floor-1-autotile.png => metal-tiles-1-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-1.png => metal-tiles-1.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-10-autotile.png => metal-tiles-10-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-11-autotile1.png => metal-tiles-11-autotile1.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-11-autotile2.png => metal-tiles-11-autotile2.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-11-autotile3.png => metal-tiles-11-autotile3.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-11.png => metal-tiles-11.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-12-autotile1.png => metal-tiles-12-autotile1.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-12-autotile2.png => metal-tiles-12-autotile2.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-12-autotile3.png => metal-tiles-12-autotile3.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-12-autotile4.png => metal-tiles-12-autotile4.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-12.png => metal-tiles-12.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-2-autotile.png => metal-tiles-2-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-3-autotile.png => metal-tiles-3-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-4-autotile.png => metal-tiles-4-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-5-autotile.png => metal-tiles-5-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-6-autotile.png => metal-tiles-6-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-autotile.png => metal-tiles-7-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-2.png => metal-tiles-7-mid-2.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-3.png => metal-tiles-7-mid-3.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-4.png => metal-tiles-7-mid-4.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-5.png => metal-tiles-7-mid-5.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-6.png => metal-tiles-7-mid-6.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-7.png => metal-tiles-7-mid-7.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-8.png => metal-tiles-7-mid-8.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-7-mid-9.png => metal-tiles-7-mid-9.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-8-autotile.png => metal-tiles-8-autotile.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-8-mid-2.png => metal-tiles-8-mid-2.png} (100%) rename core/assets-raw/sprites/blocks/environment/{crux-floor-9-autotile.png => metal-tiles-9-autotile.png} (100%) diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-1-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-1-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-1-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-1.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-1.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-1.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-1.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-10-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-10-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-10-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-10-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile1.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile1.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile1.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile1.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile2.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile2.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile2.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile3.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile3.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-11-autotile3.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-11-autotile3.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-11.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-11.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-11.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-11.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile1.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile1.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile1.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile1.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile2.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile2.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile2.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile3.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile3.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile3.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile3.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile4.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile4.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-12-autotile4.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-12-autotile4.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-12.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-12.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-12.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-12.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-2-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-2-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-2-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-3-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-3-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-3-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-3-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-4-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-4-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-4-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-5-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-5-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-5-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-6-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-6-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-6-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-2.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-2.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-2.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-3.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-3.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-3.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-3.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-4.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-4.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-4.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-4.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-5.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-5.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-5.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-5.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-6.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-6.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-6.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-6.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-7.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-7.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-7.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-7.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-8.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-8.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-8.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-8.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-9.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-9.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-7-mid-9.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-7-mid-9.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-8-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-8-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-8-autotile.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-8-mid-2.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-8-mid-2.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-8-mid-2.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-8-mid-2.png diff --git a/core/assets-raw/sprites/blocks/environment/crux-floor-9-autotile.png b/core/assets-raw/sprites/blocks/environment/metal-tiles-9-autotile.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/crux-floor-9-autotile.png rename to core/assets-raw/sprites/blocks/environment/metal-tiles-9-autotile.png diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 9034485d7a..3dd7ba580b 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1680,6 +1680,18 @@ block.metal-floor-3.name = Metal Floor 3 block.metal-floor-4.name = Metal Floor 4 block.metal-floor-5.name = Metal Floor 5 block.metal-floor-damaged.name = Damaged Metal Floor +block.metal-tiles-1.name = Metal Tiles 1 +block.metal-tiles-2.name = Metal Tiles 2 +block.metal-tiles-3.name = Metal Tiles 3 +block.metal-tiles-4.name = Metal Tiles 4 +block.metal-tiles-5.name = Metal Tiles 5 +block.metal-tiles-6.name = Metal Tiles 6 +block.metal-tiles-7.name = Metal Tiles 7 +block.metal-tiles-8.name = Metal Tiles 8 +block.metal-tiles-9.name = Metal Tiles 9 +block.metal-tiles-10.name = Metal Tiles 10 +block.metal-tiles-11.name = Metal Tiles 11 +block.metal-tiles-12.name = Metal Tiles 12 block.colored-floor.name = Colored Floor block.colored-wall.name = Colored Wall block.character-overlay.name = Character Overlay diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 83d7bd996c..ff3282c8fa 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -600,19 +600,19 @@ 63082=stone-vent|block-stone-vent-ui 63081=basalt-vent|block-basalt-vent-ui 63080=tile-logic-display|block-tile-logic-display-ui -63079=crux-floor-1|block-crux-floor-1-ui -63078=crux-floor-2|block-crux-floor-2-ui -63077=crux-floor-3|block-crux-floor-3-ui -63076=crux-floor-4|block-crux-floor-4-ui +63079=metal-tiles-1|block-metal-tiles-1-ui +63078=metal-tiles-2|block-metal-tiles-2-ui +63077=metal-tiles-3|block-metal-tiles-3-ui +63076=metal-tiles-4|block-metal-tiles-4-ui 63075=colored-floor|block-colored-floor-ui -63074=crux-floor-5|block-crux-floor-5-ui -63073=crux-floor-6|block-crux-floor-6-ui -63072=crux-floor-7|block-crux-floor-7-ui -63071=crux-floor-8|block-crux-floor-8-ui -63070=crux-floor-9|block-crux-floor-9-ui -63069=crux-floor-10|block-crux-floor-10-ui +63074=metal-tiles-5|block-metal-tiles-5-ui +63073=metal-tiles-6|block-metal-tiles-6-ui +63072=metal-tiles-7|block-metal-tiles-7-ui +63071=metal-tiles-8|block-metal-tiles-8-ui +63070=metal-tiles-9|block-metal-tiles-9-ui +63069=metal-tiles-10|block-metal-tiles-10-ui 63068=colored-wall|block-colored-wall-ui -63067=crux-floor-11|block-crux-floor-11-ui -63066=crux-floor-12|block-crux-floor-12-ui +63067=metal-tiles-11|block-metal-tiles-11-ui +63066=metal-tiles-12|block-metal-tiles-12-ui 63065=character-overlay|block-character-overlay-ui 63064=character-overlay-white|block-character-overlay-white-ui diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 39c646818c..f1e98cd80d 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -63,7 +63,7 @@ public class Blocks{ //old metal floors darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, //new metal floors - cruxFloor1, cruxFloor2, cruxFloor3, cruxFloor4, cruxFloor5, cruxFloor6, cruxFloor7, cruxFloor8, cruxFloor9, cruxFloor10, cruxFloor11, cruxFloor12, + metalTiles1, metalTiles2, metalTiles3, metalTiles4, metalTiles5, metalTiles6, metalTiles7, metalTiles8, metalTiles9, metalTiles10, metalTiles11, metalTiles12, //colored coloredFloor, coloredWall, @@ -820,37 +820,37 @@ public class Blocks{ darkMetal = new StaticWall("dark-metal"); - cruxFloor1 = new Floor("crux-floor-1"){{ + metalTiles1 = new Floor("metal-tiles-1"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor2 = new Floor("crux-floor-2"){{ + metalTiles2 = new Floor("metal-tiles-2"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor3 = new Floor("crux-floor-3"){{ + metalTiles3 = new Floor("metal-tiles-3"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor4 = new Floor("crux-floor-4"){{ + metalTiles4 = new Floor("metal-tiles-4"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor5 = new Floor("crux-floor-5"){{ + metalTiles5 = new Floor("metal-tiles-5"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor6 = new Floor("crux-floor-6"){{ + metalTiles6 = new Floor("metal-tiles-6"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; @@ -860,40 +860,40 @@ public class Blocks{ lightColor = Team.crux.color.cpy().a(0.3f); }}; - cruxFloor7 = new Floor("crux-floor-7"){{ + metalTiles7 = new Floor("metal-tiles-7"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; autotileMidVariants = 9; }}; - cruxFloor8 = new Floor("crux-floor-8"){{ + metalTiles8 = new Floor("metal-tiles-8"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; autotileMidVariants = 2; }}; - cruxFloor9 = new Floor("crux-floor-9"){{ + metalTiles9 = new Floor("metal-tiles-9"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor10 = new Floor("crux-floor-10"){{ + metalTiles10 = new Floor("metal-tiles-10"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; }}; - cruxFloor11 = new Floor("crux-floor-11"){{ + metalTiles11 = new Floor("metal-tiles-11"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false; autotileVariants = 3; }}; - cruxFloor12 = new Floor("crux-floor-12"){{ + metalTiles12 = new Floor("metal-tiles-12"){{ autotile = true; drawEdgeOut = false; drawEdgeIn = false;