diff --git a/common/src/main/java/common/network/NetConnection.java b/common/src/main/java/common/network/NetConnection.java index 38d2eb2..6a742a1 100755 --- a/common/src/main/java/common/network/NetConnection.java +++ b/common/src/main/java/common/network/NetConnection.java @@ -1,5 +1,6 @@ package common.network; +import java.io.IOException; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; import java.util.Queue; @@ -69,7 +70,7 @@ public class NetConnection extends SimpleChannelInboundHandler { } else { comp = "Interner Fehler: " + throwable; - if(!(throwable instanceof ClosedChannelException)) + if(!(throwable instanceof ClosedChannelException || throwable instanceof IOException)) Log.NETWORK.error(throwable, "Fehler in der Verbindung mit %s", this.getCutAddress()); } diff --git a/server/src/main/java/server/command/Command.java b/server/src/main/java/server/command/Command.java index 7828595..2eefab4 100644 --- a/server/src/main/java/server/command/Command.java +++ b/server/src/main/java/server/command/Command.java @@ -7,10 +7,12 @@ import java.util.Map; import common.collect.Lists; import common.collect.Maps; +import common.util.BlockPos; import common.util.CharValidator; import common.util.Vec3; import common.world.World; import server.command.DoubleParser.DefType; +import server.command.IntParser.CoordType; public abstract class Command implements Executable { private final String name; @@ -78,6 +80,25 @@ public abstract class Command implements Executable { new DoubleParser("z", defaulted ? DefType.Z : null, (double)(-World.MAX_SIZE), (double)World.MAX_SIZE, centered)); } + protected Command addBlockPos(String name, boolean defaulted) { + return this.addParameter(name, new ArgCombiner() { + public BlockPos combine(Integer[] values) { + return new BlockPos(values[0], values[1], values[2]); + } + + public Class getTypeClass() { + return BlockPos.class; + } + + public Class getInputClass() { + return Integer.class; + } + }, + new IntParser("x", defaulted ? CoordType.X : null, -World.MAX_SIZE, World.MAX_SIZE), + new IntParser("y", defaulted ? CoordType.Y : null, -World.MAX_SIZE_Y, World.MAX_SIZE_Y), + new IntParser("z", defaulted ? CoordType.Z : null, -World.MAX_SIZE, World.MAX_SIZE)); + } + protected Command addWorld(String name, boolean defaulted) { return this.addParameter(new WorldParser(name, false, defaulted)); } diff --git a/server/src/main/java/server/command/CommandEnvironment.java b/server/src/main/java/server/command/CommandEnvironment.java index 5a437b2..1d6fa90 100644 --- a/server/src/main/java/server/command/CommandEnvironment.java +++ b/server/src/main/java/server/command/CommandEnvironment.java @@ -14,6 +14,8 @@ import common.color.TextColor; import common.log.Log; import server.Server; import server.command.commands.CommandAdmin; +import server.command.commands.CommandBlock; +import server.command.commands.CommandFind; import server.command.commands.CommandHelp; import server.command.commands.CommandKick; import server.command.commands.CommandMessage; @@ -26,6 +28,7 @@ import server.command.commands.CommandRegister; import server.command.commands.CommandRemove; import server.command.commands.CommandRevoke; import server.command.commands.CommandSave; +import server.command.commands.CommandSeed; import server.command.commands.CommandShutdown; import server.command.commands.CommandSpawn; import server.command.commands.CommandTele; @@ -279,6 +282,9 @@ public class CommandEnvironment { this.registerExecutable(new CommandPlayers()); this.registerExecutable(new CommandSave()); this.registerExecutable(new CommandRegister()); + this.registerExecutable(new CommandFind()); + this.registerExecutable(new CommandBlock()); + this.registerExecutable(new CommandSeed()); this.registerExecutable(new CommandHelp(this)); } diff --git a/server/src/main/java/server/command/DoubleParser.java b/server/src/main/java/server/command/DoubleParser.java index 5b57bdb..2256de2 100644 --- a/server/src/main/java/server/command/DoubleParser.java +++ b/server/src/main/java/server/command/DoubleParser.java @@ -36,14 +36,21 @@ public class DoubleParser extends DefaultingParser { Double pre = this.defType != null && input.startsWith("~") ? this.getDefault(env) : null; input = pre != null ? input.substring(1) : input; double value; - try { - value = Double.parseDouble(input); + if(pre != null && input.isEmpty()) { + value = pre; } - catch(NumberFormatException e) { - throw new RunException("Ungültige Gleitkommazahl '%s'", input); + else { + try { + value = Double.parseDouble(input); + } + catch(NumberFormatException e) { + throw new RunException("Ungültige Gleitkommazahl '%s'", input); + } + if(this.center && pre == null && input.indexOf('.') < 0) + value += 0.5; + else if(pre != null) + value = pre + value; } - if(this.center && pre == null && input.indexOf('.') < 0) - value += 0.5; if(this.min != null && value < this.min) if(this.max != null) throw new RunException("Die Zahl muss im Bereich %f .. %f liegen, habe %f", this.min, this.max, value); diff --git a/server/src/main/java/server/command/IntParser.java b/server/src/main/java/server/command/IntParser.java index 4b9bdb4..23da522 100644 --- a/server/src/main/java/server/command/IntParser.java +++ b/server/src/main/java/server/command/IntParser.java @@ -1,24 +1,54 @@ package server.command; +import java.util.Collection; + +import common.collect.Lists; +import common.util.BlockPos; +import common.util.ExtMath; +import common.util.Position; + public class IntParser extends DefaultingParser { + public static enum CoordType { + X, Y, Z; + } + + private final CoordType defType; private final Integer min; private final Integer max; private final boolean hex; public IntParser(String name, boolean hex, Integer def, Integer min, Integer max, Object ... completions) { super(name, def, completions); + this.defType = null; this.min = min; this.max = max; this.hex = hex; } + public IntParser(String name, CoordType type, Integer min, Integer max) { + super(name, null); + this.defType = type; + this.min = min; + this.max = max; + this.hex = false; + } + public Integer parse(CommandEnvironment env, String input) { + Integer pre = this.defType != null && input.startsWith("~") ? this.getDefault(env) : null; + input = pre != null ? input.substring(1) : input; int value; - try { - value = Integer.parseInt(input, this.hex ? 16 : 10); + if(pre != null && input.isEmpty()) { + value = pre; } - catch(NumberFormatException e) { - throw new RunException("Ungültige " + (this.hex ? "Hexadezimalzahl" : "Ganzzahl") + " '%s'", input); + else { + try { + value = Integer.parseInt(input, this.hex ? 16 : 10); + } + catch(NumberFormatException e) { + throw new RunException("Ungültige " + (this.hex ? "Hexadezimalzahl" : "Ganzzahl") + " '%s'", input); + } + if(pre != null) + value = pre + value; } if(this.min != null && value < this.min) if(this.max != null) @@ -32,8 +62,36 @@ public class IntParser extends DefaultingParser { throw new RunException("Die Zahl darf höchstens %d betragen, habe %d", this.max, value); return value; } + + public Integer getDefault(CommandEnvironment env) { + Position pos = this.defType == null ? null : env.getExecutor().getExecPos(); + if(this.defType != null) + switch(this.defType) { + case X: + return pos == null ? null : ExtMath.floord(pos.x); + case Y: + return pos == null ? null : ExtMath.floord(pos.y); + case Z: + return pos == null ? null : ExtMath.floord(pos.z); + } + return (Integer)super.getDefault(env); + } public Class getTypeClass(boolean required) { return this.hasDefault() || required ? int.class : Integer.class; } + + public Collection getCompletions(CommandEnvironment env) { + BlockPos pos = this.defType == null ? null : env.getExecutor().getPointedPosition(); + if(this.defType != null) + switch(this.defType) { + case X: + return pos == null ? null : Lists.newArrayList("" + pos.getX()); + case Y: + return pos == null ? null : Lists.newArrayList("" + pos.getY()); + case Z: + return pos == null ? null : Lists.newArrayList("" + pos.getZ()); + } + return super.getCompletions(env); + } } diff --git a/server/src/main/java/server/command/commands/CommandBlock.java b/server/src/main/java/server/command/commands/CommandBlock.java new file mode 100644 index 0000000..4aa0de2 --- /dev/null +++ b/server/src/main/java/server/command/commands/CommandBlock.java @@ -0,0 +1,60 @@ +package server.command.commands; + +import java.util.Collection; +import common.init.BlockRegistry; +import common.nbt.NBTTagCompound; +import common.tileentity.TileEntity; +import common.util.BlockPos; +import common.world.State; +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; +import server.command.RunException; +import server.command.StringCompleter; +import server.world.WorldServer; + +public class CommandBlock extends Command { + public CommandBlock() { + super("block"); + + this.addString("block", false, new StringCompleter() { + public Collection complete(CommandEnvironment env) { + return BlockRegistry.REGISTRY.getKeys(); + } + }); + this.addBlockPos("position", true); + this.addWorld("dim", true); + + this.addTag("tag", 't'); + } + + public Object exec(CommandEnvironment env, Executor exec, String block, BlockPos position, WorldServer world, NBTTagCompound tag) { + State state = BlockRegistry.getFromIdName(block, null); + if(state == null) + throw new RunException("Block '%s' existiert nicht", block); + boolean success = world.setState(position, state); + if(tag != null) { + TileEntity tile = world.getTileEntity(position); + if(tile != null) { + NBTTagCompound te = new NBTTagCompound(); + tile.writeToNBT(te); + tag.setString("id", te.getString("id")); + tag.setInteger("x", position.getX()); + tag.setInteger("y", position.getY()); + tag.setInteger("z", position.getZ()); + te.merge(tag); + TileEntity newTile = TileEntity.createAndLoadEntity(te); + if(newTile != null) { + world.removeTileEntity(position); + world.setTileEntity(position, newTile); + success = true; + } + } + } + if(success) + exec.logConsole("%s bei %d, %d, %d in %s gesetzt", state.getBlock().getDisplay(), position.getX(), position.getY(), position.getZ(), world.dimension.getFormattedName(false)); + else + exec.logConsole("Block wurde nicht verändert"); + return success; + } +} diff --git a/server/src/main/java/server/command/commands/CommandFind.java b/server/src/main/java/server/command/commands/CommandFind.java new file mode 100644 index 0000000..93265fc --- /dev/null +++ b/server/src/main/java/server/command/commands/CommandFind.java @@ -0,0 +1,31 @@ +package server.command.commands; + +import java.util.List; + +import common.entity.Entity; +import common.util.BlockPos; +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; + +public class CommandFind extends Command { + public CommandFind() { + super("find"); + + this.addEntityList("entities", false); + } + + public Object exec(CommandEnvironment env, Executor exec, List entities) { + int done = 0; + for(Entity entity : entities) { + if(entity.isEntityAlive()) { + BlockPos pos = entity.getPosition(); + exec.logConsole("%s bei %d, %d, %d in %s gefunden", entity.getCommandName(), pos.getX(), pos.getY(), pos.getZ(), entity.worldObj.dimension.getFormattedName(false)); + done++; + } + } + if(done > 1) + exec.logConsole("%d Objekte gefunden", done); + return done; + } +} diff --git a/server/src/main/java/server/command/commands/CommandSeed.java b/server/src/main/java/server/command/commands/CommandSeed.java new file mode 100644 index 0000000..aa52527 --- /dev/null +++ b/server/src/main/java/server/command/commands/CommandSeed.java @@ -0,0 +1,19 @@ +package server.command.commands; + +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; +import server.world.WorldServer; + +public class CommandSeed extends Command { + public CommandSeed() { + super("seed"); + + this.addWorld("dim", true); + } + + public Object exec(CommandEnvironment env, Executor exec, WorldServer world) { + exec.logConsole("Startwert von %s: %d", world.dimension.getFormattedName(false), world.dimension.getSeed()); + return world.dimension.getSeed(); + } +} diff --git a/server/src/main/java/server/world/Converter.java b/server/src/main/java/server/world/Converter.java index 33f1ed6..56e36d5 100644 --- a/server/src/main/java/server/world/Converter.java +++ b/server/src/main/java/server/world/Converter.java @@ -2,14 +2,16 @@ package server.world; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.io.DataInput; import java.io.DataInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.RandomAccessFile; -import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.zip.GZIPInputStream; @@ -41,6 +43,7 @@ import common.block.natural.BlockSandStone; import common.block.tech.BlockPistonBase; import common.block.tech.BlockPistonHead; import common.block.tech.BlockTNT; +import common.collect.Lists; import common.collect.Maps; import common.color.DyeColor; import common.entity.Entity; @@ -66,6 +69,8 @@ import common.init.UniverseRegistry; import common.log.Log; import common.nbt.NBTLoader; import common.nbt.NBTTagCompound; +import common.nbt.NBTTagDouble; +import common.nbt.NBTTagFloat; import common.nbt.NBTTagList; import common.rng.Random; import common.tileentity.TileEntity; @@ -81,7 +86,6 @@ import common.tileentity.TileEntityFurnace; import common.tileentity.TileEntityHopper; import common.tileentity.TileEntityMobSpawner; import common.tileentity.TileEntityNote; -import common.tileentity.TileEntityPiston; import common.tileentity.TileEntitySign; import common.tileentity.TileEntitySkull; import common.util.Facing; @@ -92,6 +96,74 @@ import common.world.World; import server.Server; public abstract class Converter { + private static class OldNbtTag { + private final Map map = Maps.newHashMap(); + + private boolean has(String key, Class type) { + Object tag = this.map.get(key); + return tag != null && tag.getClass() == type; + } + + private List getList(String key, Class type) { + Object tag = this.map.get(key); + if(!(tag instanceof List)) + return Lists.newArrayList(); + List list = (List)tag; + return !list.isEmpty() && list.get(0).getClass() != type ? Lists.newArrayList() : list; + } + + public byte getByte(String key) { + return !this.has(key, Byte.class) ? 0 : (Byte)this.map.get(key); + } + + public int getInt(String key) { + return this.has(key, Integer.class) ? (Integer)this.map.get(key) : (this.has(key, Short.class) ? (Short)this.map.get(key) : this.getByte(key)); + } + + public String getString(String key) { + return !this.has(key, String.class) ? "" : (String)this.map.get(key); + } + + public byte[] getByteArray(String key) { + return !this.has(key, byte[].class) ? new byte[0] : (byte[])this.map.get(key); + } + + public int[] getIntArray(String key) { + return !this.has(key, int[].class) ? new int[0] : (int[])this.map.get(key); + } + + public OldNbtTag getTag(String key) { + return !this.has(key, OldNbtTag.class) ? new OldNbtTag() : (OldNbtTag)this.map.get(key); + } + + public float[] getFloatList(String key) { + List list = this.getList(key, Float.class); + float[] values = new float[list.size()]; + for(int z = 0; z < values.length; z++) { + values[z] = (Float)list.get(z); + } + return values; + } + + public double[] getDoubleList(String key) { + List list = this.getList(key, Double.class); + double[] values = new double[list.size()]; + for(int z = 0; z < values.length; z++) { + values[z] = (Double)list.get(z); + } + return values; + } + + public OldNbtTag[] getTagList(String key) { + List list = this.getList(key, OldNbtTag.class); + OldNbtTag[] values = new OldNbtTag[list.size()]; + for(int z = 0; z < values.length; z++) { + values[z] = (OldNbtTag)list.get(z); + } + return values; + } + } + private static enum SaveVersion { ALPHA_1_0("Alpha 1.0 - Beta 1.2"), BETA_1_3("Beta 1.3 - Release 1.8.9"), @@ -282,7 +354,7 @@ public abstract class Converter { mapTile(TileEntitySign.class, "Sign", "sign"); mapTile(TileEntityMobSpawner.class, "MobSpawner", "mob_spawner"); mapTile(TileEntityNote.class, "Music", "noteblock"); - mapTile(TileEntityPiston.class, "Piston", "piston"); + // mapTile(TileEntityPiston.class, "Piston", "piston"); mapTile(TileEntityEnchantmentTable.class, "EnchantTable", "enchanting_table"); mapTile(TileEntityBeacon.class, "Beacon", "beacon"); mapTile(TileEntitySkull.class, "Skull", "skull"); @@ -427,7 +499,7 @@ public abstract class Converter { return Blocks.wool.getState().withProperty(BlockColored.COLOR, DyeColor.byMetadata(data)); } }, 35); - mapBlockData(Blocks.piston_extension, 36); + mapBlock(Blocks.stone, 36); // mapBlockData(Blocks.piston_extension, 36); mapBlock(Blocks.flower.getState().withProperty(Blocks.flower.getTypeProperty(), BlockFlower.EnumFlowerType.DANDELION), 37); mapBlock(Blocks.flower.getState().withProperty(Blocks.flower.getTypeProperty(), BlockFlower.EnumFlowerType.POPPY), 38); @@ -801,11 +873,74 @@ public abstract class Converter { }, 252); mapBlock(Blocks.obsidian, 255); } + + private static Object read(DataInput input, byte id) throws IOException { + switch(id) { + case 0: + return null; + case 1: + return input.readByte(); + case 2: + return input.readShort(); + case 3: + return input.readInt(); + case 4: + return input.readLong(); + case 5: + return input.readFloat(); + case 6: + return input.readDouble(); + case 7: { + int len = input.readInt(); + byte[] data = new byte[len]; + input.readFully(data); + return data; + } + case 8: + return input.readUTF(); + case 9: { + byte type = input.readByte(); + int len = input.readInt(); + if(type == 0 && len > 0) + throw new RuntimeException("Liste hat keinen Typ"); + List list = new ArrayList(len); + for(int z = 0; z < len; z++) { + list.add(read(input, type)); + } + return list; + } + case 10: { + OldNbtTag tag = new OldNbtTag(); + byte type; + while((type = input.readByte()) != 0) { + String key = input.readUTF(); + tag.map.put(key, read(input, type)); + } + return tag; + } + case 11: { + int len = input.readInt(); + int[] data = new int[len]; + for(int z = 0; z < len; z++) { + data[z] = input.readInt(); + } + return data; + } + default: + return null; + } + } + + private static OldNbtTag readTag(DataInputStream in) throws IOException { + if(in.readByte() != 10) + throw new IOException("Tag hat den falschen Typ"); + in.readUTF(); + return (OldNbtTag)read(in, (byte)10); + } - private static void convertTile(NBTTagCompound ent) { - if("Sign".equals(ent.getString("id"))) { -// Log.debug("Konvertiere Schild bei " -// + ent.getInteger("x") + "," + ent.getInteger("y") + "," + ent.getInteger("z") + " ..."); + private static NBTTagCompound convertTile(OldNbtTag ent, String id) { + NBTTagCompound nent = new NBTTagCompound(); + if("Sign".equals(id)) { String[] signText = new String[4]; for(int i = 0; i < 4; ++i) { signText[i] = ent.getString("Text" + (i + 1)); @@ -815,15 +950,12 @@ public abstract class Converter { String[] old = new String[4]; for(int i = 0; i < 4; ++i) { old[i] = signText[i]; -// if(ChatFormat.hasLegacy(this.signText[i])) { - signText[i] = signText[i].indexOf('\u00A7') != -1 ? /* TextColor.replaceCodes( */ - signText[i].replaceAll("\u00A7[0-9a-fA-Fk-oK-O]", "") /* .replace("\u00A7", "$$")) */ : + signText[i] = signText[i].indexOf('\u00A7') != -1 ? + signText[i].replaceAll("\u00A7[0-9a-fA-Fk-oK-O]", "") : signText[i]; -// } if(signText[i].startsWith("{") && signText[i].endsWith("}")) { try { -// TextComponent comp = TextSerializer.toComponent(signText[i]); - signText[i] = ""; // comp.getFormattedText(); + signText[i] = ""; newComp++; } catch(Throwable e) { @@ -838,14 +970,21 @@ public abstract class Converter { if(newComp == 4 && (quotes & (1 << i)) != 0) { signText[i] = signText[i].substring(1, signText[i].length() - 1); } -// if(old[i] != signText[i]) { -// Log.debug("Zeile " + (i + 1) + ": '" + TextColor.stripCodes(signText[i]) + "'"); -// } } for(int i = 0; i < 4; ++i) { - ent.setString("Text" + (i + 1), signText[i]); + nent.setString("Text" + (i + 1), signText[i]); } } + else if("Comparator".equals(id)) { + nent.setInteger("OutputSignal", ent.getInt("OutputSignal")); + } + else if("Music".equals(id)) { + nent.setByte("note", ent.getByte("note")); + } + else if("Skull".equals(id)) { + nent.setByte("Rot", ent.getByte("Rot")); + } + return nent; } private static int getNibble(byte[] data, int x, int y, int z) { @@ -857,18 +996,33 @@ public abstract class Converter { int idx = name.indexOf(':'); return idx >= 0 ? name.substring(idx + 1) : name; // save compat } + + private static NBTTagList getList(float[] values) { + NBTTagList nlist = new NBTTagList(); + for(int z = 0; z < values.length; z++) { + nlist.appendTag(new NBTTagFloat(values[z])); + } + return nlist; + } + + private static NBTTagList getList(double[] values) { + NBTTagList nlist = new NBTTagList(); + for(int z = 0; z < values.length; z++) { + nlist.appendTag(new NBTTagDouble(values[z])); + } + return nlist; + } - private static NBTTagCompound convertChunkData(NBTTagCompound tag, boolean legacy) { - tag = tag.getCompoundTag("Level"); + private static NBTTagCompound convertChunkData(OldNbtTag tag, boolean legacy) { + NBTTagCompound ntag = new NBTTagCompound(); + tag = tag.getTag("Level"); if(legacy) { - if(tag.hasKey("LastUpdate", 3)) - tag.setLong("LastUpdate", (long)tag.getInteger("LastUpdate")); byte[] oldheight = tag.getByteArray("HeightMap"); int[] height = new int[oldheight.length]; for(int i = 0; i < oldheight.length; ++i) { height[i] = oldheight[i]; } - tag.setIntArray("HeightMap", height); + ntag.setIntArray("HeightMap", height); byte[] oldblks = tag.getByteArray("Blocks"); byte[] olddata = tag.getByteArray("Data"); byte[] oldsky = tag.getByteArray("SkyLight"); @@ -914,54 +1068,65 @@ public abstract class Converter { sections.appendTag(section); } } - tag.setTag("Sections", sections); + ntag.setTag("Sections", sections); byte[] biomes = new byte[256]; Arrays.fill(biomes, (byte)(Biome.DEF_BIOME.id & 255)); - tag.setByteArray("Biomes", biomes); + ntag.setByteArray("Biomes", biomes); } - NBTTagList ents = tag.getTagList("Entities", 10); + else { + ntag.setIntArray("HeightMap", tag.getIntArray("HeightMap")); + } + + ntag.setBoolean("TerrainPopulated", true); + ntag.setBoolean("LightPopulated", tag.getByte("LightPopulated") != 0); + + OldNbtTag[] ents = tag.getTagList("Entities"); NBTTagList entities = new NBTTagList(); - for(int z = 0; z < ents.tagCount(); z++) { - NBTTagCompound ent = ents.getCompoundTagAt(z); + for(OldNbtTag ent : ents) { + NBTTagCompound nent = new NBTTagCompound(); String mapped = ENTITY_MAP.get(trimColon(ent.getString("id"))); if(mapped != null) { - NBTTagList pos = ent.getTagList("Pos", 6); - NBTTagList motion = ent.getTagList("Motion", 6); - NBTTagList rotation = ent.getTagList("Rotation", 5); - boolean ground = ent.getBoolean("OnGround"); - ent.getKeySet().clear(); - ent.setTag("Pos", pos); - ent.setTag("Motion", motion); - ent.setTag("Rotation", rotation); - ent.setBoolean("OnGround", ground); - ent.setInteger("Dimension", 1); - ent.setString("id", mapped); - entities.appendTag(ent); + double[] pos = ent.getDoubleList("Pos"); + double[] motion = ent.getDoubleList("Motion"); + float[] rotation = ent.getFloatList("Rotation"); + if(pos.length != 3 || motion.length != 3 || rotation.length != 2) + continue; + boolean ground = ent.getByte("OnGround") != 0; + nent.setTag("Pos", getList(pos)); + nent.setTag("Motion", getList(motion)); + nent.setTag("Rotation", getList(rotation)); + nent.setBoolean("OnGround", ground); + nent.setInteger("Dimension", 1); + nent.setString("id", mapped); + entities.appendTag(nent); } } - tag.setTag("Entities", entities); + ntag.setTag("Entities", entities); - ents = tag.getTagList("TileEntities", 10); + ents = tag.getTagList("TileEntities"); entities = new NBTTagList(); - for(int z = 0; z < ents.tagCount(); z++) { - NBTTagCompound ent = ents.getCompoundTagAt(z); + for(OldNbtTag ent : ents) { + NBTTagCompound nent = new NBTTagCompound(); String mapped = TILE_MAP.get(trimColon(ent.getString("id"))); if(mapped != null) { - ent.setString("id", mapped); - convertTile(ent); - entities.appendTag(ent); + nent = convertTile(ent, mapped); + nent.setString("id", mapped); + nent.setInteger("x", ent.getInt("x")); + nent.setInteger("y", ent.getInt("y")); + nent.setInteger("z", ent.getInt("z")); + entities.appendTag(nent); } } - tag.setTag("TileEntities", entities); + ntag.setTag("TileEntities", entities); - tag.removeTag("TileTicks"); - - NBTTagList sects = tag.getTagList("Sections", 10); - for(int n = 0; n < sects.tagCount(); ++n) { - NBTTagCompound sect = sects.getCompoundTagAt(n); + OldNbtTag[] sects = tag.getTagList("Sections"); + entities = new NBTTagList(); + for(OldNbtTag sect : sects) { + NBTTagCompound nsect = new NBTTagCompound(); byte[] blocks = sect.getByteArray("Blocks"); NibbleArray data = new NibbleArray(sect.getByteArray("Data")); - NibbleArray adddata = sect.hasKey("Add", 7) ? new NibbleArray(sect.getByteArray("Add")) : null; + byte[] add = sect.getByteArray("Add"); + NibbleArray adddata = add.length > 0 ? new NibbleArray(add) : null; for(int c = 0; c < blocks.length; ++c) { int cx = c & 15; int cy = c >> 8 & 15; @@ -992,12 +1157,14 @@ public abstract class Converter { data.set(cx, cy, cz, cd & 15); } } - sect.setByteArray("Blocks", blocks); - sect.setByteArray("Data", data.getData()); + nsect.setByteArray("Blocks", blocks); + nsect.setByteArray("Data", data.getData()); if(adddata != null) - sect.setByteArray("Add", adddata.getData()); + nsect.setByteArray("Add", adddata.getData()); + entities.appendTag(nsect); } - return tag; + ntag.setTag("Sections", entities); + return ntag; } private static long convertChunks(File dir, File file, long start, int progress, int total) { @@ -1043,13 +1210,13 @@ public abstract class Converter { Log.IO.warn("Konnte " + file.getPath() + "@" + x + "," + z + " nicht lesen"); continue; } - NBTTagCompound tag = NBTLoader.read(in); + OldNbtTag tag = readTag(in); in.close(); - tag = convertChunkData(tag, legacy); + NBTTagCompound ntag = convertChunkData(tag, legacy); // DataOutputStream out = newreg.getOutputStream(nx, nz); // CompressedStreamTools.write(tag, out); // out.close(); - newreg.writeTag(nx, nz, tag); + newreg.writeTag(nx, nz, ntag); } } } @@ -1070,7 +1237,7 @@ public abstract class Converter { } return start; } - + public static boolean convert() { long cur = System.currentTimeMillis(); if(new File("server.nbt").exists()) @@ -1081,27 +1248,34 @@ public abstract class Converter { if(!ldat.exists()) return false; Log.IO.info("Welt wird konvertiert"); - NBTTagCompound nbt; + OldNbtTag nbt; + DataInputStream in = null; try { - nbt = NBTLoader.readGZip(ldat); + in = new DataInputStream(new BufferedInputStream(new GZIPInputStream(new FileInputStream(ldat)))); + nbt = readTag(in); } catch(Exception e) { Log.IO.error(e, "Fehler beim Lesen von level.dat"); return false; } - nbt = nbt.getCompoundTag("Data"); - int version = nbt.getInteger("version"); - int data = nbt.getInteger("DataVersion"); + finally { + try { + if(in != null) + in.close(); + } + catch(IOException e) { + } + } + nbt = nbt.getTag("Data"); + int version = nbt.getInt("version"); + int data = nbt.getInt("DataVersion"); // nbt.setBoolean("incompatible", data >= 1400); SaveVersion ver = data >= 1400 ? SaveVersion.RELEASE_1_13 : (data >= 100 ? SaveVersion.RELEASE_1_9 : (version == 19132 || version == 19133 ? SaveVersion.BETA_1_3 : (version == 0 ? SaveVersion.ALPHA_1_0 : null))); if(ver == null) { Log.IO.error("Version %d ist unbekannt", version); return false; } - long wtime = nbt.getLong(nbt.hasKey("DayTime", 99) ? "DayTime" : "Time") + World.START_TIME; Log.IO.info("Version: %s", ver); - Log.IO.info("Weltzeit: %d Ticks / %d Sekunden", wtime, wtime / 20L); - Log.IO.info("Zuletzt geladen: %s", new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new Date(nbt.getLong("LastPlayed")))); if(ver != SaveVersion.RELEASE_1_13) { Log.IO.info("Konvertiere Chunk-Daten von region/*.mca,*.mcr"); File regionDir = new File("region"); @@ -1143,16 +1317,14 @@ public abstract class Converter { Log.IO.info("Konvertiere Daten von level.dat"); Config.clear(); UniverseRegistry.clear(); - if(nbt.hasKey("GameRules", 10)) { - NBTTagCompound rules = nbt.getCompoundTag("GameRules"); - for(Entry rule : OLD_GAMERULES.entrySet()) { - if(rules.hasKey(rule.getKey(), 8)) - Config.set(rule.getValue(), rules.getString(rule.getKey()), false); - } + OldNbtTag rules = nbt.getTag("GameRules"); + for(Entry rule : OLD_GAMERULES.entrySet()) { + if(!rules.getString(rule.getKey()).isEmpty()) + Config.set(rule.getValue(), rules.getString(rule.getKey()), false); } Log.IO.info("Speichere neue server.nbt ..."); - Server.saveServerConfig(wtime); - Weather weather = nbt.getBoolean("thundering") ? Weather.THUNDER : (nbt.getBoolean("raining") ? Weather.RAIN : Weather.CLEAR); + Server.saveServerConfig(World.START_TIME); + Weather weather = nbt.getByte("thundering") != 0 ? Weather.THUNDER : (nbt.getByte("raining") != 0 ? Weather.RAIN : Weather.CLEAR); if(weather != Weather.CLEAR) { NBTTagCompound dataTag = new NBTTagCompound(); dataTag.setString("Weather", weather.getName());