Removed useless "multiplayer" crap and converted to singleplayer

v5stable
Ondřej Hruška 10 years ago
parent 9e4a237192
commit 3e69505787
  1. 0
      res/img/tiles.png
  2. 0
      res/img/tiles.xcf
  3. 31
      src/mightypork/gamecore/render/Render.java
  4. 3
      src/mightypork/gamecore/render/fonts/impl/CachedFont.java
  5. 24
      src/mightypork/gamecore/render/textures/DeferredTexture.java
  6. 6
      src/mightypork/rogue/App.java
  7. 2
      src/mightypork/rogue/Res.java
  8. 119
      src/mightypork/rogue/screens/ingame/WorldLayer.java
  9. 2
      src/mightypork/rogue/screens/test_cat_sound/LayerFlyingCat.java
  10. 94
      src/mightypork/rogue/world/ClientWorld.java
  11. 16
      src/mightypork/rogue/world/ClientWorldAccess.java
  12. 64
      src/mightypork/rogue/world/LevelRenderer.java
  13. 10
      src/mightypork/rogue/world/MapGenerator.java
  14. 3
      src/mightypork/rogue/world/PathStep.java
  15. 83
      src/mightypork/rogue/world/PlayerEntity.java
  16. 62
      src/mightypork/rogue/world/PlayerInfo.java
  17. 107
      src/mightypork/rogue/world/ServerWorld.java
  18. 121
      src/mightypork/rogue/world/World.java
  19. 8
      src/mightypork/rogue/world/WorldAccess.java
  20. 143
      src/mightypork/rogue/world/WorldEntity.java
  21. 30
      src/mightypork/rogue/world/WorldPos.java
  22. 44
      src/mightypork/rogue/world/entity/Entities.java
  23. 192
      src/mightypork/rogue/world/entity/Entity.java
  24. 71
      src/mightypork/rogue/world/entity/models/EntityModel.java
  25. 67
      src/mightypork/rogue/world/entity/models/PlayerModel.java
  26. 8
      src/mightypork/rogue/world/entity/renderers/EntityRenderer.java
  27. 6
      src/mightypork/rogue/world/entity/renderers/NullEntityRenderer.java
  28. 2
      src/mightypork/rogue/world/item/Item.java
  29. 2
      src/mightypork/rogue/world/item/Items.java
  30. 330
      src/mightypork/rogue/world/level/Level.java
  31. 2
      src/mightypork/rogue/world/level/MapAccess.java
  32. 3
      src/mightypork/rogue/world/level/render/EntityRenderContext.java
  33. 3
      src/mightypork/rogue/world/level/render/MapRenderContext.java
  34. 13
      src/mightypork/rogue/world/level/render/TileRenderContext.java
  35. 248
      src/mightypork/rogue/world/map/Level.java
  36. 13
      src/mightypork/rogue/world/map/MapObserver.java
  37. 3
      src/mightypork/rogue/world/tile/DroppedItemRenderer.java
  38. 47
      src/mightypork/rogue/world/tile/Tile.java
  39. 3
      src/mightypork/rogue/world/tile/Tiles.java
  40. 2
      src/mightypork/rogue/world/tile/models/AbstractNullTile.java
  41. 14
      src/mightypork/rogue/world/tile/models/SimpleTile.java
  42. 20
      src/mightypork/rogue/world/tile/models/TileModel.java
  43. 5
      src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java
  44. 4
      src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java
  45. 6
      src/mightypork/rogue/world/tile/renderers/TileRenderer.java
  46. 41
      src/mightypork/util/ion/IonBundle.java
  47. 2
      src/mightypork/util/ion/IonInput.java
  48. 2
      src/mightypork/util/ion/IonOutput.java

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

@ -5,9 +5,11 @@ import static org.lwjgl.opengl.GL11.*;
import java.io.IOException;
import mightypork.gamecore.audio.players.EffectPlayer;
import mightypork.gamecore.render.textures.FilterMode;
import mightypork.gamecore.render.textures.GLTexture;
import mightypork.gamecore.render.textures.TxQuad;
import mightypork.rogue.Res;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.caching.RectDigest;
import mightypork.util.constraints.vect.Vect;
@ -230,6 +232,8 @@ public class Render {
}
private static int pushed = 0;
/** Can be used to avoid texture binding and glBegin/glEnd in textured quads */
public static boolean batchTexturedQuadMode;
/**
@ -432,14 +436,14 @@ public class Render {
*/
public static void quadTextured(Rect quad, Rect uvs, GLTexture texture, Color tint)
{
glEnable(GL_TEXTURE_2D);
texture.bind();
if (!batchTexturedQuadMode) {
glEnable(GL_TEXTURE_2D);
texture.bind();
glBegin(GL_QUADS);
}
setColor(tint);
glBegin(GL_QUADS);
final RectDigest q = quad.digest();
final RectDigest u = uvs.digest();
@ -458,7 +462,8 @@ public class Render {
glTexCoord2d(u.left * w, u.top * h);
glVertex2d(q.left, q.top);
glEnd();
if (!batchTexturedQuadMode) glEnd();
}
@ -544,4 +549,18 @@ public class Render {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
public static void enterBatchTexturedQuadMode(GLTexture texture)
{
texture.bind();
GL11.glBegin(GL11.GL_QUADS);
batchTexturedQuadMode = true;
}
public static void leaveBatchTexturedQuadMode()
{
GL11.glEnd();
batchTexturedQuadMode = false;
}
}

@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import mightypork.gamecore.render.fonts.GLFont;
import mightypork.gamecore.render.textures.DeferredTexture;
import mightypork.gamecore.render.textures.FilterMode;
import mightypork.util.constraints.vect.Vect;
import mightypork.util.constraints.vect.VectConst;
@ -374,6 +375,8 @@ public class CachedFont implements GLFont {
{
GLUtils.checkGLContext();
DeferredTexture.lastBind = null; // needs rebind.
// PUSH
glPushAttrib(GL_ENABLE_BIT);

@ -19,6 +19,8 @@ import org.lwjgl.opengl.GL11;
@MustLoadInMainThread
public class DeferredTexture extends DeferredResource implements GLTexture {
public static DeferredTexture lastBind = null;
private org.newdawn.slick.opengl.Texture backingTexture;
private FilterMode filter = FilterMode.NEAREST;
private WrapMode wrap = WrapMode.CLAMP;
@ -70,15 +72,19 @@ public class DeferredTexture extends DeferredResource implements GLTexture {
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter.num);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureID());
if (lastBind != this) {
lastBind = this;
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter.num);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureID());
}
}

