aa
This commit is contained in:
99
core/src/mindustry/logic/LAssembler.java
Normal file
99
core/src/mindustry/logic/LAssembler.java
Normal 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(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(){
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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", "");
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user