Char tile picker support

This commit is contained in:
Anuken
2025-07-18 18:14:32 -04:00
parent 4abc2aba8c
commit fba935c527
7 changed files with 123 additions and 24 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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