@ -22,9 +22,9 @@ 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.PlayerEntity;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.control.eventbus.EventBus;
import mightypork.util.control.eventbus.events.Event;
@ -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, PlayerEntity.class);
Ion.registerBinary(Entity.ION_MARK, Entity.class);
}

@ -76,7 +76,7 @@ public final class Res {
textures.addQuad("xp_off", gui.makeQuad(.5, 1.5, .5, .5));
textures.addQuad("panel", gui.makeQuad(0, 3.75, 4, .25));
texture = textures.loadTexture("tiles", "/res/img/map_tiles.png", FilterMode.NEAREST, WrapMode.CLAMP);
texture = textures.loadTexture("tiles", "/res/img/tiles.png", FilterMode.NEAREST, WrapMode.CLAMP);
final QuadGrid tiles = texture.grid(32, 32);
textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1));

@ -7,9 +7,6 @@ import java.util.Random;
import mightypork.gamecore.gui.screens.Screen;
import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.gamecore.input.InputSystem;
import mightypork.gamecore.input.KeyStroke;
import mightypork.gamecore.input.Keys;
import mightypork.rogue.Paths;
import mightypork.rogue.world.MapGenerator;
import mightypork.rogue.world.World;
@ -28,7 +25,7 @@ public class WorldLayer extends ScreenLayer {
final World w = MapGenerator.createWorld(rand.nextLong());
try {
Ion.toFile(new File(Paths.WORKDIR,"test-world.ion"), w);
Ion.toFile(new File(Paths.WORKDIR, "test-world.ion"), w);
} catch (final IOException e) {
e.printStackTrace();
System.exit(1);
@ -49,63 +46,63 @@ public class WorldLayer extends ScreenLayer {
wr.setRect(root);
root.add(wr);
bindKey(new KeyStroke(true, Keys.LEFT), new Runnable() {
@Override
public void run()
{
w.getPlayer().walk(-1, 0);
}
});
bindKey(new KeyStroke(true, Keys.RIGHT), new Runnable() {
@Override
public void run()
{
w.getPlayer().walk(1, 0);
}
});
bindKey(new KeyStroke(true, Keys.UP), new Runnable() {
@Override
public void run()
{
w.getPlayer().walk(0, -1);
}
});
bindKey(new KeyStroke(true, Keys.DOWN), new Runnable() {
@Override
public void run()
{
w.getPlayer().walk(0, 1);
}
});
bindKey(new KeyStroke(true, Keys.SPACE), new Runnable() {
@Override
public void run()
{
w.getPlayer().walk(5, 5);
}
});
w.getPlayer().setMoveListener(new Runnable() {
@Override
public void run()
{
if (InputSystem.isKeyDown(Keys.LEFT)) {
w.getPlayer().walk(-1, 0);
} else if (InputSystem.isKeyDown(Keys.RIGHT)) {
w.getPlayer().walk(1, 0);
} else if (InputSystem.isKeyDown(Keys.UP)) {
w.getPlayer().walk(0, -1);
} else if (InputSystem.isKeyDown(Keys.DOWN)) {
w.getPlayer().walk(0, 1);
}
}
});
// bindKey(new KeyStroke(true, Keys.LEFT), new Runnable() {
//
// @Override
// public void run()
// {
// w.getPlayer().walk(-1, 0);
// }
// });
// bindKey(new KeyStroke(true, Keys.RIGHT), new Runnable() {
//
// @Override
// public void run()
// {
// w.getPlayer().walk(1, 0);
// }
// });
// bindKey(new KeyStroke(true, Keys.UP), new Runnable() {
//
// @Override
// public void run()
// {
// w.getPlayer().walk(0, -1);
// }
// });
// bindKey(new KeyStroke(true, Keys.DOWN), new Runnable() {
//
// @Override
// public void run()
// {
// w.getPlayer().walk(0, 1);
// }
// });
// bindKey(new KeyStroke(true, Keys.SPACE), new Runnable() {
//
// @Override
// public void run()
// {
// w.getPlayer().walk(5, 5);
// }
// });
//
// w.getPlayer().setMoveListener(new Runnable() {
//
// @Override
// public void run()
// {
// if (InputSystem.isKeyDown(Keys.LEFT)) {
// w.getPlayer().walk(-1, 0);
// } else if (InputSystem.isKeyDown(Keys.RIGHT)) {
// w.getPlayer().walk(1, 0);
// } else if (InputSystem.isKeyDown(Keys.UP)) {
// w.getPlayer().walk(0, -1);
// } else if (InputSystem.isKeyDown(Keys.DOWN)) {
// w.getPlayer().walk(0, 1);
// }
// }
// });
}

@ -90,7 +90,7 @@ public class LayerFlyingCat extends ScreenLayer implements MouseButtonEvent.List
{
if (!event.isDown()) return;
cat_position.setTo(event.getPos());
cat_position.animate(event.getPos());
final double newSize = root.height().perc(10 + rand.nextInt(40)).value();

@ -1,94 +0,0 @@
package mightypork.rogue.world;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.RectConst;
import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.constraints.vect.VectConst;
import mightypork.util.control.timing.Updateable;
public class ClientWorld implements Updateable, WorldAccess {
private Level level = null;
private final PlayerEntity player = null;
@Override
public void update(double delta)
{
player.update(delta);
level.updateVisual(player, delta);
}
/**
* Draw on screen
*
* @param viewport rendering area on screen
* @param xTiles Desired nr of tiles horizontally
* @param yTiles Desired nr of tiles vertically
* @param minSize minimum tile size
*/
public void render(final RectBound viewport, final int yTiles, final int xTiles, final int minSize)
{
final Rect r = viewport.getRect();
final double vpH = r.height().value();
final double vpW = r.width().value();
// adjust tile size to fit desired amount of tiles
final double allowedSizeW = vpW / xTiles;
final double allowedSizeH = vpH / yTiles;
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize));
tileSize -= tileSize % 16;
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().getVisualX();
final double playerY = player.getPosition().getVisualY();
// total map area
//@formatter:off
final RectConst mapRect = vpCenter.startRect().grow(
playerX*tileSize,
(level.getWidth() - playerX) * tileSize,
playerY*tileSize,
(level.getHeight() - playerY) * tileSize
).freeze();
//@formatter:on
// tiles to render
final int x1 = (int) Math.floor(playerX - (vpW / tileSize));
final int y1 = (int) Math.floor(playerY - (vpH / tileSize));
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize));
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize));
final TileRenderContext trc = new TileRenderContext(level, mapRect); //-tileSize*0.5
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
trc.render();
}
}
}
public PlayerEntity getPlayer()
{
return player;
}
@Override
public boolean isServer()
{
// TODO Auto-generated method stub
return false;
}
}

