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 feb29208a6
commit 809e45631c
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
/* World height data */
public final int worldheight;
public final int heightshift;
public final int heightmask;
public int worldheight; // really maxY+1
public int minY;
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) {
this(wname, worldheight, sealevel, 0);
}
protected DynmapWorld(String wname, int worldheight, int sealevel, int miny) {
this.raw_wname = wname;
this.wname = normalizeWorldName(wname);
this.hashcode = this.wname.hashCode();
this.title = wname;
this.worldheight = worldheight;
this.minY = miny;
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 */
for (int i = 0; i <= 15; ++i) {
float f1 = 1.0F - (float)i / 15.0F;
@ -319,7 +324,7 @@ public abstract class DynmapWorld {
}
title = worldconfig.getString("title", title);
ConfigurationNode ctr = worldconfig.getNode("center");
int mid_y = worldheight/2;
int mid_y = (worldheight + minY)/2;
if(ctr != null)
center = new DynmapLocation(wname, ctr.getDouble("x", 0.0), ctr.getDouble("y", mid_y), ctr.getDouble("z", 0));
else

View File

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

View File

@ -170,7 +170,7 @@ public class OBJExport {
else {
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 (centerOrigin) {
originX = (maxX + minX) / 2.0;

View File

@ -136,7 +136,6 @@ public class IsoHDPerspective implements HDPerspective {
final boolean isnether;
boolean skiptoair;
final int worldheight;
final int heightmask;
final LightLevels llcache[];
/* Cache for custom model patch lists */
@ -147,9 +146,6 @@ public class IsoHDPerspective implements HDPerspective {
mapiter = mi;
this.isnether = isnether;
worldheight = mapiter.getWorldHeight();
int shift;
for(shift = 0; (1<<shift) < worldheight; shift++) {}
heightmask = (1<<shift) - 1;
llcache = new LightLevels[4];
for(int i = 0; i < llcache.length; i++)
llcache[i] = new LightLevels();
@ -627,6 +623,7 @@ public class IsoHDPerspective implements HDPerspective {
/* Skip empty : return false if exited */
private final boolean raytraceSkipEmpty(MapChunkCache cache) {
int minsy = cache.getWorld().minY >> 4;
while(cache.isEmptySection(sx, sy, sz)) {
/* If Y step is next best */
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;
st_next_y += sdt_dy;
laststep = stepy;
if(sy < 0)
if (sy < minsy)
return false;
}
/* If X step is next best */
@ -658,7 +655,7 @@ public class IsoHDPerspective implements HDPerspective {
/**
* 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 ((t_next_y <= t_next_x) && (t_next_y <= t_next_z)) {
y += y_inc;
@ -667,7 +664,7 @@ public class IsoHDPerspective implements HDPerspective {
laststep = stepy;
mapiter.stepPosition(laststep);
/* If outside 0-(height-1) range */
if((y & (~heightmask)) != 0) {
if ((y < miny) || (y > maxy)) {
return false;
}
}
@ -694,6 +691,9 @@ public class IsoHDPerspective implements HDPerspective {
* Trace ray, based on "Voxel Tranversal along a 3D line"
*/
private final void raytrace(MapChunkCache cache, HDShaderState[] shaderstate, boolean[] shaderdone) {
int minY = cache.getWorld().minY;
int height = cache.getWorld().worldheight;
/* Initialize raytrace state variables */
raytrace_init();
@ -703,7 +703,7 @@ public class IsoHDPerspective implements HDPerspective {
raytrace_section_init();
if (y < 0)
if (y < minY)
return;
mapiter.initialize(x, y, z);
@ -712,7 +712,7 @@ public class IsoHDPerspective implements HDPerspective {
if (visit_block(shaderstate, shaderdone)) {
return;
}
if (!raytraceStepIterator()) {
if (!raytraceStepIterator(minY, height)) {
return;
}
}
@ -978,9 +978,7 @@ public class IsoHDPerspective implements HDPerspective {
/* Get max and min height */
maxheight = configuration.getInteger("maximumheight", -1);
int minh = configuration.getInteger("minimumheight", 0);
if(minh < 0) minh = 0;
minheight = minh;
minheight = configuration.getInteger("minimumheight", Integer.MIN_VALUE);
/* 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
* (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 z = 0; z <= 1; z++) {
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]);
/* Compute chunk coordinates of corner */
int cx = fastFloor(corners[idx].x / 16);
@ -1240,13 +1240,17 @@ public class IsoHDPerspective implements HDPerspective {
else
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++) {
ps.px = x;
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.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.bottom);
ps.direction.set(ps.bottom);

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@ public class FabricWorld extends DynmapWorld {
private final boolean istheend;
private final String env;
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() {
return maxWorldHeight;
@ -47,18 +47,23 @@ public class FabricWorld extends DynmapWorld {
return rk.getValue().getNamespace() + "_" + rk.getValue().getPath();
}
}
public void updateWorld(World w) {
this.updateWorldHeights(w.getHeight(), w.getDimension().getMinimumY(), w.getSeaLevel());
}
public FabricWorld(DynmapPlugin plugin, World w) {
this(plugin, getWorldName(plugin, w), w.getHeight(),
w.getSeaLevel(),
w.getRegistryKey() == World.NETHER,
w.getRegistryKey() == World.END,
w.getRegistryKey().getValue().getPath());
w.getRegistryKey().getValue().getPath(),
w.getDimension().getMinimumY());
setWorldLoaded(w);
}
public FabricWorld(DynmapPlugin plugin, String name, int height, int sealevel, boolean nether, boolean the_end, String deftitle) {
super(name, (height > maxWorldHeight) ? maxWorldHeight : height, sealevel);
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, miny);
this.plugin = plugin;
world = null;
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)
{
super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel);
super(name, (height > maxWorldHeight)?maxWorldHeight:height, sealevel, 0);
world = null;
setTitle(deftitle);
isnether = nether;

View File

@ -1537,11 +1537,6 @@ public class DynmapPlugin
/* Initialized the currently loaded worlds */
for (ServerLevel world : server.getAllLevels()) {
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()) {
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) {
fw.setWorldLoaded(w);
}
fw.updateWorld(w);
return fw;
}
}
@ -1880,6 +1876,7 @@ public class DynmapPlugin
HashMap<String, Object> vals = new HashMap<String, Object>();
vals.put("name", fw.getRawName());
vals.put("height", fw.worldheight);
vals.put("miny", fw.minY);
vals.put("sealevel", fw.sealevel);
vals.put("nether", fw.isNether());
vals.put("the_end", ((ForgeWorld)fw).isTheEnd());
@ -1917,12 +1914,13 @@ public class DynmapPlugin
try {
String name = (String)world.get("name");
int height = (Integer)world.get("height");
Integer miny = (Integer) world.get("miny");
int sealevel = (Integer)world.get("sealevel");
boolean nether = (Boolean)world.get("nether");
boolean theend = (Boolean)world.get("the_end");
String title = (String)world.get("title");
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();
core.processWorldLoad(fw);
worlds.put(fw.getName(), fw);

View File

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

View File

@ -18,7 +18,6 @@ import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Polygon;
//import org.dynmap.Log;
public class ForgeWorld extends DynmapWorld
{
@ -28,7 +27,7 @@ public class ForgeWorld extends DynmapWorld
private final boolean istheend;
private final String env;
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() {
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)
{
this(getWorldName(w),
@ -57,12 +60,13 @@ public class ForgeWorld extends DynmapWorld
w.getLevel().getSeaLevel(),
w.getLevel().dimension() == Level.NETHER,
w.getLevel().dimension() == Level.END,
getWorldName(w));
getWorldName(w),
w.getLevel().dimensionType().minY());
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;
setTitle(deftitle);
isnether = nether;

View File

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