Initial world system with tile rendering & ionization support.

v5stable
Ondřej Hruška 11 years ago
parent 65ad97994b
commit 8872fd3f5f
  1. BIN
      fuck.ion
  2. 2
      src/mightypork/gamecore/gui/components/LayoutComponent.java
  3. 1
      src/mightypork/gamecore/gui/components/VisualComponent.java
  4. 6
      src/mightypork/gamecore/render/Render.java
  5. 14
      src/mightypork/rogue/App.java
  6. 12
      src/mightypork/rogue/Res.java
  7. 15
      src/mightypork/rogue/screens/ingame/GameGui.java
  8. 1
      src/mightypork/rogue/screens/ingame/ScreenGame.java
  9. 32
      src/mightypork/rogue/screens/ingame/WorldLayer.java
  10. 68
      src/mightypork/rogue/screens/ingame/WorldRenderer.java
  11. 83
      src/mightypork/rogue/world/LocalPlayer.java
  12. 54
      src/mightypork/rogue/world/MapGenerator.java
  13. 22
      src/mightypork/rogue/world/MapObserver.java
  14. 185
      src/mightypork/rogue/world/World.java
  15. 71
      src/mightypork/rogue/world/WorldPos.java
  16. 8
      src/mightypork/rogue/world/item/Item.java
  17. 2
      src/mightypork/rogue/world/item/ItemModel.java
  18. 82
      src/mightypork/rogue/world/map/LevelMap.java
  19. 40
      src/mightypork/rogue/world/map/MapAccess.java
  20. 41
      src/mightypork/rogue/world/map/TileRenderContext.java
  21. 19
      src/mightypork/rogue/world/structs/ItemStack.java
  22. 18
      src/mightypork/rogue/world/structs/LevelList.java
  23. 19
      src/mightypork/rogue/world/tile/Tile.java
  24. 13
      src/mightypork/rogue/world/tile/TileGrid.java
  25. 25
      src/mightypork/rogue/world/tile/TileModel.java
  26. 25
      src/mightypork/rogue/world/tile/Tiles.java
  27. 22
      src/mightypork/rogue/world/tile/models/AbstractNullTile.java
  28. 18
      src/mightypork/rogue/world/tile/models/NullFloor.java
  29. 18
      src/mightypork/rogue/world/tile/models/NullWall.java
  30. 13
      src/mightypork/rogue/world/tile/models/SimpleTile.java
  31. 6
      src/mightypork/test/testworldtofile.java
  32. 64
      src/mightypork/util/constraints/rect/Rect.java
  33. 16
      src/mightypork/util/constraints/rect/RectConst.java
  34. 36
      src/mightypork/util/error/CorruptedDataException.java
  35. 56
      src/mightypork/util/files/ion/Ion.java
  36. 30
      src/mightypork/util/files/ion/IonBundle.java
  37. 11
      src/mightypork/util/files/ion/IonConstructor.java
  38. 28
      src/mightypork/util/files/ion/templates/IonizableArrayList.java
  39. 28
      src/mightypork/util/files/ion/templates/IonizableHashMap.java
  40. 28
      src/mightypork/util/files/ion/templates/IonizableHashSet.java
  41. 28
      src/mightypork/util/files/ion/templates/IonizableLinkedHashMap.java
  42. 28
      src/mightypork/util/files/ion/templates/IonizableLinkedList.java
  43. 15
      src/mightypork/util/files/ion/templates/IonizableStack.java
  44. 28
      src/mightypork/util/files/ion/templates/IonizableTreeSet.java
  45. 2
      src/mightypork/util/math/color/RGB.java

Binary file not shown.

