mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-28 19:47:45 +01:00
Improve scaling of memory use with large numbers of tiles, prep for suspend/resume support
This commit is contained in:
parent
fb366ce36b
commit
f5d5171f86
@ -29,6 +29,7 @@ import org.dynmap.utils.LegacyMapChunkCache;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.NewMapChunkCache;
|
||||
import org.dynmap.utils.SnapshotCache;
|
||||
import org.dynmap.utils.TileFlags;
|
||||
|
||||
public class MapManager {
|
||||
public AsynchronousQueue<MapTile> tileQueue;
|
||||
@ -151,8 +152,8 @@ public class MapManager {
|
||||
Location loc;
|
||||
int map_index = -1; /* Which map are we on */
|
||||
MapType map;
|
||||
HashSet<MapTile> found = null;
|
||||
HashSet<MapTile> rendered = null;
|
||||
TileFlags found = null;
|
||||
TileFlags rendered = null;
|
||||
LinkedList<MapTile> renderQueue = null;
|
||||
MapTile tile0 = null;
|
||||
MapTile tile = null;
|
||||
@ -178,8 +179,8 @@ public class MapManager {
|
||||
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender, String mapname, int radius) {
|
||||
world = dworld;
|
||||
loc = l;
|
||||
found = new HashSet<MapTile>();
|
||||
rendered = new HashSet<MapTile>();
|
||||
found = new TileFlags();
|
||||
rendered = new TileFlags();
|
||||
renderQueue = new LinkedList<MapTile>();
|
||||
this.sender = sender;
|
||||
if(radius < 0) {
|
||||
@ -275,16 +276,16 @@ public class MapManager {
|
||||
|
||||
/* Now, prime the render queue */
|
||||
for (MapTile mt : map.getTiles(loc)) {
|
||||
if (!found.contains(mt)) {
|
||||
found.add(mt);
|
||||
if (!found.getFlag(mt.tileOrdinalX(), mt.tileOrdinalY())) {
|
||||
found.setFlag(mt.tileOrdinalX(), mt.tileOrdinalY(), true);
|
||||
renderQueue.add(mt);
|
||||
}
|
||||
}
|
||||
if(world.seedloc != null) {
|
||||
for(Location seed : world.seedloc) {
|
||||
for (MapTile mt : map.getTiles(seed)) {
|
||||
if (!found.contains(mt)) {
|
||||
found.add(mt);
|
||||
if (!found.getFlag(mt.tileOrdinalX(),mt.tileOrdinalY())) {
|
||||
found.setFlag(mt.tileOrdinalX(),mt.tileOrdinalY(), true);
|
||||
renderQueue.add(mt);
|
||||
}
|
||||
}
|
||||
@ -326,16 +327,17 @@ public class MapManager {
|
||||
/* Switch to not checking if rendered tile is blank - breaks us on skylands, where tiles can be nominally blank - just work off chunk cache empty */
|
||||
if (cache.isEmpty() == false) {
|
||||
tile.render(cache, mapname);
|
||||
found.remove(tile);
|
||||
rendered.add(tile);
|
||||
found.setFlag(tile.tileOrdinalX(),tile.tileOrdinalY(),false);
|
||||
rendered.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), true);
|
||||
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
|
||||
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
|
||||
found.add(adjTile);
|
||||
if (!found.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY()) &&
|
||||
!rendered.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY())) {
|
||||
found.setFlag(adjTile.tileOrdinalX(), adjTile.tileOrdinalY(), true);
|
||||
renderQueue.add(adjTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
found.remove(tile);
|
||||
found.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), false);
|
||||
if(!cache.isEmpty()) {
|
||||
rendercnt++;
|
||||
timeaccum += System.currentTimeMillis() - tstart;
|
||||
|
@ -51,4 +51,7 @@ public abstract class MapTile {
|
||||
public abstract boolean isRawBiomeDataNeeded();
|
||||
public abstract boolean isBlockTypeDataNeeded();
|
||||
|
||||
public abstract int tileOrdinalX();
|
||||
public abstract int tileOrdinalY();
|
||||
|
||||
}
|
||||
|
@ -518,6 +518,9 @@ public class FlatMap extends MapType {
|
||||
public boolean isBiomeDataNeeded() { return false; }
|
||||
public boolean isRawBiomeDataNeeded() { return false; }
|
||||
public boolean isBlockTypeDataNeeded() { return true; }
|
||||
public int tileOrdinalX() { return x; }
|
||||
public int tileOrdinalY() { return y; }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,4 +87,8 @@ public class HDMapTile extends MapTile {
|
||||
public MapTile[] getAdjecentTiles() {
|
||||
return perspective.getAdjecentTiles(this);
|
||||
}
|
||||
|
||||
public int tileOrdinalX() { return tx; }
|
||||
public int tileOrdinalY() { return ty; }
|
||||
|
||||
}
|
||||
|
@ -91,5 +91,6 @@ public class KzedMapTile extends MapTile {
|
||||
public boolean isHightestBlockYDataNeeded() { return false; }
|
||||
public boolean isRawBiomeDataNeeded() { return map.isRawBiomeDataNeeded(); }
|
||||
public boolean isBlockTypeDataNeeded() { return true; }
|
||||
|
||||
public int tileOrdinalX() { return px >> 7; }
|
||||
public int tileOrdinalY() { return py >> 7; }
|
||||
}
|
||||
|
@ -102,5 +102,7 @@ public class KzedZoomedMapTile extends MapTile {
|
||||
public boolean isHightestBlockYDataNeeded() { return false; }
|
||||
public boolean isRawBiomeDataNeeded() { return originalTile.isRawBiomeDataNeeded(); }
|
||||
public boolean isBlockTypeDataNeeded() { return true; }
|
||||
public int tileOrdinalX() { return originalTile.px >> 8; }
|
||||
public int tileOrdinalY() { return originalTile.py >> 8; }
|
||||
|
||||
}
|
||||
|
66
src/main/java/org/dynmap/utils/TileFlags.java
Normal file
66
src/main/java/org/dynmap/utils/TileFlags.java
Normal file
@ -0,0 +1,66 @@
|
||||
package org.dynmap.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* scalable flags primitive - used for keeping track of potentially huge number of tiles
|
||||
*
|
||||
* Represents a flag for each tile, with 2D coordinates based on 0,0 origin. Flags are grouped
|
||||
* 64 x 64, represented by an array of 64 longs. Each set is stored in a hashmap, keyed by a long
|
||||
* computed by ((x/64)<<32)+(y/64).
|
||||
*
|
||||
*/
|
||||
public class TileFlags {
|
||||
private HashMap<Long, long[]> chunkmap = new HashMap<Long, long[]>();
|
||||
private long last_key = Long.MIN_VALUE;
|
||||
private long[] last_row;
|
||||
|
||||
public TileFlags() {
|
||||
}
|
||||
|
||||
public boolean getFlag(int x, int y) {
|
||||
long k = (((long)(x >> 6)) << 32) | (0xFFFFFFFFL & (long)(y >> 6));
|
||||
long[] row;
|
||||
if(k == last_key) {
|
||||
row = last_row;
|
||||
}
|
||||
else {
|
||||
row = chunkmap.get(k);
|
||||
last_key = k;
|
||||
last_row = row;
|
||||
}
|
||||
if(row == null)
|
||||
return false;
|
||||
else
|
||||
return (row[y & 0x3F] & (1L << (x & 0x3F))) != 0;
|
||||
}
|
||||
|
||||
public void setFlag(int x, int y, boolean f) {
|
||||
long k = (((long)(x >> 6)) << 32) | (0xFFFFFFFFL & (long)(y >> 6));
|
||||
long[] row;
|
||||
if(k == last_key) {
|
||||
row = last_row;
|
||||
}
|
||||
else {
|
||||
row = chunkmap.get(k);
|
||||
last_key = k;
|
||||
last_row = row;
|
||||
}
|
||||
if(f) {
|
||||
if(row == null) {
|
||||
row = new long[64];
|
||||
chunkmap.put(k, row);
|
||||
last_row = row;
|
||||
}
|
||||
row[y & 0x3F] |= (1L << (x & 0x3F));
|
||||
}
|
||||
else {
|
||||
if(row != null)
|
||||
row[y & 0x3F] &= ~(1L << (x & 0x3F));
|
||||
}
|
||||
}
|
||||
public void clear() {
|
||||
chunkmap.clear();
|
||||
last_row = null;
|
||||
last_key = Long.MIN_VALUE;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user