canvas read/write + multiplayer overwrite bug fix (#10899)

* stuff

* Update CanvasBlock.java

* canvas read/write

* updated flag

* dispose on every possible closing condition (back/cancel/ok)

* arraycopy

* hide listener

* partial colons

* fix updated and dedupe closing

* typo?
This commit is contained in:
The4codeblocks
2025-06-17 11:36:42 -05:00
committed by GitHub
parent 7a33de8fe3
commit 0185b08ca7
2 changed files with 62 additions and 16 deletions

View File

@@ -25,6 +25,7 @@ import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.logic.*; import mindustry.world.blocks.logic.*;
import mindustry.world.blocks.logic.CanvasBlock.*;
import mindustry.world.blocks.logic.LogicBlock.*; import mindustry.world.blocks.logic.LogicBlock.*;
import mindustry.world.blocks.logic.LogicDisplay.*; import mindustry.world.blocks.logic.LogicDisplay.*;
import mindustry.world.blocks.logic.MemoryBlock.*; import mindustry.world.blocks.logic.MemoryBlock.*;
@@ -581,6 +582,8 @@ public class LExecutor{
} }
}else if(target.isobj && target.objval instanceof CharSequence str){ }else if(target.isobj && target.objval instanceof CharSequence str){
output.setnum(address < 0 || address >= str.length() ? Double.NaN : (int)str.charAt(address)); output.setnum(address < 0 || address >= str.length() ? Double.NaN : (int)str.charAt(address));
}else if(from instanceof CanvasBuild canvas && (exec.privileged || (from.team == exec.team))){
output.setnum(canvas.getPixel(address));
} }
} }
} }
@@ -611,6 +614,8 @@ public class LExecutor{
toVar.numval = value.numval; toVar.numval = value.numval;
toVar.isobj = value.isobj; toVar.isobj = value.isobj;
} }
}else if(from instanceof CanvasBuild canvas && (exec.privileged || (from.team == exec.team))){
canvas.setPixel(address, (int)(value.numval));
} }
} }
} }

View File

