Logic progress

This commit is contained in:
Anuken
2020-08-08 14:14:33 -04:00
parent 8411cc16f1
commit ac46b77380
28 changed files with 6339 additions and 5755 deletions

View File

@@ -81,11 +81,14 @@ public class Blocks implements ContentList{
additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor,
repairPoint, resupplyPoint,
//logic
microProcessor, logicProcessor,
//campaign
launchPad, launchPadLarge,
//misc experimental
logicProcessor, blockForge, blockLoader, blockUnloader;
blockForge, blockLoader, blockUnloader;
@Override
public void load(){
@@ -1885,15 +1888,29 @@ public class Blocks implements ContentList{
}};
//endregion campaign
//region experimental
//region logic
logicProcessor = new LogicProcessor("logic-processor"){{
requirements(Category.effect, BuildVisibility.debugOnly, with(Items.copper, 200, Items.lead, 100));
microProcessor = new LogicBlock("micro-processor"){{
requirements(Category.effect, with(Items.copper, 30, Items.lead, 50, Items.silicon, 30));
instructionsPerTick = 2;
memory = 32;
size = 1;
}};
logicProcessor = new LogicBlock("logic-processor"){{
requirements(Category.effect, with(Items.copper, 200, Items.lead, 120, Items.silicon, 100, Items.metaglass, 50));
instructionsPerTick = 5;
memory = 128;
size = 2;
alwaysUnlocked = true;
}};
//endregion
//region experimental
blockForge = new BlockForge("block-forge"){{
requirements(Category.production, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;

View File

@@ -98,7 +98,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
sound = new SoundLoop(block.activeSound, block.activeSoundVolume);
}
health(block.health);
health = block.health;
maxHealth(block.health);
timer(new Interval(block.timers));
@@ -142,7 +142,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public final void readBase(Reads read){
health = read.f();
rotation(read.b());
rotation = read.b();
team = Team.get(read.b());
if(items != null) items.read(read);
if(power != null) power.read(read);
@@ -295,6 +295,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
public float efficiency(){
//disabled -> 0 efficiency
if(!enabled) return 0;
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
}
@@ -326,6 +328,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
//endregion
//region handler methods
/** This is for logic blocks. */
public void handleString(Object value){
}
public void created(){}
public boolean shouldConsume(){
@@ -1190,7 +1197,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
loops.play(block.idleSound, base(), block.idleSoundVolume);
}
updateTile();
if(enabled || !block.noUpdateDisabled){
updateTile();
}
if(items != null){
items.update(updateFlow);

View File

@@ -3,6 +3,7 @@ package mindustry.io;
import arc.graphics.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.io.*;
import arc.util.pooling.*;
import mindustry.ai.types.*;
@@ -78,11 +79,18 @@ public class TypeIO{
}else if(object instanceof Boolean){
write.b((byte)10);
write.bool((Boolean)object);
}else if(object instanceof Double){
write.b((byte)11);
write.d((Double)object);
}else if(object instanceof Building){
write.b((byte)12);
write.i(((Building)object).pos());
}else{
throw new IllegalArgumentException("Unknown object type: " + object.getClass());
}
}
@Nullable
public static Object readObject(Reads read){
byte type = read.b();
switch(type){
@@ -97,6 +105,8 @@ public class TypeIO{
case 8: byte len = read.b(); Point2[] out = new Point2[len]; for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i()); return out;
case 9: return TechTree.getNotNull(content.getByID(ContentType.all[read.b()], read.s()));
case 10: return read.bool();
case 11: return read.d();
case 12: return world.build(read.i());
default: throw new IllegalArgumentException("Unknown object type: " + type);
}
}

View File

@@ -2,8 +2,11 @@ package mindustry.logic;
import arc.func.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.logic.LExecutor.*;
import mindustry.type.*;
/** "Compiles" a sequence of statements into instructions. */
public class LAssembler{
@@ -16,10 +19,23 @@ public class LAssembler{
LInstruction[] instructions;
public LAssembler(){
putVar("@counter");
putConst("@time", 0);
//add default constants
putConst("false", 0);
putConst("true", 1);
putConst("null", null);
//store base content (TODO hacky?)
for(Item item : Vars.content.items()){
putConst("@" + item.name, item);
}
for(Liquid liquid : Vars.content.liquids()){
putConst("@" + liquid.name, liquid);
}
}
public static LAssembler assemble(String data){
@@ -84,7 +100,7 @@ public class LAssembler{
}
/** Adds a constant value by name. */
BVar putConst(String name, Object value){
public BVar putConst(String name, Object value){
BVar var = putVar(name);
var.constant = true;
var.value = value;
@@ -92,7 +108,7 @@ public class LAssembler{
}
/** Registers a variable name mapping. */
BVar putVar(String name){
public BVar putVar(String name){
if(vars.containsKey(name)){
return vars.get(name);
}else{
@@ -102,7 +118,11 @@ public class LAssembler{
}
}
/** A saved variable. */
public @Nullable BVar getVar(String name){
return vars.get(name);
}
/** A variable "builder". */
public static class BVar{
public int id;
public boolean constant;
@@ -113,5 +133,14 @@ public class LAssembler{
}
BVar(){}
@Override
public String toString(){
return "BVar{" +
"id=" + id +
", constant=" + constant +
", value=" + value +
'}';
}
}
}

View File

@@ -6,7 +6,8 @@ import mindustry.graphics.*;
public enum LCategory{
blocks(Pal.accentBack),
control(Color.cyan.cpy().shiftSaturation(-0.6f).mul(0.7f)),
operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f));
operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f)),
io(Pal.remove.cpy().shiftSaturation(-0.5f).mul(0.7f));;
public final Color color;

View File

@@ -4,59 +4,56 @@ import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.type.*;
public class LExecutor{
LInstruction[] instructions;
int counter;
//special variables
public static final int
varCounter = 0,
varTime = 1;
//values of all the variables
Var[] vars;
public double[] memory = {};
public LInstruction[] instructions = {};
public Var[] vars = {};
public boolean initialized(){
return instructions != null && vars != null && instructions.length > 0;
}
/** Runs all the instructions at once. Debugging only! */
public void runAll(){
counter = 0;
while(counter < instructions.length){
instructions[counter++].run(this);
}
}
/** Runs a single instruction. */
public void runOnce(){
//reset to start
if(counter >= instructions.length) counter = 0;
//set time
vars[varTime].numval = Time.millis();
if(counter < instructions.length){
instructions[counter++].run(this);
//reset to start
if(vars[varCounter].numval >= instructions.length) vars[varCounter].numval = 0;
if(vars[varCounter].numval < instructions.length){
instructions[(int)(vars[varCounter].numval++)].run(this);
}
}
public void load(Object context, String data){
load(context,LAssembler.assemble(data));
public void load(String data){
load(LAssembler.assemble(data));
}
public void load(Object context, LAssembler builder){
builder.putConst("this", context);
/** Loads with a specified assembler. Resets all variables. */
public void load(LAssembler builder){
vars = new Var[builder.vars.size];
instructions = builder.instructions;
counter = 0;
builder.vars.each((name, var) -> {
Var v = new Var();
vars[var.id] = v;
Var dest = new Var(name);
vars[var.id] = dest;
if(var.constant){
v.constant = true;
if(var.value instanceof Number){
v.numval = ((Number)var.value).doubleValue();
}else{
v.isobj = true;
v.objval = var.value;
}
dest.constant = var.constant;
if(var.value instanceof Number){
dest.isobj = false;
dest.numval = ((Number)var.value).doubleValue();
}else{
dest.isobj = true;
dest.objval = var.value;
}
});
}
@@ -65,12 +62,17 @@ public class LExecutor{
@Nullable Building building(int index){
Object o = vars[index].objval;
return o == null && o instanceof Building ? (Building)o : null;
return vars[index].isobj && o instanceof Building ? (Building)o : null;
}
@Nullable Object obj(int index){
Object o = vars[index].objval;
return vars[index].isobj ? o : null;
}
boolean bool(int index){
Var v = vars[index];
return v.isobj ? v.objval != null : Math.abs(v.numval) < 0.0001;
return v.isobj ? v.objval != null : Math.abs(v.numval) >= 0.00001;
}
double num(int index){
@@ -78,11 +80,6 @@ public class LExecutor{
return v.isobj ? 0 : v.numval;
}
String str(int index){
Var v = vars[index];
return v.isobj ? String.valueOf(v.objval) : String.valueOf(v.numval);
}
int numi(int index){
return (int)num(index);
}
@@ -104,11 +101,17 @@ public class LExecutor{
//endregion
static class Var{
boolean isobj, constant;
public static class Var{
public final String name;
Object objval;
double numval;
public boolean isobj, constant;
public Object objval;
public double numval;
public Var(String name){
this.name = name;
}
}
//region instruction types
@@ -135,11 +138,74 @@ public class LExecutor{
}
}
public static class SenseI implements LInstruction{
public static class ReadI implements LInstruction{
public int from, to;
public ReadI(int from, int to){
this.from = from;
this.to = to;
}
public ReadI(){
}
@Override
public void run(LExecutor exec){
int address = exec.numi(from);
exec.setnum(to,address < 0 || address >= exec.memory.length ? 0 : exec.memory[address]);
}
}
public static class WriteI implements LInstruction{
public int from, to;
public WriteI(int from, int to){
this.from = from;
this.to = to;
}
public WriteI(){
}
@Override
public void run(LExecutor exec){
int address = exec.numi(to);
if(address >= 0 && address < exec.memory.length){
exec.memory[address] = exec.num(from);
}
}
}
public static class SenseI implements LInstruction{
public int from, to, type;
public SenseI(int from, int to, int type){
this.from = from;
this.to = to;
this.type = type;
}
public SenseI(){
}
@Override
public void run(LExecutor exec){
Building build = exec.building(from);
Object sense = exec.obj(type);
double output = 0;
if(build != null){
if(sense instanceof Item && build.items != null){
output = build.items.get((Item)sense);
}else if(sense instanceof Liquid && build.liquids != null){
output = build.liquids.get((Liquid)sense);
}
}
exec.setnum(to, output);
}
}
@@ -195,22 +261,48 @@ public class LExecutor{
@Override
public void run(LExecutor exec){
exec.counter = exec.instructions.length;
exec.vars[varCounter].numval = exec.instructions.length;
}
}
public static class PrintI implements LInstruction{
public int value;
private static final StringBuilder out = new StringBuilder();
public PrintI(int value){
public int value, target;
public PrintI(int value, int target){
this.value = value;
this.target = target;
}
PrintI(){}
@Override
public void run(LExecutor exec){
Log.info(exec.str(value));
Building b = exec.building(target);
if(b == null) return;
//this should avoid any garbage allocation
Var v = exec.vars[value];
if(v.isobj){
if(v.objval instanceof String){
b.handleString(v.objval);
}else if(v.objval == null){
b.handleString("null");
}else{
b.handleString("[object]");
}
}else{
out.setLength(0);
//display integer version when possible
if(Math.abs(v.numval - (int)v.numval) < 0.000001){
out.append((int)v.numval);
}else{
out.append(v.numval);
}
b.handleString(out);
}
}
}
@@ -227,7 +319,7 @@ public class LExecutor{
@Override
public void run(LExecutor exec){
if(to != -1 && exec.bool(cond)){
exec.counter = to;
exec.vars[varCounter].numval = to;
}
}
}

View File

@@ -3,13 +3,102 @@ package mindustry.logic;
import arc.graphics.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.logic.LExecutor.*;
import mindustry.logic.LCanvas.*;
import mindustry.logic.LExecutor.*;
import mindustry.ui.*;
public class LStatements{
@RegisterStatement("write")
public static class WriteStatement extends LStatement{
public String to = "0";
public String from = "result";
@Override
public void build(Table table){
Log.info("mem:: ");
table.field(to, Styles.nodeField, str -> to = str)
.size(100f, 40f).pad(2f).color(table.color);
table.add(" = ");
table.field(from, Styles.nodeField, str -> from = str)
.size(100f, 40f).pad(2f).color(table.color);
}
@Override
public LCategory category(){
return LCategory.io;
}
@Override
public LInstruction build(LAssembler builder){
return new WriteI(builder.var(from), builder.var(to));
}
}
@RegisterStatement("read")
public static class ReadStatement extends LStatement{
public String to = "result";
public String from = "0";
@Override
public void build(Table table){
table.field(to, Styles.nodeField, str -> to = str)
.size(100f, 40f).pad(2f).color(table.color);
table.add(" = mem:: ");
table.field(from, Styles.nodeField, str -> from = str)
.size(100f, 40f).pad(2f).color(table.color);
}
@Override
public LCategory category(){
return LCategory.io;
}
@Override
public LInstruction build(LAssembler builder){
return new ReadI(builder.var(from), builder.var(to));
}
}
@RegisterStatement("sensor")
public static class SensorStatement extends LStatement{
public String to = "result";
public String from = "@0", type = "@copper";
@Override
public void build(Table table){
table.field(to, Styles.nodeField, str -> to = str)
.size(100f, 40f).pad(2f).color(table.color);
table.add(" = ");
table.field(type, Styles.nodeField, str -> type = str)
.size(100f, 40f).pad(2f).color(table.color);
table.add(" in ");
table.field(from, Styles.nodeField, str -> from = str)
.size(100f, 40f).pad(2f).color(table.color);
}
@Override
public LCategory category(){
return LCategory.operations;
}
@Override
public LInstruction build(LAssembler builder){
return new SenseI(builder.var(from), builder.var(to), builder.var(type));
}
}
@RegisterStatement("set")
public static class SetStatement extends LStatement{
public String to = "result";
@@ -122,16 +211,22 @@ public class LStatements{
@RegisterStatement("print")
public static class PrintStatement extends LStatement{
public String value = "\"frog\"";
public String target = "result";
@Override
public void build(Table table){
table.field(value, Styles.nodeField, str -> value = str)
.size(100f, 40f).pad(2f).color(table.color);
table.add(" to ");
table.field(target, Styles.nodeField, str -> target = str)
.size(100f, 40f).pad(2f).color(table.color);
}
@Override
public LInstruction build(LAssembler builder){
return new PrintI(builder.var(value));
return new PrintI(builder.var(value), builder.var(target));
}
@Override
@@ -182,6 +277,8 @@ public class LStatements{
}
}
//disabled until further notice - bypasses the network
/*
@RegisterStatement("getbuild")
public static class getBuildStatement extends LStatement{
public String x = "0", y = "0", dest = "result";
@@ -211,5 +308,5 @@ public class LStatements{
public LCategory category(){
return LCategory.blocks;
}
}
}*/
}

View File

@@ -2,7 +2,7 @@ package mindustry.mod;
/** Mod listing as a data class. */
public class ModListing{
public String repo, name, author, lastUpdated, description;
public String repo, name, author, lastUpdated, description, minGameVersion;
public int stars;
@Override
@@ -13,6 +13,7 @@ public class ModListing{
", author='" + author + '\'' +
", lastUpdated='" + lastUpdated + '\'' +
", description='" + description + '\'' +
", minGameVersion='" + minGameVersion + '\'' +
", stars=" + stars +
'}';
}

View File

@@ -19,7 +19,7 @@ public class Scripts implements Disposable{
private final Seq<String> blacklist = Seq.with(".net.", "java.net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk",
"runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system",
".awt", "socket", "classloader", "oracle", "invoke", "java.util.function", "java.util.stream", "org.");
private final Seq<String> whitelist = Seq.with("mindustry.net", "netserver", "netclient", "com.sun.proxy.$proxy", "mindustry.gen.");
private final Seq<String> whitelist = Seq.with("mindustry.net", "netserver", "netclient", "com.sun.proxy.$proxy", "mindustry.gen.", "mindustry.logic.");
private final Context context;
private final Scriptable scope;
private boolean errored;

View File

@@ -94,6 +94,8 @@ public class Block extends UnlockableContent{
public boolean absorbLasers = false;
/** if false, the status is never drawn */
public boolean enableDrawStatus = true;
/** if true, the block stops updating when disabled */
public boolean noUpdateDisabled = false;
/** tile entity health */
public int health = -1;
/** base block explosiveness */

View File

@@ -45,6 +45,7 @@ public class Conveyor extends Block implements Autotiler{
idleSound = Sounds.conveyor;
idleSoundVolume = 0.004f;
unloadable = false;
noUpdateDisabled = false;
}
@Override
@@ -114,7 +115,7 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void draw(){
int frame = clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * timeScale())) % 4) : 0;
int frame = enabled && clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * timeScale())) % 4) : 0;
//draw extra conveyors facing this one for non-square tiling purposes
Draw.z(Layer.blockUnder);
@@ -208,10 +209,11 @@ public class Conveyor extends Block implements Autotiler{
}
float nextMax = aligned ? 1f - Math.max(itemSpace - nextc.minitem, 0) : 1f;
float moved = speed * edelta();
for(int i = len - 1; i >= 0; i--){
float nextpos = (i == len - 1 ? 100f : ys[i + 1]) - itemSpace;
float maxmove = Mathf.clamp(nextpos - ys[i], 0, speed * delta());
float maxmove = Mathf.clamp(nextpos - ys[i], 0, moved);
ys[i] += maxmove;

View File

@@ -0,0 +1,293 @@
package mindustry.world.blocks.logic;
import arc.func.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.logic.*;
import mindustry.logic.LAssembler.*;
import mindustry.logic.LExecutor.*;
import mindustry.ui.*;
import mindustry.world.*;
import static mindustry.Vars.*;
public class LogicBlock extends Block{
private static final IntSeq removal = new IntSeq();
public int maxInstructionScale = 8;
public int instructionsPerTick = 1;
public float range = 8 * 10;
public int memory = 16;
public LogicBlock(String name){
super(name);
update = true;
configurable = true;
config(String.class, (LogicEntity entity, String code) -> entity.updateCode(code));
config(Integer.class, (LogicEntity entity, Integer pos) -> {
if(entity.connections.contains(pos)){
entity.connections.removeValue(pos);
}else{
entity.connections.add(pos);
}
entity.updateCode(entity.code);
});
}
public class LogicEntity extends Building{
/** logic "source code" as list of asm statements */
public String code = "";
public LExecutor executor = new LExecutor();
public float accumulator = 0;
public IntSeq connections = new IntSeq();
public boolean loaded = false;
public LogicEntity(){
executor.memory = new double[memory];
}
public void updateCode(String str){
updateCode(str, null);
}
public void updateCode(String str, Cons<LAssembler> assemble){
if(str != null){
code = str;
try{
//create assembler to store extra variables
LAssembler asm = LAssembler.assemble(str);
//store connections
for(int i = 0; i < connections.size; i++){
asm.putConst("@" + i, world.build(connections.get(i)));
}
//store any older variables
for(Var var : executor.vars){
if(!var.constant){
BVar dest = asm.getVar(var.name);
if(dest != null && !dest.constant){
dest.value = var.isobj ? var.objval : var.numval;
}
}
}
//inject any extra variables
if(assemble != null){
assemble.get(asm);
}
asm.putConst("@this", this);
executor.load(asm);
}catch(Exception e){
e.printStackTrace();
//handle malformed code and replace it with nothing
executor.load("");
}
}
}
@Override
public void onProximityUpdate(){
super.onProximityUpdate();
if(!loaded){
//properly fetches connections
updateCode(code);
loaded = true;
}
}
@Override
public void updateTile(){
//remove invalid links
//TODO remove variables
removal.clear();
for(int i = 0; i < connections.size; i++){
int val = connections.get(i);
if(!validLink(val)){
removal.add(val);
}
}
if(!removal.isEmpty()){
updateCode(code);
}
connections.removeAll(removal);
accumulator += edelta() * instructionsPerTick;
if(accumulator > maxInstructionScale * instructionsPerTick) accumulator = maxInstructionScale * instructionsPerTick;
for(int i = 0; i < (int)accumulator; i++){
if(executor.initialized()){
executor.runOnce();
}
accumulator --;
}
}
@Override
public String config(){
return code;
}
@Override
public void drawConfigure(){
super.drawConfigure();
Drawf.circles(x, y, range);
for(int i = 0; i < connections.size; i++){
int pos = connections.get(i);
if(validLink(pos)){
Building other = Vars.world.build(pos);
Drawf.square(other.x, other.y, other.block.size * tilesize / 2f + 1f, Pal.place);
}
}
//draw top text on separate layer
for(int i = 0; i < connections.size; i++){
int pos = connections.get(i);
if(validLink(pos)){
Building other = Vars.world.build(pos);
other.block.drawPlaceText("@" + i, other.tileX(), other.tileY(), true);
}
}
}
public boolean validLink(int pos){
Building other = Vars.world.build(pos);
return other != null && other.team == team && other.within(this, range + other.block.size*tilesize/2f);
}
@Override
public void drawSelect(){
}
@Override
public void buildConfiguration(Table table){
Table cont = new Table();
cont.defaults().size(40);
cont.button(Icon.pencil, Styles.clearTransi, () -> {
Vars.ui.logic.show(code, this::configure);
});
//cont.button(Icon.refreshSmall, Styles.clearTransi, () -> {
//});
table.add(cont);
}
@Override
public boolean onConfigureTileTapped(Building other){
if(this == other){
return true;
}
if(validLink(other.pos())){
configure(other.pos());
return false;
}
return super.onConfigureTileTapped(other);
}
@Override
public void write(Writes write){
super.write(write);
write.str(code);
write.s(connections.size);
for(int i = 0; i < connections.size; i++){
write.i(connections.get(i));
}
//write only the non-constant variables
int count = Structs.count(executor.vars, v -> !v.constant);
write.i(count);
for(int i = 0; i < executor.vars.length; i++){
Var v = executor.vars[i];
if(v.constant) continue;
//write the name and the object value
write.str(v.name);
Object value = v.isobj ? v.objval : v.numval;
TypeIO.writeObject(write, value);
}
write.i(executor.memory.length);
for(int i = 0; i < executor.memory.length; i++){
write.d(executor.memory[i]);
}
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
code = read.str();
connections.clear();
short total = read.s();
for(int i = 0; i < total; i++){
connections.add(read.i());
}
int varcount = read.i();
//variables need to be temporarily stored in an array until they can be used
String[] names = new String[varcount];
Object[] values = new Object[varcount];
for(int i = 0; i < varcount; i++){
String name = read.str();
Object value = TypeIO.readObject(read);
names[i] = name;
values[i] = value;
}
int memory = read.i();
double[] memorybank = executor.memory.length != memory ? new double[memory] : executor.memory;
for(int i = 0; i < memory; i++){
memorybank[i] = read.d();
}
updateCode(code, asm -> {
//load up the variables that were stored
for(int i = 0; i < varcount; i++){
BVar dest = asm.getVar(names[i]);
if(dest != null && !dest.constant){
dest.value = values[i];
}
}
});
executor.memory = memorybank;
}
}
}

View File

@@ -1,72 +0,0 @@
package mindustry.world.blocks.logic;
import arc.util.io.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.logic.*;
import mindustry.world.*;
public class LogicProcessor extends Block{
public LogicProcessor(String name){
super(name);
update = true;
configurable = true;
config(String.class, (LogicEntity entity, String code) -> {
if(code != null){
entity.code = code;
try{
entity.executor.load(entity, code);
}catch(Exception e){
e.printStackTrace();
//handle malformed code and replace it with nothing
entity.executor.load(entity, "");
}
}
});
}
public class LogicEntity extends Building{
/** logic "source code" as list of json statements */
String code = "";
LExecutor executor = new LExecutor();
@Override
public void updateTile(){
if(executor.initialized()){
executor.runOnce();
}
}
@Override
public boolean configTapped(){
Vars.ui.logic.show(code, this::configure);
return false;
}
@Override
public void write(Writes write){
super.write(write);
write.str(code);
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
code = read.str();
try{
executor.load(this, code);
}catch(Exception e){
e.printStackTrace();
//handle malformed code and ignore it
executor = new LExecutor();
}
}
}
}

View File

@@ -34,7 +34,9 @@ public class MessageBlock extends Block{
throw new ValidateException(player, "Player has gone above text limit.");
}
StringBuilder result = new StringBuilder(text.length());
tile.message.ensureCapacity(text.length());
tile.message.setLength(0);
text = text.trim();
int count = 0;
for(int i = 0; i < text.length(); i++){
@@ -42,21 +44,17 @@ public class MessageBlock extends Block{
if(c == '\n' || c == '\r'){
count ++;
if(count <= maxNewlines){
result.append('\n');
tile.message.append('\n');
}
}else{
result.append(c);
tile.message.append(c);
}
}
tile.message = result.toString();
tile.lines = tile.message.split("\n");
});
}
public class MessageBlockEntity extends Building{
public String message = "";
public String[] lines = {""};
public StringBuilder message = new StringBuilder();
@Override
public void drawSelect(){
@@ -68,7 +66,7 @@ public class MessageBlock extends Block{
font.getData().setScale(1 / 4f / Scl.scl(1f));
font.setUseIntegerPositions(false);
String text = message == null || message.isEmpty() ? "[lightgray]" + Core.bundle.get("empty") : message;
CharSequence text = message == null || message.length() == 0 ? "[lightgray]" + Core.bundle.get("empty") : message;
l.setText(font, text, Color.white, 90f, Align.left, true);
float offset = 1f;
@@ -90,7 +88,7 @@ public class MessageBlock extends Block{
table.button(Icon.pencil, () -> {
if(mobile){
Core.input.getTextInput(new TextInput(){{
text = message;
text = message.toString();
multiline = true;
maxLength = maxTextLength;
accepted = str -> configure(str);
@@ -98,7 +96,7 @@ public class MessageBlock extends Block{
}else{
BaseDialog dialog = new BaseDialog("@editmessage");
dialog.setFillParent(false);
TextArea a = dialog.cont.add(new TextArea(message.replace("\n", "\r"))).size(380f, 160f).get();
TextArea a = dialog.cont.add(new TextArea(message.toString().replace("\n", "\r"))).size(380f, 160f).get();
a.setFilter((textField, c) -> {
if(c == '\n' || c == '\r'){
int count = 0;
@@ -127,6 +125,12 @@ public class MessageBlock extends Block{
}).size(40f);
}
@Override
public void handleString(Object value){
message.setLength(0);
message.append(value);
}
@Override
public void updateTableAlign(Table table){
Vec2 pos = Core.input.mouseScreen(x, y + size * tilesize / 2f + 1);
@@ -135,19 +139,19 @@ public class MessageBlock extends Block{
@Override
public String config(){
return message;
return message.toString();
}
@Override
public void write(Writes write){
super.write(write);
write.str(message);
write.str(message.toString());
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
message = read.str();
message = new StringBuilder(read.str());
}
}
}