Improved exceptions thrown in the data framework. ZippedAlphaChunkStore can now detect subdirectories that the world is in.

This commit is contained in:
sk89q 2010-10-20 11:32:08 -07:00
parent 32290b4095
commit d9a4a778ef
8 changed files with 160 additions and 26 deletions

View File

@ -49,11 +49,16 @@ public class AlphaChunkStore extends NestedFileChunkStore {
* @param f2
* @param name
* @return
* @throws DataException
* @throws IOException
*/
protected InputStream getInputStream(String f1, String f2, String name)
throws IOException {
throws DataException, IOException {
String file = f1 + File.separator + f2 + File.separator + name;
try {
return new FileInputStream(new File(path, file));
} catch (FileNotFoundException e) {
throw new MissingChunkException();
}
}
}

View File

@ -57,12 +57,14 @@ public class Chunk {
rootZ = ((IntTag)getChildTag(
rootTag.getValue(), "zPos", IntTag.class)).getValue();
if (blocks.length != 16384) {
throw new InvalidFormatException("Chunk blocks byte array expected to contain 16,384 blocks");
if (blocks.length != 32768) {
throw new InvalidFormatException("Chunk blocks byte array expected "
+ "to be 32,768 bytes; found " + blocks.length);
}
if (data.length != 16384) {
throw new InvalidFormatException("Chunk block data byte array expected to contain 16,384 blocks");
throw new InvalidFormatException("Chunk block data byte array "
+ "expected to be 16,384 bytes; found " + data.length);
}
}
@ -74,8 +76,10 @@ public class Chunk {
* @throws DataException
*/
public int getBlockID(Vector pos) throws DataException {
int index = pos.getBlockY() * 16 * 16
+ (pos.getBlockZ() - rootZ) * 16 + (pos.getBlockX() - rootX);
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];
@ -92,11 +96,19 @@ public class Chunk {
* @throws DataException
*/
public int getBlockData(Vector pos) throws DataException {
int index = pos.getBlockY() * 16 * 16
+ (pos.getBlockZ() - rootZ) * 16 + (pos.getBlockX() - rootX);
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 {
return data[index];
if (!shift) {
return (data[index] & 0xF0) >> 4;
} else {
return data[index] & 0xF;
}
} catch (IndexOutOfBoundsException e) {
throw new DataException("Chunk does not contain position " + pos);
}

View File

@ -49,11 +49,11 @@ public abstract class ChunkStore {
*
* @param pos
* @return tag
* @throws ChunkStoreException
* @throws DataException
* @throws IOException
*/
public abstract CompoundTag getChunkTag(Vector2D pos)
throws ChunkStoreException, IOException;
throws DataException, IOException;
/**
* Get a chunk at a location.

View File

@ -27,4 +27,8 @@ public class ChunkStoreException extends DataException {
public ChunkStoreException(String msg) {
super(msg);
}
public ChunkStoreException() {
super();
}
}

View File

@ -28,4 +28,8 @@ public class DataException extends Exception {
public DataException(String msg) {
super(msg);
}
public DataException() {
super();
}
}

View File

@ -0,0 +1,48 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 com.sk89q.worldedit.Vector2D;
/**
*
* @author sk89q
*/
public class MissingChunkException extends ChunkStoreException {
private Vector2D pos;
public MissingChunkException() {
super();
}
public MissingChunkException(Vector2D pos) {
super();
this.pos = pos;
}
/**
* Get chunk position in question. May be null if unknown.
*
* @return
*/
public Vector2D getChunkPosition() {
return pos;
}
}

View File

@ -21,6 +21,7 @@ package com.sk89q.worldedit.data;
import com.sk89q.worldedit.Vector2D;
import java.io.*;
import java.util.*;
import org.jnbt.*;
/**
@ -36,9 +37,11 @@ public abstract class NestedFileChunkStore extends ChunkStore {
*
* @param pos
* @return tag
* @throws DataException
* @throws IOException
*/
public CompoundTag getChunkTag(Vector2D pos)
throws ChunkStoreException, IOException {
throws DataException, IOException {
int x = pos.getBlockX();
int z = pos.getBlockZ();
@ -51,15 +54,37 @@ public abstract class NestedFileChunkStore extends ChunkStore {
NBTInputStream nbt = new NBTInputStream(stream);
Tag tag;
try {
tag = nbt.readTag();
if (!(tag instanceof CompoundTag)) {
throw new ChunkStoreException("CompoundTag expected for chunk; got "
+ tag.getClass());
+ tag.getClass().getName());
}
stream.close();
Map<String,Tag> children = (Map<String,Tag>)((CompoundTag)tag).getValue();
CompoundTag rootTag = null;
return (CompoundTag)tag;
// Find Level tag
for (Map.Entry<String,Tag> entry : children.entrySet()) {
if (entry.getKey().equals("Level")) {
if (entry.getValue() instanceof CompoundTag) {
rootTag = (CompoundTag)entry.getValue();
break;
} else {
throw new ChunkStoreException("CompoundTag expected for 'Level'; got "
+ entry.getValue().getClass().getName());
}
}
}
if (rootTag == null) {
throw new ChunkStoreException("Missing root 'Level' tag");
}
return rootTag;
} finally {
stream.close();
}
}
/**
@ -83,5 +108,5 @@ public abstract class NestedFileChunkStore extends ChunkStore {
* @throws IOException
*/
protected abstract InputStream getInputStream(String f1, String f2, String name)
throws IOException;
throws IOException, DataException;
}

View File

@ -21,6 +21,7 @@ package com.sk89q.worldedit.data;
import java.io.*;
import java.util.zip.*;
import java.util.Enumeration;
/**
* Represents the chunk store used by Minecraft alpha but zipped.
@ -43,7 +44,8 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
/**
* Create an instance. The folder argument lets you choose a folder or
* path to look into in the ZIP for the files.
* path to look into in the ZIP for the files. Use a blank string for
* the folder to not look into a subdirectory.
*
* @param zipFile
* @param folder
@ -59,7 +61,8 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
}
/**
* Create an instance.
* Create an instance. The subfolder containing the chunk data will
* be detected.
*
* @param zipFile
* @param folder
@ -81,13 +84,46 @@ public class ZippedAlphaChunkStore extends NestedFileChunkStore {
* @param name
* @return
* @throws IOException
* @throws DataException
*/
protected InputStream getInputStream(String f1, String f2, String name)
throws IOException {
throws IOException, DataException {
String file = f1 + "/" + f2 + "/" + name;
// Detect subfolder for the world's files
if (folder != null) {
if (!folder.equals("")) {
file = folder + "/" + file;
}
} else {
ZipEntry testEntry = zip.getEntry("level.dat");
// So, the data is not in the root directory
if (testEntry == null) {
// Let's try a world/ sub-directory
testEntry = zip.getEntry("world/level.dat");
// So not there either...
if (testEntry == null) {
for (Enumeration e = zip.entries(); e.hasMoreElements(); ) {
testEntry = (ZipEntry)e.nextElement();
// Whoo, found level.dat!
if (testEntry.getName().matches(".+/level\\.dat")) {
file = testEntry.getName().replaceAll("level\\.dat$", "")
+ file;
break;
}
}
} else {
file = "world/" + file;
}
}
}
ZipEntry entry = zip.getEntry(file);
if (entry == null) {
throw new IOException("ZIP doesn't contain chunk");
throw new MissingChunkException();
}
try {
return zip.getInputStream(entry);