mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 09:47:38 +00:00
Implemented new Anvil saving format, fixed old chunk saving format.
- Added 'Chunk' Interface. - Moved old 'Chunk' to 'OldChunk' and replaced dynamic world height reference with '128. - Added 'AnvilChunk' implementing the new anvil chunk format. - Added temp fixes to FileMcRegionChunkStore.java, TrueZipMcRegionChunkStore.java and ZippedMcRegionChunkStore.java too allow them to read .mca files. - Added the new 'IntArrayTag' since the new heightmap tag wasn't recognized. - Moved 'getChildTag' to 'NBTUtils'.
This commit is contained in:
parent
19b353f6b5
commit
8aabfb0c67
87
src/main/java/com/sk89q/jnbt/IntArrayTag.java
Normal file
87
src/main/java/com/sk89q/jnbt/IntArrayTag.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package com.sk89q.jnbt;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JNBT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 Graham Edgecombe
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of the JNBT team nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>TAG_Int_Array</code> tag.
|
||||||
|
*
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class IntArrayTag extends Tag {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value.
|
||||||
|
*/
|
||||||
|
private final int[] value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the tag.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name.
|
||||||
|
* @param value
|
||||||
|
* The value.
|
||||||
|
*/
|
||||||
|
public IntArrayTag(String name, int[] value) {
|
||||||
|
super(name);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder hex = new StringBuilder();
|
||||||
|
for (int b : value) {
|
||||||
|
String hexDigits = Integer.toHexString(b).toUpperCase();
|
||||||
|
if (hexDigits.length() == 1) {
|
||||||
|
hex.append("0");
|
||||||
|
}
|
||||||
|
hex.append(hexDigits).append(" ");
|
||||||
|
}
|
||||||
|
String name = getName();
|
||||||
|
String append = "";
|
||||||
|
if (name != null && !name.equals("")) {
|
||||||
|
append = "(\"" + this.getName() + "\")";
|
||||||
|
}
|
||||||
|
return "TAG_Int_Array" + append + ": " + hex.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -54,7 +54,7 @@ public final class NBTConstants {
|
|||||||
public static final int TYPE_END = 0, TYPE_BYTE = 1, TYPE_SHORT = 2,
|
public static final int TYPE_END = 0, TYPE_BYTE = 1, TYPE_SHORT = 2,
|
||||||
TYPE_INT = 3, TYPE_LONG = 4, TYPE_FLOAT = 5, TYPE_DOUBLE = 6,
|
TYPE_INT = 3, TYPE_LONG = 4, TYPE_FLOAT = 5, TYPE_DOUBLE = 6,
|
||||||
TYPE_BYTE_ARRAY = 7, TYPE_STRING = 8, TYPE_LIST = 9,
|
TYPE_BYTE_ARRAY = 7, TYPE_STRING = 8, TYPE_LIST = 9,
|
||||||
TYPE_COMPOUND = 10;
|
TYPE_COMPOUND = 10, TYPE_INT_ARRAY = 11;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default private constructor.
|
* Default private constructor.
|
||||||
|
@ -199,6 +199,13 @@ public final class NBTInputStream implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new CompoundTag(name, tagMap);
|
return new CompoundTag(name, tagMap);
|
||||||
|
case NBTConstants.TYPE_INT_ARRAY:
|
||||||
|
length = is.readInt();
|
||||||
|
int[] data = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
data[i] = is.readInt();
|
||||||
|
}
|
||||||
|
return new IntArrayTag(name, data);
|
||||||
default:
|
default:
|
||||||
throw new IOException("Invalid tag type: " + type + ".");
|
throw new IOException("Invalid tag type: " + type + ".");
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,8 @@ public final class NBTOutputStream implements Closeable {
|
|||||||
case NBTConstants.TYPE_COMPOUND:
|
case NBTConstants.TYPE_COMPOUND:
|
||||||
writeCompoundTagPayload((CompoundTag) tag);
|
writeCompoundTagPayload((CompoundTag) tag);
|
||||||
break;
|
break;
|
||||||
|
case NBTConstants.TYPE_INT_ARRAY:
|
||||||
|
writeIntArrayTagPayload((IntArrayTag) tag);
|
||||||
default:
|
default:
|
||||||
throw new IOException("Invalid tag type: " + type + ".");
|
throw new IOException("Invalid tag type: " + type + ".");
|
||||||
}
|
}
|
||||||
@ -309,6 +311,14 @@ public final class NBTOutputStream implements Closeable {
|
|||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException {
|
||||||
|
int[] data = tag.getValue();
|
||||||
|
os.writeInt(data.length);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
os.writeInt(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.sk89q.jnbt;
|
package com.sk89q.jnbt;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.sk89q.jnbt.ByteArrayTag;
|
import com.sk89q.jnbt.ByteArrayTag;
|
||||||
import com.sk89q.jnbt.ByteTag;
|
import com.sk89q.jnbt.ByteTag;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
@ -13,6 +15,7 @@ import com.sk89q.jnbt.NBTConstants;
|
|||||||
import com.sk89q.jnbt.ShortTag;
|
import com.sk89q.jnbt.ShortTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.data.InvalidFormatException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JNBT License
|
* JNBT License
|
||||||
@ -85,6 +88,8 @@ public final class NBTUtils {
|
|||||||
return "TAG_Short";
|
return "TAG_Short";
|
||||||
} else if (clazz.equals(StringTag.class)) {
|
} else if (clazz.equals(StringTag.class)) {
|
||||||
return "TAG_String";
|
return "TAG_String";
|
||||||
|
} else if (clazz.equals(IntArrayTag.class)) {
|
||||||
|
return "TAG_Int_Array";
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid tag classs ("
|
throw new IllegalArgumentException("Invalid tag classs ("
|
||||||
+ clazz.getName() + ").");
|
+ clazz.getName() + ").");
|
||||||
@ -123,6 +128,8 @@ public final class NBTUtils {
|
|||||||
return NBTConstants.TYPE_SHORT;
|
return NBTConstants.TYPE_SHORT;
|
||||||
} else if (clazz.equals(StringTag.class)) {
|
} else if (clazz.equals(StringTag.class)) {
|
||||||
return NBTConstants.TYPE_STRING;
|
return NBTConstants.TYPE_STRING;
|
||||||
|
} else if (clazz.equals(IntArrayTag.class)) {
|
||||||
|
return NBTConstants.TYPE_INT_ARRAY;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid tag classs ("
|
throw new IllegalArgumentException("Invalid tag classs ("
|
||||||
+ clazz.getName() + ").");
|
+ clazz.getName() + ").");
|
||||||
@ -162,6 +169,8 @@ public final class NBTUtils {
|
|||||||
return ListTag.class;
|
return ListTag.class;
|
||||||
case NBTConstants.TYPE_COMPOUND:
|
case NBTConstants.TYPE_COMPOUND:
|
||||||
return CompoundTag.class;
|
return CompoundTag.class;
|
||||||
|
case NBTConstants.TYPE_INT_ARRAY:
|
||||||
|
return IntArrayTag.class;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid tag type : " + type
|
throw new IllegalArgumentException("Invalid tag type : " + type
|
||||||
+ ".");
|
+ ".");
|
||||||
@ -175,4 +184,25 @@ public final class NBTUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get child tag of a NBT structure.
|
||||||
|
*
|
||||||
|
* @param items
|
||||||
|
* @param key
|
||||||
|
* @param expected
|
||||||
|
* @return child tag
|
||||||
|
* @throws InvalidFormatException
|
||||||
|
*/
|
||||||
|
public static <T extends Tag> T getChildTag(Map<String,Tag> items, String key,
|
||||||
|
Class<T> expected) throws InvalidFormatException {
|
||||||
|
if (!items.containsKey(key)) {
|
||||||
|
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
||||||
|
}
|
||||||
|
Tag tag = items.get(key);
|
||||||
|
if (!expected.isInstance(tag)) {
|
||||||
|
throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName());
|
||||||
|
}
|
||||||
|
return expected.cast(tag);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ public class ChestBlock extends BaseBlock implements TileEntityBlock, ContainerB
|
|||||||
throw new DataException("'Chest' tile entity expected");
|
throw new DataException("'Chest' tile entity expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTag items = (ListTag) Chunk.getChildTag(values, "Items", ListTag.class);
|
ListTag items = (ListTag) NBTUtils.getChildTag(values, "Items", ListTag.class);
|
||||||
BaseItemStack[] newItems = new BaseItemStack[27];
|
BaseItemStack[] newItems = new BaseItemStack[27];
|
||||||
|
|
||||||
for (Tag tag : items.getValue()) {
|
for (Tag tag : items.getValue()) {
|
||||||
@ -161,20 +161,20 @@ public class ChestBlock extends BaseBlock implements TileEntityBlock, ContainerB
|
|||||||
CompoundTag item = (CompoundTag) tag;
|
CompoundTag item = (CompoundTag) tag;
|
||||||
Map<String, Tag> itemValues = item.getValue();
|
Map<String, Tag> itemValues = item.getValue();
|
||||||
|
|
||||||
short id = Chunk.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
short id = NBTUtils.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
||||||
short damage = Chunk.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
short damage = NBTUtils.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
||||||
byte count = Chunk.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
byte count = NBTUtils.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
||||||
byte slot = Chunk.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
byte slot = NBTUtils.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
||||||
|
|
||||||
if (slot >= 0 && slot <= 26) {
|
if (slot >= 0 && slot <= 26) {
|
||||||
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
||||||
|
|
||||||
if(itemValues.containsKey("tag")) {
|
if(itemValues.containsKey("tag")) {
|
||||||
ListTag ench = (ListTag) Chunk.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
ListTag ench = (ListTag) NBTUtils.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
||||||
for(Tag e : ench.getValue()) {
|
for(Tag e : ench.getValue()) {
|
||||||
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
||||||
short enchid = Chunk.getChildTag(vars, "id", ShortTag.class).getValue();
|
short enchid = NBTUtils.getChildTag(vars, "id", ShortTag.class).getValue();
|
||||||
short enchlvl = Chunk.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
short enchlvl = NBTUtils.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
||||||
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ public class DispenserBlock extends BaseBlock implements TileEntityBlock, Contai
|
|||||||
throw new DataException("'Trap' tile entity expected");
|
throw new DataException("'Trap' tile entity expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTag items = (ListTag) Chunk.getChildTag(values, "Items", ListTag.class);
|
ListTag items = (ListTag) NBTUtils.getChildTag(values, "Items", ListTag.class);
|
||||||
BaseItemStack[] newItems = new BaseItemStack[9];
|
BaseItemStack[] newItems = new BaseItemStack[9];
|
||||||
|
|
||||||
for (Tag tag : items.getValue()) {
|
for (Tag tag : items.getValue()) {
|
||||||
@ -161,20 +161,20 @@ public class DispenserBlock extends BaseBlock implements TileEntityBlock, Contai
|
|||||||
CompoundTag item = (CompoundTag) tag;
|
CompoundTag item = (CompoundTag) tag;
|
||||||
Map<String, Tag> itemValues = item.getValue();
|
Map<String, Tag> itemValues = item.getValue();
|
||||||
|
|
||||||
short id = Chunk.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
short id = NBTUtils.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
||||||
short damage = Chunk.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
short damage = NBTUtils.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
||||||
byte count = Chunk.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
byte count = NBTUtils.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
||||||
byte slot = Chunk.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
byte slot = NBTUtils.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
||||||
|
|
||||||
if (slot >= 0 && slot <= 8) {
|
if (slot >= 0 && slot <= 8) {
|
||||||
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
||||||
|
|
||||||
if(itemValues.containsKey("tag")) {
|
if(itemValues.containsKey("tag")) {
|
||||||
ListTag ench = (ListTag) Chunk.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
ListTag ench = (ListTag) NBTUtils.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
||||||
for(Tag e : ench.getValue()) {
|
for(Tag e : ench.getValue()) {
|
||||||
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
||||||
short enchid = Chunk.getChildTag(vars, "id", ShortTag.class).getValue();
|
short enchid = NBTUtils.getChildTag(vars, "id", ShortTag.class).getValue();
|
||||||
short enchlvl = Chunk.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
short enchlvl = NBTUtils.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
||||||
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ public class FurnaceBlock extends BaseBlock implements TileEntityBlock, Containe
|
|||||||
throw new DataException("'Furnace' tile entity expected");
|
throw new DataException("'Furnace' tile entity expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTag items = (ListTag) Chunk.getChildTag(values, "Items", ListTag.class);
|
ListTag items = (ListTag) NBTUtils.getChildTag(values, "Items", ListTag.class);
|
||||||
BaseItemStack[] newItems = new BaseItemStack[3];
|
BaseItemStack[] newItems = new BaseItemStack[3];
|
||||||
|
|
||||||
for (Tag tag : items.getValue()) {
|
for (Tag tag : items.getValue()) {
|
||||||
@ -205,20 +205,20 @@ public class FurnaceBlock extends BaseBlock implements TileEntityBlock, Containe
|
|||||||
CompoundTag item = (CompoundTag) tag;
|
CompoundTag item = (CompoundTag) tag;
|
||||||
Map<String, Tag> itemValues = item.getValue();
|
Map<String, Tag> itemValues = item.getValue();
|
||||||
|
|
||||||
short id = Chunk.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
short id = NBTUtils.getChildTag(itemValues, "id", ShortTag.class).getValue();
|
||||||
short damage = Chunk.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
short damage = NBTUtils.getChildTag(itemValues, "Damage", ShortTag.class).getValue();
|
||||||
byte count = Chunk.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
byte count = NBTUtils.getChildTag(itemValues, "Count", ByteTag.class).getValue();
|
||||||
byte slot = Chunk.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
byte slot = NBTUtils.getChildTag(itemValues, "Slot", ByteTag.class).getValue();
|
||||||
|
|
||||||
if (slot >= 0 && slot <= 2) {
|
if (slot >= 0 && slot <= 2) {
|
||||||
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
BaseItemStack itemstack = new BaseItemStack(id, count, damage);
|
||||||
|
|
||||||
if(itemValues.containsKey("tag")) {
|
if(itemValues.containsKey("tag")) {
|
||||||
ListTag ench = (ListTag) Chunk.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
ListTag ench = (ListTag) NBTUtils.getChildTag(itemValues, "tag", CompoundTag.class).getValue().get("ench");
|
||||||
for(Tag e : ench.getValue()) {
|
for(Tag e : ench.getValue()) {
|
||||||
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
Map<String, Tag> vars = ((CompoundTag) e).getValue();
|
||||||
short enchid = Chunk.getChildTag(vars, "id", ShortTag.class).getValue();
|
short enchid = NBTUtils.getChildTag(vars, "id", ShortTag.class).getValue();
|
||||||
short enchlvl = Chunk.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
short enchlvl = NBTUtils.getChildTag(vars, "lvl", ShortTag.class).getValue();
|
||||||
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
itemstack.getEnchantments().put((int) enchid, (int)enchlvl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,8 +151,8 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock {
|
|||||||
throw new DataException("'MobSpawner' tile entity expected");
|
throw new DataException("'MobSpawner' tile entity expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
StringTag mobTypeTag = (StringTag) Chunk.getChildTag(values, "EntityId", StringTag.class);
|
StringTag mobTypeTag = (StringTag) NBTUtils.getChildTag(values, "EntityId", StringTag.class);
|
||||||
ShortTag delayTag = (ShortTag) Chunk.getChildTag(values, "Delay", ShortTag.class);
|
ShortTag delayTag = (ShortTag) NBTUtils.getChildTag(values, "Delay", ShortTag.class);
|
||||||
|
|
||||||
this.mobType = mobTypeTag.getValue();
|
this.mobType = mobTypeTag.getValue();
|
||||||
this.delay = delayTag.getValue();
|
this.delay = delayTag.getValue();
|
||||||
|
223
src/main/java/com/sk89q/worldedit/data/AnvilChunk.java
Normal file
223
src/main/java/com/sk89q/worldedit/data/AnvilChunk.java
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
package com.sk89q.worldedit.data;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.sk89q.jnbt.ByteArrayTag;
|
||||||
|
import com.sk89q.jnbt.ByteTag;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.IntTag;
|
||||||
|
import com.sk89q.jnbt.ListTag;
|
||||||
|
import com.sk89q.jnbt.NBTUtils;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.BlockVector;
|
||||||
|
import com.sk89q.worldedit.LocalWorld;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.BlockID;
|
||||||
|
import com.sk89q.worldedit.blocks.ChestBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.DispenserBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.FurnaceBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.NoteBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.SignBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||||
|
|
||||||
|
public class AnvilChunk implements Chunk {
|
||||||
|
|
||||||
|
private CompoundTag rootTag;
|
||||||
|
private byte[][] blocks;
|
||||||
|
private byte[][] data;
|
||||||
|
private int rootX;
|
||||||
|
private int rootZ;
|
||||||
|
|
||||||
|
private Map<BlockVector, Map<String,Tag>> tileEntities;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private LocalWorld world; // TODO: remove if stays unused.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the chunk with a compound tag.
|
||||||
|
*
|
||||||
|
* @param tag
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
public AnvilChunk(LocalWorld world, CompoundTag tag) throws DataException {
|
||||||
|
rootTag = tag;
|
||||||
|
this.world = world;
|
||||||
|
|
||||||
|
rootX = NBTUtils.getChildTag( rootTag.getValue(), "xPos", IntTag.class).getValue();
|
||||||
|
rootZ = NBTUtils.getChildTag( rootTag.getValue(), "zPos", IntTag.class).getValue();
|
||||||
|
|
||||||
|
blocks = new byte[16][16*16*16];
|
||||||
|
data = new byte[16][16*16*8];
|
||||||
|
List<Tag> sections = NBTUtils.getChildTag(rootTag.getValue(), "Sections", ListTag.class).getValue();
|
||||||
|
for(Tag section : sections) {
|
||||||
|
if(!(section instanceof CompoundTag)) continue;
|
||||||
|
CompoundTag compoundsection = (CompoundTag) section;
|
||||||
|
if(!compoundsection.getValue().containsKey("Y")) continue; // Empty section.
|
||||||
|
int y = NBTUtils.getChildTag(compoundsection.getValue(), "Y", ByteTag.class).getValue();
|
||||||
|
if(y < 0 || y >= 16) continue;
|
||||||
|
blocks[y] = NBTUtils.getChildTag(compoundsection.getValue(), "Blocks", ByteArrayTag.class).getValue();
|
||||||
|
data[y] = NBTUtils.getChildTag(compoundsection.getValue(), "Data", ByteArrayTag.class).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sectionsize = 16*16*16;
|
||||||
|
for(int i = 0; i < blocks.length; i++) {
|
||||||
|
if (blocks[i].length != sectionsize) {
|
||||||
|
throw new InvalidFormatException("Chunk blocks byte array expected "
|
||||||
|
+ "to be " + sectionsize + " bytes; found " + blocks[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < data.length; i++) {
|
||||||
|
if (data[i].length != (sectionsize/2)) {
|
||||||
|
throw new InvalidFormatException("Chunk block data byte array "
|
||||||
|
+ "expected to be " + sectionsize + " bytes; found " + data[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockID(Vector pos) throws DataException {
|
||||||
|
int x = pos.getBlockX() - rootX * 16;
|
||||||
|
int y = pos.getBlockY();
|
||||||
|
int z = pos.getBlockZ() - rootZ * 16;
|
||||||
|
|
||||||
|
int section = y >> 4;
|
||||||
|
if(section < 0 || section >= blocks.length) throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
int yindex = y & 0x0F;
|
||||||
|
if(yindex < 0 || yindex >= 16) throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
|
||||||
|
|
||||||
|
int index = x + (z * 16 + (yindex * 16 * 16));
|
||||||
|
try {
|
||||||
|
return blocks[section][index];
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockData(Vector pos) throws DataException {
|
||||||
|
int x = pos.getBlockX() - rootX * 16;
|
||||||
|
int y = pos.getBlockY();
|
||||||
|
int z = pos.getBlockZ() - rootZ * 16;
|
||||||
|
|
||||||
|
int section = y >> 4;
|
||||||
|
if(section < 0 || section >= blocks.length) throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
int yindex = y & 0x0F;
|
||||||
|
if(yindex < 0 || yindex >= 16) throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
|
||||||
|
|
||||||
|
int index = x + (z * 16 + (yindex * 16 * 16));
|
||||||
|
boolean shift = index % 2 == 0;
|
||||||
|
index /= 2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!shift) {
|
||||||
|
return (data[section][index] & 0xF0) >> 4;
|
||||||
|
} else {
|
||||||
|
return data[section][index] & 0xF;
|
||||||
|
}
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to load the tile entities.
|
||||||
|
*
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
private void populateTileEntities() throws DataException {
|
||||||
|
List<Tag> tags = NBTUtils.getChildTag(
|
||||||
|
rootTag.getValue(), "TileEntities", ListTag.class)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
tileEntities = new HashMap<BlockVector, Map<String, Tag>>();
|
||||||
|
|
||||||
|
for (Tag tag : tags) {
|
||||||
|
if (!(tag instanceof CompoundTag)) {
|
||||||
|
throw new InvalidFormatException("CompoundTag expected in TileEntities");
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag t = (CompoundTag) tag;
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int z = 0;
|
||||||
|
|
||||||
|
Map<String, Tag> values = new HashMap<String, Tag>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) {
|
||||||
|
if (entry.getKey().equals("x")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
x = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
} else if (entry.getKey().equals("y")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
y = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
} else if (entry.getKey().equals("z")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
z = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockVector vec = new BlockVector(x, y, z);
|
||||||
|
tileEntities.put(vec, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the map of tags keyed to strings for a block's tile entity data. May
|
||||||
|
* return null if there is no tile entity data. Not public yet because
|
||||||
|
* what this function returns isn't ideal for usage.
|
||||||
|
*
|
||||||
|
* @param pos
|
||||||
|
* @return
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
private Map<String, Tag> getBlockTileEntity(Vector pos) throws DataException {
|
||||||
|
if (tileEntities == null) {
|
||||||
|
populateTileEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tileEntities.get(new BlockVector(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseBlock getBlock(Vector pos) throws DataException {
|
||||||
|
int id = getBlockID(pos);
|
||||||
|
int data = getBlockData(pos);
|
||||||
|
BaseBlock block;
|
||||||
|
|
||||||
|
if (id == BlockID.WALL_SIGN || id == BlockID.SIGN_POST) {
|
||||||
|
block = new SignBlock(id, data);
|
||||||
|
} else if (id == BlockID.CHEST) {
|
||||||
|
block = new ChestBlock(data);
|
||||||
|
} else if (id == BlockID.FURNACE || id == BlockID.BURNING_FURNACE) {
|
||||||
|
block = new FurnaceBlock(id, data);
|
||||||
|
} else if (id == BlockID.DISPENSER) {
|
||||||
|
block = new DispenserBlock(data);
|
||||||
|
} else if (id == BlockID.MOB_SPAWNER) {
|
||||||
|
block = new MobSpawnerBlock(data);
|
||||||
|
} else if (id == BlockID.NOTE_BLOCK) {
|
||||||
|
block = new NoteBlock(data);
|
||||||
|
} else {
|
||||||
|
block = new BaseBlock(id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof TileEntityBlock) {
|
||||||
|
Map<String, Tag> tileEntity = getBlockTileEntity(pos);
|
||||||
|
((TileEntityBlock) block).fromTileEntityNBT(tileEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,75 +1,9 @@
|
|||||||
// $Id$
|
|
||||||
/*
|
|
||||||
* WorldEdit
|
|
||||||
* Copyright (C) 2010 sk89q <http://www.sk89q.com> and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sk89q.worldedit.data;
|
package com.sk89q.worldedit.data;
|
||||||
|
|
||||||
import java.util.List;
|
import com.sk89q.worldedit.Vector;
|
||||||
import java.util.Map;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import java.util.HashMap;
|
|
||||||
import com.sk89q.jnbt.*;
|
|
||||||
import com.sk89q.worldedit.*;
|
|
||||||
import com.sk89q.worldedit.blocks.*;
|
|
||||||
|
|
||||||
/**
|
public interface Chunk {
|
||||||
* Represents a chunk.
|
|
||||||
*
|
|
||||||
* @author sk89q
|
|
||||||
*/
|
|
||||||
public class Chunk {
|
|
||||||
private CompoundTag rootTag;
|
|
||||||
private byte[] blocks;
|
|
||||||
private byte[] data;
|
|
||||||
private int rootX;
|
|
||||||
private int rootZ;
|
|
||||||
|
|
||||||
private Map<BlockVector, Map<String,Tag>> tileEntities;
|
|
||||||
private LocalWorld world;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct the chunk with a compound tag.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @throws DataException
|
|
||||||
*/
|
|
||||||
public Chunk(LocalWorld world, CompoundTag tag) throws DataException {
|
|
||||||
rootTag = tag;
|
|
||||||
this.world = world;
|
|
||||||
|
|
||||||
blocks = getChildTag(
|
|
||||||
rootTag.getValue(), "Blocks", ByteArrayTag.class).getValue();
|
|
||||||
data = getChildTag(
|
|
||||||
rootTag.getValue(), "Data", ByteArrayTag.class).getValue();
|
|
||||||
rootX = getChildTag(
|
|
||||||
rootTag.getValue(), "xPos", IntTag.class).getValue();
|
|
||||||
rootZ = getChildTag(
|
|
||||||
rootTag.getValue(), "zPos", IntTag.class).getValue();
|
|
||||||
|
|
||||||
if (blocks.length != 16*16*(world.getMaxY() + 1)) {
|
|
||||||
throw new InvalidFormatException("Chunk blocks byte array expected "
|
|
||||||
+ "to be " + 16*16*(world.getMaxY() + 1) + " bytes; found " + blocks.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.length != 16*16*((world.getMaxY() + 1)/2)) {
|
|
||||||
throw new InvalidFormatException("Chunk block data byte array "
|
|
||||||
+ "expected to be " + 16*16*((world.getMaxY() + 1)/2) + " bytes; found " + data.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the block ID of a block.
|
* Get the block ID of a block.
|
||||||
@ -78,18 +12,7 @@ public class Chunk {
|
|||||||
* @return
|
* @return
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
*/
|
*/
|
||||||
public int getBlockID(Vector pos) throws DataException {
|
public int getBlockID(Vector pos) throws DataException;
|
||||||
int x = pos.getBlockX() - rootX * 16;
|
|
||||||
int y = pos.getBlockY();
|
|
||||||
int z = pos.getBlockZ() - rootZ * 16;
|
|
||||||
int index = y + (z * (world.getMaxY() + 1) + (x * (world.getMaxY() + 1) * 16));
|
|
||||||
|
|
||||||
try {
|
|
||||||
return blocks[index];
|
|
||||||
} catch (IndexOutOfBoundsException e) {
|
|
||||||
throw new DataException("Chunk does not contain position " + pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the block data of a block.
|
* Get the block data of a block.
|
||||||
@ -98,89 +21,8 @@ public class Chunk {
|
|||||||
* @return
|
* @return
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
*/
|
*/
|
||||||
public int getBlockData(Vector pos) throws DataException {
|
public int getBlockData(Vector pos) throws DataException;
|
||||||
int x = pos.getBlockX() - rootX * 16;
|
|
||||||
int y = pos.getBlockY();
|
|
||||||
int z = pos.getBlockZ() - rootZ * 16;
|
|
||||||
int index = y + (z * (world.getMaxY() + 1) + (x * (world.getMaxY() + 1) * 16));
|
|
||||||
boolean shift = index % 2 == 0;
|
|
||||||
index /= 2;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!shift) {
|
|
||||||
return (data[index] & 0xF0) >> 4;
|
|
||||||
} else {
|
|
||||||
return data[index] & 0xF;
|
|
||||||
}
|
|
||||||
} catch (IndexOutOfBoundsException e) {
|
|
||||||
throw new DataException("Chunk does not contain position " + pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to load the tile entities.
|
|
||||||
*
|
|
||||||
* @throws DataException
|
|
||||||
*/
|
|
||||||
private void populateTileEntities() throws DataException {
|
|
||||||
List<Tag> tags = getChildTag(
|
|
||||||
rootTag.getValue(), "TileEntities", ListTag.class)
|
|
||||||
.getValue();
|
|
||||||
|
|
||||||
tileEntities = new HashMap<BlockVector, Map<String, Tag>>();
|
|
||||||
|
|
||||||
for (Tag tag : tags) {
|
|
||||||
if (!(tag instanceof CompoundTag)) {
|
|
||||||
throw new InvalidFormatException("CompoundTag expected in TileEntities");
|
|
||||||
}
|
|
||||||
|
|
||||||
CompoundTag t = (CompoundTag) tag;
|
|
||||||
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
int z = 0;
|
|
||||||
|
|
||||||
Map<String, Tag> values = new HashMap<String, Tag>();
|
|
||||||
|
|
||||||
for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) {
|
|
||||||
if (entry.getKey().equals("x")) {
|
|
||||||
if (entry.getValue() instanceof IntTag) {
|
|
||||||
x = ((IntTag) entry.getValue()).getValue();
|
|
||||||
}
|
|
||||||
} else if (entry.getKey().equals("y")) {
|
|
||||||
if (entry.getValue() instanceof IntTag) {
|
|
||||||
y = ((IntTag) entry.getValue()).getValue();
|
|
||||||
}
|
|
||||||
} else if (entry.getKey().equals("z")) {
|
|
||||||
if (entry.getValue() instanceof IntTag) {
|
|
||||||
z = ((IntTag) entry.getValue()).getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
values.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockVector vec = new BlockVector(x, y, z);
|
|
||||||
tileEntities.put(vec, values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the map of tags keyed to strings for a block's tile entity data. May
|
|
||||||
* return null if there is no tile entity data. Not public yet because
|
|
||||||
* what this function returns isn't ideal for usage.
|
|
||||||
*
|
|
||||||
* @param pos
|
|
||||||
* @return
|
|
||||||
* @throws DataException
|
|
||||||
*/
|
|
||||||
private Map<String, Tag> getBlockTileEntity(Vector pos) throws DataException {
|
|
||||||
if (tileEntities == null) {
|
|
||||||
populateTileEntities();
|
|
||||||
}
|
|
||||||
|
|
||||||
return tileEntities.get(new BlockVector(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a block;
|
* Get a block;
|
||||||
@ -189,54 +31,5 @@ public class Chunk {
|
|||||||
* @return block
|
* @return block
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
*/
|
*/
|
||||||
public BaseBlock getBlock(Vector pos) throws DataException {
|
public BaseBlock getBlock(Vector pos) throws DataException;
|
||||||
int id = getBlockID(pos);
|
|
||||||
int data = getBlockData(pos);
|
|
||||||
BaseBlock block;
|
|
||||||
|
|
||||||
if (id == BlockID.WALL_SIGN || id == BlockID.SIGN_POST) {
|
|
||||||
block = new SignBlock(id, data);
|
|
||||||
} else if (id == BlockID.CHEST) {
|
|
||||||
block = new ChestBlock(data);
|
|
||||||
} else if (id == BlockID.FURNACE || id == BlockID.BURNING_FURNACE) {
|
|
||||||
block = new FurnaceBlock(id, data);
|
|
||||||
} else if (id == BlockID.DISPENSER) {
|
|
||||||
block = new DispenserBlock(data);
|
|
||||||
} else if (id == BlockID.MOB_SPAWNER) {
|
|
||||||
block = new MobSpawnerBlock(data);
|
|
||||||
} else if (id == BlockID.NOTE_BLOCK) {
|
|
||||||
block = new NoteBlock(data);
|
|
||||||
} else {
|
|
||||||
block = new BaseBlock(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block instanceof TileEntityBlock) {
|
|
||||||
Map<String, Tag> tileEntity = getBlockTileEntity(pos);
|
|
||||||
((TileEntityBlock) block).fromTileEntityNBT(tileEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get child tag of a NBT structure.
|
|
||||||
*
|
|
||||||
* @param items
|
|
||||||
* @param key
|
|
||||||
* @param expected
|
|
||||||
* @return child tag
|
|
||||||
* @throws InvalidFormatException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T extends Tag> T getChildTag(Map<String,Tag> items, String key,
|
|
||||||
Class<T> expected) throws InvalidFormatException {
|
|
||||||
if (!items.containsKey(key)) {
|
|
||||||
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
|
||||||
}
|
|
||||||
Tag tag = items.get(key);
|
|
||||||
if (!expected.isInstance(tag)) {
|
|
||||||
throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName());
|
|
||||||
}
|
|
||||||
return (T) tag;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
package com.sk89q.worldedit.data;
|
package com.sk89q.worldedit.data;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.sk89q.jnbt.*;
|
import com.sk89q.jnbt.*;
|
||||||
import com.sk89q.worldedit.*;
|
import com.sk89q.worldedit.*;
|
||||||
|
|
||||||
@ -64,7 +66,13 @@ public abstract class ChunkStore {
|
|||||||
*/
|
*/
|
||||||
public Chunk getChunk(Vector2D pos, LocalWorld world)
|
public Chunk getChunk(Vector2D pos, LocalWorld world)
|
||||||
throws DataException, IOException {
|
throws DataException, IOException {
|
||||||
return new Chunk(world, getChunkTag(pos, world));
|
|
||||||
|
CompoundTag tag = getChunkTag(pos, world);
|
||||||
|
Map<String, Tag> tags = tag.getValue();
|
||||||
|
if(tags.containsKey("Sections")) {
|
||||||
|
return new AnvilChunk(world, tag);
|
||||||
|
}
|
||||||
|
return new OldChunk(world, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,13 @@ public class FileMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
protected InputStream getInputStream(String name, String world) throws IOException,
|
protected InputStream getInputStream(String name, String world) throws IOException,
|
||||||
DataException {
|
DataException {
|
||||||
String fileName = "region" + File.separator + name;
|
String fileName = "region" + File.separator + name;
|
||||||
File file = new File(path, fileName);
|
File file = new File(path, fileName.replace("mcr", "mca")); // TODO: does this need a separate class?
|
||||||
|
if (!file.exists()) {
|
||||||
|
file = new File(path, fileName);
|
||||||
|
}
|
||||||
|
if (!file.exists()) {
|
||||||
|
file = new File(path, "DIM-1" + File.separator + fileName.replace("mcr", "mca")); // TODO: does this need a separate class?
|
||||||
|
}
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file = new File(path, "DIM-1" + File.separator + fileName);
|
file = new File(path, "DIM-1" + File.separator + fileName);
|
||||||
}
|
}
|
||||||
|
205
src/main/java/com/sk89q/worldedit/data/OldChunk.java
Normal file
205
src/main/java/com/sk89q/worldedit/data/OldChunk.java
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
// $Id$
|
||||||
|
/*
|
||||||
|
* WorldEdit
|
||||||
|
* Copyright (C) 2010 sk89q <http://www.sk89q.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import com.sk89q.jnbt.*;
|
||||||
|
import com.sk89q.worldedit.*;
|
||||||
|
import com.sk89q.worldedit.blocks.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a chunk.
|
||||||
|
*
|
||||||
|
* @author sk89q
|
||||||
|
*/
|
||||||
|
public class OldChunk implements Chunk {
|
||||||
|
private CompoundTag rootTag;
|
||||||
|
private byte[] blocks;
|
||||||
|
private byte[] data;
|
||||||
|
private int rootX;
|
||||||
|
private int rootZ;
|
||||||
|
|
||||||
|
private Map<BlockVector, Map<String,Tag>> tileEntities;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private LocalWorld world; // TODO: remove if stays unused.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the chunk with a compound tag.
|
||||||
|
*
|
||||||
|
* @param tag
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
public OldChunk(LocalWorld world, CompoundTag tag) throws DataException {
|
||||||
|
rootTag = tag;
|
||||||
|
this.world = world;
|
||||||
|
|
||||||
|
|
||||||
|
blocks = NBTUtils.getChildTag(rootTag.getValue(), "Blocks", ByteArrayTag.class).getValue();
|
||||||
|
data = NBTUtils.getChildTag( rootTag.getValue(), "Data", ByteArrayTag.class).getValue();
|
||||||
|
rootX = NBTUtils.getChildTag( rootTag.getValue(), "xPos", IntTag.class).getValue();
|
||||||
|
rootZ = NBTUtils.getChildTag( rootTag.getValue(), "zPos", IntTag.class).getValue();
|
||||||
|
|
||||||
|
int size = 16 * 16 * 128;
|
||||||
|
if (blocks.length != size) {
|
||||||
|
throw new InvalidFormatException("Chunk blocks byte array expected "
|
||||||
|
+ "to be " + size + " bytes; found " + blocks.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.length != (size/2)) {
|
||||||
|
throw new InvalidFormatException("Chunk block data byte array "
|
||||||
|
+ "expected to be " + size + " bytes; found " + data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockID(Vector pos) throws DataException {
|
||||||
|
if(pos.getBlockY() >= 128) return 0;
|
||||||
|
|
||||||
|
int x = pos.getBlockX() - rootX * 16;
|
||||||
|
int y = pos.getBlockY();
|
||||||
|
int z = pos.getBlockZ() - rootZ * 16;
|
||||||
|
int index = y + (z * 128 + (x * 128 * 16));
|
||||||
|
try {
|
||||||
|
return blocks[index];
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockData(Vector pos) throws DataException {
|
||||||
|
if(pos.getBlockY() >= 128) return 0;
|
||||||
|
|
||||||
|
int x = pos.getBlockX() - rootX * 16;
|
||||||
|
int y = pos.getBlockY();
|
||||||
|
int z = pos.getBlockZ() - rootZ * 16;
|
||||||
|
int index = y + (z * 128 + (x * 128 * 16));
|
||||||
|
boolean shift = index % 2 == 0;
|
||||||
|
index /= 2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!shift) {
|
||||||
|
return (data[index] & 0xF0) >> 4;
|
||||||
|
} else {
|
||||||
|
return data[index] & 0xF;
|
||||||
|
}
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new DataException("Chunk does not contain position " + pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to load the tile entities.
|
||||||
|
*
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
private void populateTileEntities() throws DataException {
|
||||||
|
List<Tag> tags = NBTUtils.getChildTag(
|
||||||
|
rootTag.getValue(), "TileEntities", ListTag.class)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
tileEntities = new HashMap<BlockVector, Map<String, Tag>>();
|
||||||
|
|
||||||
|
for (Tag tag : tags) {
|
||||||
|
if (!(tag instanceof CompoundTag)) {
|
||||||
|
throw new InvalidFormatException("CompoundTag expected in TileEntities");
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag t = (CompoundTag) tag;
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int z = 0;
|
||||||
|
|
||||||
|
Map<String, Tag> values = new HashMap<String, Tag>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) {
|
||||||
|
if (entry.getKey().equals("x")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
x = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
} else if (entry.getKey().equals("y")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
y = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
} else if (entry.getKey().equals("z")) {
|
||||||
|
if (entry.getValue() instanceof IntTag) {
|
||||||
|
z = ((IntTag) entry.getValue()).getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockVector vec = new BlockVector(x, y, z);
|
||||||
|
tileEntities.put(vec, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the map of tags keyed to strings for a block's tile entity data. May
|
||||||
|
* return null if there is no tile entity data. Not public yet because
|
||||||
|
* what this function returns isn't ideal for usage.
|
||||||
|
*
|
||||||
|
* @param pos
|
||||||
|
* @return
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
private Map<String, Tag> getBlockTileEntity(Vector pos) throws DataException {
|
||||||
|
if (tileEntities == null) {
|
||||||
|
populateTileEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tileEntities.get(new BlockVector(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseBlock getBlock(Vector pos) throws DataException {
|
||||||
|
int id = getBlockID(pos);
|
||||||
|
int data = getBlockData(pos);
|
||||||
|
BaseBlock block;
|
||||||
|
|
||||||
|
if (id == BlockID.WALL_SIGN || id == BlockID.SIGN_POST) {
|
||||||
|
block = new SignBlock(id, data);
|
||||||
|
} else if (id == BlockID.CHEST) {
|
||||||
|
block = new ChestBlock(data);
|
||||||
|
} else if (id == BlockID.FURNACE || id == BlockID.BURNING_FURNACE) {
|
||||||
|
block = new FurnaceBlock(id, data);
|
||||||
|
} else if (id == BlockID.DISPENSER) {
|
||||||
|
block = new DispenserBlock(data);
|
||||||
|
} else if (id == BlockID.MOB_SPAWNER) {
|
||||||
|
block = new MobSpawnerBlock(data);
|
||||||
|
} else if (id == BlockID.NOTE_BLOCK) {
|
||||||
|
block = new NoteBlock(data);
|
||||||
|
} else {
|
||||||
|
block = new BaseBlock(id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof TileEntityBlock) {
|
||||||
|
Map<String, Tag> tileEntity = getBlockTileEntity(pos);
|
||||||
|
((TileEntityBlock) block).fromTileEntityNBT(tileEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -101,12 +101,20 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Pattern pattern = Pattern.compile(".*\\.mcr$");
|
Pattern pattern = Pattern.compile(".*\\.mcr$");
|
||||||
|
Pattern patternmca = Pattern.compile(".*\\.mca$"); // TODO: does this need a separate class?
|
||||||
// World pattern
|
// World pattern
|
||||||
Pattern worldPattern = Pattern.compile(worldname + "\\$");
|
Pattern worldPattern = Pattern.compile(worldname + "\\$");
|
||||||
for (Enumeration<? extends ZipEntry> e = zip.entries(); e.hasMoreElements(); ) {
|
for (Enumeration<? extends ZipEntry> e = zip.entries(); e.hasMoreElements(); ) {
|
||||||
ZipEntry testEntry = (ZipEntry) e.nextElement();
|
ZipEntry testEntry = (ZipEntry) e.nextElement();
|
||||||
// Check for world
|
// Check for world
|
||||||
if (worldPattern.matcher(worldname).matches()) {
|
if (worldPattern.matcher(worldname).matches()) {
|
||||||
|
// Check for file
|
||||||
|
// TODO: does this need a separate class?
|
||||||
|
if (patternmca.matcher(testEntry.getName()).matches()) {
|
||||||
|
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
||||||
|
name = folder + "/" + name.replace("mcr", "mca");
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Check for file
|
// Check for file
|
||||||
if (pattern.matcher(testEntry.getName()).matches()) {
|
if (pattern.matcher(testEntry.getName()).matches()) {
|
||||||
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
||||||
@ -164,7 +172,7 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
|
|
||||||
ZipEntry testEntry = e.nextElement();
|
ZipEntry testEntry = e.nextElement();
|
||||||
|
|
||||||
if (testEntry.getName().matches(".*\\.mcr$")) {
|
if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,10 +99,17 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Pattern pattern = Pattern.compile(".*\\.mcr$");
|
Pattern pattern = Pattern.compile(".*\\.mcr$");
|
||||||
|
Pattern patternmca = Pattern.compile(".*\\.mca$"); // TODO: does this need a separate class?
|
||||||
for (Enumeration<? extends ZipEntry> e = zip.entries(); e.hasMoreElements(); ) {
|
for (Enumeration<? extends ZipEntry> e = zip.entries(); e.hasMoreElements(); ) {
|
||||||
ZipEntry testEntry = (ZipEntry) e.nextElement();
|
ZipEntry testEntry = (ZipEntry) e.nextElement();
|
||||||
// Check for world
|
// Check for world
|
||||||
if (testEntry.getName().startsWith(worldname + "/")) {
|
if (testEntry.getName().startsWith(worldname + "/")) {
|
||||||
|
// TODO: does this need a separate class?
|
||||||
|
if (patternmca.matcher(testEntry.getName()).matches()) {
|
||||||
|
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
||||||
|
name = folder + "/" + name.replace("mcr", "mca");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (pattern.matcher(testEntry.getName()).matches()) {
|
if (pattern.matcher(testEntry.getName()).matches()) {
|
||||||
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/"));
|
||||||
name = folder + "/" + name;
|
name = folder + "/" + name;
|
||||||
@ -159,7 +166,7 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
|
|
||||||
ZipEntry testEntry = e.nextElement();
|
ZipEntry testEntry = e.nextElement();
|
||||||
|
|
||||||
if (testEntry.getName().matches(".*\\.mcr$")) {
|
if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,25 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.snapshots;
|
package com.sk89q.worldedit.snapshots;
|
||||||
|
|
||||||
import com.sk89q.worldedit.*;
|
|
||||||
import com.sk89q.worldedit.regions.*;
|
|
||||||
import com.sk89q.worldedit.blocks.*;
|
|
||||||
import com.sk89q.worldedit.data.*;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.BlockVector2D;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.data.Chunk;
|
||||||
|
import com.sk89q.worldedit.data.ChunkStore;
|
||||||
|
import com.sk89q.worldedit.data.DataException;
|
||||||
|
import com.sk89q.worldedit.data.MissingChunkException;
|
||||||
|
import com.sk89q.worldedit.data.MissingWorldException;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user