@ -1,16 +0,0 @@
package mightypork.rogue.world;
import mightypork.rogue.world.map.Level;
import mightypork.util.control.timing.Updateable;
/**
* Abstraction of client-server connection from the client's view
*
* @author MightyPork
*/
public abstract class ClientWorldAccess implements Updateable {
public abstract Level getLevel();
}

@ -1,64 +0,0 @@
package mightypork.rogue.world;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.RectConst;
import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.constraints.vect.VectConst;
public class LevelRenderer {
/**
* Draw on screen
*
* @param viewport rendering area on screen
* @param xTiles Desired nr of tiles horizontally
* @param yTiles Desired nr of tiles vertically
* @param minSize minimum tile size
*/
public static void render(Level level, PlayerEntity player, RectBound viewport, final int yTiles, final int xTiles, final int minSize)
{
final Rect r = viewport.getRect();
final double vpH = r.height().value();
final double vpW = r.width().value();
// adjust tile size to fit desired amount of tiles
final double allowedSizeW = vpW / xTiles;
final double allowedSizeH = vpH / yTiles;
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize));
tileSize -= tileSize % 16;
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().getVisualX();
final double playerY = player.getPosition().getVisualY();
// total map area
//@formatter:off
final RectConst mapRect = vpCenter.startRect().grow(
playerX*tileSize,
(level.getWidth() - playerX) * tileSize,
playerY*tileSize,
(level.getHeight() - playerY) * tileSize
).freeze();
//@formatter:on
// tiles to render
final int x1 = (int) Math.floor(playerX - (vpW / tileSize));
final int y1 = (int) Math.floor(playerY - (vpH / tileSize));
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize));
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize));
final TileRenderContext trc = new TileRenderContext(level, mapRect); //-tileSize*0.5
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
trc.render();
}
}
}
}

@ -3,9 +3,9 @@ package mightypork.rogue.world;
import java.util.Random;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tiles;
import mightypork.rogue.world.tile.models.TileModel;
public class MapGenerator {
@ -13,19 +13,19 @@ public class MapGenerator {
public static final Random rand = new Random();
public static ServerWorld createWorld(long seed)
public static World createWorld(long seed)
{
synchronized (rand) {
rand.setSeed(seed);
final ServerWorld w = new ServerWorld();
final World w = new World();
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 PlayerEntity(10, 10, 0));
w.createPlayer(10, 10, 0);
return w;
}
}

@ -16,7 +16,8 @@ public class PathStep implements IonBinary {
public int y;
public PathStep(int x, 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;

@ -1,83 +0,0 @@
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();
}
}

@ -0,0 +1,62 @@
package mightypork.rogue.world;
import java.io.IOException;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
public class PlayerInfo implements IonBundled {
private int eid = -1; // marks not initialized
private int level;
@Override
public void load(IonBundle bundle) throws IOException
{
eid = bundle.get("attached_eid", 0);
level = bundle.get("current_level", 0);
}
@Override
public void save(IonBundle bundle) throws IOException
{
bundle.put("attached_eid", eid);
bundle.put("current_level", level);
}
public void setEID(int eid)
{
if (isInitialized()) throw new RuntimeException("Cannot change player EID.");
this.eid = eid;
}
public void setLevel(int level)
{
this.level = level;
}
public int getEID()
{
return eid;
}
public int getLevel()
{
return level;
}
public boolean isInitialized()
{
return eid != -1;
}
}

@ -1,107 +0,0 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.util.*;
import mightypork.rogue.world.map.Level;
import mightypork.util.control.timing.Updateable;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
/**
* World on a server. To a server, all players and levels are equal.
*
* @author MightyPork
*/
public class ServerWorld implements IonBundled, Updateable, WorldAccess {
private final ArrayList<Level> levels = new ArrayList<>();
private final Map<String, PlayerEntity> 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);
}
@Override
public void save(IonBundle out) throws IOException
{
out.put("seed", seed);
out.put("eid", eid);
out.putSequence("levels", levels);
out.putMap("players", players);
}
public void addLevel(Level level)
{
levels.add(level);
}
public void addPlayer(String name, PlayerEntity player)
{
players.put(name, player);
}
public void removePlayer(String name)
{
players.remove(name);
}
@Override
public void update(double delta)
{
Set<Integer> occupiedLevels = new HashSet<>();
// food meters and such
for (final PlayerEntity pl : players.values()) {
if(pl.isConnected()) {
pl.updateLogic(this, delta);
occupiedLevels.add(pl.getPosition().floor);
}
}
for(int i : occupiedLevels) {
levels.get(i).updateLogic(this, delta);
}
}
public void setSeed(long seed)
{
this.seed = seed;
}
public long getSeed()
{
return seed;
}
public long generateEntityId()
{
return eid++;
}
@Override
public boolean isServer()
{
return true;
}
}

