Add support for experimental Caves and Caverns data pack

This commit is contained in:
Mike Primm 2021-08-21 18:03:07 -05:00
parent 3276134c5e
commit 0f655e8414
17 changed files with 152 additions and 109 deletions

View file

@ -52,22 +52,27 @@ public abstract class DynmapWorld {
private MapStorage storage; // Storage handler for this world's maps private MapStorage storage; // Storage handler for this world's maps
/* World height data */ /* World height data */
public final int worldheight; public int worldheight; // really maxY+1
public final int heightshift; public int minY;
public final int heightmask;
public int sealevel; public int sealevel;
protected void updateWorldHeights(int worldheight, int minY, int sealevel) {
this.worldheight = worldheight;
this.minY = minY;
this.sealevel = sealevel;
}
protected DynmapWorld(String wname, int worldheight, int sealevel) { protected DynmapWorld(String wname, int worldheight, int sealevel) {
this(wname, worldheight, sealevel, 0);
}
protected DynmapWorld(String wname, int worldheight, int sealevel, int miny) {
this.raw_wname = wname; this.raw_wname = wname;
this.wname = normalizeWorldName(wname); this.wname = normalizeWorldName(wname);
this.hashcode = this.wname.hashCode(); this.hashcode = this.wname.hashCode();
this.title = wname; this.title = wname;
this.worldheight = worldheight; this.worldheight = worldheight;
this.minY = miny;
this.sealevel = sealevel; this.sealevel = sealevel;
int shift;
for(shift = 0; ((1 << shift) < worldheight); shift++) {}
heightshift = shift;
heightmask = (1 << shift) - 1;
/* Generate default brightness table for surface world */ /* Generate default brightness table for surface world */
for (int i = 0; i <= 15; ++i) { for (int i = 0; i <= 15; ++i) {
float f1 = 1.0F - (float)i / 15.0F; float f1 = 1.0F - (float)i / 15.0F;
@ -319,7 +324,7 @@ public abstract class DynmapWorld {
} }
title = worldconfig.getString("title", title); title = worldconfig.getString("title", title);
ConfigurationNode ctr = worldconfig.getNode("center"); ConfigurationNode ctr = worldconfig.getNode("center");
int mid_y = worldheight/2; int mid_y = (worldheight + minY)/2;
if(ctr != null) if(ctr != null)
center = new DynmapLocation(wname, ctr.getDouble("x", 0.0), ctr.getDouble("y", mid_y), ctr.getDouble("z", 0)); center = new DynmapLocation(wname, ctr.getDouble("x", 0.0), ctr.getDouble("y", mid_y), ctr.getDouble("z", 0));
else else

View file

@ -198,7 +198,7 @@ public class DynmapExpCommands {
ctx.xmax = (int)Math.ceil(loc.x) + radius; ctx.xmax = (int)Math.ceil(loc.x) + radius;
ctx.zmin = (int)Math.floor(loc.z) - radius; ctx.zmin = (int)Math.floor(loc.z) - radius;
ctx.zmax = (int)Math.ceil(loc.z) + radius; ctx.zmax = (int)Math.ceil(loc.z) + radius;
ctx.ymin = 0; ctx.ymin = world.minY;
ctx.ymax = world.worldheight - 1; ctx.ymax = world.worldheight - 1;
ctx.world = world.getName(); ctx.world = world.getName();
return handleInfo(sender, args, ctx, core); return handleInfo(sender, args, ctx, core);

View file

@ -170,7 +170,7 @@ public class OBJExport {
else { else {
minZ = maxz; maxZ = minz; minZ = maxz; maxZ = minz;
} }
if (minY < 0) minY = 0; if (minY < world.minY) minY = world.minY;
if (maxY >= world.worldheight) maxY = world.worldheight - 1; if (maxY >= world.worldheight) maxY = world.worldheight - 1;
if (centerOrigin) { if (centerOrigin) {
originX = (maxX + minX) / 2.0; originX = (maxX + minX) / 2.0;

View file

@ -136,7 +136,6 @@ public class IsoHDPerspective implements HDPerspective {
final boolean isnether; final boolean isnether;
boolean skiptoair; boolean skiptoair;
final int worldheight; final int worldheight;
final int heightmask;
final LightLevels llcache[]; final LightLevels llcache[];
/* Cache for custom model patch lists */ /* Cache for custom model patch lists */
@ -147,9 +146,6 @@ public class IsoHDPerspective implements HDPerspective {
mapiter = mi; mapiter = mi;
this.isnether = isnether; this.isnether = isnether;
worldheight = mapiter.getWorldHeight(); worldheight = mapiter.getWorldHeight();
int shift;
for(shift = 0; (1<<shift) < worldheight; shift++) {}
heightmask = (1<<shift) - 1;
llcache = new LightLevels[4]; llcache = new LightLevels[4];
for(int i = 0; i < llcache.length; i++) for(int i = 0; i < llcache.length; i++)
llcache[i] = new LightLevels(); llcache[i] = new LightLevels();
@ -627,6 +623,7 @@ public class IsoHDPerspective implements HDPerspective {
/* Skip empty : return false if exited */ /* Skip empty : return false if exited */
private final boolean raytraceSkipEmpty(MapChunkCache cache) { private final boolean raytraceSkipEmpty(MapChunkCache cache) {
int minsy = cache.getWorld().minY >> 4;
while(cache.isEmptySection(sx, sy, sz)) { while(cache.isEmptySection(sx, sy, sz)) {
/* If Y step is next best */ /* If Y step is next best */
if((st_next_y <= st_next_x) && (st_next_y <= st_next_z)) { if((st_next_y <= st_next_x) && (st_next_y <= st_next_z)) {
@ -634,7 +631,7 @@ public class IsoHDPerspective implements HDPerspective {
t = st_next_y; t = st_next_y;
st_next_y += sdt_dy; st_next_y += sdt_dy;
laststep = stepy; laststep = stepy;
if(sy < 0) if (sy < minsy)
return false; return false;
} }
/* If X step is next best */ /* If X step is next best */
@ -658,7 +655,7 @@ public class IsoHDPerspective implements HDPerspective {
/** /**
* Step block iterator: false if done * Step block iterator: false if done
*/ */
private final boolean raytraceStepIterator() { private final boolean raytraceStepIterator(int miny, int maxy) {
/* If Y step is next best */ /* If Y step is next best */
if ((t_next_y <= t_next_x) && (t_next_y <= t_next_z)) { if ((t_next_y <= t_next_x) && (t_next_y <= t_next_z)) {
y += y_inc; y += y_inc;
@ -667,7 +664,7 @@ public class IsoHDPerspective implements HDPerspective {
laststep = stepy; laststep = stepy;
mapiter.stepPosition(laststep); mapiter.stepPosition(laststep);
/* If outside 0-(height-1) range */ /* If outside 0-(height-1) range */
if((y & (~heightmask)) != 0) { if ((y < miny) || (y > maxy)) {
return false; return false;
} }
} }
@ -694,6 +691,9 @@ public class IsoHDPerspective implements HDPerspective {
* Trace ray, based on "Voxel Tranversal along a 3D line" * Trace ray, based on "Voxel Tranversal along a 3D line"
*/ */
private final void raytrace(MapChunkCache cache, HDShaderState[] shaderstate, boolean[] shaderdone) { private final void raytrace(MapChunkCache cache, HDShaderState[] shaderstate, boolean[] shaderdone) {
int minY = cache.getWorld().minY;
int height = cache.getWorld().worldheight;
/* Initialize raytrace state variables */ /* Initialize raytrace state variables */
raytrace_init(); raytrace_init();
@ -703,7 +703,7 @@ public class IsoHDPerspective implements HDPerspective {
raytrace_section_init(); raytrace_section_init();
if (y < 0) if (y < minY)
return; return;
mapiter.initialize(x, y, z); mapiter.initialize(x, y, z);
@ -712,7 +712,7 @@ public class IsoHDPerspective implements HDPerspective {
if (visit_block(shaderstate, shaderdone)) { if (visit_block(shaderstate, shaderdone)) {
return; return;
} }
if (!raytraceStepIterator()) { if (!raytraceStepIterator(minY, height)) {
return; return;
} }
} }
@ -978,9 +978,7 @@ public class IsoHDPerspective implements HDPerspective {
/* Get max and min height */ /* Get max and min height */
maxheight = configuration.getInteger("maximumheight", -1); maxheight = configuration.getInteger("maximumheight", -1);
int minh = configuration.getInteger("minimumheight", 0); minheight = configuration.getInteger("minimumheight", Integer.MIN_VALUE);
if(minh < 0) minh = 0;
minheight = minh;
/* Generate transform matrix for world-to-tile coordinate mapping */ /* Generate transform matrix for world-to-tile coordinate mapping */
/* First, need to fix basic coordinate mismatches before rotation - we want zero azimuth to have north to top /* First, need to fix basic coordinate mismatches before rotation - we want zero azimuth to have north to top
* (world -X -> tile +Y) and east to right (world -Z to tile +X), with height being up (world +Y -> tile +Z) * (world -X -> tile +Y) and east to right (world -Z to tile +X), with height being up (world +Y -> tile +Z)
@ -1129,7 +1127,9 @@ public class IsoHDPerspective implements HDPerspective {
for(int y = t.ty; y <= (t.ty+1); y++) { for(int y = t.ty; y <= (t.ty+1); y++) {
for(int z = 0; z <= 1; z++) { for(int z = 0; z <= 1; z++) {
corners[idx] = new Vector3D(); corners[idx] = new Vector3D();
corners[idx].x = x*tileWidth + dx; corners[idx].y = y*tileHeight + dy; corners[idx].z = z*t.getDynmapWorld().worldheight; corners[idx].x = x*tileWidth + dx;
corners[idx].y = y*tileHeight + dy;
corners[idx].z = (z == 1) ? t.getDynmapWorld().worldheight : t.getDynmapWorld().minY;
map_to_world.transform(corners[idx]); map_to_world.transform(corners[idx]);
/* Compute chunk coordinates of corner */ /* Compute chunk coordinates of corner */
int cx = fastFloor(corners[idx].x / 16); int cx = fastFloor(corners[idx].x / 16);
@ -1240,13 +1240,17 @@ public class IsoHDPerspective implements HDPerspective {
else else
height = tile.getDynmapWorld().worldheight - 1; height = tile.getDynmapWorld().worldheight - 1;
} }
double miny = minheight;
if (miny == Integer.MIN_VALUE) { /* Not set - assume world height - 1 */
miny = tile.getDynmapWorld().minY;
}
for(int x = 0; x < tileWidth * sizescale; x++) { for(int x = 0; x < tileWidth * sizescale; x++) {
ps.px = x; ps.px = x;
for(int y = 0; y < tileHeight * sizescale; y++) { for(int y = 0; y < tileHeight * sizescale; y++) {
ps.top.x = ps.bottom.x = xbase + ((double)x)/sizescale + 0.5; /* Start at center of pixel at Y=height+0.5, bottom at Y=-0.5 */ ps.top.x = ps.bottom.x = xbase + ((double)x)/sizescale + 0.5; /* Start at center of pixel at Y=height+0.5, bottom at Y=-0.5 */
ps.top.y = ps.bottom.y = ybase + ((double)y)/sizescale + 0.5; ps.top.y = ps.bottom.y = ybase + ((double)y)/sizescale + 0.5;
ps.top.z = height + 0.5; ps.bottom.z = minheight - 0.5; ps.top.z = height + 0.5; ps.bottom.z = miny - 0.5;
map_to_world.transform(ps.top); /* Transform to world coordinates */ map_to_world.transform(ps.top); /* Transform to world coordinates */
map_to_world.transform(ps.bottom); map_to_world.transform(ps.bottom);
ps.direction.set(ps.bottom); ps.direction.set(ps.bottom);

View file

@ -17,7 +17,7 @@ allprojects {
apply plugin: 'java' apply plugin: 'java'
group = 'us.dynmap' group = 'us.dynmap'
version = '3.2-beta-3' version = '3.2-SNAPSHOT'
} }

View file

@ -2,6 +2,7 @@ package org.dynmap.bukkit.helper.v117;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.dynmap.DynmapChunk; import org.dynmap.DynmapChunk;
@ -399,5 +400,10 @@ public class BukkitVersionHelperSpigot117 extends BukkitVersionHelper {
} }
return url; return url;
} }
// Get minY for world
@Override
public int getWorldMinY(World w) {
CraftWorld cw = (CraftWorld) w;
return cw.getMinHeight();
}
} }

View file

@ -48,6 +48,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
protected World w; protected World w;
protected DynmapWorld dw; protected DynmapWorld dw;
private int nsect; private int nsect;
private int sectoff;
protected List<DynmapChunk> chunks; protected List<DynmapChunk> chunks;
protected ListIterator<DynmapChunk> iterator; protected ListIterator<DynmapChunk> iterator;
protected int x_min; protected int x_min;
@ -98,6 +99,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
private BlockStep laststep; private BlockStep laststep;
private DynmapBlockState type = null; private DynmapBlockState type = null;
private final int worldheight; private final int worldheight;
private final int ymin;
private final int x_base; private final int x_base;
private final int z_base; private final int z_base;
@ -108,6 +110,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
biomePrep(); biomePrep();
initialize(x0, y0, z0); initialize(x0, y0, z0);
worldheight = w.getMaxHeight(); worldheight = w.getMaxHeight();
ymin = dw.minY;
} }
@Override @Override
@ -126,7 +129,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
snap = snaparray[chunkindex]; snap = snaparray[chunkindex];
} }
laststep = BlockStep.Y_MINUS; laststep = BlockStep.Y_MINUS;
if((y >= 0) && (y < worldheight)) if((y >= ymin) && (y < worldheight))
type = null; type = null;
else else
type = DynmapBlockState.AIR; type = DynmapBlockState.AIR;
@ -452,7 +455,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
break; break;
case 4: case 4:
y--; y--;
if(y < 0) { if(y < ymin) {
type = DynmapBlockState.AIR; type = DynmapBlockState.AIR;
} }
break; break;
@ -498,7 +501,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
else else
laststep = BlockStep.Y_MINUS; laststep = BlockStep.Y_MINUS;
this.y = y; this.y = y;
if((y < 0) || (y >= worldheight)) { if((y < ymin) || (y >= worldheight)) {
type = DynmapBlockState.AIR; type = DynmapBlockState.AIR;
} }
else { else {
@ -520,7 +523,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
@Override @Override
public final DynmapBlockState getBlockTypeAt(BlockStep s) { public final DynmapBlockState getBlockTypeAt(BlockStep s) {
if(s == BlockStep.Y_MINUS) { if(s == BlockStep.Y_MINUS) {
if(y > 0) if(y > ymin)
return snap.getBlockType(bx, y-1, bz); return snap.getBlockType(bx, y-1, bz);
} }
else if(s == BlockStep.Y_PLUS) { else if(s == BlockStep.Y_PLUS) {
@ -547,16 +550,16 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
} }
@Override @Override
public long getBlockKey() { public long getBlockKey() {
return (((chunkindex * worldheight) + y) << 8) | (bx << 4) | bz; return (((chunkindex * (worldheight - ymin)) + (y - ymin)) << 8) | (bx << 4) | bz;
} }
@Override @Override
public final boolean isEmptySection() { public final boolean isEmptySection() {
try { boolean[] flags = isSectionNotEmpty[chunkindex];
return !isSectionNotEmpty[chunkindex][y >> 4]; if (flags == null) {
} catch (Exception x) {
initSectionData(chunkindex); initSectionData(chunkindex);
return !isSectionNotEmpty[chunkindex][y >> 4]; flags = isSectionNotEmpty[chunkindex];
} }
return !flags[(y >> 4) + sectoff];
} }
@Override @Override
public RenderPatchFactory getPatchFactory() { public RenderPatchFactory getPatchFactory() {
@ -677,7 +680,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
} }
@Override @Override
public boolean isSectionEmpty(int sy) { public boolean isSectionEmpty(int sy) {
return (sy < 4); return (sy >= 4);
} }
@Override @Override
public Object[] getBiomeBaseFromSnapshot() { public Object[] getBiomeBaseFromSnapshot() {
@ -705,7 +708,8 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
if(this.w == null) { if(this.w == null) {
this.chunks = new ArrayList<DynmapChunk>(); this.chunks = new ArrayList<DynmapChunk>();
} }
nsect = dw.worldheight >> 4; nsect = (dw.worldheight - dw.minY) >> 4;
sectoff = (-dw.minY) >> 4;
this.chunks = chunks; this.chunks = chunks;
/* Compute range */ /* Compute range */
if(chunks.size() == 0) { if(chunks.size() == 0) {
@ -966,7 +970,7 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
isSectionNotEmpty[idx] = new boolean[nsect + 1]; isSectionNotEmpty[idx] = new boolean[nsect + 1];
if(snaparray[idx] != EMPTY) { if(snaparray[idx] != EMPTY) {
for(int i = 0; i < nsect; i++) { for(int i = 0; i < nsect; i++) {
if(snaparray[idx].isSectionEmpty(i) == false) { if(snaparray[idx].isSectionEmpty(i - sectoff) == false) {
isSectionNotEmpty[idx][i] = true; isSectionNotEmpty[idx][i] = true;
} }
} }
@ -974,10 +978,12 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
} }
public boolean isEmptySection(int sx, int sy, int sz) { public boolean isEmptySection(int sx, int sy, int sz) {
int idx = (sx - x_min) + (sz - z_min) * x_dim; int idx = (sx - x_min) + (sz - z_min) * x_dim;
if(isSectionNotEmpty[idx] == null) { boolean[] flags = isSectionNotEmpty[idx];
if(flags == null) {
initSectionData(idx); initSectionData(idx);
flags = isSectionNotEmpty[idx];
} }
return !isSectionNotEmpty[idx][sy]; return !flags[sy + sectoff];
} }
/** /**

View file

@ -120,6 +120,10 @@ public abstract class BukkitVersionHelper {
* Get world border * Get world border
*/ */
public Polygon getWorldBorder(World world) { return null; } public Polygon getWorldBorder(World world) { return null; }
/**
* Get world minY
*/
public int getWorldMinY(World world) { return 0; }
/** /**
* Test if broken unloadChunk * Test if broken unloadChunk
*/ */

View file

@ -27,12 +27,13 @@ public class BukkitWorld extends DynmapWorld {
private DynmapLocation spawnloc = new DynmapLocation(); private DynmapLocation spawnloc = new DynmapLocation();
public BukkitWorld(World w) { public BukkitWorld(World w) {
this(w.getName(), w.getMaxHeight(), w.getSeaLevel(), w.getEnvironment()); this(w.getName(), w.getMaxHeight(), w.getSeaLevel(), w.getEnvironment(),
BukkitVersionHelper.helper.getWorldMinY(w));
setWorldLoaded(w); setWorldLoaded(w);
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP); new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
} }
public BukkitWorld(String name, int height, int sealevel, World.Environment env) { public BukkitWorld(String name, int height, int sealevel, World.Environment env, int miny) {
super(name, height, sealevel); super(name, height, sealevel, miny);
world = null; world = null;
this.env = env; this.env = env;
skylight = (env == World.Environment.NORMAL); skylight = (env == World.Environment.NORMAL);
@ -125,7 +126,7 @@ public class BukkitWorld extends DynmapWorld {
@Override @Override
public int getLightLevel(int x, int y, int z) { public int getLightLevel(int x, int y, int z) {
if(world != null) { if(world != null) {
if ((y >= 0) && (y < this.worldheight)) { if ((y >= minY) && (y < this.worldheight)) {
return world.getBlockAt(x, y, z).getLightLevel(); return world.getBlockAt(x, y, z).getLightLevel();
} }
return 0; return 0;
@ -153,7 +154,7 @@ public class BukkitWorld extends DynmapWorld {
@Override @Override
public int getSkyLightLevel(int x, int y, int z) { public int getSkyLightLevel(int x, int y, int z) {
if(world != null) { if(world != null) {
if ((y >= 0) && (y < this.worldheight)) { if ((y >= minY) && (y < this.worldheight)) {
return world.getBlockAt(x, y, z).getLightFromSky(); return world.getBlockAt(x, y, z).getLightFromSky();
} }
else { else {

View file

@ -821,6 +821,7 @@ public class DynmapPlugin {
if (!fw.isLoaded()) { if (!fw.isLoaded()) {
fw.setWorldLoaded(w); fw.setWorldLoaded(w);
} }
fw.updateWorld(w);
return fw; return fw;
} }
} }
@ -843,6 +844,7 @@ public class DynmapPlugin {
HashMap<String, Object> vals = new HashMap<String, Object>(); HashMap<String, Object> vals = new HashMap<String, Object>();
vals.put("name", fw.getRawName()); vals.put("name", fw.getRawName());
vals.put("height", fw.worldheight); vals.put("height", fw.worldheight);
vals.put("miny", fw.minY);
vals.put("sealevel", fw.sealevel); vals.put("sealevel", fw.sealevel);
vals.put("nether", fw.isNether()); vals.put("nether", fw.isNether());
vals.put("the_end", ((FabricWorld) fw).isTheEnd()); vals.put("the_end", ((FabricWorld) fw).isTheEnd());
@ -881,12 +883,13 @@ public class DynmapPlugin {
try { try {
String name = (String) world.get("name"); String name = (String) world.get("name");
int height = (Integer) world.get("height"); int height = (Integer) world.get("height");
Integer miny = (Integer) world.get("miny");
int sealevel = (Integer) world.get("sealevel"); int sealevel = (Integer) world.get("sealevel");
boolean nether = (Boolean) world.get("nether"); boolean nether = (Boolean) world.get("nether");
boolean theend = (Boolean) world.get("the_end"); boolean theend = (Boolean) world.get("the_end");
String title = (String) world.get("title"); String title = (String) world.get("title");
if (name != null) { if (name != null) {
FabricWorld fw = new FabricWorld(this, name, height, sealevel, nether, theend, title); FabricWorld fw = new FabricWorld(this, name, height, sealevel, nether, theend, title, (miny != null) ? miny : 0);
fw.setWorldUnloaded(); fw.setWorldUnloaded();
core.processWorldLoad(fw); core.processWorldLoad(fw);
worlds.put(fw.getName(), fw); worlds.put(fw.getName(), fw);

View file

@ -43,6 +43,7 @@ public class FabricMapChunkCache extends MapChunkCache {
private DynmapWorld dw; private DynmapWorld dw;
private ServerChunkManager cps; private ServerChunkManager cps;
private int nsect; private int nsect;
private int sectoff;
private List<DynmapChunk> chunks; private List<DynmapChunk> chunks;
private ListIterator<DynmapChunk> iterator; private ListIterator<DynmapChunk> iterator;
private int x_min, x_max, z_min, z_max; private int x_min, x_max, z_min, z_max;
@ -59,7 +60,6 @@ public class FabricMapChunkCache extends MapChunkCache {
private BiomeMap[][] biomemap; private BiomeMap[][] biomemap;
private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */
private static final BlockStep unstep[] = {BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, private static final BlockStep unstep[] = {BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS,
BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS
}; };
@ -111,6 +111,7 @@ public class FabricMapChunkCache extends MapChunkCache {
private BlockStep laststep; private BlockStep laststep;
private DynmapBlockState blk; private DynmapBlockState blk;
private final int worldheight; private final int worldheight;
private final int miny;
private final int x_base; private final int x_base;
private final int z_base; private final int z_base;
@ -124,6 +125,7 @@ public class FabricMapChunkCache extends MapChunkCache {
initialize(x0, y0, z0); initialize(x0, y0, z0);
worldheight = w.getHeight(); worldheight = w.getHeight();
miny = dw.minY;
} }
@Override @Override
@ -143,7 +145,7 @@ public class FabricMapChunkCache extends MapChunkCache {
laststep = BlockStep.Y_MINUS; laststep = BlockStep.Y_MINUS;
if ((y >= 0) && (y < worldheight)) { if ((y >= miny) && (y < worldheight)) {
blk = null; blk = null;
} else { } else {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
@ -481,7 +483,7 @@ public class FabricMapChunkCache extends MapChunkCache {
case 4: case 4:
y--; y--;
if (y < 0) { if (y < miny) {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
} }
@ -534,7 +536,7 @@ public class FabricMapChunkCache extends MapChunkCache {
this.y = y; this.y = y;
if ((y < 0) || (y >= worldheight)) { if ((y < miny) || (y >= worldheight)) {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
} else { } else {
blk = null; blk = null;
@ -559,7 +561,7 @@ public class FabricMapChunkCache extends MapChunkCache {
@Override @Override
public final DynmapBlockState getBlockTypeAt(BlockStep s) { public final DynmapBlockState getBlockTypeAt(BlockStep s) {
if (s == BlockStep.Y_MINUS) { if (s == BlockStep.Y_MINUS) {
if (y > 0) { if (y > miny) {
return snap.getBlockType(bx, y - 1, bz); return snap.getBlockType(bx, y - 1, bz);
} }
} else if (s == BlockStep.Y_PLUS) { } else if (s == BlockStep.Y_PLUS) {
@ -590,18 +592,18 @@ public class FabricMapChunkCache extends MapChunkCache {
@Override @Override
public long getBlockKey() { public long getBlockKey() {
return (((chunkindex * worldheight) + y) << 8) | (bx << 4) | bz; return (((chunkindex * (worldheight - miny)) + (y - miny)) << 8) | (bx << 4) | bz;
} }
@Override @Override
public final boolean isEmptySection() { public final boolean isEmptySection() {
try { boolean[] flags = isSectionNotEmpty[chunkindex];
return !isSectionNotEmpty[chunkindex][y >> 4]; if(flags == null) {
} catch (Exception x) { initSectionData(chunkindex);
initSectionData(chunkindex); flags = isSectionNotEmpty[chunkindex];
return !isSectionNotEmpty[chunkindex][y >> 4]; }
} return !flags[(y >> 4) + sectoff];
} }
@Override @Override
public RenderPatchFactory getPatchFactory() { public RenderPatchFactory getPatchFactory() {
@ -778,7 +780,7 @@ public class FabricMapChunkCache extends MapChunkCache {
@Override @Override
public boolean isSectionEmpty(int sy) { public boolean isSectionEmpty(int sy) {
return (sy < 4); return (sy > 3);
} }
} }
@ -836,7 +838,8 @@ public class FabricMapChunkCache extends MapChunkCache {
} else { } else {
chunks = new ArrayList<DynmapChunk>(); chunks = new ArrayList<DynmapChunk>();
} }
nsect = dw.worldheight >> 4; nsect = (dw.worldheight - dw.minY) >> 4;
sectoff = (-dw.minY) >> 4;
this.chunks = chunks; this.chunks = chunks;
/* Compute range */ /* Compute range */
@ -1261,7 +1264,7 @@ public class FabricMapChunkCache extends MapChunkCache {
if (snaparray[idx] != EMPTY) { if (snaparray[idx] != EMPTY) {
for (int i = 0; i < nsect; i++) { for (int i = 0; i < nsect; i++) {
if (snaparray[idx].isSectionEmpty(i) == false) { if (snaparray[idx].isSectionEmpty(i - sectoff) == false) {
isSectionNotEmpty[idx][i] = true; isSectionNotEmpty[idx][i] = true;
} }
} }
@ -1270,12 +1273,12 @@ public class FabricMapChunkCache extends MapChunkCache {
public boolean isEmptySection(int sx, int sy, int sz) { public boolean isEmptySection(int sx, int sy, int sz) {
int idx = (sx - x_min) + (sz - z_min) * x_dim; int idx = (sx - x_min) + (sz - z_min) * x_dim;
boolean[] flags = isSectionNotEmpty[idx];
if (isSectionNotEmpty[idx] == null) { if (flags == null) {
initSectionData(idx); initSectionData(idx);
flags = isSectionNotEmpty[idx];
} }
return !flags[sy + sectoff];
return !isSectionNotEmpty[idx][sy];
} }
/** /**

View file

@ -25,7 +25,7 @@ public class FabricWorld extends DynmapWorld {
private final boolean istheend; private final boolean istheend;
private final String env; private final String env;
private DynmapLocation spawnloc = new DynmapLocation(); private DynmapLocation spawnloc = new DynmapLocation();
private static int maxWorldHeight = 256; // Maximum allows world height private static int maxWorldHeight = 320; // Maximum allows world height
public static int getMaxWorldHeight() { public static int getMaxWorldHeight() {
return maxWorldHeight; return maxWorldHeight;
@ -48,17 +48,22 @@ public class FabricWorld extends DynmapWorld {
} }
} }
public void updateWorld(World w) {
this.updateWorldHeights(w.getHeight(), w.getDimension().getMinimumY(), w.getSeaLevel());
}
public FabricWorld(DynmapPlugin plugin, World w) { public FabricWorld(DynmapPlugin plugin, World w) {
this(plugin, getWorldName(plugin, w), w.getHeight(), this(plugin, getWorldName(plugin, w), w.getHeight(),
w.getSeaLevel(), w.getSeaLevel(),
w.getRegistryKey() == World.NETHER, w.getRegistryKey() == World.NETHER,
w.getRegistryKey() == World.END, w.getRegistryKey() == World.END,
w.getRegistryKey().getValue().getPath()); w.getRegistryKey().getValue().getPath(),
w.getDimension().getMinimumY());
setWorldLoaded(w); setWorldLoaded(w);
} }
public FabricWorld(DynmapPlugin plugin, String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle) { public FabricWorld(DynmapPlugin plugin, String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle, int miny) {
super(name, (height > maxWorldHeight) ? maxWorldHeight : height, sealevel); super(name, (height > maxWorldHeight) ? maxWorldHeight : height, sealevel, miny);
this.plugin = plugin; this.plugin = plugin;
world = null; world = null;
setTitle(deftitle); setTitle(deftitle);

View file

@ -63,7 +63,7 @@ public class ForgeWorld extends DynmapWorld
} }
public ForgeWorld(String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle) public ForgeWorld(String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle)
{ {
super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel); super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel, 0);
world = null; world = null;
setTitle(deftitle); setTitle(deftitle);
isnether = nether; isnether = nether;

View file

@ -1537,11 +1537,6 @@ public class DynmapPlugin
/* Initialized the currently loaded worlds */ /* Initialized the currently loaded worlds */
for (ServerLevel world : server.getAllLevels()) { for (ServerLevel world : server.getAllLevels()) {
ForgeWorld w = this.getWorld(world); ForgeWorld w = this.getWorld(world);
/*NOTYET - need rest of forge
if(DimensionManager.getWorld(world.provider.getDimensionId()) == null) { // If not loaded
w.setWorldUnloaded();
}
*/
} }
for(ForgeWorld w : worlds.values()) { for(ForgeWorld w : worlds.values()) {
if (core.processWorldLoad(w)) { /* Have core process load first - fire event listeners if good load after */ if (core.processWorldLoad(w)) { /* Have core process load first - fire event listeners if good load after */
@ -1858,6 +1853,7 @@ public class DynmapPlugin
if(fw.isLoaded() == false) { if(fw.isLoaded() == false) {
fw.setWorldLoaded(w); fw.setWorldLoaded(w);
} }
fw.updateWorld(w);
return fw; return fw;
} }
} }
@ -1880,6 +1876,7 @@ public class DynmapPlugin
HashMap<String, Object> vals = new HashMap<String, Object>(); HashMap<String, Object> vals = new HashMap<String, Object>();
vals.put("name", fw.getRawName()); vals.put("name", fw.getRawName());
vals.put("height", fw.worldheight); vals.put("height", fw.worldheight);
vals.put("miny", fw.minY);
vals.put("sealevel", fw.sealevel); vals.put("sealevel", fw.sealevel);
vals.put("nether", fw.isNether()); vals.put("nether", fw.isNether());
vals.put("the_end", ((ForgeWorld)fw).isTheEnd()); vals.put("the_end", ((ForgeWorld)fw).isTheEnd());
@ -1917,12 +1914,13 @@ public class DynmapPlugin
try { try {
String name = (String)world.get("name"); String name = (String)world.get("name");
int height = (Integer)world.get("height"); int height = (Integer)world.get("height");
Integer miny = (Integer) world.get("miny");
int sealevel = (Integer)world.get("sealevel"); int sealevel = (Integer)world.get("sealevel");
boolean nether = (Boolean)world.get("nether"); boolean nether = (Boolean)world.get("nether");
boolean theend = (Boolean)world.get("the_end"); boolean theend = (Boolean)world.get("the_end");
String title = (String)world.get("title"); String title = (String)world.get("title");
if(name != null) { if(name != null) {
ForgeWorld fw = new ForgeWorld(name, height, sealevel, nether, theend, title); ForgeWorld fw = new ForgeWorld(name, height, sealevel, nether, theend, title, (miny != null) ? miny : 0);
fw.setWorldUnloaded(); fw.setWorldUnloaded();
core.processWorldLoad(fw); core.processWorldLoad(fw);
worlds.put(fw.getName(), fw); worlds.put(fw.getName(), fw);

View file

@ -53,6 +53,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
private DynmapWorld dw; private DynmapWorld dw;
private ServerChunkCache cps; private ServerChunkCache cps;
private int nsect; private int nsect;
private int sectoff; // Offset for sake of negative section indexes
private List<DynmapChunk> chunks; private List<DynmapChunk> chunks;
private ListIterator<DynmapChunk> iterator; private ListIterator<DynmapChunk> iterator;
private int x_min, x_max, z_min, z_max; private int x_min, x_max, z_min, z_max;
@ -87,6 +88,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
private BlockStep laststep; private BlockStep laststep;
private DynmapBlockState blk; private DynmapBlockState blk;
private final int worldheight; private final int worldheight;
private final int ymin;
private final int x_base; private final int x_base;
private final int z_base; private final int z_base;
@ -100,6 +102,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
initialize(x0, y0, z0); initialize(x0, y0, z0);
worldheight = w.getHeight(); worldheight = w.getHeight();
ymin = dw.minY;
} }
@Override @Override
@ -119,7 +122,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
laststep = BlockStep.Y_MINUS; laststep = BlockStep.Y_MINUS;
if ((y >= 0) && (y < worldheight)) { if ((y >= ymin) && (y < worldheight)) {
blk = null; blk = null;
} else { } else {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
@ -481,7 +484,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
case 4: case 4:
y--; y--;
if (y < 0) { if (y < ymin) {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
} }
@ -535,7 +538,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
this.y = y; this.y = y;
if ((y < 0) || (y >= worldheight)) { if ((y < ymin) || (y >= worldheight)) {
blk = DynmapBlockState.AIR; blk = DynmapBlockState.AIR;
} else { } else {
blk = null; blk = null;
@ -560,7 +563,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
@Override @Override
public final DynmapBlockState getBlockTypeAt(BlockStep s) { public final DynmapBlockState getBlockTypeAt(BlockStep s) {
if (s == BlockStep.Y_MINUS) { if (s == BlockStep.Y_MINUS) {
if (y > 0) { if (y > ymin) {
return snap.getBlockType(bx, y - 1, bz); return snap.getBlockType(bx, y - 1, bz);
} }
} else if (s == BlockStep.Y_PLUS) { } else if (s == BlockStep.Y_PLUS) {
@ -591,17 +594,17 @@ public class ForgeMapChunkCache extends MapChunkCache {
@Override @Override
public long getBlockKey() { public long getBlockKey() {
return (((chunkindex * worldheight) + y) << 8) | (bx << 4) | bz; return (((chunkindex * (worldheight - ymin)) + (y - ymin)) << 8) | (bx << 4) | bz;
} }
@Override @Override
public final boolean isEmptySection() { public final boolean isEmptySection() {
try { boolean[] flags = isSectionNotEmpty[chunkindex];
return !isSectionNotEmpty[chunkindex][y >> 4]; if(flags == null) {
} catch (Exception x) {
initSectionData(chunkindex); initSectionData(chunkindex);
return !isSectionNotEmpty[chunkindex][y >> 4]; flags = isSectionNotEmpty[chunkindex];
} }
return !flags[(y >> 4) + sectoff];
} }
@Override @Override
@ -778,7 +781,7 @@ public class ForgeMapChunkCache extends MapChunkCache {
@Override @Override
public boolean isSectionEmpty(int sy) { public boolean isSectionEmpty(int sy) {
return (sy < 4); return (sy > 3);
} }
} }
@ -808,7 +811,8 @@ public class ForgeMapChunkCache extends MapChunkCache {
} else { } else {
chunks = new ArrayList<DynmapChunk>(); chunks = new ArrayList<DynmapChunk>();
} }
nsect = dw.worldheight >> 4; nsect = (dw.worldheight - dw.minY) >> 4;
sectoff = (-dw.minY) >> 4;
this.chunks = chunks; this.chunks = chunks;
/* Compute range */ /* Compute range */
@ -1227,22 +1231,22 @@ public class ForgeMapChunkCache extends MapChunkCache {
if (snaparray[idx] != EMPTY) { if (snaparray[idx] != EMPTY) {
for (int i = 0; i < nsect; i++) { for (int i = 0; i < nsect; i++) {
if (snaparray[idx].isSectionEmpty(i) == false) { if (snaparray[idx].isSectionEmpty(i - sectoff) == false) {
isSectionNotEmpty[idx][i] = true; isSectionNotEmpty[idx][i] = true;
} }
} }
} }
} }
public boolean isEmptySection(int sx, int sy, int sz) { public boolean isEmptySection(int sx, int sy, int sz) {
int idx = (sx - x_min) + (sz - z_min) * x_dim; int idx = (sx - x_min) + (sz - z_min) * x_dim;
boolean[] flags = isSectionNotEmpty[idx];
if (isSectionNotEmpty[idx] == null) { if(flags == null) {
initSectionData(idx); initSectionData(idx);
} flags = isSectionNotEmpty[idx];
}
return !isSectionNotEmpty[idx][sy]; return !flags[sy + sectoff];
} }
/** /**
* Get cache iterator * Get cache iterator

View file

@ -18,7 +18,6 @@ import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Polygon; import org.dynmap.utils.Polygon;
//import org.dynmap.Log;
public class ForgeWorld extends DynmapWorld public class ForgeWorld extends DynmapWorld
{ {
@ -28,7 +27,7 @@ public class ForgeWorld extends DynmapWorld
private final boolean istheend; private final boolean istheend;
private final String env; private final String env;
private DynmapLocation spawnloc = new DynmapLocation(); private DynmapLocation spawnloc = new DynmapLocation();
private static int maxWorldHeight = 256; // Maximum allows world height private static int maxWorldHeight = 320; // Maximum allows world height
public static int getMaxWorldHeight() { public static int getMaxWorldHeight() {
return maxWorldHeight; return maxWorldHeight;
@ -50,6 +49,10 @@ public class ForgeWorld extends DynmapWorld
} }
} }
public void updateWorld(ServerLevelAccessor w) {
this.updateWorldHeights(w.getLevel().getHeight(), w.getLevel().dimensionType().minY(), w.getLevel().getSeaLevel());
}
public ForgeWorld(ServerLevelAccessor w) public ForgeWorld(ServerLevelAccessor w)
{ {
this(getWorldName(w), this(getWorldName(w),
@ -57,12 +60,13 @@ public class ForgeWorld extends DynmapWorld
w.getLevel().getSeaLevel(), w.getLevel().getSeaLevel(),
w.getLevel().dimension() == Level.NETHER, w.getLevel().dimension() == Level.NETHER,
w.getLevel().dimension() == Level.END, w.getLevel().dimension() == Level.END,
getWorldName(w)); getWorldName(w),
w.getLevel().dimensionType().minY());
setWorldLoaded(w); setWorldLoaded(w);
} }
public ForgeWorld(String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle) public ForgeWorld(String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle, int miny)
{ {
super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel); super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel, miny);
world = null; world = null;
setTitle(deftitle); setTitle(deftitle);
isnether = nether; isnether = nether;

View file

@ -17,7 +17,7 @@ allprojects {
apply plugin: 'java' apply plugin: 'java'
group = 'us.dynmap' group = 'us.dynmap'
version = '3.2-beta-3' version = '3.2-SNAPSHOT'
} }