Massive amount of bug/crash fixes, wave saving

This commit is contained in:
Anuken 2018-06-25 18:07:11 -04:00
parent ced11c88bc
commit 5a135e108a
22 changed files with 190 additions and 96 deletions

View File

@ -2,7 +2,6 @@ package io.anuke.mindustry.ai;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Bits;
import com.badlogic.gdx.utils.IntArray;
import io.anuke.mindustry.content.AmmoTypes;
import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.entities.units.BaseUnit;
@ -13,13 +12,16 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.util.Mathf;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class WaveSpawner {
private static final int quadsize = 4;
private Bits quadrants;
private IntArray tmpArray = new IntArray();
private Array<FlyerSpawn> flySpawns = new Array<>();
private Array<GroundSpawn> groundSpawns = new Array<>();
@ -28,6 +30,37 @@ public class WaveSpawner {
Events.on(WorldLoadEvent.class, this::reset);
}
public void write(DataOutput output) throws IOException{
output.writeShort(flySpawns.size);
for (FlyerSpawn spawn : flySpawns){
output.writeFloat(spawn.angle);
}
output.writeShort(groundSpawns.size);
for (GroundSpawn spawn : groundSpawns){
output.writeShort((short)spawn.x);
output.writeShort((short)spawn.y);
}
}
public void read(DataInput input) throws IOException{
short flya = input.readShort();
for (int i = 0; i < flya; i++) {
FlyerSpawn spawn = new FlyerSpawn();
spawn.angle = input.readFloat();
flySpawns.add(spawn);
}
short grounda = input.readShort();
for (int i = 0; i < grounda; i++) {
GroundSpawn spawn = new GroundSpawn();
spawn.x = input.readShort();
spawn.y = input.readShort();
groundSpawns.add(spawn);
}
}
public void spawnEnemies(){
int spawned = Math.min(state.wave, 6);
int groundGroups = 1 + state.wave / 20;

View File

@ -155,7 +155,6 @@ public class Control extends Module{
});
Events.on(WaveEvent.class, () -> {
Sounds.play("spawn");
int last = Settings.getInt("hiscore" + world.getMap().name, 0);

View File

@ -44,6 +44,7 @@ public class Logic extends Module {
}
public void play(){
state.set(State.playing);
state.wavetime = wavespace * state.difficulty.timeScaling * 2;
//fill inventory with items for debugging
@ -157,6 +158,11 @@ public class Logic extends Module {
Entities.update(playerGroup);
Entities.update(itemGroup);
//effect group only contains item drops in the headless version, update it!
if(headless){
Entities.update(effectGroup);
}
for(EntityGroup group : unitGroups){
if(!group.isEmpty()){
EntityPhysics.collideGroups(bulletGroup, group);

View File

@ -177,7 +177,7 @@ public class NetClient extends Module {
String getUsid(String ip){
if(Settings.getString("usid-" + ip, null) != null){
return Settings.getString("usid-" + ip);
return Settings.getString("usid-" + ip, null);
}else{
byte[] bytes = new byte[8];
new Random().nextBytes(bytes);

View File

@ -177,6 +177,7 @@ public class NetServer extends Module{
player.pointerX = packet.pointerX;
player.pointerY = packet.pointerY;
player.setMineTile(packet.mining);
vector.set(packet.x - player.getInterpolator().target.x, packet.y - player.getInterpolator().target.y);

View File

@ -3,26 +3,26 @@ package io.anuke.mindustry.core;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.ai.BlockIndexer;
import io.anuke.mindustry.ai.Pathfinder;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.game.EventType.TileChangeEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.io.Map;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.io.Maps;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.mapgen.WorldGenerator;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.ThreadArray;
import io.anuke.ucore.util.Tmp;
import static io.anuke.mindustry.Vars.threads;
import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.*;
public class World extends Module{
private int seed;
@ -101,7 +101,7 @@ public class World extends Module{
}
public Tile tile(int packed){
return tile(packed % width(), packed / width());
return tiles == null ? null : tile(packed % width(), packed / width());
}
public Tile tile(int x, int y){
@ -171,6 +171,30 @@ public class World extends Module{
Events.fire(WorldLoadEvent.class);
}
/**Loads up a procedural map. This does not call play(), but calls reset().*/
public void loadProceduralMap(){
Timers.mark();
MapTileData data = WorldGenerator.generate();
Map map = new Map("generated-map", new MapMeta(0, new ObjectMap<>(), data.width(), data.height(), null), true, () -> null);
logic.reset();
beginMapLoad();
setMap(map);
int width = map.meta.width, height = map.meta.height;
Tile[][] tiles = createTiles(data.width(), data.height());
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
WorldGenerator.generate(tiles, data, true, Mathf.random(9999999));
endMapLoad();
Log.info("Time to generate: {0}", Timers.elapsed());
}
public void setMap(Map map){
this.currentMap = map;
}

View File

@ -705,6 +705,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
buffer.writeBoolean(dead);
buffer.writeByte(mech.id);
buffer.writeBoolean(isBoosting);
buffer.writeInt(mining == null ? -1 : mining.packedPosition());
}
@Override
@ -717,6 +718,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
dead = buffer.readBoolean();
mech = Upgrade.getByID(buffer.readByte());
boolean dashing = buffer.readBoolean();
int mine = buffer.readInt();
interpolator.read(lastx, lasty, x, y, time, rotation);
rotation = lastrot;
@ -724,6 +726,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
x = lastx;
y = lasty;
}else{
mining = world.tile(mine);
isBoosting = dashing;
}
}

View File

@ -44,6 +44,11 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
create(item, x, y, to, () -> {});
}
@Remote(in = In.entities, called = Loc.server, unreliable = true)
public static void transferItemToUnit(Item item, float x, float y, Unit to){
create(item, x, y, to, () -> to.inventory.addItem(item, 1));
}
@Remote(in = In.entities, called = Loc.server)
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
for (int i = 0; i < Mathf.clamp(amount/3, 1, 8); i++) {

View File

@ -8,9 +8,9 @@ import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.ItemTransfer;
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
import io.anuke.mindustry.gen.CallBlocks;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Recipe;
@ -27,10 +27,7 @@ import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.graphics.Shapes;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
import io.anuke.ucore.util.*;
import java.util.Arrays;
@ -189,10 +186,10 @@ public interface BuilderTrait {
if(unit.inventory.canAcceptItem(item) &&
Mathf.chance(Timers.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
ItemTransfer.create(item,
CallEntity.transferItemToUnit(item,
tile.worldx() + Mathf.range(tilesize/2f),
tile.worldy() + Mathf.range(tilesize/2f),
unit, () -> unit.inventory.addItem(item, 1));
unit);
}
if(Mathf.chance(0.06 * Timers.delta())){

View File

@ -53,7 +53,7 @@ public abstract class BaseUnit extends Unit{
protected boolean isWave;
protected Squad squad;
protected UnitFactoryEntity spawner;
protected int spawner = -1;
public BaseUnit(UnitType type, Team team){
this.type = type;
@ -61,7 +61,7 @@ public abstract class BaseUnit extends Unit{
}
public void setSpawner(UnitFactoryEntity spawner) {
this.spawner = spawner;
this.spawner = spawner.tile.packedPosition();
}
public UnitType getType() {
@ -267,10 +267,14 @@ public abstract class BaseUnit extends Unit{
@Override
public void removed() {
if(spawner != null){
spawner.hasSpawned = false;
spawner = null;
Tile tile = world.tile(spawner);
if(tile != null && tile.entity instanceof UnitFactoryEntity){
UnitFactoryEntity factory = (UnitFactoryEntity)tile.entity;
factory.hasSpawned = false;
}
spawner = -1;
}
@Override
@ -302,6 +306,7 @@ public abstract class BaseUnit extends Unit{
super.writeSave(stream);
stream.writeByte(type.id);
stream.writeBoolean(isWave);
stream.writeInt(spawner);
}
@Override
@ -309,6 +314,7 @@ public abstract class BaseUnit extends Unit{
super.readSave(stream);
byte type = stream.readByte();
this.isWave = stream.readBoolean();
this.spawner = stream.readInt();
this.type = UnitType.getByID(type);
add();

View File

@ -34,6 +34,10 @@ import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.ThreadQueue;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Drone extends FlyingUnit implements BuilderTrait {
@ -117,7 +121,7 @@ public class Drone extends FlyingUnit implements BuilderTrait {
@Override
public void setMineTile(Tile tile) {
this.mineTile = tile;
mineTile = tile;
}
@Override
@ -208,6 +212,21 @@ public class Drone extends FlyingUnit implements BuilderTrait {
return false;
}
@Override
public void write(DataOutput data) throws IOException {
super.write(data);
data.writeInt(mineTile == null ? -1 : mineTile.packedPosition());
}
@Override
public void read(DataInput data, long time) throws IOException {
super.read(data, time);
int mined = data.readInt();
if(mined != -1){
mineTile = world.tile(mined);
}
}
public final UnitState
build = new UnitState(){
@ -317,7 +336,7 @@ public class Drone extends FlyingUnit implements BuilderTrait {
if(target instanceof Tile) {
moveTo(type.range/1.5f);
if (distanceTo(target) < type.range) {
if (distanceTo(target) < type.range && mineTile != target) {
setMineTile((Tile)target);
}

View File

@ -92,8 +92,8 @@ public class FogRenderer implements Disposable{
Graphics.begin();
EntityDraw.setClip(false);
renderer.drawAndInterpolate(playerGroup, player -> player.getTeam() == players[0].getTeam(), Unit::drawView);
renderer.drawAndInterpolate(unitGroups[players[0].getTeam().ordinal()], unit -> true, Unit::drawView);
renderer.drawAndInterpolate(playerGroup, player -> !player.isDead() && player.getTeam() == players[0].getTeam(), Unit::drawView);
renderer.drawAndInterpolate(unitGroups[players[0].getTeam().ordinal()], unit -> !unit.isDead(), Unit::drawView);
for(Tile tile : changeQueue){
float viewRange = tile.block().viewRange;

View File

@ -53,6 +53,8 @@ public class Save16 extends SaveFileVersion {
state.wave = wave;
state.wavetime = wavetime;
state.spawner.read(stream);
//block header
int blocksize = stream.readInt();
@ -152,6 +154,8 @@ public class Save16 extends SaveFileVersion {
stream.writeByte(state.difficulty.ordinal()); //difficulty ordinal
stream.writeFloat(state.wavetime); //wave countdown
state.spawner.write(stream);
//--BLOCK HEADER--
stream.writeInt(Block.all().size);

View File

@ -14,9 +14,9 @@ import io.anuke.mindustry.io.MapMeta;
import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.util.Bits;
import java.io.*;
@ -205,6 +205,10 @@ public class NetworkIO {
for (int j = 0; j < cores; j++) {
state.teams.get(team).cores.add(world.tile(stream.readInt()));
}
if(team == players[0].getTeam() && cores > 0){
Core.camera.position.set(state.teams.get(team).cores.first().drawx(), state.teams.get(team).cores.first().drawy(), 0);
}
}
world.endMapLoad();

View File

@ -8,11 +8,14 @@ import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.net.Packet.ImportantPacket;
import io.anuke.mindustry.net.Packet.UnimportantPacket;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.io.IOUtils;
import io.anuke.ucore.util.Mathf;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.world;
/**Class for storing all packets.*/
public class Packets {
@ -104,6 +107,7 @@ public class Packets {
public long timeSent;
//player snapshot data
public float x, y, pointerX, pointerY, rotation, baseRotation, xv, yv;
public Tile mining;
public boolean boosting;
@Override
@ -125,6 +129,8 @@ public class Packets {
//saving 4 bytes, yay?
buffer.putShort((short)(player.rotation*2));
buffer.putShort((short)(player.baseRotation*2));
buffer.putInt(player.getMineTile() == null ? -1 : player.getMineTile().packedPosition());
}
@Override
@ -142,6 +148,7 @@ public class Packets {
yv = buffer.get() / Unit.velocityPercision;
rotation = buffer.getShort()/2f;
baseRotation = buffer.getShort()/2f;
mining = world.tile(buffer.getInt());
}
}

View File

@ -26,6 +26,8 @@ public class Minimap extends Table {
Image image = new Image(new TextureRegionDrawable(new TextureRegion())){
@Override
public void draw(Batch batch, float parentAlpha) {
if(renderer.minimap().getRegion() == null) return;
TextureRegionDrawable draw = (TextureRegionDrawable)getDrawable();
draw.getRegion().setRegion(renderer.minimap().getRegion());
super.draw(batch, parentAlpha);

View File

@ -3,17 +3,11 @@ package io.anuke.mindustry.ui.dialogs;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.io.Map;
import io.anuke.mindustry.io.MapMeta;
import io.anuke.mindustry.io.MapTileData;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.mapgen.WorldGenerator;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.scene.event.Touchable;
import io.anuke.ucore.scene.ui.*;
import io.anuke.ucore.scene.ui.layout.Stack;
@ -21,7 +15,6 @@ import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.scene.utils.Elements;
import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.*;
@ -133,29 +126,8 @@ public class LevelDialog extends FloatingDialog{
Timers.run(5f, () -> {
Cursors.restoreCursor();
threads.run(() -> {
Timers.mark();
MapTileData data = WorldGenerator.generate();
Map map = new Map("generated-map", new MapMeta(0, new ObjectMap<>(), data.width(), data.height(), null), true, () -> null);
logic.reset();
world.beginMapLoad();
world.setMap(map);
int width = map.meta.width, height = map.meta.height;
Tile[][] tiles = world.createTiles(data.width(), data.height());
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
WorldGenerator.generate(tiles, data, true, Mathf.random(9999999));
world.endMapLoad();
Log.info("Time to generate: {0}", Timers.elapsed());
world.loadProceduralMap();
logic.play();
Gdx.app.postRunnable(ui.loadfrag::hide);
});
});

View File

@ -64,7 +64,7 @@ public class BlocksFragment implements Fragment{
aright();
//make it only be shown when needed.
visible(() -> !state.is(State.menu) && shown);
visible(() -> !state.is(State.menu));
//create the main blocks table
mainTable = new table(){{
@ -99,7 +99,7 @@ public class BlocksFragment implements Fragment{
}}.right().bottom().end().get();
visible(() -> !state.is(State.menu) && shown);
visible(() -> !state.is(State.menu));
}}.end().get();
@ -278,8 +278,9 @@ public class BlocksFragment implements Fragment{
}
void toggle(boolean show, float t, Interpolation ip){
if(!show){
mainTable.actions(Actions.translateBy(0, -mainTable.getHeight() - descTable.getHeight(), t, ip), Actions.call(() -> shown = false));
if(shown){
shown = false;
mainTable.actions(Actions.translateBy(0, mainTable.getTranslation().y + (-mainTable.getHeight() - descTable.getHeight()), t, ip));
}else{
shown = true;
mainTable.actions(Actions.translateBy(0, -mainTable.getTranslation().y, t, ip));

View File

@ -38,7 +38,7 @@ public class HudFragment implements Fragment{
private Label infolabel;
private Table lastUnlockTable;
private Table lastUnlockLayout;
private boolean shown = true;
private boolean shown = true, done = true;
private float dsize = 58;
private float isize = 40;
@ -103,7 +103,6 @@ public class HudFragment implements Fragment{
new table() {{
touchable(Touchable.enabled);
visible(() -> shown);
addWaveTable();
}}.fillX().end();
@ -262,7 +261,8 @@ public class HudFragment implements Fragment{
}
private void toggleMenus(){
if (wavetable.getActions().size != 0) return;
wavetable.clearActions();
infolabel.clearActions();
float dur = 0.3f;
Interpolation in = Interpolation.pow3Out;
@ -270,9 +270,10 @@ public class HudFragment implements Fragment{
flip.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up");
if (shown) {
shown = false;
blockfrag.toggle(false, dur, in);
wavetable.actions(Actions.translateBy(0, wavetable.getHeight() + dsize, dur, in), Actions.call(() -> shown = false));
infolabel.actions(Actions.translateBy(0, wavetable.getHeight(), dur, in), Actions.call(() -> shown = false));
wavetable.actions(Actions.translateBy(0, (wavetable.getHeight() + dsize) - wavetable.getTranslation().y, dur, in));
infolabel.actions(Actions.translateBy(0, (wavetable.getHeight()) - wavetable.getTranslation().y, dur, in));
} else {
shown = true;
blockfrag.toggle(true, dur, in);

View File

@ -186,7 +186,9 @@ public class CoreBlock extends StorageBlock {
BaseUnit unit = droneType.create(tile.getTeam());
entity.droneID = unit.id;
unit.setDead(true);
unit.setGroup(unitGroups[unit.getTeam().ordinal()]);
CallBlocks.onCoreUnitSet(tile, unit);
unit.setGroup(null);
}
}
@ -219,6 +221,8 @@ public class CoreBlock extends StorageBlock {
@Remote(called = Loc.server, in = In.blocks)
public static void onUnitRespawn(Tile tile, Unit player){
if(player == null) return;
CoreEntity entity = tile.entity();
Effects.effect(Fx.spawn, entity);
entity.solid = false;
@ -238,6 +242,8 @@ public class CoreBlock extends StorageBlock {
@Remote(called = Loc.server, in = In.blocks)
public static void onCoreUnitSet(Tile tile, Unit player){
if(player == null) return;
CoreEntity entity = tile.entity();
entity.currentUnit = player;
entity.progress = 0f;

View File

@ -26,7 +26,7 @@ import java.util.Locale;
import static io.anuke.mindustry.Vars.*;
public class DesktopPlatform extends Platform {
final static boolean useDiscord = !OS.is64Bit;
final static boolean useDiscord = OS.is64Bit;
final static String applicationId = "398246104468291591";
final static DateFormat format = SimpleDateFormat.getDateTimeInstance();
String[] args;

View File

@ -78,17 +78,24 @@ public class ServerControl extends Module {
}
if (mode != ShuffleMode.off) {
Array<Map> maps = mode == ShuffleMode.both ? world.maps().all() :
mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps();
if(world.maps().all().size > 0) {
Array<Map> maps = mode == ShuffleMode.both ? world.maps().all() :
mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps();
Map previous = world.getMap();
Map map = previous;
while (map == previous) map = maps.random();
Map previous = world.getMap();
Map map = previous;
while (map == previous) map = maps.random();
info("Selected next map to be {0}.", map.name);
state.set(State.playing);
logic.reset();
world.loadMap(map);
info("Selected next map to be {0}.", map.name);
state.set(State.playing);
logic.reset();
world.loadMap(map);
}else{
info("Selected a procedural map.");
world.loadProceduralMap();
logic.play();
}
}else{
state.set(State.menu);
Net.closeServer();
@ -129,11 +136,6 @@ public class ServerControl extends Module {
return;
}
if(world.maps().all().size == 0){
err("No maps found to host with!");
return;
}
Map result = null;
if(arg.length > 0) {
@ -147,25 +149,27 @@ public class ServerControl extends Module {
err("No map with name &y'{0}'&lr found.", search);
return;
}
GameMode mode;
try{
mode = arg.length < 2 ? GameMode.waves : GameMode.valueOf(arg[1]);
}catch (IllegalArgumentException e){
err("No gamemode '{0}' found.", arg[1]);
return;
}
info("Loading map...");
state.mode = mode;
logic.reset();
world.loadMap(result);
}else{
result = world.maps().all().random();
Log.info("&ly&fiNo map specified, so &lb{0}&ly was chosen randomly.", result.name);
world.loadProceduralMap();
Log.info("&ly&fiNo map specified, so a procedural one was generated.");
}
GameMode mode;
try{
mode = arg.length < 2 ? GameMode.waves : GameMode.valueOf(arg[1]);
}catch (IllegalArgumentException e){
err("No gamemode '{0}' found.", arg[1]);
return;
}
info("Loading map...");
state.mode = mode;
logic.reset();
world.loadMap(result);
state.set(State.playing);
logic.play();
info("Map loaded.");
host();