Paper/src/main/java/net/minecraft/server/ChunkSection.java
Mike Primm 40e6308718 Validate chunk data array lengths. Fixes BUKKIT-4093
If a chunk has somehow managed to save with arrays that are not 4096
entries long when reading them again we will get exceptions. Checking the
array length and resizing if needed is cheap so we should do this to help
avoid crashing servers due to this error.
2013-04-15 22:50:20 -05:00

277 Zeilen
8.6 KiB
Java

package net.minecraft.server;
public class ChunkSection {
private int yPos;
private int nonEmptyBlockCount;
private int tickingBlockCount;
private byte[] blockIds;
private NibbleArray extBlockIds;
private NibbleArray blockData;
private NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSection(int i, boolean flag) {
this.yPos = i;
this.blockIds = new byte[4096];
this.blockData = new NibbleArray(this.blockIds.length, 4);
this.blockLight = new NibbleArray(this.blockIds.length, 4);
if (flag) {
this.skyLight = new NibbleArray(this.blockIds.length, 4);
}
}
// CraftBukkit start
public ChunkSection(int y, boolean flag, byte[] blkIds, byte[] extBlkIds) {
this.yPos = y;
this.blockIds = blkIds;
if (extBlkIds != null) {
this.extBlockIds = new NibbleArray(extBlkIds, 4);
}
this.blockData = new NibbleArray(this.blockIds.length, 4);
this.blockLight = new NibbleArray(this.blockIds.length, 4);
if (flag) {
this.skyLight = new NibbleArray(this.blockIds.length, 4);
}
this.recalcBlockCounts();
}
// CraftBukkit end
public int a(int i, int j, int k) {
int l = this.blockIds[j << 8 | k << 4 | i] & 255;
return this.extBlockIds != null ? this.extBlockIds.a(i, j, k) << 8 | l : l;
}
public void a(int i, int j, int k, int l) {
int i1 = this.blockIds[j << 8 | k << 4 | i] & 255;
if (this.extBlockIds != null) {
i1 |= this.extBlockIds.a(i, j, k) << 8;
}
if (i1 == 0 && l != 0) {
++this.nonEmptyBlockCount;
if (Block.byId[l] != null && Block.byId[l].isTicking()) {
++this.tickingBlockCount;
}
} else if (i1 != 0 && l == 0) {
--this.nonEmptyBlockCount;
if (Block.byId[i1] != null && Block.byId[i1].isTicking()) {
--this.tickingBlockCount;
}
} else if (Block.byId[i1] != null && Block.byId[i1].isTicking() && (Block.byId[l] == null || !Block.byId[l].isTicking())) {
--this.tickingBlockCount;
} else if ((Block.byId[i1] == null || !Block.byId[i1].isTicking()) && Block.byId[l] != null && Block.byId[l].isTicking()) {
++this.tickingBlockCount;
}
this.blockIds[j << 8 | k << 4 | i] = (byte) (l & 255);
if (l > 255) {
if (this.extBlockIds == null) {
this.extBlockIds = new NibbleArray(this.blockIds.length, 4);
}
this.extBlockIds.a(i, j, k, (l & 3840) >> 8);
} else if (this.extBlockIds != null) {
this.extBlockIds.a(i, j, k, 0);
}
}
public int b(int i, int j, int k) {
return this.blockData.a(i, j, k);
}
public void b(int i, int j, int k, int l) {
this.blockData.a(i, j, k, l);
}
public boolean a() {
return this.nonEmptyBlockCount == 0;
}
public boolean b() {
return this.tickingBlockCount > 0;
}
public int d() {
return this.yPos;
}
public void c(int i, int j, int k, int l) {
this.skyLight.a(i, j, k, l);
}
public int c(int i, int j, int k) {
return this.skyLight.a(i, j, k);
}
public void d(int i, int j, int k, int l) {
this.blockLight.a(i, j, k, l);
}
public int d(int i, int j, int k) {
return this.blockLight.a(i, j, k);
}
public void recalcBlockCounts() {
// CraftBukkit start - Optimize for speed
byte[] blkIds = this.blockIds;
int cntNonEmpty = 0;
int cntTicking = 0;
if (this.extBlockIds == null) { // No extended block IDs? Don't waste time messing with them
for (int off = 0; off < blkIds.length; off++) {
int l = blkIds[off] & 0xFF;
if (l > 0) {
if (Block.byId[l] == null) {
blkIds[off] = 0;
} else {
++cntNonEmpty;
if (Block.byId[l].isTicking()) {
++cntTicking;
}
}
}
}
} else {
byte[] ext = this.extBlockIds.a;
for (int off = 0, off2 = 0; off < blkIds.length;) {
byte extid = ext[off2];
int l = (blkIds[off] & 0xFF) | ((extid & 0xF) << 8); // Even data
if (l > 0) {
if (Block.byId[l] == null) {
blkIds[off] = 0;
ext[off2] &= 0xF0;
} else {
++cntNonEmpty;
if (Block.byId[l].isTicking()) {
++cntTicking;
}
}
}
off++;
l = (blkIds[off] & 0xFF) | ((extid & 0xF0) << 4); // Odd data
if (l > 0) {
if (Block.byId[l] == null) {
blkIds[off] = 0;
ext[off2] &= 0x0F;
} else {
++cntNonEmpty;
if (Block.byId[l].isTicking()) {
++cntTicking;
}
}
}
off++;
off2++;
}
}
this.nonEmptyBlockCount = cntNonEmpty;
this.tickingBlockCount = cntTicking;
}
public void old_recalcBlockCounts() {
// CraftBukkit end
this.nonEmptyBlockCount = 0;
this.tickingBlockCount = 0;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 16; ++j) {
for (int k = 0; k < 16; ++k) {
int l = this.a(i, j, k);
if (l > 0) {
if (Block.byId[l] == null) {
this.blockIds[j << 8 | k << 4 | i] = 0;
if (this.extBlockIds != null) {
this.extBlockIds.a(i, j, k, 0);
}
} else {
++this.nonEmptyBlockCount;
if (Block.byId[l].isTicking()) {
++this.tickingBlockCount;
}
}
}
}
}
}
}
public byte[] g() {
return this.blockIds;
}
public NibbleArray i() {
return this.extBlockIds;
}
public NibbleArray j() {
return this.blockData;
}
public NibbleArray k() {
return this.blockLight;
}
public NibbleArray l() {
return this.skyLight;
}
public void a(byte[] abyte) {
this.blockIds = this.validateByteArray(abyte); // CraftBukkit - Validate data
}
public void a(NibbleArray nibblearray) {
// CraftBukkit start - Don't hang on to an empty nibble array
boolean empty = true;
for (int i = 0; i < nibblearray.a.length; i++) {
if (nibblearray.a[i] != 0) {
empty = false;
break;
}
}
if (empty) {
return;
}
// CraftBukkit end
this.extBlockIds = this.validateNibbleArray(nibblearray); // CraftBukkit - Validate data
}
public void b(NibbleArray nibblearray) {
this.blockData = this.validateNibbleArray(nibblearray); // CraftBukkit - Validate data
}
public void c(NibbleArray nibblearray) {
this.blockLight = this.validateNibbleArray(nibblearray); // CraftBukkit - Validate data
}
public void d(NibbleArray nibblearray) {
this.skyLight = this.validateNibbleArray(nibblearray); // CraftBukkit - Validate data
}
// CraftBukkit start - Validate array lengths
private NibbleArray validateNibbleArray(NibbleArray nibbleArray) {
if (nibbleArray != null && nibbleArray.a.length < 2048) {
byte[] newArray = new byte[2048];
System.arraycopy(nibbleArray.a, 0, newArray, 0, ((nibbleArray.a.length > 2048) ? 2048 : nibbleArray.a.length));
nibbleArray = new NibbleArray(newArray, 4);
}
return nibbleArray;
}
private byte[] validateByteArray(byte[] byteArray) {
if (byteArray != null && byteArray.length < 4096) {
byte[] newArray = new byte[4096];
System.arraycopy(byteArray, 0, newArray, 0, byteArray.length);
byteArray = newArray;
}
return byteArray;
}
// CraftBukkit end
}