Merge branch 'master' of https://github.com/Anuken/Mindustry into tileable-logic-displays

# Conflicts:
#	core/assets/icons/icons.properties
#	core/assets/logicids.dat
This commit is contained in:
Anuken
2025-04-14 22:50:47 -04:00
494 changed files with 17743 additions and 9826 deletions

View File

@@ -61,6 +61,8 @@ public class LExecutor{
//yes, this is a minor memory leak, but it's probably not significant enough to matter
protected static IntFloatMap unitTimeouts = new IntFloatMap();
//lookup variable by name, lazy init.
protected @Nullable ObjectIntMap<String> nameMap;
static{
Events.on(ResetEvent.class, e -> unitTimeouts.clear());
@@ -92,6 +94,7 @@ public class LExecutor{
/** Loads with a specified assembler. Resets all variables. */
public void load(LAssembler builder){
nameMap = null;
vars = builder.vars.values().toSeq().retainAll(var -> !var.constant).toArray(LVar.class);
for(int i = 0; i < vars.length; i++){
vars[i].id = i;
@@ -106,6 +109,17 @@ public class LExecutor{
//region utility
public @Nullable LVar optionalVar(String name){
if(nameMap == null){
nameMap = new ObjectIntMap<>();
for(int i = 0; i < vars.length; i++){
nameMap.put(vars[i].name, i);
}
}
return optionalVar(nameMap.get(name, -1));
}
/** @return a Var from this processor. May be null if out of bounds. */
public @Nullable LVar optionalVar(int index){
return index < 0 || index >= vars.length ? null : vars[index];
@@ -557,6 +571,15 @@ public class LExecutor{
if(from instanceof MemoryBuild mem && (exec.privileged || (from.team == exec.team && !mem.block.privileged))){
output.setnum(address < 0 || address >= mem.memory.length ? 0 : mem.memory[address]);
}else if(from instanceof LogicBuild logic && (exec.privileged || (from.team == exec.team && !from.block.privileged)) && position.isobj && position.objval instanceof String name){
LVar fromVar = logic.executor.optionalVar(name);
if(fromVar != null && !output.constant){
output.objval = fromVar.objval;
output.numval = fromVar.numval;
output.isobj = fromVar.isobj;
}
}else if(target.isobj && target.objval instanceof CharSequence str){
output.setnum(address < 0 || address >= str.length() ? Double.NaN : (int)str.charAt(address));
}
}
}
@@ -580,6 +603,13 @@ public class LExecutor{
if(from instanceof MemoryBuild mem && (exec.privileged || (from.team == exec.team && !mem.block.privileged)) && address >= 0 && address < mem.memory.length){
mem.memory[address] = value.num();
}else if(from instanceof LogicBuild logic && (exec.privileged || (from.team == exec.team && !from.block.privileged)) && position.isobj && position.objval instanceof String name){
LVar toVar = logic.executor.optionalVar(name);
if(toVar != null && !toVar.constant){
toVar.objval = value.objval;
toVar.numval = value.numval;
toVar.isobj = value.isobj;
}
}
}
}
@@ -622,6 +652,10 @@ public class LExecutor{
}
}
}else{
if(target instanceof CharSequence seq && sense == LAccess.size){
to.setnum(seq.length());
return;
}
to.setobj(null);
}
}
@@ -984,6 +1018,29 @@ public class LExecutor{
}
}
public static class PrintCharI implements LInstruction{
public LVar value;
public PrintCharI(LVar value){
this.value = value;
}
PrintCharI(){}
@Override
public void run(LExecutor exec){
if(exec.textBuffer.length() >= maxTextBuffer) return;
if(value.isobj){
if(!(value.objval instanceof UnlockableContent cont)) return;
exec.textBuffer.append((char)cont.emojiChar());
return;
}
exec.textBuffer.append((char)Math.floor(value.numval));
}
}
public static class FormatI implements LInstruction{
public LVar value;
@@ -1376,10 +1433,10 @@ public class LExecutor{
Team t = team.team();
if(type.obj() instanceof UnitType type && !type.internal && !type.hidden && t != null && Units.canCreate(t, type)){
if(t != null && type.obj() instanceof UnitType type && !type.internal && Units.canCreate(t, type)){
//random offset to prevent stacking
var unit = type.spawn(t, World.unconv(x.numf()) + Mathf.range(0.01f), World.unconv(y.numf()) + Mathf.range(0.01f));
spawner.spawnEffect(unit, rotation.numf());
spawner.spawnEffect(unit);
result.setobj(unit);
}
}
@@ -1485,6 +1542,7 @@ public class LExecutor{
case dropZoneRadius -> state.rules.dropZoneRadius = value.numf() * 8f;
case unitCap -> state.rules.unitCap = Math.max(value.numi(), 0);
case lighting -> state.rules.lighting = value.bool();
case canGameOver -> state.rules.canGameOver = value.bool();
case mapArea -> {
int x = p1.numi(), y = p2.numi(), w = p3.numi(), h = p4.numi();
if(!checkMapArea(x, y, w, h, false)){
@@ -1511,7 +1569,7 @@ public class LExecutor{
state.rules.bannedUnits.remove(u);
}
}
case unitHealth, unitBuildSpeed, unitCost, unitDamage, blockHealth, blockDamage, buildSpeed, rtsMinSquad, rtsMinWeight -> {
case unitHealth, unitBuildSpeed, unitMineSpeed, unitCost, unitDamage, blockHealth, blockDamage, buildSpeed, rtsMinSquad, rtsMinWeight -> {
Team team = p1.team();
if(team != null){
float num = value.numf();
@@ -1519,6 +1577,7 @@ public class LExecutor{
case buildSpeed -> team.rules().buildSpeedMultiplier = Mathf.clamp(num, 0.001f, 50f);
case unitHealth -> team.rules().unitHealthMultiplier = Math.max(num, 0.001f);
case unitBuildSpeed -> team.rules().unitBuildSpeedMultiplier = Mathf.clamp(num, 0f, 50f);
case unitMineSpeed -> team.rules().unitMineSpeedMultiplier = Math.max(num, 0f);
case unitCost -> team.rules().unitCostMultiplier = Math.max(num, 0f);
case unitDamage -> team.rules().unitDamageMultiplier = Math.max(num, 0f);
case blockHealth -> team.rules().blockHealthMultiplier = Math.max(num, 0.001f);
@@ -1546,11 +1605,12 @@ public class LExecutor{
}else if(full){
//disable the rule, covers the whole map
if(set){
int prevX = state.rules.limitX, prevY = state.rules.limitY, prevW = state.rules.limitWidth, prevH = state.rules.limitHeight;
state.rules.limitMapArea = false;
if(!headless){
renderer.updateAllDarkness();
}
world.checkMapArea();
world.checkMapArea(prevX, prevY, prevW, prevH);
return false;
}
}
@@ -1559,12 +1619,20 @@ public class LExecutor{
}
if(set){
int prevX = state.rules.limitX, prevY = state.rules.limitY, prevW = state.rules.limitWidth, prevH = state.rules.limitHeight;
if(!state.rules.limitMapArea){
//it was never on in the first place, so the old bounds don't apply
prevW = 0;
prevH = 0;
prevX = -1;
prevY = -1;
}
state.rules.limitMapArea = true;
state.rules.limitX = x;
state.rules.limitY = y;
state.rules.limitWidth = w;
state.rules.limitHeight = h;
world.checkMapArea();
world.checkMapArea(prevX, prevY, prevW, prevH);
if(!headless){
renderer.updateAllDarkness();
@@ -1876,9 +1944,7 @@ public class LExecutor{
for(int i = 0; i < spawned; i++){
Tmp.v1.rnd(spread);
Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1);
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
Vars.spawner.spawnEffect(unit);
spawner.spawnUnit(group, spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
}
}
}