@@ -17,6 +17,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
@@ -35,7 +36,7 @@ public class CanvasBlock extends Block{
public @Load("@-corner1") TextureRegion corner1; public @Load("@-corner1") TextureRegion corner1;
public @Load("@-corner2") TextureRegion corner2; public @Load("@-corner2") TextureRegion corner2;
protected @Nullable Pixmap previewPixmap; protected @Nullable Pixmap previewPixmap; // please use only for previews
protected @Nullable Texture previewTexture; protected @Nullable Texture previewTexture;
protected int tempBlend = 0; protected int tempBlend = 0;
@@ -49,7 +50,7 @@ public class CanvasBlock extends Block{
config(byte[].class, (CanvasBuild build, byte[] bytes) -> { config(byte[].class, (CanvasBuild build, byte[] bytes) -> {
if(build.data.length == bytes.length){ if(build.data.length == bytes.length){
build.data = bytes; System.arraycopy(bytes, 0, build.data, 0, bytes.length);
build.updateTexture(); build.updateTexture();
} }
}); });
@@ -65,13 +66,15 @@ public class CanvasBlock extends Block{
bitsPerPixel = Mathf.log2(Mathf.nextPowerOfTwo(palette.length)); bitsPerPixel = Mathf.log2(Mathf.nextPowerOfTwo(palette.length));
clipSize = Math.max(clipSize, size * 8 - padding); clipSize = Math.max(clipSize, size * 8 - padding);
previewPixmap = new Pixmap(canvasSize, canvasSize);
} }
@Override @Override
public void drawPlanRegion(BuildPlan plan, Eachable<BuildPlan> list){ public void drawPlanRegion(BuildPlan plan, Eachable<BuildPlan> list){
//only draw the preview in schematics, as it lags otherwise //only draw the preview in schematics, as it lags otherwise
if(!plan.worldContext && plan.config instanceof byte[] data){ if(!plan.worldContext && plan.config instanceof byte[] data){
Pixmap pix = makePixmap(data); Pixmap pix = makePixmap(data, previewPixmap);
if(previewTexture == null){ if(previewTexture == null){
previewTexture = new Texture(pix); previewTexture = new Texture(pix);
@@ -123,20 +126,15 @@ public class CanvasBlock extends Block{
} }
} }
/** returns the same pixmap instance each time, use with care */ public Pixmap makePixmap(byte[] data, Pixmap target){
public Pixmap makePixmap(byte[] data){
if(previewPixmap == null){
previewPixmap = new Pixmap(canvasSize, canvasSize);
}
int bpp = bitsPerPixel; int bpp = bitsPerPixel;
int pixels = canvasSize * canvasSize; int pixels = canvasSize * canvasSize;
for(int i = 0; i < pixels; i++){ for(int i = 0; i < pixels; i++){
int bitOffset = i * bpp; int bitOffset = i * bpp;
int pal = getByte(data, bitOffset); int pal = getByte(data, bitOffset);
previewPixmap.set(i % canvasSize, i / canvasSize, palette[pal]); target.set(i % canvasSize, i / canvasSize, palette[pal]);
} }
return previewPixmap; return target;
} }
protected int getByte(byte[] data, int bitOffset){ protected int getByte(byte[] data, int bitOffset){
@@ -153,10 +151,40 @@ public class CanvasBlock extends Block{
public byte[] data = new byte[Mathf.ceil(canvasSize * canvasSize * bitsPerPixel / 8f)]; public byte[] data = new byte[Mathf.ceil(canvasSize * canvasSize * bitsPerPixel / 8f)];
public int blending; public int blending;
protected boolean updated = false;
public void setPixel(int pos, int index){
if(pos < canvasSize * canvasSize && pos >= 0 && index >= 0 && index < palette.length){
setByte(data, pos * bitsPerPixel, index);
updated = true;
}
}
public void setPixel(int x, int y, int index){
if(x >= 0 && y >= 0 && x < canvasSize && y < canvasSize && index >= 0 && index < palette.length){
setByte(data, (y * canvasSize + x) * bitsPerPixel, index);
updated = true;
}
}
public int getPixel(int pos){
if(pos >= 0 && pos < canvasSize * canvasSize){
return getByte(data, pos * bitsPerPixel);
}
return 0;
}
public int getPixel(int x, int y){
if(x >= 0 && y >= 0 && x < canvasSize && y < canvasSize){
return getByte(data, (y * canvasSize + x) * bitsPerPixel);
}
return 0;
}
public void updateTexture(){ public void updateTexture(){
if(headless) return; if(headless) return;
Pixmap pix = makePixmap(data); Pixmap pix = makePixmap(data, previewPixmap);
if(texture != null){ if(texture != null){
texture.draw(pix); texture.draw(pix);
}else{ }else{
@@ -214,7 +242,8 @@ public class CanvasBlock extends Block{
super.draw(); super.draw();
} }
if(texture == null){ if(texture == null || updated){
updated = false;
updateTexture(); updateTexture();
} }
Tmp.tr1.set(texture); Tmp.tr1.set(texture);
@@ -238,6 +267,14 @@ public class CanvasBlock extends Block{
} }
} }
@Override
public double sense(LAccess sensor){
return switch(sensor){
case displayWidth, displayHeight -> canvasSize;
default -> super.sense(sensor);
};
}
@Override @Override
public void remove(){ public void remove(){
super.remove(); super.remove();
@@ -252,12 +289,17 @@ public class CanvasBlock extends Block{
table.button(Icon.pencil, Styles.cleari, () -> { table.button(Icon.pencil, Styles.cleari, () -> {
Dialog dialog = new Dialog(); Dialog dialog = new Dialog();
Pixmap pix = makePixmap(data); Pixmap pix = makePixmap(data, new Pixmap(canvasSize, canvasSize));
Texture texture = new Texture(pix); Texture texture = new Texture(pix);
int[] curColor = {palette[0]}; int[] curColor = {palette[0]};
boolean[] modified = {false}; boolean[] modified = {false};
boolean[] fill = {false}; boolean[] fill = {false};
dialog.hidden(() -> {
texture.dispose();
pix.dispose();
});
dialog.resized(dialog::hide); dialog.resized(dialog::hide);
dialog.cont.table(Tex.pane, body -> { dialog.cont.table(Tex.pane, body -> {
@@ -395,7 +437,6 @@ public class CanvasBlock extends Block{
dialog.buttons.button("@ok", Icon.ok, () -> { dialog.buttons.button("@ok", Icon.ok, () -> {
if(modified[0]){ if(modified[0]){
configure(packPixmap(pix)); configure(packPixmap(pix));
texture.dispose();
} }
dialog.hide(); dialog.hide();
}); });