Add handling for Y=negative

This commit is contained in:
Mike Primm 2021-08-21 12:27:01 -05:00
parent 453783731c
commit c5906166a1
3 changed files with 113 additions and 45 deletions

View File

@ -25,6 +25,7 @@ import net.minecraft.world.level.chunk.storage.ChunkRegionLoader;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
/** /**
* Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread
@ -40,6 +41,7 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
} }
private final int x, z; private final int x, z;
private final Section[] section; private final Section[] section;
private final int sectionOffset;
private final int[] hmap; // Height map private final int[] hmap; // Height map
private final int[] biome; private final int[] biome;
private final Object[] biomebase; private final Object[] biomebase;
@ -135,7 +137,7 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
this.sectionCnt = worldheight / 16; this.sectionCnt = worldheight / 16;
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; this.section = new Section[this.sectionCnt+1];
this.sectionOffset = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
this.section[i] = empty_section; this.section[i] = empty_section;
@ -160,26 +162,34 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
this.inhabitedTicks = 0; this.inhabitedTicks = 0;
} }
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; LinkedList<Section> sections = new LinkedList<Section>();
int sectoff = 0; // Default to zero
int sectcnt = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
this.section[i] = empty_section; sections.add(empty_section);
sectcnt++;
} }
/* Get sections */ /* Get sections */
NBTTagList sect = nbt.getList("Sections", 10); NBTTagList sect = nbt.getList("Sections", 10);
for (int i = 0; i < sect.size(); i++) { for (int i = 0; i < sect.size(); i++) {
NBTTagCompound sec = sect.getCompound(i); NBTTagCompound sec = sect.getCompound(i);
int secnum = sec.getByte("Y"); int secnum = sec.getByte("Y");
if (secnum >= this.sectionCnt) { // Beyond end - extend up
//Log.info("Section " + (int) secnum + " above world height " + worldheight); while (secnum >= (sectcnt - sectoff)) {
continue; sections.addLast(empty_section); // Pad with empty
sectcnt++;
} }
if (secnum < 0) // Negative - see if we need to extend sectionOffset
continue; while ((secnum + sectoff) < 0) {
sections.addFirst(empty_section); // Pad with empty
sectoff++;
sectcnt++;
}
//System.out.println("section(" + secnum + ")=" + sec.asString()); //System.out.println("section(" + secnum + ")=" + sec.asString());
// Create normal section to initialize // Create normal section to initialize
StdSection cursect = new StdSection(); StdSection cursect = new StdSection();
this.section[secnum] = cursect; sections.set(secnum + sectoff, cursect);
DynmapBlockState[] states = cursect.states; DynmapBlockState[] states = cursect.states;
DynmapBlockState[] palette = null; DynmapBlockState[] palette = null;
// If we've got palette and block states list, process non-empty section // If we've got palette and block states list, process non-empty section
@ -264,6 +274,9 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
} }
} }
} }
// Finalize sections array
this.section = sections.toArray(new Section[sections.size()]);
this.sectionOffset = sectoff;
} }
public int getX() public int getX()
@ -277,18 +290,24 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
} }
public DynmapBlockState getBlockType(int x, int y, int z) public DynmapBlockState getBlockType(int x, int y, int z)
{ {
return section[y >> 4].getBlockType(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return DynmapBlockState.AIR;
return section[idx].getBlockType(x, y, z);
} }
public int getBlockSkyLight(int x, int y, int z) public int getBlockSkyLight(int x, int y, int z)
{ {
return section[y >> 4].getBlockSkyLight(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 15;
return section[idx].getBlockSkyLight(x, y, z);
} }
public int getBlockEmittedLight(int x, int y, int z) public int getBlockEmittedLight(int x, int y, int z)
{ {
return section[y >> 4].getBlockEmittedLight(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 0;
return section[idx].getBlockEmittedLight(x, y, z);
} }
public int getHighestBlockYAt(int x, int z) public int getHighestBlockYAt(int x, int z)
@ -303,7 +322,9 @@ public class MapChunkCache117 extends AbstractMapChunkCache {
public boolean isSectionEmpty(int sy) public boolean isSectionEmpty(int sy)
{ {
return section[sy].isEmpty(); int idx = sy + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return true;
return section[idx].isEmpty();
} }
public long getInhabitedTicks() { public long getInhabitedTicks() {

View File

@ -9,6 +9,7 @@ import org.dynmap.Log;
import org.dynmap.renderer.DynmapBlockState; import org.dynmap.renderer.DynmapBlockState;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
/** /**
* Represents a static, thread-safe snapshot of chunk of blocks * Represents a static, thread-safe snapshot of chunk of blocks
@ -27,6 +28,7 @@ public class ChunkSnapshot {
private final int x, z; private final int x, z;
private final Section[] section; private final Section[] section;
private final int sectionOffset;
private final int[] hmap; // Height map private final int[] hmap; // Height map
private final int[] biome; private final int[] biome;
private final long captureFulltime; private final long captureFulltime;
@ -115,7 +117,7 @@ public class ChunkSnapshot {
this.sectionCnt = worldheight / 16; this.sectionCnt = worldheight / 16;
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; this.section = new Section[this.sectionCnt+1];
this.sectionOffset = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
this.section[i] = empty_section; this.section[i] = empty_section;
@ -153,26 +155,34 @@ public class ChunkSnapshot {
this.inhabitedTicks = 0; this.inhabitedTicks = 0;
} }
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; LinkedList<Section> sections = new LinkedList<Section>();
int sectoff = 0; // Default to zero
int sectcnt = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
this.section[i] = empty_section; sections.add(empty_section);
sectcnt++;
} }
/* Get sections */ /* Get sections */
NbtList sect = nbt.getList("Sections", 10); NbtList sect = nbt.getList("Sections", 10);
for (int i = 0; i < sect.size(); i++) { for (int i = 0; i < sect.size(); i++) {
NbtCompound sec = sect.getCompound(i); NbtCompound sec = sect.getCompound(i);
int secnum = sec.getByte("Y"); int secnum = sec.getByte("Y");
if (secnum >= this.sectionCnt) { // Beyond end - extend up
//Log.info("Section " + (int) secnum + " above world height " + worldheight); while (secnum >= (sectcnt - sectoff)) {
continue; sections.addLast(empty_section); // Pad with empty
sectcnt++;
} }
if (secnum < 0) // Negative - see if we need to extend sectionOffset
continue; while ((secnum + sectoff) < 0) {
sections.addFirst(empty_section); // Pad with empty
sectoff++;
sectcnt++;
}
//System.out.println("section(" + secnum + ")=" + sec.asString()); //System.out.println("section(" + secnum + ")=" + sec.asString());
// Create normal section to initialize // Create normal section to initialize
StdSection cursect = new StdSection(); StdSection cursect = new StdSection();
this.section[secnum] = cursect; sections.set(secnum + sectoff, cursect);
DynmapBlockState[] states = cursect.states; DynmapBlockState[] states = cursect.states;
DynmapBlockState[] palette = null; DynmapBlockState[] palette = null;
// If we've got palette and block states list, process non-empty section // If we've got palette and block states list, process non-empty section
@ -258,6 +268,9 @@ public class ChunkSnapshot {
} }
} }
} }
// Finalize sections array
this.section = sections.toArray(new Section[sections.size()]);
this.sectionOffset = sectoff;
} }
public int getX() { public int getX() {
@ -268,16 +281,25 @@ public class ChunkSnapshot {
return z; return z;
} }
public DynmapBlockState getBlockType(int x, int y, int z) { public DynmapBlockState getBlockType(int x, int y, int z)
return section[y >> 4].getBlockType(x, y, z); {
int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return DynmapBlockState.AIR;
return section[idx].getBlockType(x, y, z);
} }
public int getBlockSkyLight(int x, int y, int z) { public int getBlockSkyLight(int x, int y, int z)
return section[y >> 4].getBlockSkyLight(x, y, z); {
int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 15;
return section[idx].getBlockSkyLight(x, y, z);
} }
public int getBlockEmittedLight(int x, int y, int z) { public int getBlockEmittedLight(int x, int y, int z)
return section[y >> 4].getBlockEmittedLight(x, y, z); {
int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 0;
return section[idx].getBlockEmittedLight(x, y, z);
} }
public int getHighestBlockYAt(int x, int z) { public int getHighestBlockYAt(int x, int z) {
@ -292,8 +314,11 @@ public class ChunkSnapshot {
return captureFulltime; return captureFulltime;
} }
public boolean isSectionEmpty(int sy) { public boolean isSectionEmpty(int sy)
return section[sy].isEmpty(); {
int idx = sy + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return true;
return section[idx].isEmpty();
} }
public long getInhabitedTicks() { public long getInhabitedTicks() {

View File

@ -1,6 +1,7 @@
package org.dynmap.forge_1_17_1; package org.dynmap.forge_1_17_1;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import org.dynmap.renderer.DynmapBlockState; import org.dynmap.renderer.DynmapBlockState;
import org.dynmap.utils.DataBitsPacked; import org.dynmap.utils.DataBitsPacked;
@ -25,7 +26,8 @@ public class ChunkSnapshot
} }
private final int x, z; private final int x, z;
private final Section[] section; private final Section[] section; // Section, indexed by (Y/16) + sectionOffset (to handle negatives)
private final int sectionOffset; // Offset - section[N] = section for Y = N-sectionOffset
private final int[] hmap; // Height map private final int[] hmap; // Height map
private final int[] biome; private final int[] biome;
private final long captureFulltime; private final long captureFulltime;
@ -109,6 +111,7 @@ public class ChunkSnapshot
this.sectionCnt = worldheight / 16; this.sectionCnt = worldheight / 16;
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; this.section = new Section[this.sectionCnt+1];
this.sectionOffset = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
@ -134,26 +137,34 @@ public class ChunkSnapshot
this.inhabitedTicks = 0; this.inhabitedTicks = 0;
} }
/* Allocate arrays indexed by section */ /* Allocate arrays indexed by section */
this.section = new Section[this.sectionCnt+1]; LinkedList<Section> sections = new LinkedList<Section>();
int sectoff = 0; // Default to zero
int sectcnt = 0;
/* Fill with empty data */ /* Fill with empty data */
for (int i = 0; i <= this.sectionCnt; i++) { for (int i = 0; i <= this.sectionCnt; i++) {
this.section[i] = empty_section; sections.add(empty_section);
sectcnt++;
} }
/* Get sections */ /* Get sections */
ListTag sect = nbt.getList("Sections", 10); ListTag sect = nbt.getList("Sections", 10);
for (int i = 0; i < sect.size(); i++) { for (int i = 0; i < sect.size(); i++) {
CompoundTag sec = sect.getCompound(i); CompoundTag sec = sect.getCompound(i);
int secnum = sec.getByte("Y"); int secnum = sec.getByte("Y");
if (secnum >= this.sectionCnt) { // Beyond end - extend up
//Log.info("Section " + (int) secnum + " above world height " + worldheight); while (secnum >= (sectcnt - sectoff)) {
continue; sections.addLast(empty_section); // Pad with empty
sectcnt++;
} }
if (secnum < 0) // Negative - see if we need to extend sectionOffset
continue; while ((secnum + sectoff) < 0) {
sections.addFirst(empty_section); // Pad with empty
sectoff++;
sectcnt++;
}
//System.out.println("section(" + secnum + ")=" + sec.asString()); //System.out.println("section(" + secnum + ")=" + sec.asString());
// Create normal section to initialize // Create normal section to initialize
StdSection cursect = new StdSection(); StdSection cursect = new StdSection();
this.section[secnum] = cursect; sections.set(secnum + sectoff, cursect);
DynmapBlockState[] states = cursect.states; DynmapBlockState[] states = cursect.states;
DynmapBlockState[] palette = null; DynmapBlockState[] palette = null;
// If we've got palette and block states list, process non-empty section // If we've got palette and block states list, process non-empty section
@ -234,6 +245,9 @@ public class ChunkSnapshot
} }
} }
} }
// Finalize sections array
this.section = sections.toArray(new Section[sections.size()]);
this.sectionOffset = sectoff;
} }
public int getX() public int getX()
@ -247,18 +261,24 @@ public class ChunkSnapshot
} }
public DynmapBlockState getBlockType(int x, int y, int z) public DynmapBlockState getBlockType(int x, int y, int z)
{ {
return section[y >> 4].getBlockType(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return DynmapBlockState.AIR;
return section[idx].getBlockType(x, y, z);
} }
public int getBlockSkyLight(int x, int y, int z) public int getBlockSkyLight(int x, int y, int z)
{ {
return section[y >> 4].getBlockSkyLight(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 15;
return section[idx].getBlockSkyLight(x, y, z);
} }
public int getBlockEmittedLight(int x, int y, int z) public int getBlockEmittedLight(int x, int y, int z)
{ {
return section[y >> 4].getBlockEmittedLight(x, y, z); int idx = (y >> 4) + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return 0;
return section[idx].getBlockEmittedLight(x, y, z);
} }
public int getHighestBlockYAt(int x, int z) public int getHighestBlockYAt(int x, int z)
@ -278,7 +298,9 @@ public class ChunkSnapshot
public boolean isSectionEmpty(int sy) public boolean isSectionEmpty(int sy)
{ {
return section[sy].isEmpty(); int idx = sy + sectionOffset;
if ((idx < 0) || (idx >= section.length)) return true;
return section[idx].isEmpty();
} }
public long getInhabitedTicks() { public long getInhabitedTicks() {