Code:
import java.util.LinkedList;
import java.util.ListIterator;
/**
* Handles splitting the map up into
* lazily initialized regions to combine
* the speed of a Tile system with the
* memory efficiency of the standard method.
* This unlike my old system completely separates
* internal code from the end user, and allows
* multiple region instances and sizes within a
* single server.
* @author Colby
*/
@SuppressWarnings({"unchecked", "rawtypes", "serial"})
public class RegionSystem<TileContent> {
/**
* Creates a RegionSystem with default sizes.
*/
public RegionSystem() {
this(1024 * 16, 1024 * 16, 4, 16, 16);
}
/**
* Creates a RegionSystem with custom sizes.
* @param worldAbsWidth
* @param worldAbsHeight
* @param worldAbsDepth
* @param regionAbsWidth
* @param regionAbsHeight
*/
public RegionSystem(int worldAbsWidth, int worldAbsHeight, int worldAbsDepth, int regionAbsWidth, int regionAbsHeight) {
this.regions = new Region[worldAbsWidth / regionAbsWidth][worldAbsHeight / regionAbsHeight][worldAbsDepth];
this.worldAbsWidth = worldAbsWidth;
this.worldAbsHeight = worldAbsHeight;
this.worldAbsDepth = worldAbsDepth;
this.regionAbsWidth = regionAbsWidth;
this.regionAbsHeight = regionAbsHeight;
}
//World sizes
public final int worldAbsWidth;
public final int worldAbsHeight;
public final int worldAbsDepth;
public final int regionAbsWidth;
public final int regionAbsHeight;
//Actual regions
private final Region[][][] regions;
/**
* Gets the contents at the specified X/Y/Z location.
* @param absX The X coordinate.
* @param absY The Y coordinate.
* @param absZ The Z coordinate.
* @return An UNMODIFYABLE ListIterator with the contents of
* the requested tile, or null if the parent region is not initialized.
*/
public ListIterator<TileContent> getTileContents(int absX, int absY, int absZ) {
int regX = absX / regionAbsWidth, regY = absY / regionAbsHeight;
Region region = regions[regX][regY][absZ];
if (region != null) {
return region.tiles[absX & regionAbsWidth - 1][absY & regionAbsHeight - 1].contents.listIterator();
}
return null;
}
/**
* Adds a TileContent to the specified X/Y/Z.
* @param content The TileContent to add.
* @param absX The X coordinate.
* @param absY The Y coordinate.
* @param absZ The Z coordinate.
* @return If the operation was successful.
*/
public boolean add(TileContent content, int absX, int absY, int absZ) {
int regX = absX / regionAbsWidth, regY = absY / regionAbsHeight;
Region region = regions[regX][regY][absZ];
if (region == null) {
region = (regions[regX][regY][absZ] = new Region(regX, regY, absZ));
}
return region.add(content, absX, absY);
}
/**
* Removes the specified TileContent only
* from the specified X/Y/Z.
* @param content The TileContent to remove.
* @param absX The X coordinate.
* @param absY The Y Coordinate.
* @param absZ The Z coordinate.
* @return If the operation was successful.
*/
public boolean remove(TileContent content, int absX, int absY, int absZ) {
int regX = absX / regionAbsWidth, regY = absY / regionAbsHeight;
Region region = regions[regX][regY][absZ];
if (region != null) {
return region.remove(content, absX, absY);
}
return false;
}
/**
* Attempts to move the specified TileContent.
* @param content The TileContent to move.
* @param fx The old X coordinate.
* @param fy The old Y coordinate.
* @param fz The old Z coordinate.
* @param tox The new X coordinate.
* @param toy The new Y coordinate.
* @param toz The new Z coordinate.
* @return If the add operation was successful.
*/
public boolean move(TileContent content, int fx, int fy, int fz, int tox, int toy, int toz) {
remove(content, fx, fy, fz);
return add(content, tox, toy, toz);
}
private class Region<TileContent> {
public Region(int regX, int regY, int regZ) {
this.regX = regX;
this.regY = regY;
this.regZ = regZ;
}
private final Tile[][] tiles = new Tile[regionAbsWidth][regionAbsHeight];
private final int regX, regY, regZ;
private long activeTiles = 0L;
{
for (int x = regionAbsWidth, y; --x != -1;) {
for (y = regionAbsHeight; --y != -1;) {
tiles[x][y] = new Tile();
}
}
}
private boolean add(TileContent content, int absX, int absY) {
Tile tile = tiles[absX % regionAbsWidth][absY % regionAbsHeight];
if (tile.contents.isEmpty()) {
++activeTiles;
}
return tile.contents.add(content);
}
private boolean remove(TileContent content, int absX, int absY) {
Tile tile = tiles[absX % regionAbsWidth][absY % regionAbsHeight];
if (tile.contents.remove(content)) {
if (tile.contents.isEmpty()) {
if (--activeTiles < 1) {
regions[regX][regY][regZ] = null;
}
}
return true;
}
return false;
}
}
private class Tile<TileContent> {
private TileContents contents = new TileContents();
}
private class TileContents extends LinkedList {
@Override
public ListIterator listIterator() {
return new ListIterator<TileContent>() {
private ListIterator<TileContent> parent = TileContents.super.listIterator();
@Override
public boolean hasNext() {
return parent.hasNext();
}
@Override
public TileContent next() {
return parent.next();
}
@Override
public boolean hasPrevious() {
return parent.hasPrevious();
}
@Override
public TileContent previous() {
return parent.previous();
}
@Override
public int nextIndex() {
return parent.nextIndex();
}
@Override
public int previousIndex() {
return parent.previousIndex();
}
@Override
public void add(TileContent o) {
throw new UnsupportedOperationException();
}
@Override
public void set(TileContent t) {
throw new UnsupportedOperationException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
}