diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java index 2011cd7..67b0300 100644 --- a/src/mightypork/rogue/App.java +++ b/src/mightypork/rogue/App.java @@ -22,7 +22,7 @@ import mightypork.rogue.screens.main_menu.ScreenMainMenu; import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy; import mightypork.rogue.screens.test_cat_sound.ScreenTestCat; import mightypork.rogue.screens.test_render.ScreenTestRender; -import mightypork.rogue.world.Player; +import mightypork.rogue.world.PlayerEntity; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.map.Level; import mightypork.rogue.world.tile.Tile; @@ -110,7 +110,7 @@ public final class App extends BaseApp { Ion.registerBinary(Tile.ION_MARK, Tile.class); Ion.registerBinary(Item.ION_MARK, Item.class); Ion.registerBinary(Level.ION_MARK, Level.class); - Ion.registerBinary(Level.ION_MARK, Player.class); + Ion.registerBinary(Level.ION_MARK, PlayerEntity.class); } diff --git a/src/mightypork/rogue/world/WorldClient.java b/src/mightypork/rogue/world/ClientWorld.java similarity index 85% rename from src/mightypork/rogue/world/WorldClient.java rename to src/mightypork/rogue/world/ClientWorld.java index e63db14..4b48952 100644 --- a/src/mightypork/rogue/world/WorldClient.java +++ b/src/mightypork/rogue/world/ClientWorld.java @@ -10,11 +10,11 @@ import mightypork.util.constraints.vect.VectConst; import mightypork.util.control.timing.Updateable; -public class WorldClient implements Updateable { +public class ClientWorld implements Updateable, WorldAccess { private Level level = null; - private final Player player = null; + private final PlayerEntity player = null; @Override @@ -50,8 +50,8 @@ public class WorldClient implements Updateable { final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar) - final double playerX = player.getPosition().getXVisual(); - final double playerY = player.getPosition().getYVisual(); + final double playerX = player.getPosition().getVisualX(); + final double playerY = player.getPosition().getVisualY(); // total map area //@formatter:off @@ -63,9 +63,6 @@ public class WorldClient implements Updateable { ).freeze(); //@formatter:on - System.out.println(playerX + "," + playerY + " : " + mapRect); - System.out.println(level.getWidth() + "," + level.getHeight()); - // tiles to render final int x1 = (int) Math.floor(playerX - (vpW / tileSize)); final int y1 = (int) Math.floor(playerY - (vpH / tileSize)); @@ -81,9 +78,17 @@ public class WorldClient implements Updateable { } - public Player getPlayer() + public PlayerEntity getPlayer() { return player; } + + + @Override + public boolean isServer() + { + // TODO Auto-generated method stub + return false; + } } diff --git a/src/mightypork/rogue/world/MapGenerator.java b/src/mightypork/rogue/world/MapGenerator.java index 0c3efa0..bd69cdd 100644 --- a/src/mightypork/rogue/world/MapGenerator.java +++ b/src/mightypork/rogue/world/MapGenerator.java @@ -13,19 +13,19 @@ public class MapGenerator { public static final Random rand = new Random(); - public static WorldServer createWorld(long seed) + public static ServerWorld createWorld(long seed) { synchronized (rand) { rand.setSeed(seed); - final WorldServer w = new WorldServer(); + final ServerWorld w = new ServerWorld(); w.setSeed(seed); w.addLevel(createLevel(rand.nextLong(), Tiles.CRYSTAL_FLOOR, Tiles.CRYSTAL_WALL)); w.addLevel(createLevel(rand.nextLong(), Tiles.BRCOBBLE_FLOOR, Tiles.BRCOBBLE_WALL)); // TODO place on start position - w.addPlayer("local", new Player(10, 10, 0)); + w.addPlayer("local", new PlayerEntity(10, 10, 0)); return w; } } diff --git a/src/mightypork/rogue/world/MapObserver.java b/src/mightypork/rogue/world/MapObserver.java deleted file mode 100644 index a6b13a7..0000000 --- a/src/mightypork/rogue/world/MapObserver.java +++ /dev/null @@ -1,16 +0,0 @@ -package mightypork.rogue.world; - - -/** - * Player observing a map represented by an observer. - * - * @author MightyPork - */ -public interface MapObserver extends WorldEntity { - - /** - * @return observed range (in tiles) - */ - public int getViewRange(); - -} diff --git a/src/mightypork/rogue/world/PathStep.java b/src/mightypork/rogue/world/PathStep.java new file mode 100644 index 0000000..ae57b61 --- /dev/null +++ b/src/mightypork/rogue/world/PathStep.java @@ -0,0 +1,49 @@ +package mightypork.rogue.world; + + +import java.io.IOException; + +import mightypork.util.ion.IonBinary; +import mightypork.util.ion.IonInput; +import mightypork.util.ion.IonOutput; + + +public class PathStep implements IonBinary { + + public static final int ION_MARK = 0; + + public int x; + public int y; + + + public PathStep(int x, int y) { + this.x = x < 1 ? -1 : x > 0 ? 1 : 0; + this.y = y < 1 ? -1 : y > 0 ? 1 : 0; + + y = (int) Math.signum(x); + } + + + @Override + public void load(IonInput in) throws IOException + { + x = in.readByte(); + y = in.readByte(); + } + + + @Override + public void save(IonOutput out) throws IOException + { + out.writeByte(x); + out.writeByte(y); + } + + + @Override + public short getIonMark() + { + return ION_MARK; + } + +} diff --git a/src/mightypork/rogue/world/Player.java b/src/mightypork/rogue/world/Player.java deleted file mode 100644 index d7a1bc6..0000000 --- a/src/mightypork/rogue/world/Player.java +++ /dev/null @@ -1,140 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.IOException; - -import mightypork.util.ion.IonBinary; -import mightypork.util.ion.IonBundle; -import mightypork.util.ion.IonInput; -import mightypork.util.ion.IonOutput; - - -/** - * Player info - * - * @author MightyPork - */ -public class Player implements IonBinary, MapObserver { - - public static final short ION_MARK = 0; - - private final double walktime = 0.3; // possibly make changeable for speed potion - - private final WorldPos position = new WorldPos(); - private final WorldPos target = new WorldPos(); - private Runnable moveListenerCustom; - private Runnable moveListener = new Runnable() { - - @Override - public void run() - { - if (moveListenerCustom != null) moveListenerCustom.run(); - - if (!target.equals(position)) { - - int x = (target.x - position.x); - int y = (target.y - position.y); - - if (Math.abs(x) >= Math.abs(y)) y = 0; - if (Math.abs(y) > Math.abs(x)) x = 0; - - if (x > 0) x = 1; - if (x < 0) x = -1; - - if (y > 0) y = 1; - if (y < 0) y = -1; - - position.walk(x, y, walktime); - - } - } - }; - - - public Player() - { - position.setMoveListener(moveListener); - } - - - public Player(int x, int y, int floor) - { - position.setTo(x, y, floor); - target.setTo(position); - } - - - public Player(WorldPos pos) - { - this(pos.x, pos.y, pos.floor); - } - - - @Override - public void load(IonInput in) throws IOException - { - IonBundle ib = in.readBundle(); - ib.loadBundled("pos", position); - } - - - @Override - public void save(IonOutput out) throws IOException - { - IonBundle ib = new IonBundle(); - ib.putBundled("target", target); - out.writeBundle(ib); - } - - - @Override - public short getIonMark() - { - return ION_MARK; - } - - - @Override - public WorldPos getPosition() - { - return position; - } - - - @Override - public int getViewRange() - { - return 15; - } - - - public void teleport(WorldPos pos) - { - position.setTo(pos); - target.setTo(pos); - } - - - public void walk(int offsetX, int offsetY) - { - target.setTo(position.x + offsetX, position.y + offsetY, this.position.floor); - } - - - public void setMoveListener(Runnable r) - { - this.moveListenerCustom = r; - } - - - public void updateVisual(double delta) - { - position.update(delta); - } - - - public void updateLogic(double delta) - { - // server stuffs (sleep timer etc) - } -} diff --git a/src/mightypork/rogue/world/PlayerEntity.java b/src/mightypork/rogue/world/PlayerEntity.java new file mode 100644 index 0000000..f34f348 --- /dev/null +++ b/src/mightypork/rogue/world/PlayerEntity.java @@ -0,0 +1,83 @@ +package mightypork.rogue.world; + + +import java.io.IOException; + +import mightypork.rogue.world.map.MapObserver; +import mightypork.util.ion.IonBundle; + + +/** + * Player info + * + * @author MightyPork + */ +public class PlayerEntity extends WorldEntity implements MapObserver { + + public static final double PLAYER_STEP_TIME = 0.3; + + public boolean connected = false; + + + public PlayerEntity() { + super(); + } + + + public PlayerEntity(ServerWorld world, int x, int y, int floor) { + super(world, new WorldPos(x, y, floor)); + } + + + @Override + public void load(IonBundle bundle) throws IOException + { + super.load(bundle); + } + + + @Override + public void save(IonBundle bundle) throws IOException + { + super.save(bundle); + } + + + @Override + public int getViewRange() + { + return 15; + } + + + @Override + protected double getStepTime() + { + return PLAYER_STEP_TIME; + } + + + public boolean isConnected() + { + return connected; + } + + + public void setConnected(boolean connected) + { + this.connected = connected; + } + + + @Override + public WorldPos getViewPosition() + { + return getPosition(); + } + + @Override + public boolean isPhysical() + { + return isConnected(); + } +} diff --git a/src/mightypork/rogue/world/WorldServer.java b/src/mightypork/rogue/world/ServerWorld.java similarity index 66% rename from src/mightypork/rogue/world/WorldServer.java rename to src/mightypork/rogue/world/ServerWorld.java index 9d9fa66..341e7cb 100644 --- a/src/mightypork/rogue/world/WorldServer.java +++ b/src/mightypork/rogue/world/ServerWorld.java @@ -12,24 +12,28 @@ import mightypork.util.ion.IonBundled; /** - * World server. To a server, all players and levels are equal. + * World on a server. To a server, all players and levels are equal. * * @author MightyPork */ -public class WorldServer implements IonBundled, Updateable { +public class ServerWorld implements IonBundled, Updateable, WorldAccess { private final ArrayList levels = new ArrayList<>(); - private final Map players = new HashMap<>(); + private final Map players = new HashMap<>(); /** This seed can be used to re-create identical world. */ private long seed; + + /** Next spawned entity ID */ + private long eid; @Override public void load(IonBundle in) throws IOException { seed = in.get("seed", 0L); + eid = in.get("eid", 0L); in.loadSequence("levels", levels); in.loadMap("players", players); } @@ -39,6 +43,7 @@ public class WorldServer implements IonBundled, Updateable { public void save(IonBundle out) throws IOException { out.put("seed", seed); + out.put("eid", eid); out.putSequence("levels", levels); out.putMap("players", players); } @@ -49,7 +54,7 @@ public class WorldServer implements IonBundled, Updateable { levels.add(level); } - public void addPlayer(String name, Player player) + public void addPlayer(String name, PlayerEntity player) { players.put(name, player); } @@ -63,16 +68,16 @@ public class WorldServer implements IonBundled, Updateable { public void update(double delta) { // food meters and such - for (final Player pl : players.values()) { - pl.updateLogic(delta); + for (final PlayerEntity pl : players.values()) { + if(pl.isConnected()) pl.updateLogic(this, delta); } for (int level = 0; level < levels.size(); level++) { // more than 1 player can be on floor, update for all of them - for (final Player pl : players.values()) { + for (final PlayerEntity pl : players.values()) { if (pl.getPosition().floor == level) { - levels.get(level).updateLogic(pl, delta); + levels.get(level).updateLogic(this, pl, delta); } } @@ -90,4 +95,16 @@ public class WorldServer implements IonBundled, Updateable { { return seed; } + + + public long genEid() + { + return eid++; + } + + @Override + public boolean isServer() + { + return true; + } } diff --git a/src/mightypork/rogue/world/WorldAccess.java b/src/mightypork/rogue/world/WorldAccess.java index a34edbc..81d1192 100644 --- a/src/mightypork/rogue/world/WorldAccess.java +++ b/src/mightypork/rogue/world/WorldAccess.java @@ -3,4 +3,6 @@ package mightypork.rogue.world; public interface WorldAccess { + public boolean isServer(); + } diff --git a/src/mightypork/rogue/world/WorldEntity.java b/src/mightypork/rogue/world/WorldEntity.java index 13b1c99..d25c73e 100644 --- a/src/mightypork/rogue/world/WorldEntity.java +++ b/src/mightypork/rogue/world/WorldEntity.java @@ -1,10 +1,143 @@ package mightypork.rogue.world; -import mightypork.util.constraints.vect.Vect; +import java.io.IOException; +import java.util.LinkedList; +import java.util.Queue; +import mightypork.util.ion.IonBundle; +import mightypork.util.ion.IonBundled; -public interface WorldEntity { + +public abstract class WorldEntity implements IonBundled { + + private final WorldPos position = new WorldPos(); + private Runnable moveEndListener, pathEndListener; + + private long serial_id = 0L; + + private final Queue path = new LinkedList<>(); + + + public WorldEntity(ServerWorld world, WorldPos pos) { + this.serial_id = world.genEid(); + this.position.setTo(pos); + } + + + public WorldEntity() { + // for ion + } + + + @Override + public void save(IonBundle bundle) throws IOException + { + bundle.putBundled("pos", position); + bundle.putSequence("steps", path); + bundle.put("eid", serial_id); + } + + + @Override + public void load(IonBundle bundle) throws IOException + { + bundle.loadBundled("pos", position); + bundle.loadSequence("path", path); + serial_id = bundle.get("eid", 0L); + } + + + public void setMoveEndListener(Runnable moveEndListener) + { + this.moveEndListener = moveEndListener; + } + + + public void setPathEndListener(Runnable pathEndListener) + { + this.pathEndListener = pathEndListener; + } + + + public WorldPos getPosition() + { + return position; + } + + + public void setPosition(WorldPos pos) + { + position.setTo(pos); + } + + + public void setPosition(int x, int y, int floor) + { + position.setTo(x, y, floor); + cancelPath(); // discard remaining steps + } + + + /** + * @param world the world + * @param delta delta time + */ + public void updateLogic(WorldAccess world, double delta) + { + if(!isPhysical()) return; + + if (!position.isFinished()) { + position.update(delta); + } + + if (position.isFinished()) { + + if (moveEndListener != null) moveEndListener.run(); + + if (!path.isEmpty()) { + // get next step to walk + PathStep step = path.poll(); + position.walk(step.x, step.y, getStepTime()); + } else { + // notify AI or whatever + if (pathEndListener != null) pathEndListener.run(); + } + } + } + + + /** + * @param world the world + * @param delta delta time + */ + public void updateVisual(WorldAccess world, double delta) + { + } + + + public boolean isPathFinished() + { + return position.isFinished() && path.isEmpty(); + } + + + public void addStep(PathStep step) + { + path.add(step); + } + + + public void cancelPath() + { + path.clear(); + } + + + protected abstract double getStepTime(); + + public boolean isPhysical() { + return true; + } - WorldPos getPosition(); } diff --git a/src/mightypork/rogue/world/WorldPos.java b/src/mightypork/rogue/world/WorldPos.java index fc36fe3..7a78fb2 100644 --- a/src/mightypork/rogue/world/WorldPos.java +++ b/src/mightypork/rogue/world/WorldPos.java @@ -20,11 +20,9 @@ public class WorldPos implements IonBundled, Updateable { public int x, y, floor; private final VectAnimated walkOffset = new VectAnimated(Vect.ZERO, Easing.LINEAR); - private Runnable moveListener; - public WorldPos(int x, int y, int floor) - { + public WorldPos(int x, int y, int floor) { super(); this.x = x; this.y = y; @@ -32,8 +30,13 @@ public class WorldPos implements IonBundled, Updateable { } - public WorldPos() + public WorldPos() { + } + + + public double getProgress() { + return walkOffset.getProgress(); } @@ -74,13 +77,13 @@ public class WorldPos implements IonBundled, Updateable { } - public double getXVisual() + public double getVisualX() { return x + walkOffset.x(); } - public double getYVisual() + public double getVisualY() { return y + walkOffset.y(); } @@ -135,12 +138,6 @@ public class WorldPos implements IonBundled, Updateable { } - public void add(int x, int y) - { - setTo(this.x + x, this.y + y); - } - - public void walk(int x, int y, double secs) { setTo(this.x + x, this.y + y); @@ -152,17 +149,13 @@ public class WorldPos implements IonBundled, Updateable { @Override public void update(double delta) { - if (!walkOffset.isFinished()) { - walkOffset.update(delta); - } - - if (walkOffset.isFinished()) moveListener.run(); + walkOffset.update(delta); } - public void setMoveListener(Runnable listener) + public boolean isFinished() { - this.moveListener = listener; + return walkOffset.isFinished(); } } diff --git a/src/mightypork/rogue/world/map/Level.java b/src/mightypork/rogue/world/map/Level.java index d24bf48..2e2ee04 100644 --- a/src/mightypork/rogue/world/map/Level.java +++ b/src/mightypork/rogue/world/map/Level.java @@ -2,9 +2,12 @@ package mightypork.rogue.world.map; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; -import mightypork.rogue.world.MapObserver; -import mightypork.rogue.world.Player; +import mightypork.rogue.world.PlayerEntity; +import mightypork.rogue.world.WorldAccess; +import mightypork.rogue.world.WorldEntity; import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; @@ -30,19 +33,19 @@ public class Level implements MapAccess, IonBinary { /** Array of tiles [y][x] */ private Tile[][] tiles; + private final List entities = new ArrayList<>(); + /** Level seed (used for generation and tile variation) */ public long seed; private transient NoiseGen noiseGen; - public Level() - { + public Level() { } - public Level(int width, int height) - { + public Level(int width, int height) { this.width = width; this.height = height; buildArray(); @@ -136,6 +139,8 @@ public class Level implements MapAccess, IonBinary { width = ib.get("w", 0); height = ib.get("h", 0); + ib.loadSequence("entities", entities); + // init array of size buildArray(); @@ -159,6 +164,7 @@ public class Level implements MapAccess, IonBinary { ib.put("seed", seed); ib.put("w", width); ib.put("h", height); + ib.putSequence("entities", entities); out.writeBundle(ib); // tiles (writing this way to save space) @@ -178,25 +184,25 @@ public class Level implements MapAccess, IonBinary { } - public void updateLogic(MapObserver observer, double delta) + public void updateLogic(WorldAccess world, MapObserver observer, double delta) { - updateForObserver(observer, delta, true, false); + updateForObserver(world, observer, delta, true, false); } - public void updateVisual(Player player, double delta) + public void updateVisual(WorldAccess world, PlayerEntity player, double delta) { - updateForObserver(player, delta, false, true); + updateForObserver(world, player, delta, false, true); } - private void updateForObserver(MapObserver observer, double delta, boolean logic, boolean visual) + private void updateForObserver(WorldAccess world, MapObserver observer, double delta, boolean logic, boolean visual) { final int viewRange = observer.getViewRange(); - final WorldPos position = observer.getPosition(); + final WorldPos eyepos = observer.getViewPosition(); - int x1 = position.x - viewRange; - int y1 = position.y - viewRange; + int x1 = eyepos.x - viewRange; + int y1 = eyepos.y - viewRange; int x2 = x1 + viewRange * 2; int y2 = y1 + viewRange * 2; @@ -208,8 +214,8 @@ public class Level implements MapAccess, IonBinary { for (int y = y1; y <= y2; y++) { for (int x = x1; x <= x2; x++) { - if (logic) getTile(x, y).updateLogic(delta); - if (visual) getTile(x, y).updateVisual(delta); + if (logic) getTile(x, y).updateLogic(world, delta); + if (visual) getTile(x, y).updateVisual(world, delta); } } } diff --git a/src/mightypork/rogue/world/map/MapObserver.java b/src/mightypork/rogue/world/map/MapObserver.java new file mode 100644 index 0000000..8c41375 --- /dev/null +++ b/src/mightypork/rogue/world/map/MapObserver.java @@ -0,0 +1,13 @@ +package mightypork.rogue.world.map; + + +import mightypork.rogue.world.WorldPos; + + +public interface MapObserver { + + int getViewRange(); + + + WorldPos getViewPosition(); +} diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java index 6eb2a7b..0a6a1cb 100644 --- a/src/mightypork/rogue/world/tile/Tile.java +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -4,10 +4,10 @@ package mightypork.rogue.world.tile; import java.io.IOException; import java.util.Stack; +import mightypork.rogue.world.WorldAccess; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.map.TileRenderContext; import mightypork.util.control.timing.Animator; -import mightypork.util.control.timing.Updateable; import mightypork.util.ion.IonBinary; import mightypork.util.ion.IonBundle; import mightypork.util.ion.IonInput; @@ -99,14 +99,14 @@ public final class Tile implements IonBinary { } - public void updateLogic(double delta) + public void updateLogic(WorldAccess world, double delta) { - model.updateLogic(this, delta); + model.updateLogic(this, world, delta); } - public void updateVisual(double delta) + public void updateVisual(WorldAccess world, double delta) { - model.updateVisual(this, delta); + model.updateVisual(this, world, delta); if (hasItems()) { getItemRenderer().updateVisual(delta); } diff --git a/src/mightypork/rogue/world/tile/TileModel.java b/src/mightypork/rogue/world/tile/TileModel.java index 7f8f6cb..1169a72 100644 --- a/src/mightypork/rogue/world/tile/TileModel.java +++ b/src/mightypork/rogue/world/tile/TileModel.java @@ -1,6 +1,7 @@ package mightypork.rogue.world.tile; +import mightypork.rogue.world.WorldAccess; import mightypork.rogue.world.map.TileRenderContext; import mightypork.util.annotations.DefaultImpl; import mightypork.util.ion.IonBundle; @@ -17,8 +18,7 @@ public abstract class TileModel { public final int id; - public TileModel(int id) - { + public TileModel(int id) { Tiles.register(id, this); this.id = id; } @@ -73,18 +73,20 @@ public abstract class TileModel { * Update tile state etc * * @param tile tile + * @param world * @param delta delta time */ - public abstract void updateLogic(Tile tile, double delta); + public abstract void updateLogic(Tile tile, WorldAccess world, double delta); /** * Update tile effects * * @param tile tile + * @param world * @param delta delta time */ - public abstract void updateVisual(Tile tile, double delta); + public abstract void updateVisual(Tile tile, WorldAccess world, double delta); /**