@ -0,0 +1,121 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.util.ArrayList;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.Level;
import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.control.timing.Updateable;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
/**
* World on a server. To a server, all players and levels are equal.
*
* @author MightyPork
*/
public class World implements IonBundled, Updateable {
private final ArrayList<Level> levels = new ArrayList<>();
private final PlayerInfo player = new PlayerInfo();
private long seed; // world seed
private int eid; // next entity ID
@Override
public void load(IonBundle in) throws IOException
{
seed = in.get("seed", 0L);
eid = in.get("next_eid", 0);
in.loadSequence("levels", levels);
in.loadBundled("player", player);
}
@Override
public void save(IonBundle out) throws IOException
{
out.put("seed", seed);
out.put("next_eid", eid);
out.putSequence("levels", levels);
out.putBundled("player", player);
}
public void addLevel(Level level)
{
levels.add(level);
}
@Override
public void update(double delta)
{
getCurrentLevel().update(delta);
}
public void setSeed(long seed)
{
this.seed = seed;
}
public long getSeed()
{
return seed;
}
/**
* @return new entity ID
*/
public int getNewEID()
{
return eid++;
}
public void createPlayer(int x, int y, int level)
{
if (player.isInitialized()) {
throw new RuntimeException("Player already created.");
}
// make entity
int playerEid = getNewEID();
final Entity entity = Entities.PLAYER.createEntity(playerEid, new WorldPos(x, y));
player.setLevel(level);
player.setEID(playerEid);
levels.get(level).addEntity(entity);
}
/**
* Draw on screen
*
* @param viewport rendering area on screen
* @param xTiles Desired nr of tiles horizontally
* @param yTiles Desired nr of tiles vertically
* @param minSize minimum tile size
*/
public void render(RectBound viewport, final int yTiles, final int xTiles, final int minSize)
{
getCurrentLevel().render(player, viewport, yTiles, xTiles, minSize);
}
public Level getCurrentLevel()
{
return levels.get(player.getLevel());
}
}

@ -1,8 +0,0 @@
package mightypork.rogue.world;
public interface WorldAccess {
public boolean isServer();
}

@ -1,143 +0,0 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
public abstract class WorldEntity implements IonBundled {
private final WorldPos position = new WorldPos();
private Runnable moveEndListener, pathEndListener;
private long serial_id = 0L;
private final Queue<PathStep> path = new LinkedList<>();
public WorldEntity(ServerWorld world, WorldPos pos) {
this.serial_id = world.generateEntityId();
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;
}
}

