Processor global variable dialog

This commit is contained in:
Anuken
2024-02-09 18:09:41 -05:00
parent 3d1067aac0
commit 2fd92b8c80
6 changed files with 201 additions and 29 deletions

View File

@@ -501,6 +501,7 @@ editor.default = [lightgray]<Default>
details = Details... details = Details...
edit = Edit edit = Edit
variables = Vars variables = Vars
logic.globals = Built-in Variables
editor.name = Name: editor.name = Name:
editor.spawn = Spawn Unit editor.spawn = Spawn Unit
editor.removeunit = Remove Unit editor.removeunit = Remove Unit
@@ -2330,6 +2331,49 @@ lst.makemarker = Create a new logic marker in the world.\nAn ID to identify this
lst.setmarker = Set a property for a marker.\nThe ID used must be the same as in the Make Marker instruction.\n[accent]null []values are ignored. lst.setmarker = Set a property for a marker.\nThe ID used must be the same as in the Make Marker instruction.\n[accent]null []values are ignored.
lst.localeprint = Add map locale property value to the text buffer.\nTo set map locale bundles in map editor, check [accent]Map Info > Locale Bundles[].\nIf client is a mobile device, tries to print a property ending in ".mobile" first. lst.localeprint = Add map locale property value to the text buffer.\nTo set map locale bundles in map editor, check [accent]Map Info > Locale Bundles[].\nIf client is a mobile device, tries to print a property ending in ".mobile" first.
lglobal.false = 0
lglobal.true = 1
lglobal.null = null
lglobal.@pi = The mathematical constant pi (3.141...)
lglobal.@e = The mathematical constant e (2.718...)
lglobal.@degToRad = Multiply by this number to convert degrees to radians
lglobal.@radToDeg = Multiply by this number to convert radians to degrees
lglobal.@time = Playtime of current save, in milliseconds
lglobal.@tick = Playtime of current save, in ticks (1 second = 60 ticks)
lglobal.@second = Playtime of current save, in seconds
lglobal.@minute = Playtime of current save, in minutes
lglobal.@waveNumber = Current wave number, if waves are enabled
lglobal.@waveTime = Countdown timer for waves, in seconds
lglobal.@mapw = Map width in tiles
lglobal.@maph = Map height in tiles
lglobal.sectionMap = Map
lglobal.sectionGeneral = General
lglobal.sectionNetwork = Network/Clientside [World Processor Only]
lglobal.sectionProcessor = Processor
lglobal.sectionLookup = Lookup
lglobal.@this = The logic block executing the code
lglobal.@thisx = X coordinate of block executing the code
lglobal.@thisy = Y coordinate of block executing the code
lglobal.@links = Total number of blocks linked to this processors
lglobal.@ipt = Execution speed of the processor in instructions per tick (60 ticks = 1 second)
lglobal.@unitCount = Total number of types of unit content in the game; used with the lookup instruction
lglobal.@blockCount = Total number of types of block content in the game; used with the lookup instruction
lglobal.@itemCount = Total number of types of item content in the game; used with the lookup instruction
lglobal.@liquidCount = Total number of types of liquid content in the game; used with the lookup instruction
lglobal.@server = True if the code is running on a server or in singleplayer, false otherwise
lglobal.@client = True if the code is running on a client connected to a server
lglobal.@clientLocale = Locale of the client running the code. For example: en_US
lglobal.@clientUnit = Unit of client running the code
lglobal.@clientName = Player name of client running the code
lglobal.@clientTeam = Team ID of client running the code
lglobal.@clientMobile = True is the client running the code is on mobile, false otherwise
logic.nounitbuild = [red]Unit building logic is not allowed here. logic.nounitbuild = [red]Unit building logic is not allowed here.
lenum.type = Type of building/unit.\ne.g. for any router, this will return [accent]@router[].\nNot a string. lenum.type = Type of building/unit.\ne.g. for any router, this will return [accent]@router[].\nNot a string.

View File

