diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 43a3517ff0..293373a9df 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -1,10 +1,13 @@ #Maps entity names to IDs. Autogenerated. alpha=0 +arkyid=29 atrax=1 +beta=30 block=2 corvus=24 flare=3 +gamma=31 mace=4 mega=5 mindustry.entities.comp.BuildingComp=6 @@ -26,6 +29,8 @@ oct=26 poly=18 pulsar=19 quad=23 +quasar=32 risso=20 spiroct=21 +toxopid=33 vela=25 \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/alpha/0.json b/annotations/src/main/resources/revisions/alpha/0.json new file mode 100644 index 0000000000..eff5fa651d --- /dev/null +++ b/annotations/src/main/resources/revisions/alpha/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/arkyid/0.json b/annotations/src/main/resources/revisions/arkyid/0.json new file mode 100644 index 0000000000..eff5fa651d --- /dev/null +++ b/annotations/src/main/resources/revisions/arkyid/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/beta/0.json b/annotations/src/main/resources/revisions/beta/0.json new file mode 100644 index 0000000000..eff5fa651d --- /dev/null +++ b/annotations/src/main/resources/revisions/beta/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/block/4.json b/annotations/src/main/resources/revisions/block/4.json new file mode 100644 index 0000000000..7503c106b6 --- /dev/null +++ b/annotations/src/main/resources/revisions/block/4.json @@ -0,0 +1 @@ +{version:4,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/corvus/4.json b/annotations/src/main/resources/revisions/corvus/4.json new file mode 100644 index 0000000000..7503c106b6 --- /dev/null +++ b/annotations/src/main/resources/revisions/corvus/4.json @@ -0,0 +1 @@ +{version:4,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/flare/4.json b/annotations/src/main/resources/revisions/flare/4.json new file mode 100644 index 0000000000..7503c106b6 --- /dev/null +++ b/annotations/src/main/resources/revisions/flare/4.json @@ -0,0 +1 @@ +{version:4,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/gamma/0.json b/annotations/src/main/resources/revisions/gamma/0.json new file mode 100644 index 0000000000..eff5fa651d --- /dev/null +++ b/annotations/src/main/resources/revisions/gamma/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/mace/4.json b/annotations/src/main/resources/revisions/mace/4.json new file mode 100644 index 0000000000..786a64a7e2 --- /dev/null +++ b/annotations/src/main/resources/revisions/mace/4.json @@ -0,0 +1 @@ +{version:4,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/mono/3.json b/annotations/src/main/resources/revisions/mono/3.json new file mode 100644 index 0000000000..364fdca813 --- /dev/null +++ b/annotations/src/main/resources/revisions/mono/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/pulsar/0.json b/annotations/src/main/resources/revisions/pulsar/0.json new file mode 100644 index 0000000000..b2a9e3161a --- /dev/null +++ b/annotations/src/main/resources/revisions/pulsar/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/quasar/0.json b/annotations/src/main/resources/revisions/quasar/0.json new file mode 100644 index 0000000000..b2a9e3161a --- /dev/null +++ b/annotations/src/main/resources/revisions/quasar/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/risso/4.json b/annotations/src/main/resources/revisions/risso/4.json new file mode 100644 index 0000000000..7503c106b6 --- /dev/null +++ b/annotations/src/main/resources/revisions/risso/4.json @@ -0,0 +1 @@ +{version:4,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/toxopid/0.json b/annotations/src/main/resources/revisions/toxopid/0.json new file mode 100644 index 0000000000..eff5fa651d --- /dev/null +++ b/annotations/src/main/resources/revisions/toxopid/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 06533c4bcd..e20bd856c8 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1279,6 +1279,7 @@ liquid.slag.description = Refined in separators into constituent metals, or spra liquid.oil.description = Used in advanced material production and as incendiary ammunition. liquid.cryofluid.description = Used as coolant in reactors, turrets and factories. +block.resupply-point.description = Resupplies nearby units with copper ammunition. Not compatible with units that require battery power. block.armored-conveyor.description = Moves items forward. Does not accept inputs from the sides. block.illuminator.description = Emits light. block.message.description = Stores a message for communication between allies. diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index 76200981ac..acb7464b9d 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -14,21 +14,20 @@ import static mindustry.Vars.*; public class BuilderAI extends AIController{ float buildRadius = 1500; boolean found = false; - @Nullable Builderc following; + @Nullable Unit following; @Override public void updateMovement(){ - Builderc builder = (Builderc)unit; - if(builder.moving()){ - builder.lookAt(builder.vel().angle()); + if(unit.moving()){ + unit.lookAt(unit.vel.angle()); } if(target != null && shouldShoot()){ unit.lookAt(target); } - builder.updateBuilding(true); + unit.updateBuilding = true; if(following != null){ //try to follow and mimic someone @@ -36,18 +35,18 @@ public class BuilderAI extends AIController{ //validate follower if(!following.isValid() || !following.activelyBuilding()){ following = null; - builder.plans().clear(); + unit.plans.clear(); return; } //set to follower's first build plan, whatever that is - builder.plans().clear(); - builder.plans().addFirst(following.buildPlan()); + unit.plans.clear(); + unit.plans.addFirst(following.buildPlan()); } - if(builder.buildPlan() != null){ + if(unit.buildPlan() != null){ //approach request if building - BuildPlan req = builder.buildPlan(); + BuildPlan req = unit.buildPlan(); boolean valid = (req.tile().build instanceof ConstructBuild && req.tile().bc().cblock == req.block) || @@ -60,7 +59,7 @@ public class BuilderAI extends AIController{ moveTo(req.tile(), buildingRange - 20f); }else{ //discard invalid request - builder.plans().removeFirst(); + unit.plans.removeFirst(); } }else{ @@ -71,8 +70,8 @@ public class BuilderAI extends AIController{ Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> { if(found) return; - if(u instanceof Builderc b && u != unit && b.activelyBuilding()){ - BuildPlan plan = b.buildPlan(); + if(u.canBuild() && u != unit && u.activelyBuilding()){ + BuildPlan plan = u.buildPlan(); Building build = world.build(plan.x, plan.y); if(build instanceof ConstructBuild cons){ @@ -80,7 +79,7 @@ public class BuilderAI extends AIController{ //make sure you can reach the request in time if(dist / unit.speed() < cons.buildCost * 0.9f){ - following = b; + following = u; found = true; } } @@ -98,7 +97,7 @@ public class BuilderAI extends AIController{ blocks.removeFirst(); }else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid. //add build request. - builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config)); + unit.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config)); //shift build plan to tail so next unit builds something else. blocks.addLast(blocks.removeFirst()); }else{ diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index 98f4874779..6c6d3c127d 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -59,13 +59,13 @@ public class FormationAI extends AIController implements FormationMember{ unit.moveAt(realtarget.sub(unit).limit(speed)); } - if(unit instanceof Minerc mine && leader instanceof Minerc com){ - if(com.mineTile() != null && mine.validMine(com.mineTile())){ - mine.mineTile(com.mineTile()); + if(unit.canMine() && leader.canMine()){ + if(leader.mineTile != null && unit.validMine(leader.mineTile)){ + unit.mineTile(leader.mineTile); CoreBuild core = unit.team.core(); - if(core != null && com.mineTile().drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(com.mineTile().drop())){ + if(core != null && leader.mineTile.drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(leader.mineTile.drop())){ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); @@ -73,13 +73,13 @@ public class FormationAI extends AIController implements FormationMember{ } } }else{ - mine.mineTile(null); + unit.mineTile(null); } } - if(unit instanceof Builderc build && leader instanceof Builderc com && com.activelyBuilding()){ - build.clearBuilding(); - build.addBuild(com.buildPlan()); + if(unit.canBuild() && leader.canBuild() && leader.activelyBuilding()){ + unit.clearBuilding(); + leader.addBuild(unit.buildPlan()); } } diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java index 20650efe53..d2f759150b 100644 --- a/core/src/mindustry/ai/types/LogicAI.java +++ b/core/src/mindustry/ai/types/LogicAI.java @@ -92,9 +92,7 @@ public class LogicAI extends AIController{ } } case stop -> { - if(unit instanceof Builderc build){ - build.clearBuilding(); - } + unit.clearBuilding(); } } diff --git a/core/src/mindustry/ai/types/MinerAI.java b/core/src/mindustry/ai/types/MinerAI.java index ae18e8085b..97d8198bb2 100644 --- a/core/src/mindustry/ai/types/MinerAI.java +++ b/core/src/mindustry/ai/types/MinerAI.java @@ -17,21 +17,21 @@ public class MinerAI extends AIController{ protected void updateMovement(){ Building core = unit.closestCore(); - if(!(unit instanceof Minerc miner) || core == null) return; + if(!(unit.canMine()) || core == null) return; - if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type.range)){ - miner.mineTile(null); + if(unit.mineTile != null && !unit.mineTile.within(unit, unit.type.range)){ + unit.mineTile(null); } if(mining){ if(timer.get(timerTarget2, 60 * 4) || targetItem == null){ - targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i)); + targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i)); } //core full of the target item, do nothing if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){ unit.clearItem(); - miner.mineTile(null); + unit.mineTile(null); return; } @@ -47,7 +47,7 @@ public class MinerAI extends AIController{ moveTo(ore, unit.type.range / 2f, 20f); if(unit.within(ore, unit.type.range)){ - miner.mineTile(ore); + unit.mineTile = ore; } if(ore.block() != Blocks.air){ @@ -56,7 +56,7 @@ public class MinerAI extends AIController{ } } }else{ - miner.mineTile(null); + unit.mineTile = null; if(unit.stack.amount == 0){ mining = true; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index b9a0ee1d09..19606cf7f7 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -17,11 +17,13 @@ import static mindustry.Vars.*; public class UnitTypes implements ContentList{ //region definitions + //(the wall of shame - should fix the legacy stuff eventually...) + //mech public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; - //mech + builder + miner - public static @EntityDef({Unitc.class, Mechc.class, Builderc.class}) UnitType nova, pulsar, quasar; + //mech + public static @EntityDef(value = {Unitc.class, Mechc.class}, legacy = true) UnitType nova, pulsar, quasar; //mech public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela; @@ -29,29 +31,29 @@ public class UnitTypes implements ContentList{ //legs public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus, atrax; - //legs + building - public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid; + //legs + public static @EntityDef(value = {Unitc.class, Legsc.class}, legacy = true) UnitType spiroct, arkyid, toxopid; - //air (no special traits) + //air public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra; - //air, legacy mining + //air public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType mono; - //air + building + mining - public static @EntityDef({Unitc.class, Builderc.class}) UnitType poly; + //air + public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType poly; - //air + building + mining + payload - public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType mega; + //air + payload + public static @EntityDef({Unitc.class, Payloadc.class}) UnitType mega; - //air + building + payload - public static @EntityDef(value = {Unitc.class, Builderc.class, Payloadc.class}, legacy = true) UnitType quad; + //air + payload + public static @EntityDef(value = {Unitc.class, Payloadc.class}, legacy = true) UnitType quad; - //air + building + payload - public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; + //air + payload + ammo distribution + public static @EntityDef({Unitc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; - //air + building + mining - public static @EntityDef({Unitc.class, Builderc.class}) UnitType alpha, beta, gamma; + //air + public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType alpha, beta, gamma; //water public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura; @@ -470,7 +472,6 @@ public class UnitTypes implements ContentList{ mineTier = 1; hitSize = 29f; health = 18000f; - buildSpeed = 1.7f; armor = 9f; landShake = 1.5f; rotateSpeed = 1.5f; @@ -700,6 +701,7 @@ public class UnitTypes implements ContentList{ rippleScale = 2f; legSpeed = 0.2f; ammoType = AmmoTypes.power; + buildSpeed = 1f; legSplashDamage = 32; legSplashRange = 30; @@ -802,6 +804,7 @@ public class UnitTypes implements ContentList{ rippleScale = 3f; legSpeed = 0.19f; ammoType = AmmoTypes.powerHigh; + buildSpeed = 1f; legSplashDamage = 80; legSplashRange = 60; diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 9fff2051e1..f2cc3d6353 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -571,13 +571,13 @@ public class NetClient implements ApplicationListener{ BuildPlan[] requests = null; if(player.isBuilder()){ //limit to 10 to prevent buffer overflows - int usedRequests = Math.min(player.builder().plans().size, 10); + int usedRequests = Math.min(player.unit().plans().size, 10); int totalLength = 0; //prevent buffer overflow by checking config length for(int i = 0; i < usedRequests; i++){ - BuildPlan plan = player.builder().plans().get(i); + BuildPlan plan = player.unit().plans().get(i); if(plan.config instanceof byte[] b){ int length = b.length; totalLength += length; @@ -591,7 +591,7 @@ public class NetClient implements ApplicationListener{ requests = new BuildPlan[usedRequests]; for(int i = 0; i < usedRequests; i++){ - requests[i] = player.builder().plans().get(i); + requests[i] = player.unit().plans().get(i); } } @@ -607,7 +607,7 @@ public class NetClient implements ApplicationListener{ unit.rotation, unit instanceof Mechc m ? m.baseRotation() : 0, unit.vel.x, unit.vel.y, - player.unit().mineTile(), + player.unit().mineTile, player.boosting, player.shooting, ui.chatfrag.shown(), control.input.isBuilding, requests, Core.camera.position.x, Core.camera.position.y, diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index a3340f510b..959874e82d 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -600,8 +600,8 @@ public class NetServer implements ApplicationListener{ player.unit().aim(pointerX, pointerY); if(player.isBuilder()){ - player.builder().clearBuilding(); - player.builder().updateBuilding(building); + player.unit().clearBuilding(); + player.unit().updateBuilding(building); if(requests != null){ for(BuildPlan req : requests){ @@ -625,7 +625,7 @@ public class NetServer implements ApplicationListener{ con.rejectedRequests.add(req); continue; } - player.builder().plans().addLast(req); + player.unit().plans().addLast(req); } } } diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 4d9f81fa65..12fd9e8029 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -13,6 +13,7 @@ import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; import mindustry.world.blocks.ConstructBlock.*; @@ -22,17 +23,22 @@ import java.util.*; import static mindustry.Vars.*; @Component -abstract class BuilderComp implements Unitc{ +abstract class BuilderComp implements Posc, Teamc, Rotc{ static final Vec2[] vecs = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()}; @Import float x, y, rotation; + @Import UnitType type; @SyncLocal Queue plans = new Queue<>(1); @SyncLocal transient boolean updateBuilding = true; + public boolean canBuild(){ + return type.buildSpeed > 0; + } + @Override public void update(){ - if(!updateBuilding) return; + if(!updateBuilding || !canBuild()) return; float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; boolean infinite = state.rules.infiniteResources || team().rules().infiniteResources; @@ -102,9 +108,9 @@ abstract class BuilderComp implements Unitc{ ConstructBuild entity = tile.bc(); if(current.breaking){ - entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier); + entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier); }else{ - entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config); + entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier, current.config); } current.stuck = Mathf.equal(current.progress, entity.progress); @@ -161,6 +167,8 @@ abstract class BuilderComp implements Unitc{ /** Add another build requests to the queue, if it doesn't exist there yet. */ void addBuild(BuildPlan place, boolean tail){ + if(!canBuild()) return; + BuildPlan replace = null; for(BuildPlan request : plans){ if(request.x == place.x && request.y == place.y){ @@ -196,9 +204,8 @@ abstract class BuilderComp implements Unitc{ return plans.size == 0 ? null : plans.first(); } - @Override public void draw(){ - if(!isBuilding() || !updateBuilding) return; + if(!isBuilding() || !updateBuilding || !canBuild()) return; //TODO check correctness Draw.z(Layer.flyingUnit); diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 2dc21c8c66..2f63bd1063 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1122,7 +1122,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, /** Returns whether or not a hand cursor should be shown over this block. */ public Cursor getCursor(){ - return block.configurable ? SystemCursor.hand : SystemCursor.arrow; + return block.configurable && team == player.team() ? SystemCursor.hand : SystemCursor.arrow; } /** diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java index 8a55a19c1f..eb5802711e 100644 --- a/core/src/mindustry/entities/comp/MinerComp.java +++ b/core/src/mindustry/entities/comp/MinerComp.java @@ -32,7 +32,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{ } boolean mining(){ - return mineTile != null && !(((Object)this) instanceof Builderc b && b.activelyBuilding()); + return mineTile != null && !this.self().activelyBuilding(); } public boolean validMine(Tile tile, boolean checkDst){ @@ -44,6 +44,10 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{ return validMine(tile, true); } + public boolean canMine(){ + return type.mineSpeed > 0; + } + @Override public void update(){ Building core = closestCore(); diff --git a/core/src/mindustry/entities/comp/PlayerComp.java b/core/src/mindustry/entities/comp/PlayerComp.java index bde8712e36..0f8236377c 100644 --- a/core/src/mindustry/entities/comp/PlayerComp.java +++ b/core/src/mindustry/entities/comp/PlayerComp.java @@ -48,7 +48,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra transient float textFadeTime; public boolean isBuilder(){ - return unit instanceof Builderc; + return unit.canBuild(); } public @Nullable CoreBuild closestCore(){ @@ -160,10 +160,6 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra return unit; } - public Builderc builder(){ - return !(unit instanceof Builderc) ? Nulls.builder : (Builderc)unit; - } - public void unit(Unit unit){ if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead."); if(this.unit == unit) return; diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 097cce0130..aa02f25022 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -31,7 +31,7 @@ import mindustry.world.blocks.payloads.*; import static mindustry.Vars.*; @Component(base = true) -abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc{ +abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc, Builderc{ @Import boolean hovering, dead; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed; @@ -88,8 +88,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I /** @return where the unit wants to look at. */ public float prefRotation(){ - if(this instanceof Builderc builder && builder.activelyBuilding()){ - return angleTo(builder.buildPlan()); + if(activelyBuilding()){ + return angleTo(buildPlan()); }else if(mineTile() != null){ return angleTo(mineTile()); }else if(moving()){ diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index d2a3cb3700..6723f81c66 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -28,7 +28,7 @@ public class OverlayRenderer{ if(player.dead()) return; if(player.isBuilder()){ - player.builder().drawBuildRequests(); + player.unit().drawBuildRequests(); } input.drawBottom(); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 611c9b5305..b35778c881 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -59,7 +59,7 @@ public class DesktopInput extends InputHandler{ group.fill(t -> { t.bottom(); t.visible(() -> { - t.color.a = Mathf.lerpDelta(t.color.a, player.builder().isBuilding() ? 1f : 0f, 0.15f); + t.color.a = Mathf.lerpDelta(t.color.a, player.unit().isBuilding() ? 1f : 0f, 0.15f); return ui.hudfrag.shown && Core.settings.getBool("hints") && selectRequests.isEmpty() && t.color.a > 0.01f; }); @@ -290,7 +290,7 @@ public class DesktopInput extends InputHandler{ cursorType = cursor.build.getCursor(); } - if(isPlacing() || !selectRequests.isEmpty()){ + if((isPlacing() && player.isBuilder()) || !selectRequests.isEmpty()){ cursorType = SystemCursor.hand; } @@ -366,7 +366,7 @@ public class DesktopInput extends InputHandler{ int rawCursorX = World.toTile(Core.input.mouseWorld().x), rawCursorY = World.toTile(Core.input.mouseWorld().y); // automatically pause building if the current build queue is empty - if(Core.settings.getBool("buildautopause") && isBuilding && !player.builder().isBuilding()){ + if(Core.settings.getBool("buildautopause") && isBuilding && !player.unit().isBuilding()){ isBuilding = false; buildWasAutoPaused = true; } @@ -388,7 +388,7 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyTap(Binding.clear_building)){ - player.builder().clearBuilding(); + player.unit().clearBuilding(); } if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard() && mode != breaking){ @@ -480,8 +480,8 @@ public class DesktopInput extends InputHandler{ deleting = true; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.builder().activelyBuilding() && !droppingItem && - !tryBeginMine(selected) && player.unit().mineTile() == null && !Core.scene.hasKeyboard()){ + if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.unit().activelyBuilding() && !droppingItem && + !tryBeginMine(selected) && player.unit().mineTile == null && !Core.scene.hasKeyboard()){ player.shooting = shouldShoot; } }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine @@ -506,7 +506,7 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){ BuildPlan req = getRequest(cursorX, cursorY); if(req != null && req.breaking){ - player.builder().plans().remove(req); + player.unit().plans().remove(req); } }else{ deleting = false; @@ -547,7 +547,7 @@ public class DesktopInput extends InputHandler{ if(sreq != null){ if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){ - player.builder().plans().remove(sreq, true); + player.unit().plans().remove(sreq, true); } sreq = null; } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index bd72655e18..ed219c026e 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -169,7 +169,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(variants = Variant.one) public static void removeQueueBlock(int x, int y, boolean breaking){ - player.builder().removeBuild(x, y, breaking); + player.unit().removeBuild(x, y, breaking); } @Remote(targets = Loc.both, called = Loc.server) @@ -383,7 +383,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public Eachable allRequests(){ return cons -> { - for(BuildPlan request : player.builder().plans()) cons.get(request); + for(BuildPlan request : player.unit().plans()) cons.get(request); for(BuildPlan request : selectRequests) cons.get(request); for(BuildPlan request : lineRequests) cons.get(request); }; @@ -401,7 +401,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ player.typing = ui.chatfrag.shown(); if(player.isBuilder()){ - player.builder().updateBuilding(isBuilding); + player.unit().updateBuilding(isBuilding); } if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && player.unit().ammo <= 0){ @@ -653,7 +653,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return r2.overlaps(r1); }; - for(BuildPlan req : player.builder().plans()){ + for(BuildPlan req : player.unit().plans()){ if(test.get(req)) return req; } @@ -678,7 +678,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Draw.color(Pal.remove); Lines.stroke(1f); - for(BuildPlan req : player.builder().plans()){ + for(BuildPlan req : player.unit().plans()){ if(req.breaking) continue; if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){ drawBreaking(req); @@ -740,7 +740,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ for(BuildPlan req : requests){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ BuildPlan copy = req.copy(); - player.builder().addBuild(copy); + player.unit().addBuild(copy); } } } @@ -804,7 +804,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //remove build requests Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); - Iterator it = player.builder().plans().iterator(); + Iterator it = player.unit().plans().iterator(); while(it.hasNext()){ BuildPlan req = it.next(); if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){ @@ -1044,7 +1044,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public boolean canShoot(){ - return block == null && !onConfigurable() && !isDroppingItem() && !player.builder().activelyBuilding() && + return block == null && !onConfigurable() && !isDroppingItem() && !player.unit().activelyBuilding() && !(player.unit() instanceof Mechc && player.unit().isFlying()); } @@ -1090,7 +1090,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public boolean validPlace(int x, int y, Block type, int rotation, BuildPlan ignore){ - for(BuildPlan req : player.builder().plans()){ + for(BuildPlan req : player.unit().plans()){ if(req != ignore && !req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2)) @@ -1108,15 +1108,15 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void placeBlock(int x, int y, Block block, int rotation){ BuildPlan req = getRequest(x, y); if(req != null){ - player.builder().plans().remove(req); + player.unit().plans().remove(req); } - player.builder().addBuild(new BuildPlan(x, y, rotation, block, block.nextConfig())); + player.unit().addBuild(new BuildPlan(x, y, rotation, block, block.nextConfig())); } public void breakBlock(int x, int y){ Tile tile = world.tile(x, y); if(tile != null && tile.build != null) tile = tile.build.tile; - player.builder().addBuild(new BuildPlan(tile.x, tile.y)); + player.unit().addBuild(new BuildPlan(tile.x, tile.y)); } public void drawArrow(Block block, int x, int y, int rotation){ diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 6edea2d80a..fa39ad5492 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -114,7 +114,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - for(BuildPlan req : player.builder().plans()){ + for(BuildPlan req : player.unit().plans()){ Tile other = world.tile(req.x, req.y); if(other == null || req.breaking) continue; @@ -219,10 +219,10 @@ public class MobileInput extends InputHandler implements GestureListener{ BuildPlan copy = request.copy(); if(other == null){ - player.builder().addBuild(copy); + player.unit().addBuild(copy); }else if(!other.breaking && other.x == request.x && other.y == request.y && other.block.size == request.block.size){ - player.builder().plans().remove(other); - player.builder().addBuild(copy); + player.unit().plans().remove(other); + player.unit().addBuild(copy); } } @@ -245,10 +245,10 @@ public class MobileInput extends InputHandler implements GestureListener{ Boolp schem = () -> lastSchematic != null && !selectRequests.isEmpty(); group.fill(t -> { - t.visible(() -> (player.builder().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); + t.visible(() -> (player.unit().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); t.bottom().left(); t.button("@cancel", Icon.cancel, () -> { - player.builder().clearBuilding(); + player.unit().clearBuilding(); selectRequests.clear(); mode = none; block = null; @@ -914,7 +914,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } //update shooting if not building + not mining - if(!player.builder().isBuilding() && player.unit().mineTile() == null){ + if(!player.unit().isBuilding() && player.unit().mineTile == null){ //autofire targeting if(manualShooting){ diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index d4c20eaf5e..244746ef81 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -321,13 +321,8 @@ public class LExecutor{ ((LogicAI)unit.controller()).controller = exec.building(varThis); //clear old state - if(unit instanceof Minerc miner){ - miner.mineTile(null); - } - - if(unit instanceof Builderc builder){ - builder.clearBuilding(); - } + unit.mineTile = null; + unit.clearBuilding(); return (LogicAI)unit.controller(); } @@ -357,12 +352,8 @@ public class LExecutor{ //stop mining/building if(type == LUnitControl.stop){ - if(unit instanceof Minerc miner){ - miner.mineTile(null); - } - if(unit instanceof Builderc build){ - build.clearBuilding(); - } + unit.mineTile = null; + unit.clearBuilding(); } } case within -> { @@ -390,8 +381,8 @@ public class LExecutor{ } case mine -> { Tile tile = world.tileWorld(x1, y1); - if(unit instanceof Minerc miner){ - miner.mineTile(miner.validMine(tile) ? tile : null); + if(unit.canMine()){ + unit.mineTile = unit.validMine(tile) ? tile : null; } } case payDrop -> { @@ -432,12 +423,12 @@ public class LExecutor{ } } case build -> { - if(unit instanceof Builderc builder && exec.obj(p3) instanceof Block block){ + if(unit.canBuild() && exec.obj(p3) instanceof Block block){ int x = World.toTile(x1), y = World.toTile(y1); int rot = exec.numi(p4); //reset state of last request when necessary - if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || builder.plans().isEmpty()){ + if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || unit.plans.isEmpty()){ ai.plan.progress = 0; ai.plan.initialized = false; ai.plan.stuck = false; @@ -446,11 +437,11 @@ public class LExecutor{ ai.plan.set(x, y, rot, block); ai.plan.config = exec.obj(p5) instanceof Content c ? c : null; - builder.clearBuilding(); + unit.clearBuilding(); if(ai.plan.tile() != null){ - builder.updateBuilding(true); - builder.addBuild(ai.plan); + unit.updateBuilding = true; + unit.addBuild(ai.plan); } } } diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 2a5be98056..6da3a75ec0 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -80,7 +80,7 @@ public class UnitType extends UnlockableContent{ public int ammoCapacity = -1; public AmmoType ammoType = AmmoTypes.copper; public int mineTier = -1; - public float buildSpeed = 1f, mineSpeed = 1f; + public float buildSpeed = -1f, mineSpeed = 1f; public Sound mineSound = Sounds.minebeam; public float mineSoundVolume = 0.6f; @@ -225,7 +225,7 @@ public class UnitType extends UnlockableContent{ stats.addPercent(Stat.mineSpeed, mineSpeed); stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable)); } - if(inst instanceof Builderc){ + if(buildSpeed > 0){ stats.addPercent(Stat.buildSpeed, buildSpeed); } if(inst instanceof Payloadc){ diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 4c268e5dcd..9115b16785 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -102,7 +102,7 @@ public class PlacementFragment extends Fragment{ Block tryRecipe = tile == null ? null : tile.block instanceof ConstructBlock ? ((ConstructBuild)tile).cblock : tile.block; Object tryConfig = tile == null ? null : tile.config(); - for(BuildPlan req : player.builder().plans()){ + for(BuildPlan req : player.unit().plans()){ if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){ tryRecipe = req.block; tryConfig = req.config; diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index ce37e80dde..34532df8b0 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -179,7 +179,7 @@ public class ConstructBlock extends Block{ if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){ control.input.isBuilding = true; } - player.builder().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock, lastConfig), false); + player.unit().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock, lastConfig), false); } } diff --git a/core/src/mindustry/world/blocks/payloads/Payload.java b/core/src/mindustry/world/blocks/payloads/Payload.java index 0e4773538f..ec174f238d 100644 --- a/core/src/mindustry/world/blocks/payloads/Payload.java +++ b/core/src/mindustry/world/blocks/payloads/Payload.java @@ -57,6 +57,7 @@ public interface Payload{ return (T)payload; }else if(type == payloadUnit){ byte id = read.b(); + if(EntityMapping.map(id) == null) throw new RuntimeException("No type with ID " + id + " found."); Unit unit = (Unit)EntityMapping.map(id).get(); unit.read(read); return (T)new UnitPayload(unit); diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 72393306ad..5895b7fe10 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -433,6 +433,15 @@ public class ApplicationTests{ assertEquals(256, world.height()); } + @Test + void load114Save(){ + resetWorld(); + SaveIO.load(Core.files.internal("114.msav")); + + assertEquals(500, world.width()); + assertEquals(500, world.height()); + } + @Test void arrayIterators(){ Seq arr = Seq.with("a", "b" , "c", "d", "e", "f"); diff --git a/tests/src/test/resources/114.msav b/tests/src/test/resources/114.msav new file mode 100644 index 0000000000..e0c9277c77 Binary files /dev/null and b/tests/src/test/resources/114.msav differ