@ -18,19 +18,20 @@ import mightypork.util.math.Easing;
*/
public class WorldPos implements IonBundled, Updateable {
public int x, y, floor;
public int x, y;
private final VectAnimated walkOffset = new VectAnimated(Vect.ZERO, Easing.LINEAR);
public WorldPos(int x, int y, int floor) {
public WorldPos(int x, int y)
{
super();
this.x = x;
this.y = y;
this.floor = floor;
}
public WorldPos() {
public WorldPos()
{
}
@ -45,7 +46,6 @@ public class WorldPos implements IonBundled, Updateable {
{
x = in.get("x", 0);
y = in.get("y", 0);
floor = in.get("z", 0);
walkOffset.reset();
}
@ -55,7 +55,6 @@ public class WorldPos implements IonBundled, Updateable {
{
out.put("x", x);
out.put("y", y);
out.put("z", floor);
}
@ -71,12 +70,6 @@ public class WorldPos implements IonBundled, Updateable {
}
public double getFloor()
{
return floor;
}
public double getVisualX()
{
return x + walkOffset.x();
@ -97,18 +90,9 @@ public class WorldPos implements IonBundled, Updateable {
}
public void setTo(int x, int y, int floor)
{
this.x = x;
this.y = y;
this.floor = floor;
walkOffset.reset();
}
public void setTo(WorldPos other)
{
setTo(other.x, other.y, other.floor);
setTo(other.x, other.y);
}
@ -117,7 +101,6 @@ public class WorldPos implements IonBundled, Updateable {
{
final int prime = 31;
int result = 1;
result = prime * result + floor;
result = prime * result + x;
result = prime * result + y;
return result;
@ -131,7 +114,6 @@ public class WorldPos implements IonBundled, Updateable {
if (obj == null) return false;
if (!(obj instanceof WorldPos)) return false;
final WorldPos other = (WorldPos) obj;
if (floor != other.floor) return false;
if (x != other.x) return false;
if (y != other.y) return false;
return true;

@ -0,0 +1,44 @@
package mightypork.rogue.world.entity;
import mightypork.rogue.world.entity.models.EntityModel;
import mightypork.rogue.world.entity.models.PlayerModel;
/**
* Tile registry
*
* @author MightyPork
*/
public final class Entities {
private static final EntityModel[] entities = new EntityModel[256];
public static final EntityModel PLAYER = new PlayerModel(0);
public static void register(int id, EntityModel model)
{
if (id < 0 || id >= entities.length) {
throw new IllegalArgumentException("Entity model ID " + id + " is out of range.");
}
if (entities[id] != null) {
throw new IllegalArgumentException("Entity model ID " + id + " already in use.");
}
entities[id] = model;
}
public static EntityModel get(int id)
{
final EntityModel e = entities[id];
if (e == null) {
throw new IllegalArgumentException("No entity model with ID " + id + ".");
}
return e;
}
}

@ -0,0 +1,192 @@
package mightypork.rogue.world.entity;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import mightypork.rogue.world.PathStep;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.models.EntityModel;
import mightypork.rogue.world.level.Level;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
import mightypork.util.ion.IonInput;
import mightypork.util.ion.IonOutput;
/**
* World entity (mob or player)
*
* @author MightyPork
*/
public final class Entity implements IonBinary, IonBundled {
// binary & bundled - binary stores via a bundle
public static final int ION_MARK = 52;
private final WorldPos position = new WorldPos();
/** Entity ID */
private int eid = 0;
/** Model ID */
private int id;
private final Queue<PathStep> path = new LinkedList<>();
private EntityModel model;
private final IonBundle metadata = new IonBundle();
public Entity(int eid, WorldPos pos, EntityModel entityModel)
{
this.eid = eid;
this.position.setTo(pos);
setModel(entityModel);
}
private void setModel(EntityModel entityModel)
{
this.id = entityModel.id;
this.model = entityModel;
}
public Entity()
{
// for ion
}
@Override
public short getIonMark()
{
return ION_MARK;
}
@Override
public void save(IonOutput out) throws IOException
{
final IonBundle ib = new IonBundle();
save(ib);
out.writeBundle(ib);
}
@Override
public void load(IonInput in) throws IOException
{
load(in.readBundle());
}
@Override
public void save(IonBundle bundle) throws IOException
{
bundle.put("id", id);
bundle.putBundled("pos", position);
bundle.putSequence("steps", path);
bundle.put("eid", eid);
bundle.put("metadata", metadata);
}
@Override
public void load(IonBundle bundle) throws IOException
{
id = bundle.get("id", 0);
if (model == null || id != model.id) {
setModel(Entities.get(id));
}
bundle.loadBundled("pos", position);
bundle.loadSequence("path", path);
eid = bundle.get("eid", eid);
metadata.clear();
bundle.loadBundle("metadata", metadata);
}
public int getEID()
{
return eid;
}
public WorldPos getPosition()
{
return position;
}
public void setPosition(WorldPos pos)
{
position.setTo(pos);
}
public void setPosition(int x, int y)
{
position.setTo(x, y);
cancelPath(); // discard remaining steps
}
/**
* @param world the world
* @param delta delta time
*/
public void update(World world, Level level, double delta)
{
if (!position.isFinished()) {
position.update(delta);
}
if (position.isFinished()) {
model.onStepFinished(this, world, level);
if (!path.isEmpty()) {
// get next step to walk
final PathStep step = path.poll();
position.walk(step.x, step.y, getStepTime());
} else {
// notify AI or whatever
model.onPathFinished(this, world, level);
}
}
}
public boolean isPathFinished()
{
return position.isFinished() && path.isEmpty();
}
public void addStep(PathStep step)
{
path.add(step);
}
public void cancelPath()
{
path.clear();
}
protected double getStepTime()
{
return model.getStepTime(this);
}
}

@ -0,0 +1,71 @@
package mightypork.rogue.world.entity.models;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.renderers.EntityRenderer;
import mightypork.rogue.world.level.Level;
/**
* Entity model
*
* @author MightyPork
*/
public abstract class EntityModel {
/** Model ID */
public final int id;
public EntityRenderer renderer = EntityRenderer.NONE;
public EntityModel(int id)
{
Entities.register(id, this);
this.id = id;
}
public EntityModel setRenderer(EntityRenderer renderer)
{
this.renderer = renderer;
return this;
}
/**
* @return new tile of this type; if 100% invariant, can return cached one.
*/
public Entity createEntity(int eid, WorldPos pos)
{
return new Entity(eid, pos, this);
}
/**
* Update entity
*/
public abstract void update(Entity entity, Level level, double delta);
/**
* @return true if this entity type has metadata worth saving
*/
public abstract boolean hasMetadata();
/**
* @param entity the value is valid for
* @return step time (seconds)
*/
public abstract double getStepTime(Entity entity);
public abstract void onStepFinished(Entity entity, World world, Level level);
public abstract void onPathFinished(Entity entity, World world, Level level);
}

@ -0,0 +1,67 @@
package mightypork.rogue.world.entity.models;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.Level;
/**
* Player info
*
* @author MightyPork
*/
public class PlayerModel extends EntityModel {
private static final double STEP_TIME = 0.3;
public PlayerModel(int id)
{
super(id);
}
@Override
public Entity createEntity(int eid, WorldPos pos)
{
final Entity e = super.createEntity(eid, pos);
// set metadata
return e;
}
@Override
public void update(Entity entity, Level level, double delta)
{
}
@Override
public boolean hasMetadata()
{
return true;
}
@Override
public double getStepTime(Entity entity)
{
return STEP_TIME;
}
@Override
public void onStepFinished(Entity entity, World world, Level level)
{
}
@Override
public void onPathFinished(Entity entity, World world, Level level)
{
}
}

@ -0,0 +1,8 @@
package mightypork.rogue.world.entity.renderers;
public class EntityRenderer {
public static final EntityRenderer NONE = new NullEntityRenderer();
}

@ -0,0 +1,6 @@
package mightypork.rogue.world.entity.renderers;
public class NullEntityRenderer extends EntityRenderer {
}

@ -13,7 +13,7 @@ public class Item implements IonBinary {
public static final short ION_MARK = 51;
private transient ItemModel model;
private ItemModel model;
public int id;

@ -11,7 +11,7 @@ public final class Items {
private static final ItemModel[] items = new ItemModel[256];
static void register(int id, ItemModel model)
public static void register(int id, ItemModel model)
{
if (id < 0 || id >= items.length) if (items[id] != null) throw new IllegalArgumentException("Item ID " + id + " already in use.");

@ -0,0 +1,330 @@
package mightypork.rogue.world.level;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.lwjgl.opengl.GL11;
import mightypork.gamecore.render.Render;
import mightypork.rogue.Res;
import mightypork.rogue.world.PlayerInfo;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.Tiles;
import mightypork.rogue.world.tile.models.TileModel;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.RectConst;
import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.constraints.vect.VectConst;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonInput;
import mightypork.util.ion.IonOutput;
import mightypork.util.math.noise.NoiseGen;
/**
* One level of the dungeon
*
* @author MightyPork
*/
public class Level implements MapAccess, IonBinary {
public static final int ION_MARK = 53;
private static final boolean USE_BATCH_RENDERING = true;
private int width, height;
/** Array of tiles [y][x] */
private Tile[][] tiles;
private final Map<Integer, Entity> entity_map = new HashMap<>();
private final Set<Entity> entity_set = new HashSet<>();
/** Level seed (used for generation and tile variation) */
public long seed;
private transient NoiseGen noiseGen;
public Level()
{
}
public Level(int width, int height)
{
this.width = width;
this.height = height;
buildArray();
}
private void buildArray()
{
this.tiles = new Tile[height][width];
}
public void fill(short id)
{
fill(Tiles.get(id));
}
public void fill(TileModel model)
{
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
tiles[y][x] = model.createTile();
}
}
}
@Override
public final Tile getTile(int x, int y)
{
if (x < 0 || x >= width || y < 0 || y >= height) return Tiles.NULL_SOLID.createTile(); // out of range
return tiles[y][x];
}
public final void setTile(TileModel model, int x, int y)
{
setTile(model.createTile(), x, y);
}
public final void setTile(int tileId, int x, int y)
{
setTile(new Tile(tileId), x, y);
}
public final void setTile(Tile tile, int x, int y)
{
if (x < 0 || x > width || y < 0 || y >= height) return; // out of range
tiles[y][x] = tile;
}
@Override
public final int getWidth()
{
return width;
}
@Override
public final int getHeight()
{
return height;
}
public void setSeed(long seed)
{
this.seed = seed;
}
@Override
public long getSeed()
{
return seed;
}
@Override
public void load(IonInput in) throws IOException
{
// metadata
final IonBundle ib = in.readBundle();
seed = ib.get("seed", 0L);
width = ib.get("w", 0);
height = ib.get("h", 0);
ib.loadSequence("entities", entity_set);
for (final Entity ent : entity_set) {
entity_map.put(ent.getEID(), ent);
}
// init array of size
buildArray();
// load tiles
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// no mark
tiles[y][x] = new Tile();
tiles[y][x].load(in);
}
}
}
@Override
public void save(IonOutput out) throws IOException
{
// metadata
final IonBundle ib = new IonBundle();
ib.put("seed", seed);
ib.put("w", width);
ib.put("h", height);
ib.putSequence("entities", entity_set);
out.writeBundle(ib);
// tiles (writing this way to save space)
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// no mark to save space
tiles[y][x].save(out);
}
}
}
@Override
public short getIonMark()
{
return ION_MARK;
}
public void update(double delta)
{
// just update them all
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
getTile(x, y).update(this, delta);
}
}
}
@Override
public NoiseGen getNoiseGen()
{
if (noiseGen == null) {
noiseGen = new NoiseGen(0.2, 0, 0.5, 1, seed);
}
return noiseGen;
}
/**
* Draw on screen
*
* @param playerInfo layer
* @param viewport rendering area on screen
* @param xTiles Desired nr of tiles horizontally
* @param yTiles Desired nr of tiles vertically
* @param minSize minimum tile size
*/
public void render(PlayerInfo playerInfo, RectBound viewport, final int yTiles, final int xTiles, final int minSize)
{
final WorldPos pos;
try {
pos = getEntity(playerInfo.getEID()).getPosition();
} catch (NullPointerException e) {
throw new RuntimeException("Player entity not found in level.", e);
}
final Rect r = viewport.getRect();
final double vpH = r.height().value();
final double vpW = r.width().value();
// adjust tile size to fit desired amount of tiles
final double allowedSizeW = vpW / xTiles;
final double allowedSizeH = vpH / yTiles;
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize));
tileSize -= tileSize % 16;
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 = pos.getVisualX();
final double playerY = pos.getVisualY();
// total map area
//@formatter:off
final RectConst mapRect = vpCenter.startRect().grow(
playerX*tileSize,
(getWidth() - playerX) * tileSize,
playerY*tileSize,
(getHeight() - playerY) * tileSize
).freeze();
//@formatter:on
// tiles to render
final int x1 = (int) Math.floor(playerX - (vpW / tileSize / 2));
final int y1 = (int) Math.floor(playerY - (vpH / tileSize / 2));
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize / 2));
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize / 2));
final TileRenderContext trc = new TileRenderContext(this, mapRect); //-tileSize*0.5
// batch rendering of the tiles
if (USE_BATCH_RENDERING) {
Render.enterBatchTexturedQuadMode(Res.getTexture("tiles"));
}
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
trc.renderTile();
}
}
if (USE_BATCH_RENDERING) {
Render.leaveBatchTexturedQuadMode();
}
// render extras
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
trc.renderItems();
}
}
}
public Entity getEntity(int eid)
{
return entity_map.get(eid);
}
public void addEntity(Entity entity)
{
entity_map.put(entity.getEID(), entity);
entity_set.add(entity);
}
public void removeEntity(Entity entity)
{
entity_map.remove(entity.getEID());
entity_set.remove(entity);
}
public void removeEntity(int eid)
{
final Entity removed = entity_map.remove(eid);
entity_set.remove(removed);
}
}

