This commit is contained in:
Anuken
2020-08-07 17:50:54 -04:00
parent 33fdea7b7d
commit 090e0f35dc
7 changed files with 234 additions and 92 deletions

View File

@@ -0,0 +1,99 @@
package mindustry.logic;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import mindustry.io.*;
import mindustry.logic.LCanvas.*;
import mindustry.logic.LExecutor.*;
/** "Compiles" a sequence of statements into instructions. */
public class LAssembler{
private transient int lastVar;
/** Maps names to variable IDs. */
ObjectMap<String, BVar> vars = new ObjectMap<>();
/** All instructions to be executed. */
LInstruction[] instructions;
/** Statement UI elements being processed. */
@Nullable Seq<StatementElem> elements;
public LAssembler(){
//add default constants
putConst("false", 0);
putConst("true", 1);
putConst("null", null);
}
public static LAssembler assemble(Seq<StatementElem> seq){
LAssembler out = new LAssembler();
out.elements = seq;
out.instructions = seq.map(s -> s.st.build(out)).toArray(LInstruction.class);
return out;
}
//TODO this is awful and confusing
public static LAssembler fromJson(String json){
LAssembler asm = new LAssembler();
LStatement[] statements = JsonIO.read(LStatement[].class, json);
for(LStatement s : statements){
s.afterLoad(asm);
}
asm.instructions = Seq.with(statements).map(l -> l.build(asm)).toArray(LInstruction.class);
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.
* This may be a constant variable referring to a number or object. */
public int var(String symbol){
symbol = symbol.trim();
try{
double value = Double.parseDouble(symbol);
//this creates a hidden const variable with the specified value
String key = "___" + value;
return putConst(key, value).id;
}catch(NumberFormatException e){
return putVar(symbol).id;
}
}
/** Adds a constant value by name. */
private BVar putConst(String name, Object value){
BVar var = putVar(name);
var.constant = true;
var.value = value;
return var;
}
/** Registers a variable name mapping. */
private BVar putVar(String name){
if(vars.containsKey(name)){
return vars.get(name);
}else{
BVar var = new BVar(lastVar++);
vars.put(name, var);
return var;
}
}
/** A saved variable. */
public static class BVar{
public int id;
public boolean constant;
public Object value;
public BVar(int id){
this.id = id;
}
BVar(){}
}
}

View File

@@ -1,49 +0,0 @@
package mindustry.logic;
import arc.struct.*;
/** "Compiles" a sequence of statements into instructions. */
public class LBuilder{
private int lastVar;
/** Maps names to variable IDs. */
private ObjectIntMap<String> vars = new ObjectIntMap<>();
/** Maps variable IDs to their constant value. */
private IntMap<Object> constants = new IntMap<>();
public LBuilder(){
//add default constant variables
putConst("false", 0);
putConst("true", 1);
}
/** @return a variable ID by name.
* This may be a constant variable referring to a number or object. */
public int var(String symbol){
try{
double value = Double.parseDouble(symbol);
//this creates a hidden const variable with the specified value
String key = "___" + value;
return putConst(key, value);
}catch(NumberFormatException e){
return putVar(symbol);
}
}
/** Adds a constant value by name. */
private int putConst(String name, double value){
int id = putVar(name);
constants.put(id, value);
return id;
}
/** Registers a variable name mapping. */
private int putVar(String name){
if(vars.containsKey(name)){
return vars.get(name);
}else{
int id = lastVar++;
vars.put(name, id);
return id;
}
}
}

View File

@@ -13,13 +13,16 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.logic.LStatements.*; import mindustry.logic.LStatements.*;
import mindustry.ui.*; import mindustry.ui.*;
public class LCanvas extends Table{ public class LCanvas extends Table{
private static final Color backgroundCol = Pal.darkMetal.cpy().mul(0.1f), gridCol = Pal.darkMetal.cpy().mul(0.5f); private static final Color backgroundCol = Pal.darkMetal.cpy().mul(0.1f), gridCol = Pal.darkMetal.cpy().mul(0.5f);
private static Seq<Runnable> postDraw = new Seq<>();
private Vec2 offset = new Vec2(); private Vec2 offset = new Vec2();
private DragLayout statements; private DragLayout statements;
@@ -32,11 +35,11 @@ public class LCanvas extends Table{
pane(statements).grow().get().setClip(false); pane(statements).grow().get().setClip(false);
add(new LStatements.AssignStatement()); add(new AssignStatement());
add(new FetchBuildStatement()); add(new FetchBuildStatement());
add(new JumpStatement()); add(new JumpStatement());
add(new ToggleStatement()); add(new ToggleStatement());
add(new LStatements.OpStatement()); add(new OpStatement());
} }
private void drawGrid(){ private void drawGrid(){
@@ -66,9 +69,35 @@ public class LCanvas extends Table{
} }
void add(LStatement statement){ void add(LStatement statement){
StatementElem e = new StatementElem(statement); statements.addChild(new StatementElem(statement));
}
statements.addChild(e); String save(){
return LAssembler.assemble(statements.getChildren().as()).toJson();
}
void load(String json){
statements.clearChildren();
LStatement[] statements = JsonIO.read(LStatement[].class, json);
for(LStatement st : statements){
add(st);
}
LAssembler asm = new LAssembler();
asm.elements = this.statements.getChildren().as();
for(LStatement st : statements){
st.afterLoad(asm);
}
this.statements.layout();
}
@Override
public void draw(){
postDraw.clear();
super.draw();
postDraw.each(Runnable::run);
} }
public class DragLayout extends WidgetGroup{ public class DragLayout extends WidgetGroup{
@@ -119,6 +148,7 @@ public class LCanvas extends Table{
seq.get(i).y -= shiftAmount; seq.get(i).y -= shiftAmount;
} }
} }
} }
@Override @Override
@@ -246,20 +276,22 @@ public class LCanvas extends Table{
} }
public static class JumpButton extends ImageButton{ public static class JumpButton extends ImageButton{
StatementElem to; @NonNull Prov<StatementElem> to;
boolean selecting; boolean selecting;
float mx, my; float mx, my;
public JumpButton(Color color, Cons<StatementElem> setter){ public JumpButton(Color color, @NonNull Prov<StatementElem> getter, Cons<StatementElem> setter){
super(Tex.logicNode, Styles.colori); super(Tex.logicNode, Styles.colori);
to = getter;
getStyle().imageUpColor = color; getStyle().imageUpColor = color;
addListener(new InputListener(){ addListener(new InputListener(){
@Override @Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode code){ public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode code){
selecting = true; selecting = true;
setter.get(to = null); setter.get(null);
mx = x; mx = x;
my = y; my = y;
return true; return true;
@@ -277,18 +309,17 @@ public class LCanvas extends Table{
StatementElem elem = hovered(); StatementElem elem = hovered();
if(elem != null && !isDescendantOf(elem)){ if(elem != null && !isDescendantOf(elem)){
to = elem; setter.get(elem);
}else{ }else{
to = null; setter.get(null);
} }
setter.get(to);
selecting = false; selecting = false;
} }
}); });
update(() -> { update(() -> {
if(to != null && to.parent == null){ if(to.get() != null && to.get().parent == null){
setter.get(to = null); setter.get(null);
} }
}); });
} }
@@ -296,26 +327,39 @@ public class LCanvas extends Table{
@Override @Override
public void draw(){ public void draw(){
super.draw(); super.draw();
Element hover = to == null && selecting ? hovered() : to;
float tx = 0, ty = 0;
boolean draw = false;
if(hover != null){
tx = hover.getX(Align.right) + hover.translation.x;
ty = hover.getY(Align.right) + hover.translation.y;
draw = true;
}else if(selecting){
tx = x + mx;
ty = y + my;
draw = true;
}
if(draw){
drawCurve(x + width/2f, y + height/2f, tx, ty, color);
float s = width; postDraw.add(() -> {
Tex.logicNode.draw(tx + s*0.75f, ty - s/2f, -s, s); Element hover = to.get() == null && selecting ? hovered() : to.get();
} float tx = 0, ty = 0;
boolean draw = false;
//capture coordinates for use in lambda
float rx = x, ry = y;
Element p = parent;
while(p != null){
rx += p.x;
ry += p.y;
p = p.parent;
}
if(hover != null){
tx = hover.getX(Align.right) + hover.translation.x;
ty = hover.getY(Align.right) + hover.translation.y;
draw = true;
}else if(selecting){
tx = rx + mx;
ty = ry + my;
draw = true;
}
if(draw){
drawCurve(rx + width/2f, ry + height/2f, tx, ty, color);
float s = width;
Tex.logicNode.draw(tx + s*0.75f, ty - s/2f, -s, s);
}
});
} }
StatementElem hovered(){ StatementElem hovered(){

View File

@@ -20,6 +20,29 @@ public class LExecutor{
} }
} }
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;
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;
}
}
});
}
//region utility
@Nullable Building building(int index){ @Nullable Building building(int index){
Object o = vars[index].objval; Object o = vars[index].objval;
return o == null && o instanceof Building ? (Building)o : null; return o == null && o instanceof Building ? (Building)o : null;
@@ -54,6 +77,8 @@ public class LExecutor{
v.isobj = true; v.isobj = true;
} }
//endregion
static class Var{ static class Var{
boolean isobj, constant; boolean isobj, constant;

View File

@@ -7,7 +7,15 @@ public abstract class LStatement{
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(LBuilder builder); public abstract LExecutor.LInstruction build(LAssembler builder);
public void afterLoad(LAssembler assembler){
}
public void beforeSave(LAssembler assembler){
}
public String name(){ public String name(){
return getClass().getSimpleName().replace("Statement", ""); return getClass().getSimpleName().replace("Statement", "");

View File

@@ -30,7 +30,7 @@ public class LStatements{
} }
@Override @Override
public LExecutor.LInstruction build(LBuilder builder){ public LInstruction build(LAssembler builder){
//TODO internal consts need to start with ___ and not be assignable to //TODO internal consts need to start with ___ and not be assignable to
return new LExecutor.AssignI(builder.var(from), builder.var(to)); return new LExecutor.AssignI(builder.var(from), builder.var(to));
} }
@@ -57,13 +57,13 @@ public class LStatements{
} }
@Override @Override
public LExecutor.LInstruction build(LBuilder builder){ public LExecutor.LInstruction build(LAssembler builder){
return new LExecutor.ToggleI(builder.var(target), builder.var(value)); return new LExecutor.ToggleI(builder.var(target), builder.var(value));
} }
} }
public static class OpStatement extends LStatement{ public static class OpStatement extends LStatement{
public mindustry.logic.BinaryOp op = mindustry.logic.BinaryOp.add; public BinaryOp op = BinaryOp.add;
public String a = "a", b = "b", dest = "result"; public String a = "a", b = "b", dest = "result";
@Override @Override
@@ -79,7 +79,7 @@ public class LStatements{
TextButton[] button = {null}; TextButton[] button = {null};
button[0] = table.button(op.symbol, Styles.cleart, () -> { button[0] = table.button(op.symbol, Styles.cleart, () -> {
op = mindustry.logic.BinaryOp.all[(op.ordinal() + 1) % BinaryOp.all.length]; op = BinaryOp.all[(op.ordinal() + 1) % BinaryOp.all.length];
button[0].setText(op.symbol); button[0].setText(op.symbol);
}).size(50f, 30f).pad(4f).get(); }).size(50f, 30f).pad(4f).get();
@@ -88,7 +88,7 @@ public class LStatements{
} }
@Override @Override
public LInstruction build(LBuilder builder){ public LInstruction build(LAssembler builder){
return new BinaryOpI(op,builder.var(a), builder.var(b), builder.var(dest)); return new BinaryOpI(op,builder.var(a), builder.var(b), builder.var(dest));
} }
@@ -105,7 +105,7 @@ public class LStatements{
} }
@Override @Override
public LInstruction build(LBuilder builder){ public LInstruction build(LAssembler builder){
return new EndI(); return new EndI();
} }
@@ -116,8 +116,9 @@ public class LStatements{
} }
public static class JumpStatement extends LStatement{ public static class JumpStatement extends LStatement{
public StatementElem dest; public transient StatementElem dest;
public String condition = " true"; public int destIndex;
public String condition = "true";
@Override @Override
public void build(Table table){ public void build(Table table){
@@ -125,12 +126,26 @@ public class LStatements{
table.field(condition, Styles.nodeField, str -> condition = str) table.field(condition, Styles.nodeField, str -> condition = str)
.size(100f, 40f).pad(2f).color(table.color); .size(100f, 40f).pad(2f).color(table.color);
table.add().growX(); table.add().growX();
table.add(new JumpButton(Color.white, s -> dest = s)).size(30).right().padRight(-17); table.add(new JumpButton(Color.white, () -> dest, s -> dest = s)).size(30).right().padRight(-17);
}
//elements need separate conversion logic
@Override
public void afterLoad(LAssembler assembler){
if(assembler.elements != null){
dest = assembler.elements.get(destIndex);
}
} }
@Override @Override
public LInstruction build(LBuilder builder){ public void beforeSave(LAssembler assembler){
return new JumpI(builder.var(condition), dest == null ? -1 : dest.parent.getChildren().indexOf(dest)); destIndex = dest == null ? -1 : dest.parent.getChildren().indexOf(dest);
}
@Override
public LInstruction build(LAssembler builder){
beforeSave(builder);
return new JumpI(builder.var(condition),destIndex);
} }
@Override @Override
@@ -159,7 +174,7 @@ public class LStatements{
} }
@Override @Override
public LExecutor.LInstruction build(LBuilder builder){ public LInstruction build(LAssembler builder){
return new FetchBuildI(builder.var(dest), builder.var(x), builder.var(y)); return new FetchBuildI(builder.var(dest), builder.var(x), builder.var(y));
} }

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=c18b1b1bff478e44baabebe1a944b2fb4bd37bad archash=746b415d20da18753c6f477361979621d4e78ac2