mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-02-10 10:47:13 +07:00
aa
This commit is contained in:
parent
33fdea7b7d
commit
090e0f35dc
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.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.io.*;
|
||||
import mindustry.logic.LStatements.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
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 Seq<Runnable> postDraw = new Seq<>();
|
||||
private Vec2 offset = new Vec2();
|
||||
|
||||
private DragLayout statements;
|
||||
@ -32,11 +35,11 @@ public class LCanvas extends Table{
|
||||
|
||||
pane(statements).grow().get().setClip(false);
|
||||
|
||||
add(new LStatements.AssignStatement());
|
||||
add(new AssignStatement());
|
||||
add(new FetchBuildStatement());
|
||||
add(new JumpStatement());
|
||||
add(new ToggleStatement());
|
||||
add(new LStatements.OpStatement());
|
||||
add(new OpStatement());
|
||||
}
|
||||
|
||||
private void drawGrid(){
|
||||
@ -66,9 +69,35 @@ public class LCanvas extends Table{
|
||||
}
|
||||
|
||||
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{
|
||||
@ -119,6 +148,7 @@ public class LCanvas extends Table{
|
||||
seq.get(i).y -= shiftAmount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -246,20 +276,22 @@ public class LCanvas extends Table{
|
||||
}
|
||||
|
||||
public static class JumpButton extends ImageButton{
|
||||
StatementElem to;
|
||||
@NonNull Prov<StatementElem> to;
|
||||
boolean selecting;
|
||||
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);
|
||||
|
||||
to = getter;
|
||||
|
||||
getStyle().imageUpColor = color;
|
||||
|
||||
addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode code){
|
||||
selecting = true;
|
||||
setter.get(to = null);
|
||||
setter.get(null);
|
||||
mx = x;
|
||||
my = y;
|
||||
return true;
|
||||
@ -277,18 +309,17 @@ public class LCanvas extends Table{
|
||||
StatementElem elem = hovered();
|
||||
|
||||
if(elem != null && !isDescendantOf(elem)){
|
||||
to = elem;
|
||||
setter.get(elem);
|
||||
}else{
|
||||
to = null;
|
||||
setter.get(null);
|
||||
}
|
||||
setter.get(to);
|
||||
selecting = false;
|
||||
}
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
if(to != null && to.parent == null){
|
||||
setter.get(to = null);
|
||||
if(to.get() != null && to.get().parent == null){
|
||||
setter.get(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -296,26 +327,39 @@ public class LCanvas extends Table{
|
||||
@Override
|
||||
public void 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;
|
||||
Tex.logicNode.draw(tx + s*0.75f, ty - s/2f, -s, s);
|
||||
}
|
||||
postDraw.add(() -> {
|
||||
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(){
|
||||
|
@ -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){
|
||||
Object o = vars[index].objval;
|
||||
return o == null && o instanceof Building ? (Building)o : null;
|
||||
@ -54,6 +77,8 @@ public class LExecutor{
|
||||
v.isobj = true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
static class Var{
|
||||
boolean isobj, constant;
|
||||
|
||||
|
@ -7,7 +7,15 @@ public abstract class LStatement{
|
||||
|
||||
public abstract void build(Table table);
|
||||
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(){
|
||||
return getClass().getSimpleName().replace("Statement", "");
|
||||
|
@ -30,7 +30,7 @@ public class LStatements{
|
||||
}
|
||||
|
||||
@Override
|
||||
public LExecutor.LInstruction build(LBuilder builder){
|
||||
public LInstruction build(LAssembler builder){
|
||||
//TODO internal consts need to start with ___ and not be assignable to
|
||||
return new LExecutor.AssignI(builder.var(from), builder.var(to));
|
||||
}
|
||||
@ -57,13 +57,13 @@ public class LStatements{
|
||||
}
|
||||
|
||||
@Override
|
||||
public LExecutor.LInstruction build(LBuilder builder){
|
||||
public LExecutor.LInstruction build(LAssembler builder){
|
||||
return new LExecutor.ToggleI(builder.var(target), builder.var(value));
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
@Override
|
||||
@ -79,7 +79,7 @@ public class LStatements{
|
||||
|
||||
TextButton[] button = {null};
|
||||
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);
|
||||
}).size(50f, 30f).pad(4f).get();
|
||||
|
||||
@ -88,7 +88,7 @@ public class LStatements{
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LBuilder builder){
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new BinaryOpI(op,builder.var(a), builder.var(b), builder.var(dest));
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ public class LStatements{
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LBuilder builder){
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new EndI();
|
||||
}
|
||||
|
||||
@ -116,8 +116,9 @@ public class LStatements{
|
||||
}
|
||||
|
||||
public static class JumpStatement extends LStatement{
|
||||
public StatementElem dest;
|
||||
public String condition = " true";
|
||||
public transient StatementElem dest;
|
||||
public int destIndex;
|
||||
public String condition = "true";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
@ -125,12 +126,26 @@ public class LStatements{
|
||||
table.field(condition, Styles.nodeField, str -> condition = str)
|
||||
.size(100f, 40f).pad(2f).color(table.color);
|
||||
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
|
||||
public LInstruction build(LBuilder builder){
|
||||
return new JumpI(builder.var(condition), dest == null ? -1 : dest.parent.getChildren().indexOf(dest));
|
||||
public void beforeSave(LAssembler assembler){
|
||||
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
|
||||
@ -159,7 +174,7 @@ public class LStatements{
|
||||
}
|
||||
|
||||
@Override
|
||||
public LExecutor.LInstruction build(LBuilder builder){
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new FetchBuildI(builder.var(dest), builder.var(x), builder.var(y));
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=c18b1b1bff478e44baabebe1a944b2fb4bd37bad
|
||||
archash=746b415d20da18753c6f477361979621d4e78ac2
|
||||
|
Loading…
Reference in New Issue
Block a user