From 38c0284bbe8bd888933e12326961bb96e802f02b Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 8 Feb 2022 12:18:48 -0500 Subject: [PATCH] Functional world processors --- .../sprites/blocks/logic/world-processor.png | Bin 0 -> 586 bytes core/assets/icons/icons.properties | 1 + core/assets/logicids.dat | Bin 4015 -> 4032 bytes core/src/mindustry/content/Blocks.java | 11 ++ core/src/mindustry/core/Logic.java | 2 + core/src/mindustry/core/World.java | 2 +- core/src/mindustry/graphics/Pal.java | 1 + core/src/mindustry/logic/GlobalConstants.java | 36 +++++- core/src/mindustry/logic/LAssembler.java | 25 ++-- core/src/mindustry/logic/LCanvas.java | 4 +- core/src/mindustry/logic/LExecutor.java | 108 ++++++++++++++---- core/src/mindustry/logic/LParser.java | 16 +-- core/src/mindustry/logic/LStatement.java | 13 ++- core/src/mindustry/logic/LStatements.java | 104 +++++++++++++++++ core/src/mindustry/logic/LogicDialog.java | 7 +- core/src/mindustry/logic/TileLayer.java | 10 ++ core/src/mindustry/world/Block.java | 2 + core/src/mindustry/world/Tile.java | 2 +- .../src/mindustry/world/blocks/Autotiler.java | 1 + .../world/blocks/logic/LogicBlock.java | 76 +++++++++--- gradle.properties | 2 +- 21 files changed, 363 insertions(+), 60 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/logic/world-processor.png create mode 100644 core/src/mindustry/logic/TileLayer.java diff --git a/core/assets-raw/sprites/blocks/logic/world-processor.png b/core/assets-raw/sprites/blocks/logic/world-processor.png new file mode 100644 index 0000000000000000000000000000000000000000..8b98451cabc7d8b863ee7a866767b5e9e2de0ae1 GIT binary patch literal 586 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U}Euf zaSVxQ-8y~07qg?lvHi9zxjI2EN-iD~Ul}azotl~RRr3;uV*Uh~9}G%2euylaY;r4F zD>_!tU_wHdNLZ6V_lDE=QogOXy88Csox1(A=kA;HSf+TLc(BgvG37 zd{7taK5zTQ4AW*YFG2IaF3SaG3b8lD<#K9z|4)hYJ=27=cp6-`ATm{?@>O#w{G&ua`?Cxun zIKO)~#}9>d>eYS+ML0_1^BZ}c&aQs-;7GFKnV(*K0UYruK?*M-zOXB2i_Vz#{H?|W zx7CtQp08;NDQq}DS*1bbqeRC7jz7yQ8JFlx7Uw_NynthgLyOu&zPT^1PWyFB$653A zgPH}8p8a$XwVjg5+w!7IxE3Bgn|xFCU3bs>$glScE9=x4lDYHp-5za!WG64msmf$?2)M!h+!s!*yYkRne@slo=Qp7(8A5T-G@yGywn=MFB4W literal 0 HcmV?d00001 diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 87f7fec7cc..d42e4a4b87 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -530,3 +530,4 @@ 63173=beam-link|block-beam-link-ui 63172=drone-center|block-drone-center-ui 63171=effect-drone|unit-effect-drone-ui +63170=world-processor|block-world-processor-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index 81f0eb070c406074e63eae1f39025e460e852d12..7110c0986cdb4c30a8f4e84c339e879e21298c27 100644 GIT binary patch delta 32 ocmZ24e?Xpz;pRrBXFUA;<@rT9DY^wk`N^rp#rd0`@tkA=0K`2Ee*gdg delta 16 YcmX>gzh0h+;l@U$XFQvK@*HOZ05^aJt^fc4 diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index e6752d0b5b..f52a2b4503 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -149,6 +149,7 @@ public class Blocks{ //logic message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank, + worldProcessor, //campaign //TODO launch pad on erekir, 5x5, uses nuclear(?) fuel @@ -3778,6 +3779,16 @@ public class Blocks{ size = 6; }}; + worldProcessor = new LogicBlock("world-processor"){{ + //currently incomplete, debugOnly for now + requirements(Category.logic, BuildVisibility.debugOnly, with()); + + instructionsPerTick = 2; + forceDark = true; + privileged = true; + size = 1; + }}; + //endregion } } \ No newline at end of file diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index bf77ed5fc7..102635fbfd 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -402,6 +402,8 @@ public class Logic implements ApplicationListener{ } Time.update(); + constants.update(); + //weather is serverside if(!net.client() && !state.isEditor()){ updateWeather(); diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 69921a72ef..835d6d8360 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -530,7 +530,7 @@ public class World{ } Tile tile = world.tile(x, y); - if(tile != null && tile.block().solid && tile.block().fillsTile && !tile.block().synthetic()){ + if(tile != null && tile.isDarkened()){ dark = Math.max(dark, tile.data); } diff --git a/core/src/mindustry/graphics/Pal.java b/core/src/mindustry/graphics/Pal.java index c1bca3c7f7..73f8ccfe99 100644 --- a/core/src/mindustry/graphics/Pal.java +++ b/core/src/mindustry/graphics/Pal.java @@ -119,6 +119,7 @@ public class Pal{ logicOperations = Color.valueOf("877bad"), logicIo = Color.valueOf("a08a8a"), logicUnits = Color.valueOf("c7b59d"), + logicWorld = Color.valueOf("6b84d4"), berylShot = Color.valueOf("b1dd7e"), tungstenShot = Color.valueOf("768a9a"), diff --git a/core/src/mindustry/logic/GlobalConstants.java b/core/src/mindustry/logic/GlobalConstants.java index d86735f405..0bd4d85dc5 100644 --- a/core/src/mindustry/logic/GlobalConstants.java +++ b/core/src/mindustry/logic/GlobalConstants.java @@ -15,6 +15,8 @@ import mindustry.world.*; import java.io.*; +import static mindustry.Vars.*; + /** Stores global constants for logic processors. */ public class GlobalConstants{ public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3; @@ -22,6 +24,9 @@ public class GlobalConstants{ /** Global random state. */ public static final Rand rand = new Rand(); + //non-constants that depend on state + private static int varTime, varTick, varWave, varWaveTime; + private ObjectIntMap namesToIds = new ObjectIntMap<>(); private Seq vars = new Seq<>(Var.class); private UnlockableContent[][] logicIdToContent; @@ -34,6 +39,12 @@ public class GlobalConstants{ put("true", 1); put("null", null); + //time + varTime = put("@time", 0); + varTick = put("@tick", 0); + varWave = put("@waveNumber", 0); + varWaveTime = put("@waveTime", 0); + //special enums put("@ctrlProcessor", ctrlProcessor); @@ -51,9 +62,7 @@ public class GlobalConstants{ } for(Block block : Vars.content.blocks()){ - if(block.synthetic()){ - put("@" + block.name, block); - } + put("@" + block.name, block); } //used as a special value for any environmental solid block @@ -105,6 +114,18 @@ public class GlobalConstants{ } } + /** Updates global time and other state variables. */ + public void update(){ + //set up time; note that @time is now only updated once every invocation and directly based off of @tick. + //having time be based off of user system time was a very bad idea. + vars.items[varTime].numval = state.tick / 60.0 * 1000.0; + vars.items[varTick].numval = state.tick; + + //wave state + vars.items[varWave].numval = state.wave; + vars.items[varWaveTime].numval = state.wavetime / 60f; + } + /** @return a piece of content based on its logic ID. This is not equivalent to content ID. */ public @Nullable Content lookupContent(ContentType type, int id){ var arr = logicIdToContent[type.ordinal()]; @@ -127,8 +148,13 @@ public class GlobalConstants{ return vars.items[id]; } + /** Sets a global variable by an ID returned from put(). */ + public void set(int id, double value){ + get(id).numval = value; + } + /** Adds a constant value by name. */ - public Var put(String name, Object value){ + public int put(String name, Object value){ Var var = new Var(name); var.constant = true; if(value instanceof Number num){ @@ -141,6 +167,6 @@ public class GlobalConstants{ int index = vars.size; namesToIds.put(name, index); vars.add(var); - return var; + return index; } } diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index 5df928457d..4323f27402 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -22,20 +22,28 @@ public class LAssembler{ public LAssembler(){ //instruction counter putVar("@counter").value = 0; - //timestamp - putConst("@time", 0); //currently controlled unit putConst("@unit", null); //reference to self putConst("@this", null); - //global tick - putConst("@tick", 0); } + /** @deprecated use the one with the privileged parameter */ + @Deprecated public static LAssembler assemble(String data){ + return assemble(data, false); + } + + /** @deprecated use the one with the privileged parameter */ + @Deprecated + public static Seq read(String text){ + return read(text, false); + } + + public static LAssembler assemble(String data, boolean privileged){ LAssembler asm = new LAssembler(); - Seq st = read(data); + Seq st = read(data, privileged); asm.instructions = st.map(l -> l.build(asm)).filter(l -> l != null).toArray(LInstruction.class); return asm; @@ -51,8 +59,11 @@ public class LAssembler{ return out.toString(); } - public static Seq read(String data){ - return LParser.parse(data); + /** Parses a sequence of statements from a string. */ + public static Seq read(String text, boolean privileged){ + //don't waste time parsing null/empty text + if(text == null || text.isEmpty()) return new Seq<>(); + return new LParser(text, privileged).parse(); } /** @return a variable ID by name. diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java index 2537296566..3e39986cb7 100644 --- a/core/src/mindustry/logic/LCanvas.java +++ b/core/src/mindustry/logic/LCanvas.java @@ -27,10 +27,12 @@ public class LCanvas extends Table{ public DragLayout statements; public ScrollPane pane; public Group jumps; + StatementElem dragging; StatementElem hovered; float targetWidth; int jumpCount = 0; + boolean privileged; Seq tooltips = new Seq<>(); public LCanvas(){ @@ -146,7 +148,7 @@ public class LCanvas extends Table{ public void load(String asm){ jumps.clear(); - Seq statements = LAssembler.read(asm); + Seq statements = LAssembler.read(asm, privileged); statements.truncate(LExecutor.maxInstructions); this.statements.clearChildren(); for(LStatement st : statements){ diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 65e68cea42..d069c1d444 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -16,6 +16,7 @@ import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.environment.*; import mindustry.world.blocks.logic.*; import mindustry.world.blocks.logic.LogicDisplay.*; import mindustry.world.blocks.logic.MemoryBlock.*; @@ -31,10 +32,8 @@ public class LExecutor{ //special variables public static final int varCounter = 0, - varTime = 1, - varUnit = 2, - varThis = 3, - varTick = 4; + varUnit = 1, + varThis = 2; public static final int maxGraphicsBuffer = 256, @@ -43,6 +42,7 @@ public class LExecutor{ public LInstruction[] instructions = {}; public Var[] vars = {}; + public Var counter; public int[] binds; public LongSeq graphicsBuffer = new LongSeq(); @@ -50,32 +50,24 @@ public class LExecutor{ public Building[] links = {}; public IntSet linkIds = new IntSet(); public Team team = Team.derelict; + public boolean privileged = false; public boolean initialized(){ - return instructions != null && vars != null && instructions.length > 0; + return instructions.length > 0; } /** Runs a single instruction. */ public void runOnce(){ - //set up time; note that @time is now only updated once every invocation and directly based off of @tick. - //having time be based off of user system time was a very bad idea. - vars[varTime].numval = state.tick / 60.0 * 1000.0; - vars[varTick].numval = state.tick; - //reset to start - if(vars[varCounter].numval >= instructions.length || vars[varCounter].numval < 0){ - vars[varCounter].numval = 0; + if(counter.numval >= instructions.length || counter.numval < 0){ + counter.numval = 0; } - if(vars[varCounter].numval < instructions.length){ - instructions[(int)(vars[varCounter].numval++)].run(this); + if(counter.numval < instructions.length){ + instructions[(int)(counter.numval++)].run(this); } } - public void load(String data){ - load(LAssembler.assemble(data)); - } - /** Loads with a specified assembler. Resets all variables. */ public void load(LAssembler builder){ vars = new Var[builder.vars.size]; @@ -95,6 +87,8 @@ public class LExecutor{ dest.objval = var.value; } }); + + counter = vars[varCounter]; } //region utility @@ -560,7 +554,7 @@ public class LExecutor{ @Override public void run(LExecutor exec){ Object obj = exec.obj(target); - if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id)){ + if(obj instanceof Building b && (exec.privileged || (b.team == exec.team && exec.linkIds.contains(b.id)))){ if(type.isObj && exec.var(p1).isobj){ b.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4)); }else{ @@ -921,7 +915,7 @@ public class LExecutor{ //graphics on headless servers are useless. if(Vars.headless) return; - if(exec.building(target) instanceof LogicDisplayBuild d && d.team == exec.team){ + if(exec.building(target) instanceof LogicDisplayBuild d && (d.team == exec.team || exec.privileged)){ if(d.commands.size + exec.graphicsBuffer.size < maxDisplayBuffer){ for(int i = 0; i < exec.graphicsBuffer.size; i++){ d.commands.addLast(exec.graphicsBuffer.items[i]); @@ -1067,6 +1061,7 @@ public class LExecutor{ } } + //TODO lookup color instruction and inverse lookup public static class LookupI implements LInstruction{ public int dest; public int from; @@ -1087,6 +1082,79 @@ public class LExecutor{ } } + //endregion + //region privileged / world instructions + + public static class GetBlockI implements LInstruction{ + public int x, y; + public int dest; + public TileLayer layer = TileLayer.block; + + public GetBlockI(int x, int y, int dest, TileLayer layer){ + this.x = x; + this.y = y; + this.dest = dest; + this.layer = layer; + } + + public GetBlockI(){ + } + + @Override + public void run(LExecutor exec){ + Tile tile = world.tile(exec.numi(x), exec.numi(y)); + if(tile == null){ + exec.setobj(dest, null); + }else{ + exec.setobj(dest, switch(layer){ + case floor -> tile.floor(); + case ore -> tile.overlay(); + case block -> tile.block(); + case building -> tile.build; + }); + } + } + } + + public static class SetBlockI implements LInstruction{ + public int x, y; + public int block; + public int team, rotation; + public TileLayer layer = TileLayer.block; + + public SetBlockI(int x, int y, int block, int team, int rotation, TileLayer layer){ + this.x = x; + this.y = y; + this.block = block; + this.team = team; + this.rotation = rotation; + this.layer = layer; + } + + public SetBlockI(){ + } + + @Override + public void run(LExecutor exec){ + Tile tile = world.tile(exec.numi(x), exec.numi(y)); + if(tile != null && exec.obj(block) instanceof Block b){ + //TODO this can be quite laggy... + switch(layer){ + case ore -> { + if(b instanceof OverlayFloor o) tile.setOverlay(o); + } + case floor -> { + if(b instanceof Floor f) tile.setFloor(f); + } + case block -> { + Team t = exec.obj(team) instanceof Team steam ? steam : Team.derelict; + tile.setBlock(b, t, Mathf.clamp(exec.numi(rotation), 0, 3)); + } + //building case not allowed + } + } + } + } //endregion } diff --git a/core/src/mindustry/logic/LParser.java b/core/src/mindustry/logic/LParser.java index f8d3d37bfa..6f65e9981f 100644 --- a/core/src/mindustry/logic/LParser.java +++ b/core/src/mindustry/logic/LParser.java @@ -19,18 +19,13 @@ public class LParser{ Seq statements = new Seq<>(); char[] chars; int pos, line, tok; + boolean privileged; - LParser(String text){ + LParser(String text, boolean privileged){ + this.privileged = privileged; this.chars = text.toCharArray(); } - /** Parses a sequence of statements from a string. */ - public static Seq parse(String text){ - //don't waste time parsing null/empty text - if(text == null || text.isEmpty()) return new Seq<>(); - return new LParser(text).parse(); - } - void comment(){ //read until \n or eof while(pos < chars.length && chars[pos++] != '\n'); @@ -142,6 +137,11 @@ public class LParser{ st = new InvalidStatement(); } + //discard misplaced privileged instructions + if(!privileged && st != null && st.privileged()){ + st = new InvalidStatement(); + } + //store jumps that use labels if(st instanceof JumpStatement jump && wasJump){ jumps.add(new JumpIndex(jump, jumpLoc)); diff --git a/core/src/mindustry/logic/LStatement.java b/core/src/mindustry/logic/LStatement.java index 9368a9a8b1..df3f95f76e 100644 --- a/core/src/mindustry/logic/LStatement.java +++ b/core/src/mindustry/logic/LStatement.java @@ -30,7 +30,8 @@ public abstract class LStatement{ public LStatement copy(){ StringBuilder build = new StringBuilder(); write(build); - Seq read = LAssembler.read(build.toString()); + //assume privileged when copying, because there's no way privileged instructions can appear here anyway, and the instructions get validated on load anyway + Seq read = LAssembler.read(build.toString(), true); return read.size == 0 ? null : read.first(); } @@ -38,6 +39,16 @@ public abstract class LStatement{ return false; } + /** Privileged instructions are only allowed in world processors. */ + public boolean privileged(){ + return false; + } + + /** If true, this statement is considered useless with privileged processors and is not allowed in them. */ + public boolean nonPrivileged(){ + return false; + } + //protected methods are only for internal UI layout utilities protected void param(Cell