Logic progress
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
293
core/src/mindustry/world/blocks/logic/LogicBlock.java
Normal file
293
core/src/mindustry/world/blocks/logic/LogicBlock.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user