@ -1,4 +1,4 @@
package mightypork.rogue.world.map;
package mightypork.rogue.world.level;
import mightypork.rogue.world.tile.Tile;

@ -1,6 +1,7 @@
package mightypork.rogue.world.map;
package mightypork.rogue.world.level.render;
import mightypork.rogue.world.level.MapAccess;
import mightypork.util.constraints.rect.Rect;

@ -1,6 +1,7 @@
package mightypork.rogue.world.map;
package mightypork.rogue.world.level.render;
import mightypork.rogue.world.level.MapAccess;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.builders.TiledRect;

@ -1,6 +1,7 @@
package mightypork.rogue.world.map;
package mightypork.rogue.world.level.render;
import mightypork.rogue.world.level.MapAccess;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.proxy.RectBound;
@ -60,11 +61,15 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
}
public void render()
public void renderTile()
{
map.getTile(x, y).render(this);
map.getTile(x, y).renderTile(this);
}
public void renderItems()
{
map.getTile(x, y).renderItems(this);
}
/**
* Rect of the current tile to draw

@ -1,248 +0,0 @@
package mightypork.rogue.world.map;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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;
import mightypork.rogue.world.tile.Tiles;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonInput;
import mightypork.util.ion.IonOutput;
import mightypork.util.math.noise.NoiseGen;
/**
* One level of the dungeon
*
* @author MightyPork
*/
public class Level implements MapAccess, IonBinary {
public static final int ION_MARK = 53;
private int width, height;
/** Array of tiles [y][x] */
private Tile[][] tiles;
private final List<WorldEntity> entities = new ArrayList<>();
/** Level seed (used for generation and tile variation) */
public long seed;
private transient NoiseGen noiseGen;
public Level()
{
}
public Level(int width, int height)
{
this.width = width;
this.height = height;
buildArray();
}
private void buildArray()
{
this.tiles = new Tile[height][width];
}
public void fill(short id)
{
fill(Tiles.get(id));
}
public void fill(TileModel model)
{
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
tiles[y][x] = model.createTile();
}
}
}
@Override
public final Tile getTile(int x, int y)
{
if (x < 0 || x >= width || y < 0 || y >= height) return Tiles.NULL_SOLID.createTile(); // out of range
return tiles[y][x];
}
public final void setTile(TileModel model, int x, int y)
{
setTile(model.createTile(), x, y);
}
public final void setTile(int tileId, int x, int y)
{
setTile(new Tile(tileId), x, y);
}
public final void setTile(Tile tile, int x, int y)
{
if (x < 0 || x > width || y < 0 || y >= height) return; // out of range
tiles[y][x] = tile;
}
@Override
public final int getWidth()
{
return width;
}
@Override
public final int getHeight()
{
return height;
}
public void setSeed(long seed)
{
this.seed = seed;
}
@Override
public long getSeed()
{
return seed;
}
@Override
public void load(IonInput in) throws IOException
{
// metadata
final IonBundle ib = in.readBundle();
seed = ib.get("seed", 0L);
width = ib.get("w", 0);
height = ib.get("h", 0);
ib.loadSequence("entities", entities);
// init array of size
buildArray();
// load tiles
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// no mark
tiles[y][x] = new Tile();
tiles[y][x].load(in);
}
}
}
@Override
public void save(IonOutput out) throws IOException
{
// metadata
final IonBundle ib = new IonBundle();
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)
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// no mark to save space
tiles[y][x].save(out);
}
}
}
@Override
public short getIonMark()
{
return ION_MARK;
}
public void updateLogic(WorldAccess world, double delta)
{
if (!world.isServer()) {
throw new RuntimeException("Not allowed for client.");
}
// just update them all
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
getTile(x, y).updateLogic(world, this, delta);
}
}
}
/**
* Update visuals for player (particle effects etc)
*
* @param world
* @param player
* @param delta
*/
public void updateVisual(WorldAccess world, PlayerEntity player, double delta)
{
if (world.isServer()) {
throw new RuntimeException("Not allowed for server.");
}
final int viewRange = player.getViewRange();
final WorldPos eyepos = player.getViewPosition();
int x1 = eyepos.x - viewRange;
int y1 = eyepos.y - viewRange;
int x2 = x1 + viewRange * 2;
int y2 = y1 + viewRange * 2;
x1 = Math.min(Math.max(0, x1), width);
y1 = Math.min(Math.max(0, y1), height);
x2 = Math.min(x2, width);
y2 = Math.max(y2, height);
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
getTile(x, y).updateVisual(world, this, delta);
}
}
}
@Override
public NoiseGen getNoiseGen()
{
if (noiseGen == null) {
noiseGen = new NoiseGen(0.2, 0, 0.5, 1, seed);
}
return noiseGen;
}
}

