Better colored floor/wall support

This commit is contained in:
Anuken
2025-07-17 16:09:45 -04:00
parent 4c8f956fef
commit 24cfb000de
19 changed files with 134 additions and 84 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

+1
View File
@@ -121,6 +121,7 @@ continue = Continue
maps.none = [lightgray]No maps found! maps.none = [lightgray]No maps found!
invalid = Invalid invalid = Invalid
pickcolor = Pick Color pickcolor = Pick Color
color = Color
preparingconfig = Preparing Config preparingconfig = Preparing Config
preparingcontent = Preparing Content preparingcontent = Preparing Content
uploadingcontent = Uploading Content uploadingcontent = Uploading Content
-6
View File
@@ -905,16 +905,10 @@ public class Blocks{
autotile = true; autotile = true;
drawEdgeOut = false; drawEdgeOut = false;
drawEdgeIn = false; drawEdgeIn = false;
//there is no proper support for displaying colors or placing with colors
inEditor = false;
}}; }};
coloredWall = new ColoredWall("colored-wall"){{ coloredWall = new ColoredWall("colored-wall"){{
autotile = true; 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) Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6)
@@ -36,6 +36,7 @@ public class EditorTile extends Tile{
op(DrawOperation.opFloor, floor.id); op(DrawOperation.opFloor, floor.id);
this.floor = type; this.floor = type;
type.floorChanged(this);
} }
@Override @Override
@@ -134,6 +134,10 @@ public class MapRenderer implements Disposable{
width, height, width, height,
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg()); tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg());
}else{ }else{
if(floor instanceof ColoredFloor){
mesh.setColor(Tmp.c1.set(tile.extraData | 0xff));
}
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)]; region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)];
mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8); mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8);
@@ -155,6 +159,8 @@ public class MapRenderer implements Disposable{
if(wall == Blocks.cliff){ if(wall == Blocks.cliff){
mesh.setColor(Tmp.c1.set(floor.mapColor).mul(1.6f)); mesh.setColor(Tmp.c1.set(floor.mapColor).mul(1.6f));
region = ((Cliff)Blocks.cliff).editorCliffs[tile.data & 0xff]; 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; offsetX = tilesize / 2f - region.width * region.scl() / 2f;
@@ -1627,6 +1627,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Draws a placement icon for a specific block. */ /** Draws a placement icon for a specific block. */
protected void drawPlan(int x, int y, Block block, int rotation){ protected void drawPlan(int x, int y, Block block, int rotation){
bplan.set(x, y, rotation, block); bplan.set(x, y, rotation, block);
if(block.saveConfig){
bplan.config = block.lastConfig;
}
bplan.animScale = 1f; bplan.animScale = 1f;
block.drawPlan(bplan, allPlans(), validPlace(x, y, block, rotation)); block.drawPlan(bplan, allPlans(), validPlace(x, y, block, rotation));
} }
+25 -1
View File
@@ -139,6 +139,23 @@ public class MapIO{
} }
return tile; 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); floors.draw(walls, true);
@@ -154,7 +171,14 @@ public class MapIO{
for(int x = 0; x < pixmap.width; x++){ for(int x = 0; x < pixmap.width; x++){
for(int y = 0; y < pixmap.height; y++){ for(int y = 0; y < pixmap.height; y++){
Tile tile = tiles.getn(x, 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; return pixmap;
+1
View File
@@ -347,6 +347,7 @@ public abstract class SaveVersion extends SaveFileReader{
tile.floorData = floorData; tile.floorData = floorData;
tile.overlayData = overlayData; tile.overlayData = overlayData;
tile.extraData = extraData; tile.extraData = extraData;
context.onReadTileData();
} }
if(hadEntity){ if(hadEntity){
@@ -78,6 +78,24 @@ public class HudFragment{
.name("editor/search").maxTextLength(maxNameLength).get().setMessageText("@players.search"); .name("editor/search").maxTextLength(maxNameLength).get().setMessageText("@players.search");
}).growX().pad(-2).padLeft(6f); }).growX().pad(-2).padLeft(6f);
cont.row(); 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(); cont.add(pane).expandY().top().left();
rebuildBlockSelection(blockSelection, ""); rebuildBlockSelection(blockSelection, "");
@@ -126,39 +126,41 @@ public class PlacementFragment{
} }
boolean updatePick(InputHandler input){ boolean updatePick(InputHandler input){
if(Core.input.keyTap(Binding.pick) && player.isBuilder() && !Core.scene.hasDialog()){ //mouse eyedropper select Tile tile = world.tileWorld(Core.input.mouseWorldX(), Core.input.mouseWorldY());
var build = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); 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 //can't middle click buildings in fog
if(build != null && build.inFogTo(player.team())){ if(build != null && build.inFogTo(player.team())){
build = null; 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(); 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()){ for(BuildPlan req : player.unit().plans()){
if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){ 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; tryConfig = req.config;
break; break;
} }
} }
if(tryRecipe == null && state.rules.editor){ if(tryBlock == null && state.rules.editor){
var tile = world.tileWorld(Core.input.mouseWorldX(), Core.input.mouseWorldY()); tryBlock =
if(tile != null){
tryRecipe =
tile.block() != Blocks.air ? tile.block() : tile.block() != Blocks.air ? tile.block() :
tile.overlay() != Blocks.air ? tile.overlay() : tile.overlay() != Blocks.air ? tile.overlay() :
tile.floor() != Blocks.air ? tile.floor() : null; tile.floor() != Blocks.air ? tile.floor() : null;
}
} }
if(tryRecipe != null && ((tryRecipe.isVisible() && unlocked(tryRecipe)) || state.rules.editor)){ if(tryBlock != null && ((tryBlock.isVisible() && unlocked(tryBlock)) || state.rules.editor)){
input.block = tryRecipe; input.block = tryBlock;
tryRecipe.lastConfig = tryConfig; tryBlock.lastConfig = tryConfig;
if(tryRecipe.isVisible()){ if(tryBlock.isVisible()){
currentCategory = input.block.category; currentCategory = input.block.category;
} }
return true; return true;
+2
View File
@@ -80,6 +80,8 @@ public class Block extends UnlockableContent implements Senseable{
public boolean displayFlow = true; public boolean displayFlow = true;
/** whether this block is visible in the editor */ /** whether this block is visible in the editor */
public boolean inEditor = true; 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. */ /** the last configuration value applied to this block. */
public @Nullable Object lastConfig; public @Nullable Object lastConfig;
/** whether to save the last config and apply it to newly placed blocks */ /** whether to save the last config and apply it to newly placed blocks */
@@ -26,6 +26,9 @@ public interface WorldContext{
/** Called when a building is finished reading. */ /** Called when a building is finished reading. */
default void onReadBuilding(){} default void onReadBuilding(){}
/** Called when data finishes reading for a tile. */
default void onReadTileData(){}
default @Nullable Sector getSector(){ default @Nullable Sector getSector(){
return null; return null;
} }
@@ -24,12 +24,14 @@ public class ColoredFloor extends Floor{
public ColoredFloor(String name){ public ColoredFloor(String name){
super(name); super(name);
saveData = true; saveData = true;
showColorEdit = true;
saveConfig = true;
} }
@Override @Override
public void init(){ public void init(){
super.init(); super.init();
defaultColorRgba = defaultColor.rgba(); lastConfig = defaultColorRgba = defaultColor.rgba();
} }
@Override @Override
@@ -132,7 +134,9 @@ public class ColoredFloor extends Floor{
@Override @Override
public void floorChanged(Tile tile){ public void floorChanged(Tile tile){
//reset to white //reset to white
tile.extraData = defaultColorRgba; if(tile.extraData == 0){
tile.extraData = defaultColorRgba;
}
} }
@Override @Override
@@ -19,17 +19,19 @@ public class ColoredWall extends StaticWall{
public ColoredWall(String name){ public ColoredWall(String name){
super(name); super(name);
saveData = true; saveData = true;
showColorEdit = true;
saveConfig = true;
} }
@Override @Override
public void init(){ public void init(){
super.init(); super.init();
defaultColorRgba = defaultColor.rgba(); lastConfig = defaultColorRgba = defaultColor.rgba();
} }
@Override @Override
public void drawBase(Tile tile){ 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); Draw.color(tile.extraData | 0xff);
super.drawBase(tile); super.drawBase(tile);
Draw.color(); Draw.color();
@@ -37,8 +39,10 @@ public class ColoredWall extends StaticWall{
@Override @Override
public void blockChanged(Tile tile){ public void blockChanged(Tile tile){
//reset to white //reset to white on first placement
tile.extraData = defaultColorRgba; if(tile.extraData == 0){
tile.extraData = defaultColorRgba;
}
} }
@Override @Override
@@ -59,12 +63,12 @@ public class ColoredWall extends StaticWall{
@Override @Override
public boolean checkAutotileSame(Tile tile, @Nullable Tile other){ 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 @Override
public boolean isDarkened(Tile tile){ public boolean isDarkened(Tile tile){
return (tile.extraData & flagApplyDarkness) != 0; return (tile.extraData == flagApplyDarkness);
} }
@Override @Override
@@ -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){ public int realBlendId(Tile tile){
if(tile.floor().isLiquid && !tile.overlay().isAir() && !(tile.overlay() instanceof OreBlock)){ if(tile.floor().isLiquid && !tile.overlay().isAir() && !(tile.overlay() instanceof OreBlock)){
return -((tile.overlay().blendId) | (tile.floor().blendId << 15)); return -((tile.overlay().blendId) | (tile.floor().blendId << 15));
@@ -31,7 +31,7 @@ import static mindustry.Vars.*;
public class DesktopLauncher extends ClientLauncher{ public class DesktopLauncher extends ClientLauncher{
public final static long discordID = 610508934456934412L; public final static long discordID = 610508934456934412L;
public final String[] args; public final String[] args;
boolean useDiscord = !OS.hasProp("nodiscord"), loadError = false; boolean useDiscord = !OS.hasProp("nodiscord"), loadError = false;
Throwable steamError; Throwable steamError;
@@ -48,21 +48,17 @@ public class DesktopLauncher extends ClientLauncher{
for(int i = 0; i < arg.length; i++){ for(int i = 0; i < arg.length; i++){
if(arg[i].charAt(0) == '-'){ if(arg[i].charAt(0) == '-'){
String name = arg[i].substring(1); String name = arg[i].substring(1);
try{ switch(name){
switch(name){ case "width": width = Strings.parseInt(arg[i + 1], width); break;
case "width": width = Strings.parseInt(arg[i + 1], width); break; case "height": height = Strings.parseInt(arg[i + 1], height); break;
case "height": height = Strings.parseInt(arg[i + 1], height); break; case "glMajor": gl30Major = Strings.parseInt(arg[i + 1], gl30Major);
case "glMajor": gl30Major = Strings.parseInt(arg[i + 1], gl30Major); case "glMinor": gl30Minor = Strings.parseInt(arg[i + 1], gl30Minor);
case "glMinor": gl30Minor = Strings.parseInt(arg[i + 1], gl30Minor); case "gl3": gl30 = true; break;
case "gl3": gl30 = true; break; case "gl2": gl30 = false; break;
case "gl2": gl30 = false; break; case "coreGl": coreProfile = true; break;
case "coreGl": coreProfile = true; break; case "antialias": samples = 16; break;
case "antialias": samples = 16; break; case "debug": Log.level = LogLevel.debug; break;
case "debug": Log.level = LogLevel.debug; break; case "maximized": maximized = Boolean.parseBoolean(arg[i + 1]); break;
case "maximized": maximized = Boolean.parseBoolean(arg[i + 1]); break;
}
}catch(NumberFormatException number){
Log.warn("Invalid parameter number value.");
} }
} }
} }
@@ -75,7 +71,7 @@ public class DesktopLauncher extends ClientLauncher{
public DesktopLauncher(String[] args){ public DesktopLauncher(String[] args){
this.args = args; this.args = args;
Version.init(); Version.init();
boolean useSteam = Version.modifier.contains("steam"); boolean useSteam = Version.modifier.contains("steam");
testMobile = Seq.with(args).contains("-testMobile"); testMobile = Seq.with(args).contains("-testMobile");
+1 -1
View File
@@ -26,4 +26,4 @@ org.gradle.caching=true
org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000 org.gradle.internal.http.connectionTimeout=100000
android.enableR8.fullMode=false android.enableR8.fullMode=false
archash=ae3b50eaca archash=f18ba925db
+29 -25
View File
@@ -394,34 +394,38 @@ public class Generators{
save(padded, region.name); 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; 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; boolean hasEmpty = false;
Color average = new Color(), c = new Color(); Color average = new Color(), c = new Color();
float asum = 0f; float asum = 0f;