diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 7f3669c9b..792940723 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -27,6 +27,7 @@ import com.volmit.iris.core.link.OraxenLink; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.service.StudioSVC; +import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.engine.object.IrisCompat; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisWorld; @@ -476,6 +477,16 @@ public class Iris extends VolmitPlugin implements Listener { } } + public static void panic() + { + EnginePanic.panic(); + } + + public static void addPanic(String s, String v) + { + EnginePanic.add(s, v); + } + @SuppressWarnings("unchecked") public void onEnable() { enable(); diff --git a/src/main/java/com/volmit/iris/engine/EnginePanic.java b/src/main/java/com/volmit/iris/engine/EnginePanic.java new file mode 100644 index 000000000..41689f282 --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/EnginePanic.java @@ -0,0 +1,54 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * 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 . + */ + +package com.volmit.iris.engine; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.collection.KMap; + +public class EnginePanic { + private static final KMap stuff = new KMap<>(); + private static KMap last = new KMap<>(); + + public static void add(String key, String value) + { + stuff.put(key, value); + } + + public static void saveLast() + { + last = stuff.copy(); + } + + public static void lastPanic() + { + for(String i : last.keySet()) + { + Iris.error("Last Panic " + i + ": " + stuff.get(i)); + } + } + + public static void panic() + { + lastPanic(); + for(String i : stuff.keySet()) + { + Iris.error("Engine Panic " + i + ": " + stuff.get(i)); + } + } +} diff --git a/src/main/java/com/volmit/iris/util/data/DUTF.java b/src/main/java/com/volmit/iris/util/data/DUTF.java new file mode 100644 index 000000000..54ba81a01 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/data/DUTF.java @@ -0,0 +1,55 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * 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 . + */ + +package com.volmit.iris.util.data; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +/** + *

Encodes signed and unsigned values using a common variable-length + * scheme, found for example in + * + * Google's Protocol Buffers. It uses fewer bytes to encode smaller values, + * but will use slightly more bytes to encode large values.

+ *

+ *

Signed values are further encoded using so-called zig-zag encoding + * in order to make them "compatible" with variable-length encoding.

+ */ +public final class DUTF { + + private DUTF() { + } + + public static void write(String s, DataOutputStream dos) throws IOException { + byte[] b = s.getBytes(StandardCharsets.UTF_8); + dos.writeShort(b.length); + dos.write(b); + } + + public static String read(DataInputStream din) throws IOException { + byte[] d = new byte[din.readShort()]; + din.read(d); + return new String(d, StandardCharsets.UTF_8); + } +} \ No newline at end of file diff --git a/src/main/java/com/volmit/iris/util/hunk/bits/DataContainer.java b/src/main/java/com/volmit/iris/util/hunk/bits/DataContainer.java index 65c7fcbf7..ca236c6ed 100644 --- a/src/main/java/com/volmit/iris/util/hunk/bits/DataContainer.java +++ b/src/main/java/com/volmit/iris/util/hunk/bits/DataContainer.java @@ -30,8 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class DataContainer { - protected static final int INITIAL_BITS = 2; - protected static final int LINEAR_BITS_LIMIT = 5; + protected static final int INITIAL_BITS = 3; + protected static final int LINEAR_BITS_LIMIT = 4; protected static final int LINEAR_INITIAL_LENGTH = (int) Math.pow(2, LINEAR_BITS_LIMIT) + 1; protected static final int[] BIT = computeBitLimits(); private final AtomicReference> palette; @@ -56,6 +56,51 @@ public class DataContainer { this.bits = new AtomicInteger(palette.get().bits()); } + public static String readBitString(DataInputStream din) throws IOException + { + DataContainer c = new DataContainer<>(din, new Writable() { + @Override + public Character readNodeData(DataInputStream din) throws IOException { + return din.readChar(); + } + + @Override + public void writeNodeData(DataOutputStream dos, Character character) throws IOException { + dos.writeChar(character); + } + }); + + StringBuilder sb = new StringBuilder(); + + for(int i = c.size()-1; i >= 0; i--) + { + sb.setCharAt(i, c.get(i)); + } + + return sb.toString(); + } + + public static void writeBitString(String s, DataOutputStream dos) throws IOException { + DataContainer c = new DataContainer<>(new Writable() { + @Override + public Character readNodeData(DataInputStream din) throws IOException { + return din.readChar(); + } + + @Override + public void writeNodeData(DataOutputStream dos, Character character) throws IOException { + dos.writeChar(character); + } + }, s.length()); + + for(int i = 0; i < s.length(); i++) + { + c.set(i, s.charAt(i)); + } + + c.writeDos(dos); + } + public DataBits getData() { return data.get(); @@ -125,7 +170,7 @@ public class DataContainer { } private void expandOne() { - if (palette.get().size() + 1 >= BIT[bits.get()] - 1) { + if (palette.get().size() + 1 >= BIT[bits.get()]) { setBits(bits.get() + 1); } } diff --git a/src/main/java/com/volmit/iris/util/hunk/bits/TecTest.java b/src/main/java/com/volmit/iris/util/hunk/bits/TecTest.java index b8dded4a8..8b840ccec 100644 --- a/src/main/java/com/volmit/iris/util/hunk/bits/TecTest.java +++ b/src/main/java/com/volmit/iris/util/hunk/bits/TecTest.java @@ -18,10 +18,93 @@ package com.volmit.iris.util.hunk.bits; +import com.volmit.iris.Iris; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.matter.slices.BlockMatter; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Set; + public class TecTest { + public static Set randomBlocks(int max) + { + KSet d = new KSet<>(); + + while(d.size() < max) + { + Material m = Material.values()[RNG.r.i(Material.values().length - 1)]; + if(m.isBlock()) + { + d.add(m.createBlockData()); + } + } + + return d; + } + public static void go() { + } + public static boolean test(int size, int pal) + { + try + { + Iris.info("Test? " + size + " " + pal); + KList blocks = new KList<>(randomBlocks(pal)); + Iris.info("Fill " + pal + " -> " + size + " Entries"); + Writable writer = new BlockMatter(); + DataContainer dc = new DataContainer<>(writer, size); + + for(int i = 0; i < dc.size(); i++) + { + dc.set(i, blocks.getRandom()); + } + + Iris.info(dc.toString()); + byte[] dat = dc.write(); + DataContainer dx = new DataContainer<>(new DataInputStream(new ByteArrayInputStream(dat)), writer); + Iris.info(dx.toString()); + byte[] dat2 = dx.write(); + Iris.info("Size: " + Form.memSize(dat.length, 2) + " -> " + Form.memSize(dat2.length, 2)); + + if(Arrays.equals(dat, dat2)) { + Iris.info("MATCH"); + return true; + } + else + { + for(int i = 0; i < dc.size(); i++) + { + if(!dx.get(i).equals(dc.get(i))) + { + Iris.info("FAIL Expected " + dc.get(i).getAsString(true) + " but got " + dx.get(i).getAsString(true)); + return false; + } + } + Iris.info("MATCH but different output?"); + + return true; + } + } + + catch(Throwable e) + { + e.printStackTrace(); + return false; + } } } diff --git a/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 6c843699a..7e593927c 100644 --- a/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -476,6 +476,7 @@ public class Mantle { if (file.exists()) { try { + Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); region = TectonicPlate.read(worldHeight, file); if (region.getX() != x || region.getZ() != z) { @@ -488,6 +489,7 @@ public class Mantle { Iris.error("Failed to read Tectonic Plate " + file.getAbsolutePath() + " creating a new chunk instead."); Iris.reportError(e); e.printStackTrace(); + Iris.panic(); region = new TectonicPlate(worldHeight, x, z); loadedRegions.put(k, region); Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z); diff --git a/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index fc341f687..f7123e7d3 100644 --- a/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -18,6 +18,8 @@ package com.volmit.iris.util.mantle; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.matter.IrisMatter; @@ -77,8 +79,9 @@ public class MantleChunk { } for (int i = 0; i < s; i++) { + Iris.addPanic("read.section", "Section[" + i + "]"); if (din.readBoolean()) { - sections.set(i, Matter.read(din)); + sections.set(i, Matter.readDin(din)); } } } diff --git a/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index e88ffb593..d404710a6 100644 --- a/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.mantle; import com.volmit.iris.Iris; +import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.format.C; @@ -74,7 +75,9 @@ public class TectonicPlate { this(worldHeight, din.readInt(), din.readInt()); for (int i = 0; i < chunks.length(); i++) { if (din.readBoolean()) { + Iris.addPanic("read-chunk", "Chunk[" + i + "]"); chunks.set(i, new MantleChunk(sectionHeight, din)); + EnginePanic.saveLast(); } } } diff --git a/src/main/java/com/volmit/iris/util/matter/IrisMatter.java b/src/main/java/com/volmit/iris/util/matter/IrisMatter.java index f8ccd8692..1e4893192 100644 --- a/src/main/java/com/volmit/iris/util/matter/IrisMatter.java +++ b/src/main/java/com/volmit/iris/util/matter/IrisMatter.java @@ -44,6 +44,11 @@ public class IrisMatter extends IrisRegistrant implements Matter { private final KMap, MatterSlice> sliceMap; public IrisMatter(int width, int height, int depth) { + if(width < 1 || height < 1 || depth < 1) + { + throw new RuntimeException("Invalid Matter Size " + width + "x" + height + "x" + depth); + } + this.width = width; this.height = height; this.depth = depth; diff --git a/src/main/java/com/volmit/iris/util/matter/Matter.java b/src/main/java/com/volmit/iris/util/matter/Matter.java index 14a3cec48..1254822cb 100644 --- a/src/main/java/com/volmit/iris/util/matter/Matter.java +++ b/src/main/java/com/volmit/iris/util/matter/Matter.java @@ -18,6 +18,7 @@ package com.volmit.iris.util.matter; +import com.volmit.iris.Iris; import com.volmit.iris.engine.object.IrisObject; import com.volmit.iris.engine.object.IrisPosition; import com.volmit.iris.util.collection.KSet; @@ -95,6 +96,10 @@ public interface Matter { return read(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ())); } + static Matter readDin(DataInputStream in) throws IOException, ClassNotFoundException { + return readDin(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ())); + } + /** * Reads the input stream into a matter object using a matter factory. * Does not close the input stream. Be a man, close it yourself. @@ -105,16 +110,26 @@ public interface Matter { * @throws IOException shit happens yo */ static Matter read(InputStream in, Function matterFactory) throws IOException, ClassNotFoundException { - DataInputStream din = new DataInputStream(in); - Matter matter = matterFactory.apply(new BlockPosition( - Varint.readUnsignedVarInt(din), - Varint.readUnsignedVarInt(din), - Varint.readUnsignedVarInt(din))); - int sliceCount = din.readByte(); - matter.getHeader().read(din); + return readDin(new DataInputStream(in), matterFactory); + } - while (sliceCount-- > 0) { + static Matter readDin(DataInputStream din, Function matterFactory) throws IOException, ClassNotFoundException { + Matter matter = matterFactory.apply(new BlockPosition( + din.readInt(), + din.readInt(), + din.readInt())); + Iris.addPanic("read.matter.size", matter.getWidth() + "x" + matter.getHeight() + "x" + matter.getDepth()); + int sliceCount = din.readByte(); + Iris.addPanic("read.matter.slicecount", sliceCount + ""); + + matter.getHeader().read(din); + Iris.addPanic("read.matter.header", matter.getHeader().toString()); + + for(int i = 0; i < sliceCount; i++) + { + Iris.addPanic("read.matter.slice", i + ""); String cn = din.readUTF(); + Iris.addPanic("read.matter.slice.class", cn); try { Class type = Class.forName(cn); MatterSlice slice = matter.createSlice(type, matter); @@ -336,10 +351,6 @@ public interface Matter { Map, MatterSlice> getSliceMap(); default void write(File f) throws IOException { - write(f, true); - } - - default void write(File f, boolean compression) throws IOException { OutputStream out = new FileOutputStream(f); write(out); out.close(); @@ -381,9 +392,9 @@ public interface Matter { default void writeDos(DataOutputStream dos) throws IOException { trimSlices(); - Varint.writeUnsignedVarInt(getWidth(), dos); - Varint.writeUnsignedVarInt(getHeight(), dos); - Varint.writeUnsignedVarInt(getDepth(), dos); + dos.writeInt(getWidth()); + dos.writeInt(getHeight()); + dos.writeInt(getDepth()); dos.writeByte(getSliceTypes().size()); getHeader().write(dos); diff --git a/src/main/java/com/volmit/iris/util/matter/MatterHeader.java b/src/main/java/com/volmit/iris/util/matter/MatterHeader.java index a00a53d75..d6852eb1b 100644 --- a/src/main/java/com/volmit/iris/util/matter/MatterHeader.java +++ b/src/main/java/com/volmit/iris/util/matter/MatterHeader.java @@ -34,13 +34,13 @@ public class MatterHeader { public void write(DataOutputStream out) throws IOException { out.writeUTF(author); - Varint.writeUnsignedVarLong(createdAt, out); - Varint.writeUnsignedVarInt(version, out); + out.writeLong(createdAt); + out.writeShort(version); } public void read(DataInputStream din) throws IOException { setAuthor(din.readUTF()); - setCreatedAt(Varint.readUnsignedVarLong(din)); - setVersion(Varint.readUnsignedVarInt(din)); + setCreatedAt(din.readLong()); + setVersion(din.readShort()); } } diff --git a/src/main/java/com/volmit/iris/util/matter/MatterSlice.java b/src/main/java/com/volmit/iris/util/matter/MatterSlice.java index 08333fd4e..24c8c5b48 100644 --- a/src/main/java/com/volmit/iris/util/matter/MatterSlice.java +++ b/src/main/java/com/volmit/iris/util/matter/MatterSlice.java @@ -160,6 +160,7 @@ public interface MatterSlice extends Hunk, PaletteType, Writable { default void write(DataOutputStream dos) throws IOException { dos.writeUTF(getType().getCanonicalName()); + if ((this instanceof PaletteOrHunk f && f.isPalette())) { f.palette().writeDos(dos); return; @@ -185,15 +186,7 @@ public interface MatterSlice extends Hunk, PaletteType, Writable { default void read(DataInputStream din) throws IOException { if ((this instanceof PaletteOrHunk f && f.isPalette())) { - try { - f.setPalette(new DataContainer<>(din, this)); - } - - catch(Throwable e) - { - Iris.error("Failed to read " + getType() + " Matter! ?? "); - throw new IOException(e); - } + f.setPalette(new DataContainer<>(din, this)); return; } diff --git a/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java b/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java index eb25aa8de..51612897e 100644 --- a/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java +++ b/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.matter.slices; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.palette.Palette; import com.volmit.iris.util.matter.Sliced; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.data.BlockData; @@ -58,6 +59,6 @@ public class BlockMatter extends RawMatter { @Override public BlockData readNode(DataInputStream din) throws IOException { - return B.get(din.readUTF()); + return Bukkit.createBlockData(din.readUTF()); } }