@ -1,13 +0,0 @@
package mightypork.rogue.world.map;
import mightypork.rogue.world.WorldPos;
public interface MapObserver {
int getViewRange();
WorldPos getViewPosition();
}

@ -2,12 +2,11 @@ package mightypork.rogue.world.tile;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.proxy.RectBoundAdapter;
import mightypork.util.control.timing.Animator;
import mightypork.util.control.timing.AnimatorBounce;
import mightypork.util.control.timing.Updateable;
import mightypork.util.math.Easing;

@ -4,11 +4,11 @@ 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.Level;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.control.timing.Animator;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.models.TileModel;
import mightypork.rogue.world.tile.renderers.TileRenderer;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonInput;
@ -27,16 +27,13 @@ public final class Tile implements IonBinary {
private TileModel model;
private TileRenderer renderer;
public int id;
private int id;
private final Stack<Item> items = new Stack<>();
/** persistent field for model, reflected by renderer */
public final IonBundle metadata = new IonBundle();
/** non-persistent data field for model */
public Object tmpdata;
public Tile(int id)
{
@ -63,7 +60,10 @@ public final class Tile implements IonBinary {
}
public void render(TileRenderContext context)
/**
* Render the tile alone (must not use other than the main map texture)
*/
public void renderTile(TileRenderContext context)
{
renderer.render(context);
@ -73,6 +73,19 @@ public final class Tile implements IonBinary {
}
/**
* Render items
* @param context
*/
public void renderItems(TileRenderContext context)
{
if (hasItems()) {
renderer.renderItemOnTile(items.peek(), context);
}
}
@Override
public void save(IonOutput out) throws IOException
{
@ -82,7 +95,7 @@ public final class Tile implements IonBinary {
out.writeSequence(items);
}
if (model.hasPersistentMetadata()) {
if (model.hasMetadata()) {
out.writeBundle(metadata);
}
}
@ -102,7 +115,7 @@ public final class Tile implements IonBinary {
in.readSequence(items);
}
if (model.hasPersistentMetadata()) {
if (model.hasMetadata()) {
in.readBundle(metadata);
}
}
@ -111,18 +124,12 @@ public final class Tile implements IonBinary {
/**
* Update tile logic state (on server)
*
* @param world the world
* @param level the level
* @param delta delta time
*/
public void updateLogic(WorldAccess world, Level level, double delta)
{
model.updateLogic(this, world, level, delta);
}
public void updateVisual(WorldAccess world, Level level, double delta)
public void update(Level level, double delta)
{
model.updateVisual(this, world, level, delta);
model.update(this, level, delta);
}

@ -4,6 +4,7 @@ package mightypork.rogue.world.tile;
import mightypork.rogue.world.tile.models.Floor;
import mightypork.rogue.world.tile.models.NullFloor;
import mightypork.rogue.world.tile.models.NullWall;
import mightypork.rogue.world.tile.models.TileModel;
import mightypork.rogue.world.tile.models.Wall;
@ -35,7 +36,7 @@ public final class Tiles {
public static final TileModel CRYSTAL_WALL = new Wall(11).setTexture("tile.wall.crystal");
static void register(int id, TileModel model)
public static void register(int id, TileModel model)
{
if (id < 0 || id >= tiles.length) {
throw new IllegalArgumentException("Tile ID " + id + " is out of range.");

@ -39,7 +39,7 @@ public abstract class AbstractNullTile extends SimpleTile {
@Override
public boolean hasPersistentMetadata()
public boolean hasMetadata()
{
return false;
}

@ -1,10 +1,8 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.WorldAccess;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel;
import mightypork.util.annotations.DefaultImpl;
@ -33,7 +31,7 @@ public abstract class SimpleTile extends TileModel {
@Override
public boolean hasPersistentMetadata()
public boolean hasMetadata()
{
return false;
}
@ -41,13 +39,7 @@ public abstract class SimpleTile extends TileModel {
@Override
@DefaultImpl
public void updateLogic(Tile tile, WorldAccess world, Level level, double delta)
{
}
@Override
@DefaultImpl
public void updateVisual(Tile tile, WorldAccess world, Level level, double delta)
public void update(Tile tile, Level level, double delta)
{
}
}

@ -1,9 +1,11 @@
package mightypork.rogue.world.tile;
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.WorldAccess;
import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.Tiles;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
import mightypork.rogue.world.tile.renderers.TileRenderer;
/**
@ -68,21 +70,15 @@ public abstract class TileModel {
/**
* Update tile in world, called by server
* Update tile in world
*/
public abstract void updateLogic(Tile tile, WorldAccess world, Level level, double delta);
/**
* Update tile visuals (particles / update for renderer)
*/
public abstract void updateVisual(Tile tile, WorldAccess world, Level level, double delta);
public abstract void update(Tile tile, Level level, double delta);
/**
* @return true if this item type has metadata worth saving
*/
public abstract boolean hasPersistentMetadata();
public abstract boolean hasMetadata();
/**

@ -4,13 +4,12 @@ package mightypork.rogue.world.tile.renderers;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.render.textures.TxSheet;
import mightypork.rogue.Res;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.level.render.TileRenderContext;
public class BasicTileRenderer extends TileRenderer {
private TxSheet sheet;
private final TxSheet sheet;
public BasicTileRenderer(String sheetKey)

@ -1,7 +1,7 @@
package mightypork.rogue.world.tile.renderers;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.level.render.TileRenderContext;
public class NullTileRenderer extends TileRenderer {

@ -1,9 +1,9 @@
package mightypork.rogue.world.tile;
package mightypork.rogue.world.tile.renderers;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.tile.renderers.NullTileRenderer;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.DroppedItemRenderer;
/**

@ -42,6 +42,29 @@ public class IonBundle implements IonBinary {
}
public void loadBundle(String key, IonBundle bundle)
{
if (!containsKey(key)) return;
final IonBundle ib = get(key, null);
bundle.clear();
bundle.putAll(ib);
}
public boolean containsKey(Object key)
{
return backingMap.containsKey(key);
}
public boolean containsValue(Object value)
{
return backingMap.containsValue(value);
}
public <K, V> Map<K, V> getMap(String key)
{
final Map<K, V> m = new HashMap<>();
@ -50,12 +73,12 @@ public class IonBundle implements IonBinary {
}
public <K, V> void loadMap(String key, Map<K, V> map)
public <K, V> void loadMap(String key, Map<K, V> filled)
{
final IonMapWrapper imw = get(key, null);
if (imw == null) return;
map.clear();
imw.fill(map);
filled.clear();
imw.fill(filled);
}
@ -67,12 +90,12 @@ public class IonBundle implements IonBinary {
}
public <E> void loadSequence(String key, Collection<E> sequence)
public <E> void loadSequence(String key, Collection<E> filled)
{
final IonSequenceWrapper isw = get(key, null);
if (isw == null) return;
sequence.clear();
isw.fill(sequence);
filled.clear();
isw.fill(filled);
}
@ -262,6 +285,12 @@ public class IonBundle implements IonBinary {
}
public void putAll(IonBundle otherBundle)
{
backingMap.putAll(otherBundle.backingMap);
}
@Override
public String toString()
{

@ -224,7 +224,7 @@ public class IonInput {
*/
public IonBundle readBundle() throws IOException
{
IonBundle ib = new IonBundle();
final IonBundle ib = new IonBundle();
ib.load(this);
return ib;
}

@ -270,7 +270,7 @@ public class IonOutput {
}
if (obj instanceof IonBundled) {
throw new IOException("Bundled objects cannot be written to ION stream directly.");
throw new IOException("Bundled objects cannot be written to ION stream directly at " + obj);
}
if (obj instanceof Boolean) {

Loading…
Cancel
Save