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

View file

@ -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

View file

@ -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)

View file

@ -36,6 +36,7 @@ public class EditorTile extends Tile{
op(DrawOperation.opFloor, floor.id);
this.floor = type;
type.floorChanged(this);
}
@Override

View file

@ -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;

View file

@ -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));
}

View file

@ -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;

View file

@ -347,6 +347,7 @@ public abstract class SaveVersion extends SaveFileReader{
tile.floorData = floorData;
tile.overlayData = overlayData;
tile.extraData = extraData;
context.onReadTileData();
}
if(hadEntity){

View file

@ -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, "");

View file

@ -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;

View file

@ -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 */

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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");

View file

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

View file

@ -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;