Barely functional logic
This commit is contained in:
@@ -18,6 +18,7 @@ import mindustry.world.blocks.environment.*;
|
|||||||
import mindustry.world.blocks.experimental.*;
|
import mindustry.world.blocks.experimental.*;
|
||||||
import mindustry.world.blocks.legacy.*;
|
import mindustry.world.blocks.legacy.*;
|
||||||
import mindustry.world.blocks.liquid.*;
|
import mindustry.world.blocks.liquid.*;
|
||||||
|
import mindustry.world.blocks.logic.*;
|
||||||
import mindustry.world.blocks.power.*;
|
import mindustry.world.blocks.power.*;
|
||||||
import mindustry.world.blocks.production.*;
|
import mindustry.world.blocks.production.*;
|
||||||
import mindustry.world.blocks.sandbox.*;
|
import mindustry.world.blocks.sandbox.*;
|
||||||
@@ -1886,7 +1887,7 @@ public class Blocks implements ContentList{
|
|||||||
//endregion campaign
|
//endregion campaign
|
||||||
//region experimental
|
//region experimental
|
||||||
|
|
||||||
logicProcessor = new ResearchBlock("logic-processor"){{
|
logicProcessor = new LogicProcessor("logic-processor"){{
|
||||||
requirements(Category.effect, BuildVisibility.debugOnly, with(Items.copper, 200, Items.lead, 100));
|
requirements(Category.effect, BuildVisibility.debugOnly, with(Items.copper, 200, Items.lead, 100));
|
||||||
|
|
||||||
size = 3;
|
size = 3;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package mindustry.logic;
|
package mindustry.logic;
|
||||||
|
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.ArcAnnotate.*;
|
|
||||||
import mindustry.io.*;
|
import mindustry.io.*;
|
||||||
import mindustry.logic.LCanvas.*;
|
import mindustry.logic.LCanvas.*;
|
||||||
import mindustry.logic.LExecutor.*;
|
import mindustry.logic.LExecutor.*;
|
||||||
@@ -13,8 +12,6 @@ public class LAssembler{
|
|||||||
ObjectMap<String, BVar> vars = new ObjectMap<>();
|
ObjectMap<String, BVar> vars = new ObjectMap<>();
|
||||||
/** All instructions to be executed. */
|
/** All instructions to be executed. */
|
||||||
LInstruction[] instructions;
|
LInstruction[] instructions;
|
||||||
/** Statement UI elements being processed. */
|
|
||||||
@Nullable Seq<StatementElem> elements;
|
|
||||||
|
|
||||||
public LAssembler(){
|
public LAssembler(){
|
||||||
//add default constants
|
//add default constants
|
||||||
@@ -26,35 +23,42 @@ public class LAssembler{
|
|||||||
public static LAssembler assemble(Seq<StatementElem> seq){
|
public static LAssembler assemble(Seq<StatementElem> seq){
|
||||||
LAssembler out = new LAssembler();
|
LAssembler out = new LAssembler();
|
||||||
|
|
||||||
out.elements = seq;
|
seq.each(s -> s.st.saveUI());
|
||||||
out.instructions = seq.map(s -> s.st.build(out)).toArray(LInstruction.class);
|
out.instructions = seq.map(s -> s.st.build(out)).toArray(LInstruction.class);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toJson(Seq<StatementElem> seq){
|
||||||
|
seq.each(s -> s.st.saveUI());
|
||||||
|
LStatement[] statements = seq.map(s -> s.st).toArray(LStatement.class);
|
||||||
|
|
||||||
|
return JsonIO.write(statements);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO this is awful and confusing
|
//TODO this is awful and confusing
|
||||||
public static LAssembler fromJson(String json){
|
public static LAssembler fromJson(String json){
|
||||||
LAssembler asm = new LAssembler();
|
LAssembler asm = new LAssembler();
|
||||||
|
|
||||||
LStatement[] statements = JsonIO.read(LStatement[].class, json);
|
LStatement[] statements = JsonIO.read(LStatement[].class, json);
|
||||||
for(LStatement s : statements){
|
for(LStatement s : statements){
|
||||||
s.afterLoad(asm);
|
s.setupUI();
|
||||||
}
|
}
|
||||||
asm.instructions = Seq.with(statements).map(l -> l.build(asm)).toArray(LInstruction.class);
|
asm.instructions = Seq.with(statements).map(l -> l.build(asm)).toArray(LInstruction.class);
|
||||||
|
|
||||||
return asm;
|
return asm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toJson(){
|
|
||||||
Seq<LStatement> states = elements.map(s -> s.st);
|
|
||||||
states.each(s -> s.beforeSave(this));
|
|
||||||
return JsonIO.write(states.toArray(LStatement.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return a variable ID by name.
|
/** @return a variable ID by name.
|
||||||
* This may be a constant variable referring to a number or object. */
|
* This may be a constant variable referring to a number or object. */
|
||||||
public int var(String symbol){
|
public int var(String symbol){
|
||||||
symbol = symbol.trim();
|
symbol = symbol.trim();
|
||||||
|
|
||||||
|
//string case
|
||||||
|
if(symbol.startsWith("\"") && symbol.endsWith("\"")){
|
||||||
|
return putConst("___" + symbol, symbol.substring(1, symbol.length() - 1)).id;
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
double value = Double.parseDouble(symbol);
|
double value = Double.parseDouble(symbol);
|
||||||
//this creates a hidden const variable with the specified value
|
//this creates a hidden const variable with the specified value
|
||||||
@@ -66,7 +70,7 @@ public class LAssembler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Adds a constant value by name. */
|
/** Adds a constant value by name. */
|
||||||
private BVar putConst(String name, Object value){
|
BVar putConst(String name, Object value){
|
||||||
BVar var = putVar(name);
|
BVar var = putVar(name);
|
||||||
var.constant = true;
|
var.constant = true;
|
||||||
var.value = value;
|
var.value = value;
|
||||||
@@ -74,7 +78,7 @@ public class LAssembler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Registers a variable name mapping. */
|
/** Registers a variable name mapping. */
|
||||||
private BVar putVar(String name){
|
BVar putVar(String name){
|
||||||
if(vars.containsKey(name)){
|
if(vars.containsKey(name)){
|
||||||
return vars.get(name);
|
return vars.get(name);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -35,11 +35,8 @@ public class LCanvas extends Table{
|
|||||||
|
|
||||||
pane(statements).grow().get().setClip(false);
|
pane(statements).grow().get().setClip(false);
|
||||||
|
|
||||||
|
add(new PrintStatement());
|
||||||
add(new AssignStatement());
|
add(new AssignStatement());
|
||||||
add(new FetchBuildStatement());
|
|
||||||
add(new JumpStatement());
|
|
||||||
add(new ToggleStatement());
|
|
||||||
add(new OpStatement());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawGrid(){
|
private void drawGrid(){
|
||||||
@@ -73,7 +70,7 @@ public class LCanvas extends Table{
|
|||||||
}
|
}
|
||||||
|
|
||||||
String save(){
|
String save(){
|
||||||
return LAssembler.assemble(statements.getChildren().as()).toJson();
|
return LAssembler.toJson(statements.getChildren().as());
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(String json){
|
void load(String json){
|
||||||
@@ -83,11 +80,8 @@ public class LCanvas extends Table{
|
|||||||
add(st);
|
add(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
LAssembler asm = new LAssembler();
|
|
||||||
asm.elements = this.statements.getChildren().as();
|
|
||||||
|
|
||||||
for(LStatement st : statements){
|
for(LStatement st : statements){
|
||||||
st.afterLoad(asm);
|
st.setupUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.statements.layout();
|
this.statements.layout();
|
||||||
@@ -197,6 +191,7 @@ public class LCanvas extends Table{
|
|||||||
|
|
||||||
public StatementElem(LStatement st){
|
public StatementElem(LStatement st){
|
||||||
this.st = st;
|
this.st = st;
|
||||||
|
st.elem = this;
|
||||||
|
|
||||||
background(Tex.whitePane);
|
background(Tex.whitePane);
|
||||||
setColor(st.category().color);
|
setColor(st.category().color);
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package mindustry.logic;
|
package mindustry.logic;
|
||||||
|
|
||||||
|
import arc.func.*;
|
||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
|
import arc.util.*;
|
||||||
import mindustry.ui.dialogs.*;
|
import mindustry.ui.dialogs.*;
|
||||||
|
|
||||||
public class LDialog extends BaseDialog{
|
public class LDialog extends BaseDialog{
|
||||||
mindustry.logic.LCanvas canvas;
|
LCanvas canvas;
|
||||||
|
Cons<String> consumer = s -> Log.info(s);
|
||||||
|
|
||||||
public LDialog(){
|
public LDialog(){
|
||||||
super("logic");
|
super("logic");
|
||||||
@@ -17,5 +20,16 @@ public class LDialog extends BaseDialog{
|
|||||||
t.bottom();
|
t.bottom();
|
||||||
t.add(buttons);
|
t.add(buttons);
|
||||||
})).grow();
|
})).grow();
|
||||||
|
|
||||||
|
hidden(() -> {
|
||||||
|
consumer.get(canvas.save());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(String code, Cons<String> consumer){
|
||||||
|
canvas.load(code);
|
||||||
|
this.consumer = consumer;
|
||||||
|
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mindustry.logic;
|
package mindustry.logic;
|
||||||
|
|
||||||
import arc.util.ArcAnnotate.*;
|
import arc.util.ArcAnnotate.*;
|
||||||
|
import arc.util.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
|
||||||
@@ -11,6 +12,10 @@ public class LExecutor{
|
|||||||
//values of all the variables
|
//values of all the variables
|
||||||
Var[] vars;
|
Var[] vars;
|
||||||
|
|
||||||
|
public boolean initialized(){
|
||||||
|
return instructions != null && vars != null && instructions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Runs all the instructions at once. Debugging only. */
|
/** Runs all the instructions at once. Debugging only. */
|
||||||
public void runAll(){
|
public void runAll(){
|
||||||
counter = 0;
|
counter = 0;
|
||||||
@@ -20,7 +25,9 @@ public class LExecutor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load(LAssembler builder){
|
public void load(Object context, LAssembler builder){
|
||||||
|
builder.putConst("this", context);
|
||||||
|
|
||||||
vars = new Var[builder.vars.size];
|
vars = new Var[builder.vars.size];
|
||||||
instructions = builder.instructions;
|
instructions = builder.instructions;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
@@ -58,6 +65,11 @@ public class LExecutor{
|
|||||||
return v.isobj ? 0 : v.numval;
|
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){
|
int numi(int index){
|
||||||
return (int)num(index);
|
return (int)num(index);
|
||||||
}
|
}
|
||||||
@@ -101,6 +113,8 @@ public class LExecutor{
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToggleI(){}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
Building b = exec.building(target);
|
Building b = exec.building(target);
|
||||||
@@ -125,6 +139,8 @@ public class LExecutor{
|
|||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssignI(){}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
Var v = exec.vars[to];
|
Var v = exec.vars[to];
|
||||||
@@ -144,7 +160,7 @@ public class LExecutor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class BinaryOpI implements LInstruction{
|
public static class BinaryOpI implements LInstruction{
|
||||||
public mindustry.logic.BinaryOp op;
|
public BinaryOp op;
|
||||||
public int a, b, dest;
|
public int a, b, dest;
|
||||||
|
|
||||||
public BinaryOpI(BinaryOp op, int a, int b, int dest){
|
public BinaryOpI(BinaryOp op, int a, int b, int dest){
|
||||||
@@ -154,6 +170,8 @@ public class LExecutor{
|
|||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinaryOpI(){}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
exec.setnum(dest, op.function.get(exec.num(a), exec.num(b)));
|
exec.setnum(dest, op.function.get(exec.num(a), exec.num(b)));
|
||||||
@@ -168,6 +186,21 @@ public class LExecutor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PrintI implements LInstruction{
|
||||||
|
public int value;
|
||||||
|
|
||||||
|
public PrintI(int value){
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintI(){}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(LExecutor exec){
|
||||||
|
Log.info(exec.str(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class JumpI implements LInstruction{
|
public static class JumpI implements LInstruction{
|
||||||
public int cond, to;
|
public int cond, to;
|
||||||
|
|
||||||
@@ -176,6 +209,8 @@ public class LExecutor{
|
|||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JumpI(){}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
if(to != -1 && exec.bool(cond)){
|
if(to != -1 && exec.bool(cond)){
|
||||||
@@ -194,6 +229,8 @@ public class LExecutor{
|
|||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FetchBuildI(){}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
exec.setobj(dest, Vars.world.build(exec.numi(x), exec.numi(y)));
|
exec.setobj(dest, Vars.world.build(exec.numi(x), exec.numi(y)));
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
package mindustry.logic;
|
package mindustry.logic;
|
||||||
|
|
||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
|
import arc.util.ArcAnnotate.*;
|
||||||
|
import mindustry.logic.LCanvas.*;
|
||||||
|
import mindustry.logic.LExecutor.*;
|
||||||
|
|
||||||
/** A statement is an intermediate representation of an instruction, to be used in UI. */
|
/** A statement is an intermediate representation of an instruction, to be used in UI. */
|
||||||
public abstract class LStatement{
|
public abstract class LStatement{
|
||||||
|
public transient @Nullable StatementElem elem;
|
||||||
|
|
||||||
public abstract void build(Table table);
|
public abstract void build(Table table);
|
||||||
public abstract LCategory category();
|
public abstract LCategory category();
|
||||||
public abstract LExecutor.LInstruction build(LAssembler builder);
|
public abstract LInstruction build(LAssembler builder);
|
||||||
|
|
||||||
public void afterLoad(LAssembler assembler){
|
public void setupUI(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beforeSave(LAssembler assembler){
|
public void saveUI(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,8 +115,29 @@ public class LStatements{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PrintStatement extends LStatement{
|
||||||
|
public String value = "\"frog\"";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(Table table){
|
||||||
|
table.field(value, Styles.nodeField, str -> value = str)
|
||||||
|
.size(100f, 40f).pad(2f).color(table.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LInstruction build(LAssembler builder){
|
||||||
|
return new PrintI(builder.var(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LCategory category(){
|
||||||
|
return LCategory.control;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class JumpStatement extends LStatement{
|
public static class JumpStatement extends LStatement{
|
||||||
public transient StatementElem dest;
|
public transient StatementElem dest;
|
||||||
|
|
||||||
public int destIndex;
|
public int destIndex;
|
||||||
public String condition = "true";
|
public String condition = "true";
|
||||||
|
|
||||||
@@ -131,20 +152,21 @@ public class LStatements{
|
|||||||
|
|
||||||
//elements need separate conversion logic
|
//elements need separate conversion logic
|
||||||
@Override
|
@Override
|
||||||
public void afterLoad(LAssembler assembler){
|
public void setupUI(){
|
||||||
if(assembler.elements != null){
|
if(elem != null){
|
||||||
dest = assembler.elements.get(destIndex);
|
dest = (StatementElem)elem.parent.getChildren().get(destIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeSave(LAssembler assembler){
|
public void saveUI(){
|
||||||
destIndex = dest == null ? -1 : dest.parent.getChildren().indexOf(dest);
|
if(elem != null){
|
||||||
|
destIndex = dest == null ? -1 : dest.parent.getChildren().indexOf(dest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LInstruction build(LAssembler builder){
|
public LInstruction build(LAssembler builder){
|
||||||
beforeSave(builder);
|
|
||||||
return new JumpI(builder.var(condition),destIndex);
|
return new JumpI(builder.var(condition),destIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package mindustry.world.blocks.logic;
|
package mindustry.world.blocks.logic;
|
||||||
|
|
||||||
|
import arc.util.io.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
import mindustry.logic.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
|
|
||||||
public class LogicProcessor extends Block{
|
public class LogicProcessor extends Block{
|
||||||
@@ -10,19 +12,46 @@ public class LogicProcessor extends Block{
|
|||||||
super(name);
|
super(name);
|
||||||
update = true;
|
update = true;
|
||||||
configurable = true;
|
configurable = true;
|
||||||
|
|
||||||
|
config(String.class, (LogicEntity entity, String code) -> {
|
||||||
|
if(code != null){
|
||||||
|
entity.code = code;
|
||||||
|
entity.executor.load(entity, LAssembler.fromJson(code));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LogicEntity extends Building{
|
public class LogicEntity extends Building{
|
||||||
|
/** logic "source code" as list of json statements */
|
||||||
|
String code = "[]";
|
||||||
|
LExecutor executor = new LExecutor();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTile(){
|
public void updateTile(){
|
||||||
|
if(executor.initialized()){
|
||||||
|
executor.runAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean configTapped(){
|
public boolean configTapped(){
|
||||||
Vars.ui.logic.show();
|
Vars.ui.logic.show(code, this::configure);
|
||||||
return false;
|
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();
|
||||||
|
executor.load(this, LAssembler.fromJson(code));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user