@@ -27,45 +27,63 @@ public class GlobalVars{
public static final Rand rand = new Rand(); public static final Rand rand = new Rand();
//non-constants that depend on state //non-constants that depend on state
private static int varTime, varTick, varSecond, varMinute, varWave, varWaveTime, varServer, varClient, varClientLocale, varClientUnit, varClientName, varClientTeam, varClientMobile; private static int varTime, varTick, varSecond, varMinute, varWave, varWaveTime, varMapW, varMapH, varServer, varClient, varClientLocale, varClientUnit, varClientName, varClientTeam, varClientMobile;
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>(); private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
private Seq<Var> vars = new Seq<>(Var.class); private Seq<Var> vars = new Seq<>(Var.class);
private Seq<VarEntry> varEntries = new Seq<>();
private IntSet privilegedIds = new IntSet(); private IntSet privilegedIds = new IntSet();
private UnlockableContent[][] logicIdToContent; private UnlockableContent[][] logicIdToContent;
private int[][] contentIdToLogicId; private int[][] contentIdToLogicId;
public void init(){ public void init(){
put("the end", null); putEntryOnly("sectionProcessor");
putEntryOnly("@this");
putEntryOnly("@thisx");
putEntryOnly("@thisy");
putEntryOnly("@links");
putEntryOnly("@ipt");
putEntryOnly("sectionGeneral");
put("the end", null, false, true);
//add default constants //add default constants
put("false", 0); putEntry("false", 0);
put("true", 1); putEntry("true", 1);
put("null", null); put("null", null, false, true);
//math //math
put("@pi", Mathf.PI); putEntry("@pi", Mathf.PI);
put("π", Mathf.PI); //for the "cool" kids put("π", Mathf.PI, false, true); //for the "cool" kids
put("@e", Mathf.E); putEntry("@e", Mathf.E);
put("@degToRad", Mathf.degRad); putEntry("@degToRad", Mathf.degRad);
put("@radToDeg", Mathf.radDeg); putEntry("@radToDeg", Mathf.radDeg);
putEntryOnly("sectionMap");
//time //time
varTime = put("@time", 0); varTime = putEntry("@time", 0);
varTick = put("@tick", 0); varTick = putEntry("@tick", 0);
varSecond = put("@second", 0); varSecond = putEntry("@second", 0);
varMinute = put("@minute", 0); varMinute = putEntry("@minute", 0);
varWave = put("@waveNumber", 0); varWave = putEntry("@waveNumber", 0);
varWaveTime = put("@waveTime", 0); varWaveTime = putEntry("@waveTime", 0);
varServer = put("@server", 0, true); varMapW = putEntry("@mapw", 0);
varClient = put("@client", 0, true); varMapH = putEntry("@maph", 0);
putEntryOnly("sectionNetwork");
varServer = putEntry("@server", 0, true);
varClient = putEntry("@client", 0, true);
//privileged desynced client variables //privileged desynced client variables
varClientLocale = put("@clientLocale", null, true); varClientLocale = putEntry("@clientLocale", null, true);
varClientUnit = put("@clientUnit", null, true); varClientUnit = putEntry("@clientUnit", null, true);
varClientName = put("@clientName", null, true); varClientName = putEntry("@clientName", null, true);
varClientTeam = put("@clientTeam", 0, true); varClientTeam = putEntry("@clientTeam", 0, true);
varClientMobile = put("@clientMobile", 0, true); varClientMobile = putEntry("@clientMobile", 0, true);
//special enums //special enums
put("@ctrlProcessor", ctrlProcessor); put("@ctrlProcessor", ctrlProcessor);
@@ -115,6 +133,8 @@ public class GlobalVars{
logicIdToContent = new UnlockableContent[ContentType.all.length][]; logicIdToContent = new UnlockableContent[ContentType.all.length][];
contentIdToLogicId = new int[ContentType.all.length][]; contentIdToLogicId = new int[ContentType.all.length][];
putEntryOnly("sectionLookup");
Fi ids = Core.files.internal("logicids.dat"); Fi ids = Core.files.internal("logicids.dat");
if(ids.exists()){ if(ids.exists()){
//read logic ID mapping data (generated in ImagePacker) //read logic ID mapping data (generated in ImagePacker)
@@ -125,7 +145,7 @@ public class GlobalVars{
contentIdToLogicId[ctype.ordinal()] = new int[Vars.content.getBy(ctype).size]; contentIdToLogicId[ctype.ordinal()] = new int[Vars.content.getBy(ctype).size];
//store count constants //store count constants
put("@" + ctype.name() + "Count", amount); putEntry("@" + ctype.name() + "Count", amount);
for(int i = 0; i < amount; i++){ for(int i = 0; i < amount; i++){
String name = in.readUTF(); String name = in.readUTF();
@@ -159,6 +179,9 @@ public class GlobalVars{
vars.items[varWave].numval = state.wave; vars.items[varWave].numval = state.wave;
vars.items[varWaveTime].numval = state.wavetime / 60f; vars.items[varWaveTime].numval = state.wavetime / 60f;
vars.items[varMapW].numval = world.width();
vars.items[varMapH].numval = world.height();
//network //network
vars.items[varServer].numval = (net.server() || !net.active()) ? 1 : 0; vars.items[varServer].numval = (net.server() || !net.active()) ? 1 : 0;
vars.items[varClient].numval = net.client() ? 1 : 0; vars.items[varClient].numval = net.client() ? 1 : 0;
@@ -173,6 +196,10 @@ public class GlobalVars{
} }
} }
public Seq<VarEntry> getEntries(){
return varEntries;
}
/** @return a piece of content based on its logic ID. This is not equivalent to content ID. */ /** @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){ public @Nullable Content lookupContent(ContentType type, int id){
var arr = logicIdToContent[type.ordinal()]; var arr = logicIdToContent[type.ordinal()];
@@ -209,6 +236,11 @@ public class GlobalVars{
/** Adds a constant value by name. */ /** Adds a constant value by name. */
public int put(String name, Object value, boolean privileged){ public int put(String name, Object value, boolean privileged){
return put(name, value, privileged, true);
}
/** Adds a constant value by name. */
public int put(String name, Object value, boolean privileged, boolean hidden){
int existingIdx = namesToIds.get(name, -1); int existingIdx = namesToIds.get(name, -1);
if(existingIdx != -1){ //don't overwrite existing vars (see #6910) if(existingIdx != -1){ //don't overwrite existing vars (see #6910)
Log.debug("Failed to add global logic variable '@', as it already exists.", name); Log.debug("Failed to add global logic variable '@', as it already exists.", name);
@@ -228,10 +260,44 @@ public class GlobalVars{
namesToIds.put(name, index); namesToIds.put(name, index);
if(privileged) privilegedIds.add(index); if(privileged) privilegedIds.add(index);
vars.add(var); vars.add(var);
if(!hidden){
varEntries.add(new VarEntry(index, name, "", "", privileged));
}
return index; return index;
} }
public int put(String name, Object value){ public int put(String name, Object value){
return put(name, value, false); return put(name, value, false);
} }
public int putEntry(String name, Object value){
return put(name, value, false, false);
}
public int putEntry(String name, Object value, boolean privileged){
return put(name, value, privileged, false);
}
public void putEntryOnly(String name){
varEntries.add(new VarEntry(0, name, "", "", false));
}
/** An entry that describes a variable for documentation purposes. This is *only* used inside UI for global variables. */
public static class VarEntry{
public int id;
public String name, description, icon;
public boolean privileged;
public VarEntry(int id, String name, String description, String icon, boolean privileged){
this.id = id;
this.name = name;
this.description = description;
this.icon = icon;
this.privileged = privileged;
}
public VarEntry(){
}
}
} }

View File

@@ -0,0 +1,61 @@
package mindustry.logic;
import arc.*;
import arc.graphics.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.ui.dialogs.*;
public class GlobalVarsDialog extends BaseDialog{
public GlobalVarsDialog(){
super("@logic.globals");
addCloseButton();
shown(this::setup);
onResize(this::setup);
}
void setup(){
float prefWidth = Math.min(Core.graphics.getWidth() * 0.9f / Scl.scl(1f) - 220f, 600f);
cont.clearChildren();
cont.pane(t -> {
t.margin(10f).marginRight(16f);
t.defaults().fillX().fillY();
for(var entry : Vars.logicVars.getEntries()){
if(entry.name.startsWith("section")){
Color color = Pal.accent;
t.add("@lglobal." + entry.name).fillX().center().labelAlign(Align.center).colspan(4).color(color).padTop(4f).padBottom(2f).row();
t.image(Tex.whiteui).height(4f).color(color).colspan(4).padBottom(8f).row();
}else{
Color varColor = Pal.gray;
float stub = 8f, mul = 0.5f, pad = 4;
String desc = entry.description;
if(desc == null || desc.isEmpty()){
desc = Core.bundle.get("lglobal." + entry.name, "");
}
String fdesc = desc;
t.add(new Image(Tex.whiteui, varColor.cpy().mul(mul))).width(stub);
t.stack(new Image(Tex.whiteui, varColor), new Label(" " + entry.name + " ", Styles.outlineLabel)).padRight(pad);
t.add(new Image(Tex.whiteui, Pal.gray.cpy().mul(mul))).width(stub);
t.table(Tex.pane, out -> out.add(fdesc).style(Styles.outlineLabel).width(prefWidth).padLeft(2).padRight(2).wrap()).padRight(pad);
t.row();
t.add().fillX().colspan(4).height(4).row();
}
}
}).grow();
}
}

View File

@@ -26,6 +26,7 @@ public class LogicDialog extends BaseDialog{
Cons<String> consumer = s -> {}; Cons<String> consumer = s -> {};
boolean privileged; boolean privileged;
@Nullable LExecutor executor; @Nullable LExecutor executor;
GlobalVarsDialog globalsDialog = new GlobalVarsDialog();
public LogicDialog(){ public LogicDialog(){
super("logic"); super("logic");
@@ -51,7 +52,7 @@ public class LogicDialog extends BaseDialog{
add(buttons).growX().name("canvas"); add(buttons).growX().name("canvas");
} }
private Color typeColor(Var s, Color color){ public static Color typeColor(Var s, Color color){
return color.set( return color.set(
!s.isobj ? Pal.place : !s.isobj ? Pal.place :
s.objval == null ? Color.darkGray : s.objval == null ? Color.darkGray :
@@ -65,7 +66,7 @@ public class LogicDialog extends BaseDialog{
); );
} }
private String typeName(Var s){ public static String typeName(Var s){
return return
!s.isobj ? "number" : !s.isobj ? "number" :
s.objval == null ? "null" : s.objval == null ? "null" :
@@ -178,6 +179,8 @@ public class LogicDialog extends BaseDialog{
}); });
dialog.addCloseButton(); dialog.addCloseButton();
dialog.buttons.button("@logic.globals", Icon.list, () -> globalsDialog.show()).size(210f, 64f);
dialog.show(); dialog.show();
}).name("variables").disabled(b -> executor == null || executor.vars.length == 0); }).name("variables").disabled(b -> executor == null || executor.vars.length == 0);

View File

@@ -354,8 +354,6 @@ public class LogicBlock extends Block{
} }
} }
asm.putConst("@mapw", world.width());
asm.putConst("@maph", world.height());
asm.putConst("@links", executor.links.length); asm.putConst("@links", executor.links.length);
asm.putConst("@ipt", instructionsPerTick); asm.putConst("@ipt", instructionsPerTick);

View File

@@ -25,4 +25,4 @@ org.gradle.caching=true
#used for slow jitpack builds; TODO see if this actually works #used for slow jitpack builds; TODO see if this actually works
org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000 org.gradle.internal.http.connectionTimeout=100000
archash=f3b941e548 archash=a2acd2ee5f