parent
							
								
									9e4a237192
								
							
						
					
					
						commit
						3e69505787
					
				| 
		 Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 320 KiB  | 
@ -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(); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -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; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
} | 
				
			||||
@ -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 { | 
				
			||||
	 | 
				
			||||
} | 
				
			||||
@ -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,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(); | 
				
			||||
} | 
				
			||||
@ -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; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
					Loading…
					
					
				
		Reference in new issue