diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index b5eedaf12c..af9c4fc4f6 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -195,6 +195,7 @@ public class NetServer implements ApplicationListener{ result.append("Unnecessary mods:[lightgray]\n").append("> ").append(extraMods.toString("\n> ")); } con.kick(result.toString(), 0); + return; } if(!admins.isWhitelisted(packet.uuid, packet.usid)){ diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index e0a753530c..5b68f07daa 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -48,7 +48,7 @@ import static mindustry.Vars.*; @EntityDef(value = {Buildingc.class}, isFinal = false, genio = false, serialize = false) @Component(base = true) -abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Senseable, Controllable, Sized{ +abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Sized, Senseable, Controllable, Settable{ //region vars and initialization static final float timeToSleep = 60f * 1, recentDamageTime = 60f * 5f; static final ObjectSet tmpTiles = new ObjectSet<>(); @@ -1951,6 +1951,58 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } + @Override + public void setProp(LAccess prop, double value){ + switch(prop){ + case health -> { + health = (float)Mathf.clamp(value, 0, maxHealth); + healthChanged(); + } + case team -> { + Team team = Team.get((int)value); + if(this.team != team){ + changeTeam(team); + } + } + case totalPower -> { + if(power != null && block.consPower != null && block.consPower.buffered){ + power.status = Mathf.clamp((float)(value / block.consPower.capacity)); + } + } + } + } + + @Override + public void setProp(LAccess prop, Object value){ + switch(prop){ + case team -> { + if(value instanceof Team team && this.team != team){ + changeTeam(team); + } + } + } + } + + @Override + public void setProp(UnlockableContent content, double value){ + if(content instanceof Item item && items != null){ + int amount = (int)value; + if(items.get(item) != amount){ + if(items.get(item) < amount){ + handleStack(item, acceptStack(item, amount - items.get(item), null), null); + }else if(amount > 0){ + removeStack(item, items.get(item) - amount); + } + } + }else if(content instanceof Liquid liquid && liquids != null){ + float amount = Mathf.clamp((float)value, 0f, block.liquidCapacity); + //decreasing amount is always allowed + if(amount < liquids.get(liquid) || (acceptLiquid(self(), liquid) && (liquids.current() == liquid || liquids.currentAmount() <= 0.1f))){ + liquids.set(liquid, amount); + } + } + } + @Replace @Override public boolean inFogTo(Team viewer){ diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 88bf6bd672..550a68f45e 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -31,7 +31,7 @@ import static mindustry.Vars.*; import static mindustry.logic.GlobalVars.*; @Component(base = true) -abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable, Ranged, Minerc, Builderc{ +abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Ranged, Minerc, Builderc, Senseable, Settable{ @Import boolean hovering, dead, disarmed; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, dragMultiplier; @@ -40,6 +40,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Import @Nullable Tile mineTile; @Import Vec2 vel; @Import WeaponMount[] mounts; + @Import ItemStack stack; private UnitController controller; Ability[] abilities = {}; @@ -257,6 +258,60 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return Float.NaN; } + @Override + public void setProp(LAccess prop, double value){ + switch(prop){ + case health -> health = (float)Mathf.clamp(value, 0, maxHealth); + case x -> x = World.unconv((float)value); + case y -> y = World.unconv((float)value); + case rotation -> rotation = (float)value; + case team -> { + if(!net.client()){ + Team team = Team.get((int)value); + if(controller instanceof Player p){ + p.team(team); + } + this.team = team; + } + } + case flag -> flag = value; + } + } + + @Override + public void setProp(LAccess prop, Object value){ + switch(prop){ + case team -> { + if(value instanceof Team t && !net.client()){ + if(controller instanceof Player p) p.team(t); + team = t; + } + } + case payloadType -> { + //only serverside + if(((Object)this) instanceof Payloadc pay && !net.client()){ + if(value instanceof Block b){ + Building build = b.newBuilding().create(b, team()); + if(pay.canPickup(build)) pay.addPayload(new BuildPayload(build)); + }else if(value instanceof UnitType ut){ + Unit unit = ut.create(team()); + if(pay.canPickup(unit)) pay.addPayload(new UnitPayload(unit)); + }else if(value == null && pay.payloads().size > 0){ + pay.dropLastPayload(); + } + } + } + } + } + + @Override + public void setProp(UnlockableContent content, double value){ + if(content instanceof Item item){ + stack.item = item; + stack.amount = Mathf.clamp((int)value, 0, type.itemCapacity); + } + } + @Override @Replace public boolean canDrown(){ diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java index 14d8730893..f5fcf7a477 100644 --- a/core/src/mindustry/logic/LAccess.java +++ b/core/src/mindustry/logic/LAccess.java @@ -59,7 +59,8 @@ public enum LAccess{ public static final LAccess[] all = values(), senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class), - controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class); + controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class), + settable = {x, y, rotation, team, flag, health, totalPower, payloadType}; //TODO LAccess(String... params){ this.params = params; diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 122369f374..f425336c8e 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1695,5 +1695,37 @@ public class LExecutor{ } } + public static class SetPropI implements LInstruction{ + public int type, of, value; + + public SetPropI(int type, int of, int value){ + this.type = type; + this.of = of; + this.value = value; + } + + public SetPropI(){ + } + + @Override + public void run(LExecutor exec){ + Object target = exec.obj(of); + Object key = exec.obj(type); + + if(target instanceof Settable sp){ + if(key instanceof LAccess property){ + Var var = exec.var(value); + if(var.isobj){ + sp.setProp(property, var.objval); + }else{ + sp.setProp(property, var.numval); + } + }else if(key instanceof UnlockableContent content){ + sp.setProp(content, exec.num(value)); + } + } + } + } + //endregion } diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 2e54844f4f..4ab61ea825 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -1683,4 +1683,113 @@ public class LStatements{ return LCategory.world; } } + + @RegisterStatement("setprop") + public static class SetPropStatement extends LStatement{ + public String type = "@copper", of = "block1", value = "0"; + + private transient int selected = 0; + private transient TextField tfield; + + @Override + public void build(Table table){ + table.add(" set "); + + tfield = field(table, type, str -> type = str).padRight(0f).get(); + + table.button(b -> { + b.image(Icon.pencilSmall); + //240 + b.clicked(() -> showSelectTable(b, (t, hide) -> { + Table[] tables = { + //items + new Table(i -> { + i.left(); + int c = 0; + for(Item item : Vars.content.items()){ + if(item.hidden) continue; + i.button(new TextureRegionDrawable(item.uiIcon), Styles.flati, iconSmall, () -> { + stype("@" + item.name); + hide.run(); + }).size(40f); + + if(++c % 6 == 0) i.row(); + } + }), + //liquids + new Table(i -> { + i.left(); + int c = 0; + for(Liquid item : Vars.content.liquids()){ + if(!item.unlockedNow() || item.hidden) continue; + i.button(new TextureRegionDrawable(item.uiIcon), Styles.flati, iconSmall, () -> { + stype("@" + item.name); + hide.run(); + }).size(40f); + + if(++c % 6 == 0) i.row(); + } + }), + //sensors + new Table(i -> { + for(LAccess property : LAccess.settable){ + i.button(property.name(), Styles.flatt, () -> { + stype("@" + property.name()); + hide.run(); + }).size(240f, 40f).self(c -> tooltip(c, property)).row(); + } + }) + }; + + Drawable[] icons = {Icon.box, Icon.liquid, Icon.tree}; + Stack stack = new Stack(tables[selected]); + ButtonGroup