@ -13,6 +13,7 @@ import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.control.Enableable; import mightypork.util.control.Enableable;
import mightypork.util.control.eventbus.EventBus; import mightypork.util.control.eventbus.EventBus;
import mightypork.util.control.eventbus.clients.ClientHub; import mightypork.util.control.eventbus.clients.ClientHub;
import mightypork.util.logging.Log;
public abstract class LayoutComponent extends VisualComponent implements Enableable, ClientHub, AppAccess { public abstract class LayoutComponent extends VisualComponent implements Enableable, ClientHub, AppAccess {
@ -131,6 +132,7 @@ public abstract class LayoutComponent extends VisualComponent implements Enablea
public final void attach(Component component) public final void attach(Component component)
{ {
if (component == null) return; if (component == null) return;
if (component == this) throw new IllegalArgumentException("Uruboros. (infinite recursion evaded)");
components.add(component); components.add(component);
addChildClient(component); addChildClient(component);

@ -77,6 +77,7 @@ public abstract class VisualComponent extends AbstractRectCache implements Compo
@Override @Override
public final void onLayoutChanged() public final void onLayoutChanged()
{ {
if (source == null) throw new NullPointerException("Component is missing a bounding rect.");
poll(); poll();
} }

@ -434,6 +434,12 @@ public class Render {
} }
public static void quadColor(Rect quad, Color color)
{
quadColor(quad, color, color, color, color);
}
/** /**
* Draw quad with coloured vertices. * Draw quad with coloured vertices.
* *

@ -22,10 +22,12 @@ import mightypork.rogue.screens.main_menu.ScreenMainMenu;
import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy; import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy;
import mightypork.rogue.screens.test_cat_sound.ScreenTestCat; import mightypork.rogue.screens.test_cat_sound.ScreenTestCat;
import mightypork.rogue.screens.test_render.ScreenTestRender; import mightypork.rogue.screens.test_render.ScreenTestRender;
import mightypork.rogue.world.WorldMap; import mightypork.rogue.world.LocalPlayer;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.LevelMap;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileItems;
import mightypork.util.control.eventbus.EventBus; import mightypork.util.control.eventbus.EventBus;
import mightypork.util.control.eventbus.events.Event; import mightypork.util.control.eventbus.events.Event;
import mightypork.util.files.ion.Ion; import mightypork.util.files.ion.Ion;
@ -107,10 +109,12 @@ public final class App extends BaseApp {
@Override @Override
protected void preInit() protected void preInit()
{ {
Ion.registerIonizable(Tile.ION_MARK, Tile.class);
Ion.registerIonizable(Item.ION_MARK, Item.class); Ion.registerIonizable(Item.ION_MARK, Item.class);
Ion.registerIonizable(WorldMap.ION_MARK, WorldMap.class); Ion.registerIonizable(LevelMap.ION_MARK, LevelMap.class);
Ion.registerIonizable(TileItems.ION_MARK, TileItems.class); // used by tile to store contained items Ion.registerIonizable(LocalPlayer.ION_MARK, LocalPlayer.class);
Ion.registerIonizable(Tile.ION_MARK, Tile.class);
Ion.registerIonizable(World.ION_MARK, World.class);
Ion.registerIonizable(WorldPos.ION_MARK, WorldPos.class);
} }

@ -80,8 +80,16 @@ public final class Res {
texture = textures.loadTexture("tiles", "/res/img/map_tiles.png", FilterMode.NEAREST, WrapMode.CLAMP); texture = textures.loadTexture("tiles", "/res/img/map_tiles.png", FilterMode.NEAREST, WrapMode.CLAMP);
final QuadGrid tiles = texture.grid(32, 32); final QuadGrid tiles = texture.grid(32, 32);
textures.addSheet("tile.mossy_bricks.wall", tiles.makeSheet(4, 0, 7, 1)); textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1));
textures.addSheet("tile.mossy_bricks.floor", tiles.makeSheet(16, 5, 7, 1)); textures.addSheet("tile.wall.small_bricks", tiles.makeSheet(0, 0, 4, 1));
textures.addSheet("tile.floor.mossy_bricks", tiles.makeSheet(16, 5, 7, 1));
textures.addSheet("tile.floor.rect_bricks", tiles.makeSheet(23, 5, 4, 1));
textures.addSheet("tile.wall.sandstone", tiles.makeSheet(0, 3, 10, 1));
textures.addSheet("tile.floor.sandstone", tiles.makeSheet(0, 6, 10, 1));
textures.addSheet("tile.wall.brown_cobble", tiles.makeSheet(0, 8, 8, 1));
textures.addSheet("tile.floor.brown_cobble", tiles.makeSheet(0, 11, 9, 1));
textures.addSheet("tile.floor.crystal", tiles.makeSheet(4, 5, 6, 1));
textures.addSheet("tile.wall.crystal", tiles.makeSheet(12, 2, 14, 1));
} }

@ -8,14 +8,17 @@ import mightypork.gamecore.gui.components.painters.ImagePainter;
import mightypork.gamecore.gui.components.painters.QuadPainter; import mightypork.gamecore.gui.components.painters.QuadPainter;
import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.Screen;
import mightypork.gamecore.gui.screens.ScreenLayer; import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.gamecore.render.Render;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.util.constraints.num.Num; import mightypork.util.constraints.num.Num;
import mightypork.util.constraints.rect.Rect; import mightypork.util.constraints.rect.Rect;
import mightypork.util.math.color.PAL16; import mightypork.util.math.color.PAL16;
import mightypork.util.math.color.RGB;
public class GameGui extends ScreenLayer { public class GameGui extends ScreenLayer {
public GameGui(Screen screen) public GameGui(Screen screen)
{ {
super(screen); super(screen);
@ -24,10 +27,6 @@ public class GameGui extends ScreenLayer {
final Num w = root.width(); final Num w = root.width();
final Num minWH = w.min(h).max(700); // avoid too small shrinking final Num minWH = w.min(h).max(700); // avoid too small shrinking
final Component qp = new QuadPainter(PAL16.VOID);
qp.setRect(root);
root.add(qp);
final ImagePainter nav = new ImagePainter(Res.getTxQuad("panel")); final ImagePainter nav = new ImagePainter(Res.getTxQuad("panel"));
nav.setRect(root.bottomEdge().growUp(minWH.perc(7))); nav.setRect(root.bottomEdge().growUp(minWH.perc(7)));
root.add(nav); root.add(nav);
@ -60,4 +59,12 @@ public class GameGui extends ScreenLayer {
return 100; return 100;
} }
@Override
public void render()
{
super.render();
}
} }

@ -11,6 +11,7 @@ public class ScreenGame extends LayeredScreen {
{ {
super(app); super(app);
addLayer(new WorldLayer(this)); //TODO with provided world
addLayer(new GameGui(this)); addLayer(new GameGui(this));
} }

@ -0,0 +1,32 @@
package mightypork.rogue.screens.ingame;
import java.util.Random;
import mightypork.gamecore.gui.screens.Screen;
import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.rogue.world.MapGenerator;
import mightypork.rogue.world.World;
public class WorldLayer extends ScreenLayer {
public WorldLayer(Screen screen)
{
super(screen);
Random rand = new Random();
World w = MapGenerator.createWorld(rand.nextLong());
WorldRenderer wr = new WorldRenderer(w);
wr.setRect(root);
root.add(wr);
}
@Override
public int getPriority()
{
return -1;
}
}

@ -0,0 +1,68 @@
package mightypork.rogue.screens.ingame;
import mightypork.gamecore.control.events.MouseButtonEvent;
import mightypork.gamecore.gui.components.InputComponent;
import mightypork.gamecore.render.Render;
import mightypork.rogue.world.World;
import mightypork.util.constraints.num.Num;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.control.timing.Updateable;
import mightypork.util.math.color.PAL16;
import mightypork.util.math.color.RGB;
public class WorldRenderer extends InputComponent implements Updateable {
private final World world;
private final Rect rightShadow;
private final Rect leftShadow;
private final Rect topShadow;
private final Rect bottomShadow;
public WorldRenderer(World world)
{
this.world = world;
final Num h = height();
final Num w = width();
final Num minWH = w.min(h).max(700);
Num grX = w.perc(30);
Num grY = h.perc(20);
leftShadow = leftEdge().growRight(grX);
rightShadow = rightEdge().growLeft(grX);
topShadow = topEdge().growDown(grY);
bottomShadow = bottomEdge().growUp(grY).moveY(minWH.perc(-6));
}
@Override
public void receive(MouseButtonEvent event)
{
System.out.println("world clciked, yo");
}
@Override
protected void renderComponent()
{
world.render(this, 8, 6, 64);
Render.quadGradH(leftShadow, RGB.BLACK, RGB.NONE);
Render.quadGradH(rightShadow, RGB.NONE, RGB.BLACK);
Render.quadGradV(topShadow, RGB.BLACK, RGB.NONE);
Render.quadGradV(bottomShadow, RGB.NONE, RGB.BLACK);
}
@Override
public void update(double delta)
{
world.update(delta);
}
}

@ -0,0 +1,83 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonConstructor;
import mightypork.util.files.ion.Ionizable;
/**
* Player info
*
* @author MightyPork
*/
public class LocalPlayer implements Ionizable, MapObserver {
public static final short ION_MARK = 708;
public WorldPos position = new WorldPos();
@IonConstructor
public LocalPlayer()
{
}
public LocalPlayer(int x, int y, int floor)
{
this.position.setTo(x, y, floor);
}
public LocalPlayer(WorldPos pos)
{
this.position = pos;
}
@Override
public void load(InputStream in) throws IOException
{
IonBundle ib = (IonBundle) Ion.readObject(in);
position = ib.get("pos", position);
}
@Override
public void save(OutputStream out) throws IOException
{
IonBundle ib = new IonBundle();
ib.put("pos", position);
Ion.writeObject(out, ib);
}
@Override
public short getIonMark()
{
return ION_MARK;
}
@Override
public WorldPos getPosition()
{
return position;
}
@Override
public int getViewRange()
{
return 15;
}
}

@ -0,0 +1,54 @@
package mightypork.rogue.world;
import java.util.Random;
import mightypork.rogue.world.map.LevelMap;
import mightypork.rogue.world.tile.Tiles;
public class MapGenerator {
public static final Random rand = new Random();
public static World createWorld(long seed)
{
synchronized (rand) {
rand.setSeed(seed);
World w = new World();
w.setSeed(seed);
int levels = 4 + rand.nextInt(6);
for (int i = 0; i < levels; i++) {
w.addLevel(createLevel(rand.nextLong()));
}
// TODO place on start position
w.setPlayer(new LocalPlayer(10, 10, 0));
return w;
}
}
private static LevelMap createLevel(long seed)
{
// TODO
LevelMap lm = new LevelMap(20, 20);
lm.fill(Tiles.CRYSTAL_FLOOR);
Random rand = new Random();
rand.setSeed(seed);
for (int i = 0; i < 150; i++) {
lm.setTile(Tiles.CRYSTAL_WALL, rand.nextInt(20), rand.nextInt(20));
}
return lm;
}
}

@ -0,0 +1,22 @@
package mightypork.rogue.world;
/**
* Player observing a map represented by an observer.
*
* @author MightyPork
*/
public interface MapObserver {
/**
* @return observer's position
*/
public WorldPos getPosition();
/**
* @return observed range (in tiles)
*/
public int getViewRange();
}

@ -0,0 +1,185 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;
import mightypork.gamecore.render.Render;
import mightypork.rogue.world.map.LevelMap;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.structs.LevelList;
import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.RectConst;
import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.constraints.vect.Vect;
import mightypork.util.constraints.vect.VectConst;
import mightypork.util.control.timing.Updateable;
import mightypork.util.error.CorruptedDataException;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.Ionizable;
import mightypork.util.math.color.RGB;
public class World implements Ionizable, Updateable {
public static final short ION_MARK = 706;
private LevelList levels = new LevelList();
private LocalPlayer player = new LocalPlayer();
private transient final Set<MapObserver> observers = new HashSet<>();
private long seed;
@Override
public void load(InputStream in) throws IOException
{
// world data
IonBundle ib = (IonBundle) Ion.readObject(in);
player = ib.get("player", player);
levels = ib.get("levels", levels);
seed = ib.get("seed", seed);
// levels
Ion.readSequence(in, levels);
if (player == null) throw new CorruptedDataException("Null player in world.");
}
@Override
public void save(OutputStream out) throws IOException
{
IonBundle ib = new IonBundle();
ib.put("player", player);
ib.put("levels", levels);
ib.put("seed", seed);
}
public void setPlayer(LocalPlayer player)
{
removeObserver(this.player);
this.player = player;
addObserver(player);
}
public void removeObserver(MapObserver observer)
{
observers.remove(observer);
}
public void addObserver(MapObserver observer)
{
observers.add(observer);
}
public void addLevel(LevelMap level)
{
levels.add(level);
}
@Override
public short getIonMark()
{
return ION_MARK;
}
@Override
public void update(double delta)
{
for (int level = 0; level < levels.size(); level++) {
for (MapObserver observer : observers) {
if (observer.getPosition().floor == level) {
levels.get(level).update(observer, delta);
}
}
}
}
public LevelMap getLevelForObserver(MapObserver observer)
{
return levels.get(observer.getPosition().floor);
}
/**
* 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)
{
LevelMap floor = getLevelForObserver(player); // TODO fractional movement
Rect r = viewport.getRect();
double vpH = r.height().value();
double vpW = r.width().value();
// adjust tile size to fit desired amount of tiles
double allowedSizeW = vpW / xTiles;
double allowedSizeH = vpH / yTiles;
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize));
tileSize -= tileSize % 16;
VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar)
int playerX = player.getPosition().x;
int playerY = player.getPosition().y;
// total map area
//@formatter:off
RectConst mapRect = vpCenter.startRect().grow(
playerX*tileSize,
playerY*tileSize,//
(floor.getWidth() - playerX) * tileSize,
(floor.getHeight() - playerY) * tileSize
).freeze();
//@formatter:on
// tiles to render
int x1 = (int) Math.floor(playerX - (vpW / tileSize));
int y1 = (int) Math.floor(playerY - (vpH / tileSize));
int x2 = (int) Math.ceil(playerX + (vpW / tileSize));
int y2 = (int) Math.ceil(playerY + (vpH / tileSize));
TileRenderContext trc = new TileRenderContext(floor, 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 void setSeed(long seed)
{
this.seed = seed;
}
public long getSeed()
{
return seed;
}
}

@ -0,0 +1,71 @@
package mightypork.rogue.world;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.IonConstructor;
import mightypork.util.files.ion.Ionizable;
/**
* A simple dimension data object
*
* @author MightyPork
*/
public class WorldPos implements Ionizable {
public static final short ION_MARK = 707;
public int x, y, floor;
public WorldPos(int x, int y, int z)
{
super();
this.x = x;
this.y = y;
this.floor = z;
}
@IonConstructor
public WorldPos()
{
}
@Override
public void load(InputStream in) throws IOException
{
x = Ion.readInt(in);
y = Ion.readInt(in);
floor = Ion.readInt(in);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeInt(out, x);
Ion.writeInt(out, y);
Ion.writeInt(out, floor);
}
@Override
public short getIonMark()
{
return ION_MARK;
}
public void setTo(int x, int y, int z)
{
this.x = x;
this.y = y;
this.floor = z;
}
}

@ -5,7 +5,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import mightypork.rogue.world.tile.TileRenderContext; import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.constraints.rect.proxy.RectBound; import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.control.timing.Animator; import mightypork.util.control.timing.Animator;
import mightypork.util.control.timing.AnimatorBounce; import mightypork.util.control.timing.AnimatorBounce;
@ -75,9 +75,9 @@ public class Item implements Updateable, Ionizable {
{ {
final IonBundle ib = (IonBundle) Ion.readObject(in); final IonBundle ib = (IonBundle) Ion.readObject(in);
id = ib.get("id", id); id = ib.get("id", 0);
flags = ib.get("flags", flags); flags = ib.get("flags", null);
numbers = ib.get("numbers", numbers); numbers = ib.get("numbers", null);
if (id != model.id) { if (id != model.id) {
model = Items.get(id); model = Items.get(id);

@ -1,7 +1,7 @@
package mightypork.rogue.world.item; package mightypork.rogue.world.item;
import mightypork.rogue.world.tile.TileRenderContext; import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.annotations.DefaultImpl; import mightypork.util.annotations.DefaultImpl;
import mightypork.util.constraints.num.proxy.NumBoundAdapter; import mightypork.util.constraints.num.proxy.NumBoundAdapter;
import mightypork.util.constraints.rect.Rect; import mightypork.util.constraints.rect.Rect;

@ -1,19 +1,27 @@
package mightypork.rogue.world; package mightypork.rogue.world.map;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import mightypork.rogue.world.MapObserver;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileGrid; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.Tiles;
import mightypork.util.files.ion.Ion; import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.IonConstructor; import mightypork.util.files.ion.IonConstructor;
import mightypork.util.files.ion.Ionizable; import mightypork.util.files.ion.Ionizable;
import mightypork.util.logging.Log;
public class WorldMap implements TileGrid, Ionizable { /**
* One level of the dungeon
*
* @author MightyPork
*/
public class LevelMap implements MapAccess, Ionizable {
public static final int ION_MARK = 702; public static final int ION_MARK = 702;
@ -22,14 +30,17 @@ public class WorldMap implements TileGrid, Ionizable {
/** Array of tiles [y][x] */ /** Array of tiles [y][x] */
private Tile[][] tiles; private Tile[][] tiles;
/** Level seed (used for generation and tile variation) */
public long seed;
@IonConstructor @IonConstructor
public WorldMap() public LevelMap()
{ {
} }
public WorldMap(int width, int height) public LevelMap(int width, int height)
{ {
this.width = width; this.width = width;
this.height = height; this.height = height;
@ -41,9 +52,21 @@ public class WorldMap implements TileGrid, Ionizable {
{ {
this.tiles = new Tile[height][width]; this.tiles = new Tile[height][width];
fill(Tiles.NULL_EMPTY);
}
public void fill(int id)
{
fill(Tiles.get(id));
}
public void fill(TileModel model)
{
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
tiles[y][x] = Tiles.NONE.create(); tiles[y][x] = model.createTile();
} }
} }
} }
@ -52,10 +75,18 @@ public class WorldMap implements TileGrid, Ionizable {
@Override @Override
public final Tile getTile(int x, int y) 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]; 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) public final void setTile(int tileId, int x, int y)
{ {
setTile(new Tile(tileId), x, y); setTile(new Tile(tileId), x, y);
@ -64,6 +95,8 @@ public class WorldMap implements TileGrid, Ionizable {
public final void setTile(Tile tile, int x, int 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; tiles[y][x] = tile;
} }
@ -82,6 +115,19 @@ public class WorldMap implements TileGrid, Ionizable {
} }
public void setSeed(long seed)
{
this.seed = seed;
}
@Override
public long getSeed()
{
return seed;
}
@Override @Override
public void load(InputStream in) throws IOException public void load(InputStream in) throws IOException
{ {
@ -132,4 +178,28 @@ public class WorldMap implements TileGrid, Ionizable {
return ION_MARK; return ION_MARK;
} }
public void update(MapObserver observer, double delta)
{
int viewRange = observer.getViewRange();
WorldPos position = observer.getPosition();
int x1 = position.x - viewRange;
int y1 = position.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).update(delta);
}
}
}
} }

@ -0,0 +1,40 @@
package mightypork.rogue.world.map;
import mightypork.rogue.world.tile.Tile;
/**
* Access interface for a level map.
*
* @author MightyPork
*/
public interface MapAccess {
/**
* Ge tile at X,Y
*
* @param x
* @param y
* @return tile
*/
Tile getTile(int x, int y);
/**
* @return map width in tiles
*/
int getWidth();
/**
* @return map height in tiles
*/
int getHeight();
/**
* @return map seed
*/
long getSeed();
}

@ -1,45 +1,65 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.map;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.constraints.rect.Rect; import mightypork.util.constraints.rect.Rect;
import mightypork.util.constraints.rect.builders.TiledRect; import mightypork.util.constraints.rect.builders.TiledRect;
import mightypork.util.constraints.rect.proxy.RectBound; import mightypork.util.constraints.rect.proxy.RectBound;
import mightypork.util.math.noise.NoiseGen; import mightypork.util.math.noise.NoiseGen;
/**
* Context for tile rendering. Provides tile rect, surrounding tiles, rendered
* tile and random noise values for position-static tile variation.
*
* @author MightyPork
*/
public final class TileRenderContext implements RectBound { public final class TileRenderContext implements RectBound {
private final TileGrid map; private final MapAccess map;
private final TiledRect tiler; private final TiledRect tiler;
private final NoiseGen noise; private final NoiseGen noise;
public int x, y; public int x, y;
public TileRenderContext(TileGrid map, Rect drawArea, long renderNoiseSeed) public TileRenderContext(MapAccess map, Rect drawArea)
{ {
this.map = map; this.map = map;
this.tiler = drawArea.tiles(map.getWidth(), map.getHeight()); this.tiler = drawArea.tiles(map.getWidth(), map.getHeight());
this.noise = new NoiseGen(0.2, 0, 0.5, 1, renderNoiseSeed); this.noise = new NoiseGen(0.2, 0, 0.5, 1, map.getSeed());
} }
/**
* @return the rendered tile.
*/
public Tile getTile() public Tile getTile()
{ {
return map.getTile(x, y); return map.getTile(x, y);
} }
/**
* Get a neighbor tile
*
* @param offsetX x offset (left-right)
* @param offsetY y offset (up-down)
* @return the tile at that position
*/
public Tile getAdjacentTile(int offsetX, int offsetY) public Tile getAdjacentTile(int offsetX, int offsetY)
{ {
return map.getTile(x + offsetX, y + offsetY); return map.getTile(x + offsetX, y + offsetY);
} }
/**
* Rect of the current tile to draw
*/
@Override @Override
public Rect getRect() public Rect getRect()
{ {
return tiler.tile(x, y); return tiler.tile(x, y).grow(0.01); // important to avoid gaps b/w tiles when scaled.
} }
@ -52,15 +72,8 @@ public final class TileRenderContext implements RectBound {
} }
public void setCoord(int x, int y) public void render()
{
this.x = x;
this.y = y;
}
public void renderTile(Tile t)
{ {
t.render(this); map.getTile(x, y).render(this);
} }
} }

@ -0,0 +1,19 @@
package mightypork.rogue.world.structs;
import mightypork.rogue.world.item.Item;
import mightypork.util.files.ion.templates.IonizableStack;
public class ItemStack extends IonizableStack<Item> {
private static final short ION_MARK = 710;
@Override
public short getIonMark()
{
return ION_MARK;
}
}

@ -0,0 +1,18 @@
package mightypork.rogue.world.structs;
import mightypork.rogue.world.map.LevelMap;
import mightypork.util.files.ion.templates.IonizableArrayList;
public class LevelList extends IonizableArrayList<LevelMap> {
public static final short ION_MARK = 709;
@Override
public short getIonMark()
{
return ION_MARK;
}
}

@ -4,7 +4,10 @@ package mightypork.rogue.world.tile;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Stack;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.control.timing.Animator; import mightypork.util.control.timing.Animator;
import mightypork.util.control.timing.Updateable; import mightypork.util.control.timing.Updateable;
import mightypork.util.files.ion.Ion; import mightypork.util.files.ion.Ion;
@ -23,7 +26,7 @@ public final class Tile implements Ionizable, Updateable {
public int id; public int id;
public TileItems items; public Stack<Item> items = new Stack<>();
public boolean[] flags; public boolean[] flags;
public int[] numbers; public int[] numbers;
@ -45,13 +48,12 @@ public final class Tile implements Ionizable, Updateable {
{ {
this.model = model; this.model = model;
this.id = model.id; this.id = model.id;
this.items = new TileItems();
} }
public void render(TileRenderContext context) public void render(TileRenderContext context)
{ {
model.render(this, context); model.render(context);
if (!items.isEmpty()) { if (!items.isEmpty()) {
items.peek().renderOnTile(context); items.peek().renderOnTile(context);
@ -69,7 +71,8 @@ public final class Tile implements Ionizable, Updateable {
ib.put("id", id); ib.put("id", id);
ib.put("flags", flags); ib.put("flags", flags);
ib.put("numbers", numbers); ib.put("numbers", numbers);
ib.put("items", items);
Ion.writeSequence(out, items);
Ion.writeObject(out, ib); Ion.writeObject(out, ib);
} }
@ -78,12 +81,15 @@ public final class Tile implements Ionizable, Updateable {
@Override @Override
public void load(InputStream in) throws IOException public void load(InputStream in) throws IOException
{ {
// bundle of data
final IonBundle ib = (IonBundle) Ion.readObject(in); final IonBundle ib = (IonBundle) Ion.readObject(in);
id = ib.get("id", id); id = ib.get("id", id);
flags = ib.get("flags", flags); flags = ib.get("flags", flags);
numbers = ib.get("numbers", numbers); numbers = ib.get("numbers", numbers);
items = ib.get("items", items);
// stored items
items.clear();
Ion.readSequence(in, items);
// renew model // renew model
if (model == null || id != model.id) { if (model == null || id != model.id) {
@ -102,6 +108,7 @@ public final class Tile implements Ionizable, Updateable {
@Override @Override
public void update(double delta) public void update(double delta)
{ {
model.update(this, delta);
if (!items.isEmpty()) { if (!items.isEmpty()) {
items.peek().update(delta); items.peek().update(delta);
} }

@ -1,13 +0,0 @@
package mightypork.rogue.world.tile;
public interface TileGrid {
Tile getTile(int x, int y);
int getWidth();
int getHeight();
}

@ -1,6 +1,7 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.tile;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.annotations.DefaultImpl; import mightypork.util.annotations.DefaultImpl;
@ -23,10 +24,14 @@ public abstract class TileModel {
/** /**
* Create a tile. In case of null tiles / tiles with absolutely no
* variability, the same instance can be returned over and over (created ie.
* using lazy load)
*
* @return new tile with this model * @return new tile with this model
*/ */
@DefaultImpl @DefaultImpl
public Tile create() public Tile createTile()
{ {
return new Tile(this); return new Tile(this);
} }
@ -35,10 +40,9 @@ public abstract class TileModel {
/** /**
* Render the tile. * Render the tile.
* *
* @param tile
* @param context * @param context
*/ */
public abstract void render(Tile tile, TileRenderContext context); public abstract void render(TileRenderContext context);
/** /**
@ -49,7 +53,11 @@ public abstract class TileModel {
/** /**
* @return true if the tile can be walkable at some conditions * Check if the tile is walkable at some conditions. Used for world
* generation to distinguish between doors etc and regular walls.<br>
* Null tile should return true, if it can be replaced by a regular floor.
*
* @return if it's potentially walkable
*/ */
public abstract boolean isPotentiallyWalkable(); public abstract boolean isPotentiallyWalkable();
@ -59,4 +67,13 @@ public abstract class TileModel {
return false; return false;
} }
/**
* Update a tile
*
* @param tile tile
* @param delta delta time
*/
public abstract void update(Tile tile, double delta);
} }

@ -2,7 +2,9 @@ package mightypork.rogue.world.tile;
import mightypork.rogue.world.tile.models.Floor; import mightypork.rogue.world.tile.models.Floor;
import mightypork.rogue.world.tile.models.NullTile; import mightypork.rogue.world.tile.models.NullFloor;
import mightypork.rogue.world.tile.models.NullWall;
import mightypork.rogue.world.tile.models.Wall;
/** /**
@ -14,14 +16,27 @@ public final class Tiles {
private static final TileModel[] tiles = new TileModel[256]; private static final TileModel[] tiles = new TileModel[256];
public static final TileModel NONE = new NullTile(0); public static final TileModel NULL_SOLID = new NullWall(0);
public static final TileModel FLOOR_MOSSY = new Floor(1, "tile.mossy_bricks.floor"); public static final TileModel NULL_EMPTY = new NullFloor(1);
public static final TileModel WALL_MOSSY = new Floor(2, "tile.mossy_bricks.wall"); public static final TileModel BRICK_FLOOR_VINES = new Floor(2, "tile.floor.mossy_bricks");
public static final TileModel BRICK_WALL_VINES = new Wall(3, "tile.wall.mossy_bricks");
public static final TileModel BRICK_FLOOR_RECT = new Floor(4, "tile.floor.rect_bricks");
public static final TileModel BRICK_WALL_SMALL = new Wall(5, "tile.wall.small_bricks");
public static final TileModel SANDSTONE_FLOOR = new Floor(6, "tile.floor.sandstone");
public static final TileModel SANDSTONE_WALL = new Wall(7, "tile.wall.sandstone");
public static final TileModel BRCOBBLE_FLOOR = new Floor(8, "tile.floor.brown_cobble");
public static final TileModel BRCOBBLE_WALL = new Wall(9, "tile.wall.brown_cobble");
public static final TileModel CRYSTAL_FLOOR = new Floor(10, "tile.floor.crystal");
public static final TileModel CRYSTAL_WALL = new Wall(11, "tile.wall.crystal");
static void register(int id, TileModel model) static void register(int id, TileModel model)
{ {
if (id < 0 || id >= tiles.length) if (tiles[id] != null) { if (id < 0 || id >= tiles.length) {
throw new IllegalArgumentException("Tile ID " + id + " is out of range.");
}
if (tiles[id] != null) {
throw new IllegalArgumentException("Tile ID " + id + " already in use."); throw new IllegalArgumentException("Tile ID " + id + " already in use.");
} }

@ -1,39 +1,43 @@
package mightypork.rogue.world.tile.models; package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderContext;
public class NullTile extends TileModel { /**
* Null tile
*
* @author MightyPork
*/
public abstract class AbstractNullTile extends TileModel {
private Tile inst; private Tile inst;
public NullTile(int id) public AbstractNullTile(int id)
{ {
super(id); super(id);
} }
@Override @Override
public void render(Tile tile, TileRenderContext context) public void render(TileRenderContext context)
{ {
} }
@Override @Override
public boolean isWalkable(Tile tile) public void update(Tile tile, double delta)
{ {
return false;
} }
@Override @Override
public boolean isPotentiallyWalkable() public boolean isWalkable(Tile tile)
{ {
return true; return isPotentiallyWalkable();
} }
@ -45,7 +49,7 @@ public class NullTile extends TileModel {
@Override @Override
public Tile create() public Tile createTile()
{ {
if (inst == null) { if (inst == null) {
inst = new Tile(this); inst = new Tile(this);

@ -0,0 +1,18 @@
package mightypork.rogue.world.tile.models;
public class NullFloor extends AbstractNullTile {
public NullFloor(int id)
{
super(id);
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
}

@ -0,0 +1,18 @@
package mightypork.rogue.world.tile.models;
public class NullWall extends AbstractNullTile {
public NullWall(int id)
{
super(id);
}
@Override
public boolean isPotentiallyWalkable()
{
return false;
}
}

@ -1,13 +1,16 @@
package mightypork.rogue.world.tile.models; package mightypork.rogue.world.tile.models;
import mightypork.gamecore.render.DisplaySystem;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Render;
import mightypork.gamecore.render.textures.TxSheet; import mightypork.gamecore.render.textures.TxSheet;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.map.TileRenderContext;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderContext;
import mightypork.util.annotations.DefaultImpl; import mightypork.util.annotations.DefaultImpl;
import mightypork.util.constraints.vect.Vect;
import mightypork.util.math.color.RGB;
public abstract class SimpleTile extends TileModel { public abstract class SimpleTile extends TileModel {
@ -23,11 +26,17 @@ public abstract class SimpleTile extends TileModel {
@Override @Override
public void render(Tile tile, TileRenderContext context) public void render(TileRenderContext context)
{ {
Render.quadTextured(context.getRect(), sheet.getRandomQuad(context.getTileNoise())); Render.quadTextured(context.getRect(), sheet.getRandomQuad(context.getTileNoise()));
} }
@Override
@DefaultImpl
public void update(Tile tile, double delta)
{
}
@Override @Override
@DefaultImpl @DefaultImpl

@ -0,0 +1,6 @@
package mightypork.test;
public class testworldtofile {
}

@ -727,6 +727,69 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
} }
/**
* Round coords down
*
* @return result
*/
public Rect floor()
{
return new Rect() {
private final Rect t = Rect.this;
@Override
public Vect size()
{
return t.size().floor();
}
@Override
public Vect origin()
{
return t.origin().floor();
}
};
}
/**
* Round coords up
*
* @return result
*/
public Rect ceil()
{
return new Rect() {
private final Rect t = Rect.this;
@Override
public Vect size()
{
return t.size().ceil();
}
@Override
public Vect origin()
{
return t.origin().ceil();
}
};
}
public Num x() public Num x()
{ {
return p_x != null ? p_x : (p_x = origin().xn()); return p_x != null ? p_x : (p_x = origin().xn());
@ -985,4 +1048,5 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
// overflow || intersect // overflow || intersect
return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry)); return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry));
} }
} }

@ -36,6 +36,8 @@ public class RectConst extends Rect {
private RectConst v_edge_t; private RectConst v_edge_t;
private RectConst v_edge_b; private RectConst v_edge_b;
private RectDigest digest; private RectDigest digest;
private RectConst v_floor;
private RectConst v_ceil;
/** /**
@ -152,6 +154,20 @@ public class RectConst extends Rect {
} }
@Override
public RectConst floor()
{
return (v_floor != null) ? v_floor : (v_floor = Rect.make(pos.floor(), size.floor()));
}
@Override
public RectConst ceil()
{
return (v_ceil != null) ? v_ceil : (v_ceil = Rect.make(pos.ceil(), size.ceil()));
}
@Override @Override
public NumConst x() public NumConst x()
{ {

@ -0,0 +1,36 @@
package mightypork.util.error;
import java.io.IOException;
/**
* To be used when a data could not be read successfully.
*
* @author MightyPork
*/
public class CorruptedDataException extends IOException {
public CorruptedDataException()
{
super();
}
public CorruptedDataException(String message, Throwable cause)
{
super(message, cause);
}
public CorruptedDataException(String message)
{
super(message);
}
public CorruptedDataException(Throwable cause)
{
super(cause);
}
}

@ -6,6 +6,7 @@ import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import mightypork.util.error.CorruptedDataException;
import mightypork.util.logging.Log; import mightypork.util.logging.Log;
@ -83,7 +84,7 @@ public class Ion {
static final short DATA_LIST = 81; static final short DATA_LIST = 81;
/** Ionizables<Mark, Class> */ /** Ionizables<Mark, Class> */
private static Map<Short, Class<?>> customIonizables = new HashMap<>(); private static Map<Short, Class<? extends Ionizable>> customIonizables = new HashMap<>();
// buffers and helper arrays for storing to streams. // buffers and helper arrays for storing to streams.
private static ByteBuffer bi = ByteBuffer.allocate(Integer.SIZE / 8); private static ByteBuffer bi = ByteBuffer.allocate(Integer.SIZE / 8);
@ -122,7 +123,7 @@ public class Ion {
* except * except
* @param objClass class of the registered Ionizable * @param objClass class of the registered Ionizable
*/ */
public static void registerIonizable(int mark, Class<?> objClass) public static void registerIonizable(int mark, Class<? extends Ionizable> objClass)
{ {
// negative marks are allowed. // negative marks are allowed.
if (mark > Short.MAX_VALUE) throw new IllegalArgumentException("Mark too high (max " + Short.MAX_VALUE + ")."); if (mark > Short.MAX_VALUE) throw new IllegalArgumentException("Mark too high (max " + Short.MAX_VALUE + ").");
@ -147,9 +148,9 @@ public class Ion {
* *
* @param path file path * @param path file path
* @return the loaded object * @return the loaded object
* @throws IOException on failure * @throws CorruptedDataException
*/ */
public static Object fromFile(String path) throws IOException public static Object fromFile(String path) throws CorruptedDataException
{ {
return fromFile(new File(path)); return fromFile(new File(path));
} }
@ -160,9 +161,9 @@ public class Ion {
* *
* @param file file * @param file file
* @return the loaded object * @return the loaded object
* @throws IOException on failure * @throws CorruptedDataException
*/ */
public static Object fromFile(File file) throws IOException public static Object fromFile(File file) throws CorruptedDataException
{ {
try(InputStream in = new FileInputStream(file)) { try(InputStream in = new FileInputStream(file)) {
@ -170,7 +171,7 @@ public class Ion {
return obj; return obj;
} catch (final IOException e) { } catch (final IOException e) {
throw new IOException("Error loading ION file.", e); throw new CorruptedDataException("Error loading ION file.", e);
} }
} }
@ -257,7 +258,7 @@ public class Ion {
loaded = ((Ionizable) clz.newInstance()); loaded = ((Ionizable) clz.newInstance());
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
throw new IOException("Cound not instantiate: " + Log.str(customIonizables.get(mark)), e); throw new RuntimeException("Cound not instantiate: " + Log.str(customIonizables.get(mark)), e);
} }
loaded.load(in); loaded.load(in);
@ -370,14 +371,14 @@ public class Ion {
return Strings; return Strings;
default: default:
throw new IOException("Invalid Ion mark: " + mark); throw new CorruptedDataException("Invalid Ion mark: " + mark);
} }
} }
public static void expect(InputStream in, short mark) throws IOException public static void expect(InputStream in, short mark) throws IOException
{ {
if (readMark(in) != mark) throw new IOException("Unexpected mark in ION stream."); if (readMark(in) != mark) throw new CorruptedDataException("Unexpected mark in ION stream.");
} }
@ -403,7 +404,20 @@ public class Ion {
public static void writeObject(OutputStream out, Object obj) throws IOException public static void writeObject(OutputStream out, Object obj) throws IOException
{ {
if (obj instanceof Ionizable) { if (obj instanceof Ionizable) {
writeMark(out, ((Ionizable) obj).getIonMark());
short mark = ((Ionizable) obj).getIonMark();
Class<? extends Ionizable> clzRegistered = customIonizables.get(mark);
if (clzRegistered == null) {
throw new IOException("Ionizable object not registered: " + Log.str(obj.getClass()));
}
if (clzRegistered != obj.getClass()) {
throw new IOException("Registered class does not match actual one for " + Log.str(obj.getClass()));
}
writeMark(out, mark);
((Ionizable) obj).save(out); ((Ionizable) obj).save(out);
return; return;
} }
@ -1172,12 +1186,12 @@ public class Ion {
if (mark == ENTRY) return true; if (mark == ENTRY) return true;
if (mark == END) return false; if (mark == END) return false;
throw new IOException("Unexpected mark encountered while reading sequence."); throw new CorruptedDataException("Unexpected mark " + mark + " encountered in sequence, expected " + ENTRY + " or " + END);
} }
/** /**
* Read a sequence of elements * Read a sequence of elements into an ArrayList
* *
* @param in input stream * @param in input stream
* @return the collection * @return the collection
@ -1185,12 +1199,12 @@ public class Ion {
*/ */
public static <T> Collection<T> readSequence(InputStream in) throws IOException public static <T> Collection<T> readSequence(InputStream in) throws IOException
{ {
return readSequence(in, new LinkedList<T>()); return readSequence(in, new ArrayList<T>());
} }
/** /**
* Load entries into a collection * Load entries into a collection. The collection is cleaned first.
* *
* @param in input stream * @param in input stream
* @param filled collection to populate * @param filled collection to populate
@ -1201,12 +1215,13 @@ public class Ion {
public static <T> Collection<T> readSequence(InputStream in, Collection<T> filled) throws IOException public static <T> Collection<T> readSequence(InputStream in, Collection<T> filled) throws IOException
{ {
try { try {
filled.clear();
while (hasNextEntry(in)) { while (hasNextEntry(in)) {
filled.add((T) readObject(in)); filled.add((T) readObject(in));
} }
return filled; return filled;
} catch (final ClassCastException e) { } catch (final ClassCastException e) {
throw new IOException("Unexpected element type."); throw new CorruptedDataException("Unexpected element type.", e);
} }
} }
@ -1229,7 +1244,7 @@ public class Ion {
/** /**
* Read a map of elements * Read element pairs into a HashMap
* *
* @param in input stream * @param in input stream
* @return the map * @return the map
@ -1237,12 +1252,12 @@ public class Ion {
*/ */
public static <K, V> Map<K, V> readMap(InputStream in) throws IOException public static <K, V> Map<K, V> readMap(InputStream in) throws IOException
{ {
return readMap(in, new LinkedHashMap<K, V>()); return readMap(in, new HashMap<K, V>());
} }
/** /**
* Load data into a map * Load data into a map. The map is cleaned first.
* *
* @param in input stream * @param in input stream
* @param filled filled map * @param filled filled map
@ -1253,6 +1268,7 @@ public class Ion {
public static <K, V> Map<K, V> readMap(InputStream in, Map<K, V> filled) throws IOException public static <K, V> Map<K, V> readMap(InputStream in, Map<K, V> filled) throws IOException
{ {
try { try {
filled.clear();
while (hasNextEntry(in)) { while (hasNextEntry(in)) {
final K key = (K) readObject(in); final K key = (K) readObject(in);
final V value = (V) readObject(in); final V value = (V) readObject(in);
@ -1261,7 +1277,7 @@ public class Ion {
} }
return filled; return filled;
} catch (final ClassCastException e) { } catch (final ClassCastException e) {
throw new IOException("Unexpected element type."); throw new CorruptedDataException("Unexpected element type.", e);
} }
} }

@ -1,18 +1,21 @@
package mightypork.util.files.ion; package mightypork.util.files.ion;
import mightypork.util.files.ion.templates.IonizableHashMap;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
/** /**
* <p>
* Data bundle. * Data bundle.
* </p>
* <p>
* Storing data in a bundle guarantees that future versions will be compatible
* with the older format. Reading using default values ensures that you will get
* some value even if it was not saved in the file.
* </p>
* *
* @author MightyPork * @author MightyPork
*/ */
public class IonBundle extends LinkedHashMap<String, Object> implements Ionizable { public class IonBundle extends IonizableHashMap<String, Object> {
/** /**
* Get an object. If not found, fallback is returned. * Get an object. If not found, fallback is returned.
@ -51,19 +54,4 @@ public class IonBundle extends LinkedHashMap<String, Object> implements Ionizabl
return Ion.DATA_BUNDLE; return Ion.DATA_BUNDLE;
} }
@Override
public void load(InputStream in) throws IOException
{
clear();
Ion.readMap(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeMap(out, this);
}
} }

@ -9,8 +9,17 @@ import java.lang.annotation.Target;
/** /**
* <p>
* Implicit constructor marked like this is intended to be solely used for ION * Implicit constructor marked like this is intended to be solely used for ION
* de-serialization. This is a description annotation and has no other function. * de-serialization.
* </p>
* <p>
* Constructors marked like this should create a functional instance with
* default values.
* </p>
* <p>
* This is a descriptive annotation and has no other function.
* </p>
* *
* @author MightyPork * @author MightyPork
*/ */

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableArrayList<E> extends ArrayList<E> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableHashMap<K, V> extends HashMap<K, V> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readMap(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeMap(out, this);
}
}

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableHashSet<E> extends HashSet<E> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableLinkedHashMap<K, V> extends LinkedHashMap<K, V> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readMap(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeMap(out, this);
}
}

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableLinkedList<E> extends LinkedList<E> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}

@ -1,4 +1,4 @@
package mightypork.rogue.world.tile; package mightypork.util.files.ion.templates;
import java.io.IOException; import java.io.IOException;
@ -6,15 +6,11 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Stack; import java.util.Stack;
import mightypork.rogue.world.item.Item;
import mightypork.util.files.ion.Ion; import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable; import mightypork.util.files.ion.Ionizable;
public class TileItems extends Stack<Item> implements Ionizable { public abstract class IonizableStack<E> extends Stack<E> implements Ionizable {
public static final short ION_MARK = 703;
@Override @Override
public void load(InputStream in) throws IOException public void load(InputStream in) throws IOException
@ -29,11 +25,4 @@ public class TileItems extends Stack<Item> implements Ionizable {
Ion.writeSequence(out, this); Ion.writeSequence(out, this);
} }
@Override
public short getIonMark()
{
return ION_MARK;
}
} }

@ -0,0 +1,28 @@
package mightypork.util.files.ion.templates;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TreeSet;
import mightypork.util.files.ion.Ion;
import mightypork.util.files.ion.Ionizable;
public abstract class IonizableTreeSet<E> extends TreeSet<E> implements Ionizable {
@Override
public void load(InputStream in) throws IOException
{
Ion.readSequence(in, this);
}
@Override
public void save(OutputStream out) throws IOException
{
Ion.writeSequence(out, this);
}
}

@ -23,4 +23,6 @@ public interface RGB {
Color PINK = Color.fromHex(0xFF3FFC); Color PINK = Color.fromHex(0xFF3FFC);
Color ORANGE = Color.fromHex(0xFC4800); Color ORANGE = Color.fromHex(0xFC4800);
Color NONE = Color.NONE;
} }

Loading…
Cancel
Save