From 976b39414f01987a42f1b4e9a4faa8f90fc39a05 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 23 Feb 2019 15:08:07 -0500 Subject: [PATCH] Fixed: missing spawns / incorrect ranks / jittery movement / tests --- core/src/io/anuke/mindustry/core/Control.java | 4 +--- core/src/io/anuke/mindustry/core/Logic.java | 1 - .../src/io/anuke/mindustry/core/Renderer.java | 13 ++---------- core/src/io/anuke/mindustry/core/World.java | 14 ++++++++++++- .../entities/traits/SpawnerTrait.java | 3 ++- .../anuke/mindustry/entities/type/Player.java | 10 +++++++++- .../io/anuke/mindustry/game/DefaultWaves.java | 4 ++-- core/src/io/anuke/mindustry/game/Rules.java | 2 +- core/src/io/anuke/mindustry/game/Stats.java | 2 +- .../anuke/mindustry/io/SaveFileVersion.java | 14 ++++--------- .../io/anuke/mindustry/maps/MapException.java | 10 ++++++++++ .../mindustry/ui/fragments/HudFragment.java | 2 +- .../world/blocks/storage/CoreBlock.java | 4 ++-- .../anuke/mindustry/server/ServerControl.java | 20 ++++++++++++++----- tests/src/test/java/ApplicationTests.java | 2 ++ 15 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 core/src/io/anuke/mindustry/maps/MapException.java diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index ddcd40d6d0..d1ec5eefc0 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -101,9 +101,7 @@ public class Control implements ApplicationListener{ }); Events.on(WorldLoadEvent.class, event -> { - if(mobile){ - Core.app.post(() -> Core.camera.position.set(players[0])); - } + Core.app.post(() -> Core.camera.position.set(players[0])); }); Events.on(ResetEvent.class, event -> { diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 164a92e322..fde7380d48 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -68,7 +68,6 @@ public class Logic implements ApplicationListener{ state.gameOver = state.launched = false; state.teams = new Teams(); state.rules = new Rules(); - state.rules.spawns = DefaultWaves.getDefaultSpawns(); state.stats = new Stats(); Time.clear(); diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index 30e1faff4d..28affd9348 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -15,6 +15,7 @@ import io.anuke.arc.math.geom.Rectangle; import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.ScreenRecorder; import io.anuke.arc.util.Time; +import io.anuke.arc.util.Tmp; import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.core.GameState.State; @@ -48,7 +49,6 @@ public class Renderer implements ApplicationListener{ private float targetscale = io.anuke.arc.scene.ui.layout.Unit.dp.scl(4); private float camerascale = targetscale; private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); - private Vector2 avgPosition = new Vector2(); private float shakeIntensity, shaketime; public Renderer(){ @@ -115,7 +115,7 @@ public class Renderer implements ApplicationListener{ if(state.is(State.menu)){ graphics.clear(Color.BLACK); }else{ - Vector2 position = averagePosition(); + Vector2 position = Tmp.v3.set(players[0]); if(players[0].isDead()){ TileEntity core = players[0].getClosestCore(); @@ -288,15 +288,6 @@ public class Renderer implements ApplicationListener{ return camerascale; } - public Vector2 averagePosition(){ - avgPosition.setZero(); - - drawAndInterpolate(playerGroup, p -> p.isLocal, p -> avgPosition.add(p.x, p.y)); - - avgPosition.scl(1f / players.length); - return avgPosition; - } - public void scaleCamera(float amount){ targetscale += amount; clampScale(); diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 412cd43c3f..c93e7151aa 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -5,7 +5,6 @@ import io.anuke.arc.Core; import io.anuke.arc.Events; import io.anuke.arc.collection.Array; import io.anuke.arc.collection.IntArray; -import io.anuke.mindustry.entities.EntityQuery; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Geometry; import io.anuke.arc.math.geom.Point2; @@ -17,11 +16,13 @@ import io.anuke.mindustry.ai.Pathfinder; import io.anuke.mindustry.ai.WaveSpawner; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.core.GameState.State; +import io.anuke.mindustry.entities.EntityQuery; import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; +import io.anuke.mindustry.maps.MapException; import io.anuke.mindustry.maps.MapTileData; import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.maps.Maps; @@ -270,6 +271,17 @@ public class World implements ApplicationListener{ ui.showError("$map.nospawn.pvp"); } } + }else{ + invalidMap = true; + for(Team team : Team.all){ + if(state.teams.get(team).cores.size != 0){ + invalidMap = false; + } + } + + if(invalidMap){ + throw new MapException(map, "Map has no cores!"); + } } if(invalidMap) Core.app.post(() -> state.set(State.menu)); diff --git a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java index cb98c0086a..df23a1053d 100644 --- a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java @@ -1,9 +1,10 @@ package io.anuke.mindustry.entities.traits; +import io.anuke.arc.math.geom.Position; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.world.Tile; -public interface SpawnerTrait extends TargetTrait{ +public interface SpawnerTrait extends TargetTrait, Position{ Tile getTile(); void updateSpawning(Player unit); diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index e973c7126c..fd19b36531 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -464,8 +464,12 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ //region update methods + Vector2 last = new Vector2(); + @Override public void update(){ + last.set(this); + hitTime -= Time.delta(); if(Float.isNaN(x) || Float.isNaN(y)){ @@ -766,6 +770,8 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ }else if(getClosestCore() != null){ this.spawner = (SpawnerTrait)getClosestCore(); } + }else if(getClosestCore() != null){ + set(getClosestCore().getX(), getClosestCore().getY()); } } @@ -841,7 +847,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ @Override public void read(DataInput buffer) throws IOException{ - float lastx = x, lasty = y, lastrot = rotation; + float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y; super.readSave(buffer); name = TypeIO.readStringData(buffer); byte bools = buffer.readByte(); @@ -862,6 +868,8 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ if(isLocal){ x = lastx; y = lasty; + velocity.x = lastvx; + velocity.y = lastvy; }else{ mining = world.tile(mine); isBoosting = boosting; diff --git a/core/src/io/anuke/mindustry/game/DefaultWaves.java b/core/src/io/anuke/mindustry/game/DefaultWaves.java index e9a0a33de6..dda11e2c48 100644 --- a/core/src/io/anuke/mindustry/game/DefaultWaves.java +++ b/core/src/io/anuke/mindustry/game/DefaultWaves.java @@ -10,7 +10,7 @@ public class DefaultWaves{ private static Array spawns; public static Array getDefaultSpawns(){ - if(spawns == null){ + if(spawns == null && UnitTypes.dagger != null){ spawns = Array.with( new SpawnGroup(UnitTypes.dagger){{ end = 8; @@ -164,6 +164,6 @@ public class DefaultWaves{ }} ); } - return spawns; + return spawns == null ? new Array<>() : spawns; } } diff --git a/core/src/io/anuke/mindustry/game/Rules.java b/core/src/io/anuke/mindustry/game/Rules.java index b7d9c86dc7..a23b15321d 100644 --- a/core/src/io/anuke/mindustry/game/Rules.java +++ b/core/src/io/anuke/mindustry/game/Rules.java @@ -28,5 +28,5 @@ public class Rules{ /**Zone ID, -1 for invalid zone.*/ public byte zone = -1; /**Spawn layout. Since only zones modify this, it should be assigned on save load.*/ - public transient Array spawns = new Array<>(); + public transient Array spawns = DefaultWaves.getDefaultSpawns(); } diff --git a/core/src/io/anuke/mindustry/game/Stats.java b/core/src/io/anuke/mindustry/game/Stats.java index 989f5f741f..8080c41c00 100644 --- a/core/src/io/anuke/mindustry/game/Stats.java +++ b/core/src/io/anuke/mindustry/game/Stats.java @@ -30,7 +30,7 @@ public class Stats{ //each new launch period adds onto the rank 1.5 'points' if(wavesLasted >= zone.conditionWave){ - score += (float)((zone.conditionWave - wavesLasted) / zone.launchPeriod + 1) * 1.5f; + score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.5f; } int capacity = zone.generator.coreBlock.itemCapacity; diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index 22979ac185..e304816eef 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -1,11 +1,11 @@ package io.anuke.mindustry.io; import io.anuke.arc.collection.Array; +import io.anuke.arc.util.Pack; +import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.entities.Entities; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.traits.Entity; -import io.anuke.arc.util.Pack; -import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.entities.traits.SaveTrait; import io.anuke.mindustry.entities.traits.TypeTrait; import io.anuke.mindustry.game.Content; @@ -16,13 +16,13 @@ import io.anuke.mindustry.gen.Serialization; import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.BlockPart; -import io.anuke.mindustry.world.blocks.storage.CoreBlock; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.content; +import static io.anuke.mindustry.Vars.world; public abstract class SaveFileVersion{ public final int version; @@ -110,8 +110,6 @@ public abstract class SaveFileVersion{ byte team = Pack.leftByte(tr); byte rotation = Pack.rightByte(tr); - Team t = Team.all[team]; - tile.setTeam(Team.all[team]); tile.entity.health = health; tile.setRotation(rotation); @@ -123,10 +121,6 @@ public abstract class SaveFileVersion{ tile.entity.readConfig(stream); tile.entity.read(stream); - - if(tile.block() instanceof CoreBlock){ - state.teams.get(t).cores.add(tile); - } }else if(wallid == 0){ int consecutives = stream.readUnsignedByte(); diff --git a/core/src/io/anuke/mindustry/maps/MapException.java b/core/src/io/anuke/mindustry/maps/MapException.java new file mode 100644 index 0000000000..7bc1c76805 --- /dev/null +++ b/core/src/io/anuke/mindustry/maps/MapException.java @@ -0,0 +1,10 @@ +package io.anuke.mindustry.maps; + +public class MapException extends RuntimeException{ + public final Map map; + + public MapException(Map map, String s){ + super(s); + this.map = map; + } +} diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 467be52441..07b2a1aefe 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -144,7 +144,7 @@ public class HudFragment extends Fragment{ } infolabel.visible(() -> Core.settings.getBool("fps")).update(() -> infolabel.setPosition(0, - healthTable.isVisible() ? healthTable.getY() + healthTable.getTranslation().y : wavetable.isVisible() ? wavetable.getY() : 0f, + healthTable.isVisible() ? healthTable.getY() + healthTable.getTranslation().y : waves.isVisible() ? wavetable.getY() : Core.graphics.getHeight(), Align.topLeft)); infolabel.pack(); diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java index 4de3eb3f00..2ade6ec0b1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java @@ -4,17 +4,17 @@ import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.Remote; import io.anuke.arc.Core; import io.anuke.arc.collection.EnumSet; -import io.anuke.mindustry.entities.Effects; import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Lines; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.math.Mathf; import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.Fx; +import io.anuke.mindustry.entities.Effects; +import io.anuke.mindustry.entities.traits.SpawnerTrait; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.entities.type.Unit; -import io.anuke.mindustry.entities.traits.SpawnerTrait; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.graphics.Shaders; diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index 3703d60776..180430a1ee 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -19,6 +19,7 @@ import io.anuke.mindustry.game.EventType.GameOverEvent; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.maps.Map; +import io.anuke.mindustry.maps.MapException; import io.anuke.mindustry.net.Administration.PlayerInfo; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Packets.KickReason; @@ -220,12 +221,16 @@ public class ServerControl implements ApplicationListener{ logic.reset(); state.rules = preset.get(); - world.loadMap(result); - logic.play(); + try{ + world.loadMap(result); + logic.play(); - info("Map loaded."); + info("Map loaded."); - host(); + host(); + }catch(MapException e){ + Log.err(e.map.getDisplayName() + ": " + e.getMessage()); + } }); handler.register("port", "[port]", "Sets or displays the port for hosting the server.", arg -> { @@ -657,7 +662,12 @@ public class ServerControl implements ApplicationListener{ lastTask = new Task(){ @Override public void run(){ - r.run(); + try{ + r.run(); + }catch(MapException e){ + Log.err(e.map.getDisplayName() + ": " + e.getMessage()); + Net.closeServer(); + } } }; diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 9c796a4edb..f67122d9a7 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -181,6 +181,7 @@ public class ApplicationTests{ @Test void save(){ world.loadMap(testMap); + assertTrue(state.teams.get(defaultTeam).cores.size > 0); SaveIO.saveToSlot(0); } @@ -195,6 +196,7 @@ public class ApplicationTests{ assertEquals(world.width(), map.meta.width); assertEquals(world.height(), map.meta.height); + assertTrue(state.teams.get(defaultTeam).cores.size > 0); } @Test