From 094985275810620e9d53a4f788886d3bd483bae1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 24 Jun 2021 15:38:20 -0400 Subject: [PATCH] Logic wait & content look up instructions --- core/assets/bundles/bundle.properties | 2 + core/assets/logicids.dat | Bin 0 -> 2669 bytes .../mindustry/ctype/UnlockableContent.java | 4 + core/src/mindustry/logic/GlobalConstants.java | 51 +++++++++++++ core/src/mindustry/logic/LExecutor.java | 20 +++++ core/src/mindustry/logic/LStatements.java | 40 +++++++++- core/src/mindustry/world/Block.java | 5 ++ gradle.properties | 2 +- tools/src/mindustry/tools/ImagePacker.java | 72 +++++++++++++++++- 9 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 core/assets/logicids.dat diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 280d6624e6..ff28ac6f11 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1591,6 +1591,8 @@ lst.sensor = Get data from a building or unit. lst.set = Set a variable. lst.operation = Perform an operation on 1-2 variables. lst.end = Jump to the top of the instruction stack. +lst.wait = Wait a certain number of seconds. +lst.lookup = Look up a item/liquid/unit/block type by ID.\nTotal counts of each type can be accessed with:\n[accent]@unitCount[] / [accent]@itemCount[] / [accent]@liquidCount[] / [accent]@blockCount[] lst.jump = Conditionally jump to another statement. lst.unitbind = Bind to the next unit of a type, and store it in [accent]@unit[]. lst.unitcontrol = Control the currently bound unit. diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat new file mode 100644 index 0000000000000000000000000000000000000000..c34c5571b73c1e01591eadc39c3385019462c1f2 GIT binary patch literal 2669 zcmZuz+m_=d5bSeSzKmsCo=md2oIK}EAB7Q?*+GKkVvqJu^0%p$knA~|7n^Px1l?8D z(7$wSy>M3@RqebAfyyqKsIyT8ZM3v~9Xe&A@^qRV(kH3UMp5yuO;5i$BSI9tPF*c+ zH*RG;?cG%bRo|7kVevs2V~1t0O8UWGOwvu==?}~w-QY#!qfB;r=1sG)&L?;Y$_a$= z?u`y21l8djp32~?pKq~q$>5Xv2PP_Mg{h_Lqt}d4W5nAhGsjdx=9^}|x!ToazT#&j|GsRx#8$MiBh)Q%%F<%>fxhM~kYNX;3c<`}( zGRt5=%i4)vfvr!*jOm$EUWpN=N8LG$>e)U$)dJ-M%_`Tc)IoP7*AtEss)KZ7W741; zdPfa>tv;fkcHc=B%iE|%2dmAeDORI!6~18w!uVnVB76s6-H(nwNuyGr)lFaWvjlyDv?$vq5WbUdT~QJ=ee(6e8^Tz-m6GQ+%MtMAmBKCa$?|gKWj(!WP1HEM?mVB zmyGX;5c`QQ!6pbDWhULMZqQ|->Yy>>#LH-m{+YRXrp#m==l1h=M(a3Rb12Z6Ae|%J zc1A$@uAo9gf8mnKLm_%K>WYw3p(T!Sn+{!FK;75jt|PEhby|AMqAf9l>{rIN0RNNY zI&epPILb~zcL$W5>5+{yOU+?g3+2Su2YMTOX8qZTHqM$4Sm6}=$;jwFPS%38y5Qj80JrBK;OF{>>UF%*7CkU^XD?`@q|pw1DLUI* zDx5U~#;O%m;NuN_;f+^bBc-%Lk=_-p&VGPcehEs`%619ctbxB2@NYkc-l8aSPz;=n zP_4#AX~T@^aoCkGXkb*FQBqp90;Ho8UyWZYR2YSCzI2#uAy&iBSqVcl~I^dZ3(472i Vqk>kWLgEZYv`7g=>ScN5{Ri?Yo3sD` literal 0 HcmV?d00001 diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index c28496bb81..b557bbaf89 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -126,6 +126,10 @@ public abstract class UnlockableContent extends MappableContent{ return true; } + public boolean logicVisible(){ + return !isHidden(); + } + /** Makes this piece of content unlocked; if it already unlocked, nothing happens. */ public void unlock(){ if(!unlocked && !alwaysUnlocked){ diff --git a/core/src/mindustry/logic/GlobalConstants.java b/core/src/mindustry/logic/GlobalConstants.java index 479eda46ab..e631906760 100644 --- a/core/src/mindustry/logic/GlobalConstants.java +++ b/core/src/mindustry/logic/GlobalConstants.java @@ -1,20 +1,28 @@ package mindustry.logic; +import arc.*; +import arc.files.*; import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.content.*; +import mindustry.ctype.*; import mindustry.entities.units.*; import mindustry.logic.LExecutor.*; import mindustry.type.*; import mindustry.world.*; +import java.io.*; + /** Stores global constants for logic processors. */ public class GlobalConstants{ public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3; + public static final ContentType[] lookableContent = {ContentType.block, ContentType.unit, ContentType.item, ContentType.liquid}; private ObjectIntMap namesToIds = new ObjectIntMap<>(); private Seq vars = new Seq<>(Var.class); + private UnlockableContent[][] logicIdToContent; + private int[][] contentIdToLogicId; public void init(){ put("the end", null); @@ -61,6 +69,49 @@ public class GlobalConstants{ for(UnitCommand cmd : UnitCommand.all){ put("@command" + Strings.capitalize(cmd.name()), cmd); } + + logicIdToContent = new UnlockableContent[ContentType.all.length][]; + contentIdToLogicId = new int[ContentType.all.length][]; + + Fi ids = Core.files.internal("logicids.dat"); + if(ids.exists()){ + //read logic ID mapping data (generated in ImagePacker) + try(DataInputStream in = new DataInputStream(ids.readByteStream())){ + for(ContentType ctype : lookableContent){ + short amount = in.readShort(); + logicIdToContent[ctype.ordinal()] = new UnlockableContent[amount]; + contentIdToLogicId[ctype.ordinal()] = new int[Vars.content.getBy(ctype).size]; + + //store count constants + put("@" + ctype.name() + "Count", amount); + + for(int i = 0; i < amount; i++){ + String name = in.readUTF(); + UnlockableContent fetched = Vars.content.getByName(ctype, name); + + if(fetched != null){ + logicIdToContent[ctype.ordinal()][i] = fetched; + contentIdToLogicId[ctype.ordinal()][fetched.id] = i; + } + } + } + }catch(IOException e){ + //don't crash? + Log.err("Error reading logic ID mapping", e); + } + } + } + + /** @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()]; + return arr != null && id >= 0 && id < arr.length ? arr[id] : null; + } + + /** @return the integer logic ID of content, or -1 if invalid. */ + public int lookupLogicId(UnlockableContent content){ + var arr = contentIdToLogicId[content.getContentType().ordinal()]; + return arr != null && content.id >= 0 && content.id < arr.length ? arr[content.id] : -1; } /** @return a constant ID > 0 if there is a constant with this name, otherwise -1. */ diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 21585610c1..73a83c00b2 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1023,6 +1023,26 @@ public class LExecutor{ } } + public static class LookupI implements LInstruction{ + public int dest; + public int from; + public ContentType type; + + public LookupI(int dest, int from, ContentType type){ + this.dest = dest; + this.from = from; + this.type = type; + } + + public LookupI(){ + } + + @Override + public void run(LExecutor exec){ + exec.setobj(dest, constants.lookupContent(type, exec.numi(from))); + } + } + //endregion } diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 9b78de37f8..1d04b21052 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -7,6 +7,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import mindustry.*; import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.logic.LCanvas.*; @@ -662,8 +663,7 @@ public class LStatements{ } } - //TODO untested - //@RegisterStatement("wait") + @RegisterStatement("wait") public static class WaitStatement extends LStatement{ public String value = "0.5"; @@ -684,6 +684,42 @@ public class LStatements{ } } + @RegisterStatement("lookup") + public static class LookupStatement extends LStatement{ + public ContentType type = ContentType.item; + public String result = "result", id = "0"; + + @Override + public void build(Table table){ + fields(table, result, str -> result = str); + + table.add(" = lookup "); + + row(table); + + table.button(b -> { + b.label(() -> type.name()); + b.clicked(() -> showSelect(b, GlobalConstants.lookableContent, type, o -> { + type = o; + })); + }, Styles.logict, () -> {}).size(64f, 40f).pad(4f).color(table.color); + + table.add(" # "); + + fields(table, id, str -> id = str); + } + + @Override + public Color color(){ + return Pal.logicOperations; + } + + @Override + public LInstruction build(LAssembler builder){ + return new LookupI(builder.var(result), builder.var(id), type); + } + } + @RegisterStatement("end") public static class EndStatement extends LStatement{ @Override diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 6e2e2c1afc..131c5878d6 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -774,6 +774,11 @@ public class Block extends UnlockableContent{ return ContentType.block; } + @Override + public boolean logicVisible(){ + return buildVisibility != BuildVisibility.hidden; + } + /** Called after all blocks are created. */ @Override @CallSuper diff --git a/gradle.properties b/gradle.properties index ddd72aa92f..da7bb247ba 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,4 @@ kapt.include.compile.classpath=false kotlin.stdlib.default.dependency=false #needed for android compilation android.useAndroidX=true -archash=52f21644b8f70c3a926d3d8d8130f0d71e0e4e79 +archash=d9fd4b9092c136de8a9b35ca0e393b1a306d0628 diff --git a/tools/src/mindustry/tools/ImagePacker.java b/tools/src/mindustry/tools/ImagePacker.java index a787540c15..0df257f52f 100644 --- a/tools/src/mindustry/tools/ImagePacker.java +++ b/tools/src/mindustry/tools/ImagePacker.java @@ -14,6 +14,7 @@ import mindustry.*; import mindustry.content.*; import mindustry.core.*; import mindustry.ctype.*; +import mindustry.logic.*; import mindustry.world.blocks.*; import java.io.*; @@ -86,7 +87,8 @@ public class ImagePacker{ Time.mark(); Generators.run(); Log.info("&ly[Generator]&lc Total time to generate: &lg@&lcms", Time.elapsed()); - //Log.info("&ly[Generator]&lc Total images created: &lg@", Image.total()); + + //write icons to icons.properties //format: //character-ID=contentname:texture-name @@ -118,6 +120,74 @@ public class ImagePacker{ } writer.close(); + + //now, write the IDs to logicids.dat + + //don't write to the file unless I'm packing, because logic IDs rarely change and I don't want merge conflicts from PRs + if(!OS.username.equals("anuke")) return; + + //format: ([content type (byte)] [content count (short)] (repeat [name (string)])) until EOF + Fi logicidfile = Fi.get("../../../assets/logicids.dat"); + + Seq lookupCont = new Seq<>(); + + for(ContentType t : GlobalConstants.lookableContent){ + lookupCont.addAll(Vars.content.getBy(t).select(UnlockableContent::logicVisible)); + } + + ObjectIntMap[] registered = new ObjectIntMap[ContentType.all.length]; + IntMap[] idToContent = new IntMap[ContentType.all.length]; + + for(int i = 0; i < ContentType.all.length; i++){ + registered[i] = new ObjectIntMap<>(); + idToContent[i] = new IntMap<>(); + } + + if(logicidfile.exists()){ + try(DataInputStream in = new DataInputStream(logicidfile.readByteStream())){ + for(ContentType ctype : GlobalConstants.lookableContent){ + short amount = in.readShort(); + for(int i = 0; i < amount; i++){ + String name = in.readUTF(); + UnlockableContent fetched = Vars.content.getByName(ctype, name); + if(fetched != null){ + registered[ctype.ordinal()].put(fetched, i); + idToContent[ctype.ordinal()].put(i, fetched); + } + } + } + } + } + + //map stuff that hasn't been mapped yet + for(UnlockableContent c : lookupCont){ + int ctype = c.getContentType().ordinal(); + if(!registered[ctype].containsKey(c)){ + int nextId = 0; + //find next ID - this is O(N) but content counts are so low that I don't really care + //checking the last ID doesn't work because there might be "holes" + for(UnlockableContent other : lookupCont){ + if(!idToContent[ctype].containsKey(other.id + 1)){ + nextId = other.id + 1; + break; + } + } + + idToContent[ctype].put(nextId, c); + registered[ctype].put(c, nextId); + } + } + + //write the resulting IDs + try(DataOutputStream out = new DataOutputStream(logicidfile.write(false, 2048))){ + for(ContentType t : GlobalConstants.lookableContent){ + Seq all = idToContent[t.ordinal()].values().toArray().sort(u -> registered[t.ordinal()].get(u)); + out.writeShort(all.size); + for(UnlockableContent u : all){ + out.writeUTF(u.name); + } + } + } } static String texname(UnlockableContent c){