mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-04 00:46:08 +00:00
add more safety to mantle
This commit is contained in:
parent
cacef8c8fc
commit
1dca502a90
@ -42,6 +42,7 @@ import com.volmit.iris.util.decree.annotations.Decree;
|
|||||||
import com.volmit.iris.util.decree.annotations.Param;
|
import com.volmit.iris.util.decree.annotations.Param;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
import com.volmit.iris.util.mantle.TectonicPlate;
|
import com.volmit.iris.util.mantle.TectonicPlate;
|
||||||
import com.volmit.iris.util.math.Spiraler;
|
import com.volmit.iris.util.math.Spiraler;
|
||||||
@ -262,7 +263,7 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
VolmitSender sender = sender();
|
VolmitSender sender = sender();
|
||||||
service.submit(() -> {
|
service.submit(() -> {
|
||||||
try {
|
try {
|
||||||
DataInputStream raw = new DataInputStream(new FileInputStream(file));
|
CountingDataInputStream raw = CountingDataInputStream.wrap(new FileInputStream(file));
|
||||||
TectonicPlate plate = new TectonicPlate(height, raw);
|
TectonicPlate plate = new TectonicPlate(height, raw);
|
||||||
raw.close();
|
raw.close();
|
||||||
|
|
||||||
@ -281,7 +282,7 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
size = tmp.length();
|
size = tmp.length();
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
DataInputStream din = createInput(tmp, algorithm);
|
CountingDataInputStream din = createInput(tmp, algorithm);
|
||||||
new TectonicPlate(height, din);
|
new TectonicPlate(height, din);
|
||||||
din.close();
|
din.close();
|
||||||
d2 += System.currentTimeMillis() - start;
|
d2 += System.currentTimeMillis() - start;
|
||||||
@ -301,10 +302,10 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataInputStream createInput(File file, String algorithm) throws Throwable {
|
private CountingDataInputStream createInput(File file, String algorithm) throws Throwable {
|
||||||
FileInputStream in = new FileInputStream(file);
|
FileInputStream in = new FileInputStream(file);
|
||||||
|
|
||||||
return new DataInputStream(switch (algorithm) {
|
return CountingDataInputStream.wrap(switch (algorithm) {
|
||||||
case "gzip" -> new GZIPInputStream(in);
|
case "gzip" -> new GZIPInputStream(in);
|
||||||
case "lz4f" -> new LZ4FrameInputStream(in);
|
case "lz4f" -> new LZ4FrameInputStream(in);
|
||||||
case "lz4b" -> new LZ4BlockInputStream(in);
|
case "lz4b" -> new LZ4BlockInputStream(in);
|
||||||
|
@ -459,7 +459,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
IrisEngineData ed = getEngine().getEngineData();
|
IrisEngineData ed = getEngine().getEngineData();
|
||||||
IrisEngineSpawnerCooldown cd = null;
|
IrisEngineSpawnerCooldown cd = null;
|
||||||
|
|
||||||
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns()) {
|
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
|
||||||
if (j.getSpawner().equals(i.getLoadKey())) {
|
if (j.getSpawner().equals(i.getLoadKey())) {
|
||||||
cd = j;
|
cd = j;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.volmit.iris.util.io;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class CountingDataInputStream extends DataInputStream {
|
||||||
|
private final Counter counter;
|
||||||
|
|
||||||
|
private CountingDataInputStream(@NotNull InputStream in) {
|
||||||
|
super(in);
|
||||||
|
if (!(in instanceof Counter c))
|
||||||
|
throw new IllegalArgumentException("Underlying stream must be a Counter");
|
||||||
|
this.counter = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CountingDataInputStream wrap(@NotNull InputStream in) {
|
||||||
|
return new CountingDataInputStream(new Counter(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long count() {
|
||||||
|
return counter.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipTo(long target) throws IOException {
|
||||||
|
skipNBytes(Math.max(target - counter.count, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class Counter extends InputStream {
|
||||||
|
private final InputStream in;
|
||||||
|
private long count;
|
||||||
|
private long mark = -1;
|
||||||
|
private int markLimit = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
int i = in.read();
|
||||||
|
if (i != -1) count(1);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(@NotNull byte[] b, int off, int len) throws IOException {
|
||||||
|
int i = in.read(b, off, len);
|
||||||
|
count(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void count(int i) {
|
||||||
|
count += i;
|
||||||
|
if (mark == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
markLimit -= i;
|
||||||
|
if (markLimit <= 0)
|
||||||
|
mark = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return in.markSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void mark(int readlimit) {
|
||||||
|
if (!in.markSupported()) return;
|
||||||
|
in.mark(readlimit);
|
||||||
|
mark = count;
|
||||||
|
markLimit = readlimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void reset() throws IOException {
|
||||||
|
in.reset();
|
||||||
|
count = mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -567,9 +567,6 @@ public class Mantle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
File file = fileForRegion(dataFolder, x, z);
|
File file = fileForRegion(dataFolder, x, z);
|
||||||
if (!file.exists())
|
|
||||||
file = new File(dataFolder, file.getName().substring(".lz4b".length()));
|
|
||||||
|
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());
|
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());
|
||||||
|
@ -21,12 +21,13 @@ package com.volmit.iris.util.mantle;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||||
import com.volmit.iris.util.function.Consumer4;
|
import com.volmit.iris.util.function.Consumer4;
|
||||||
|
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||||
import com.volmit.iris.util.matter.IrisMatter;
|
import com.volmit.iris.util.matter.IrisMatter;
|
||||||
import com.volmit.iris.util.matter.Matter;
|
import com.volmit.iris.util.matter.Matter;
|
||||||
import com.volmit.iris.util.matter.MatterSlice;
|
import com.volmit.iris.util.matter.MatterSlice;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||||
@ -69,7 +70,7 @@ public class MantleChunk {
|
|||||||
* @throws IOException shit happens
|
* @throws IOException shit happens
|
||||||
* @throws ClassNotFoundException shit happens
|
* @throws ClassNotFoundException shit happens
|
||||||
*/
|
*/
|
||||||
public MantleChunk(int sectionHeight, DataInputStream din) throws IOException, ClassNotFoundException {
|
public MantleChunk(int sectionHeight, CountingDataInputStream din) throws IOException {
|
||||||
this(sectionHeight, din.readByte(), din.readByte());
|
this(sectionHeight, din.readByte(), din.readByte());
|
||||||
int s = din.readByte();
|
int s = din.readByte();
|
||||||
|
|
||||||
@ -79,8 +80,23 @@ public class MantleChunk {
|
|||||||
|
|
||||||
for (int i = 0; i < s; i++) {
|
for (int i = 0; i < s; i++) {
|
||||||
Iris.addPanic("read.section", "Section[" + i + "]");
|
Iris.addPanic("read.section", "Section[" + i + "]");
|
||||||
if (din.readBoolean()) {
|
long size = din.readInt();
|
||||||
|
if (size == 0) continue;
|
||||||
|
long start = din.count();
|
||||||
|
|
||||||
|
try {
|
||||||
sections.set(i, Matter.readDin(din));
|
sections.set(i, Matter.readDin(din));
|
||||||
|
} catch (IOException e) {
|
||||||
|
long end = start + size;
|
||||||
|
Iris.error("Failed to read chunk section, skipping it.");
|
||||||
|
Iris.addPanic("read.byte.range", start + " " + end);
|
||||||
|
Iris.addPanic("read.byte.current", din.count() + "");
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
Iris.panic();
|
||||||
|
|
||||||
|
din.skipTo(end);
|
||||||
|
TectonicPlate.addError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,15 +190,22 @@ public class MantleChunk {
|
|||||||
dos.writeBoolean(flags.get(i) == 1);
|
dos.writeBoolean(flags.get(i) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bytes = new ByteArrayOutputStream(8192);
|
||||||
|
var sub = new DataOutputStream(bytes);
|
||||||
for (int i = 0; i < sections.length(); i++) {
|
for (int i = 0; i < sections.length(); i++) {
|
||||||
trimSlice(i);
|
trimSlice(i);
|
||||||
|
|
||||||
if (exists(i)) {
|
if (exists(i)) {
|
||||||
dos.writeBoolean(true);
|
try {
|
||||||
Matter matter = get(i);
|
Matter matter = get(i);
|
||||||
matter.writeDos(dos);
|
matter.writeDos(sub);
|
||||||
|
dos.writeInt(bytes.size());
|
||||||
|
bytes.writeTo(dos);
|
||||||
|
} finally {
|
||||||
|
bytes.reset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dos.writeBoolean(false);
|
dos.writeInt(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,26 +21,31 @@ package com.volmit.iris.util.mantle;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.engine.EnginePanic;
|
import com.volmit.iris.engine.EnginePanic;
|
||||||
import com.volmit.iris.engine.data.cache.Cache;
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||||
import net.jpountz.lz4.LZ4FrameInputStream;
|
|
||||||
import net.jpountz.lz4.LZ4FrameOutputStream;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
import java.util.zip.GZIPOutputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tectonic Plates are essentially representations of regions in minecraft.
|
* Tectonic Plates are essentially representations of regions in minecraft.
|
||||||
* Tectonic Plates are fully atomic & thread safe
|
* Tectonic Plates are fully atomic & thread safe
|
||||||
*/
|
*/
|
||||||
public class TectonicPlate {
|
public class TectonicPlate {
|
||||||
|
private static final KSet<Thread> errors = new KSet<>();
|
||||||
|
|
||||||
private final int sectionHeight;
|
private final int sectionHeight;
|
||||||
private final AtomicReferenceArray<MantleChunk> chunks;
|
private final AtomicReferenceArray<MantleChunk> chunks;
|
||||||
|
|
||||||
@ -68,33 +73,58 @@ public class TectonicPlate {
|
|||||||
* @param worldHeight the height of the world
|
* @param worldHeight the height of the world
|
||||||
* @param din the data input
|
* @param din the data input
|
||||||
* @throws IOException shit happens yo
|
* @throws IOException shit happens yo
|
||||||
* @throws ClassNotFoundException real shit bro
|
|
||||||
*/
|
*/
|
||||||
public TectonicPlate(int worldHeight, DataInputStream din) throws IOException, ClassNotFoundException {
|
public TectonicPlate(int worldHeight, CountingDataInputStream din) throws IOException {
|
||||||
this(worldHeight, din.readInt(), din.readInt());
|
this(worldHeight, din.readInt(), din.readInt());
|
||||||
|
if (!din.markSupported())
|
||||||
|
throw new IOException("Mark not supported!");
|
||||||
|
|
||||||
for (int i = 0; i < chunks.length(); i++) {
|
for (int i = 0; i < chunks.length(); i++) {
|
||||||
if (din.readBoolean()) {
|
long size = din.readInt();
|
||||||
|
if (size == 0) continue;
|
||||||
|
long start = din.count();
|
||||||
|
|
||||||
|
try {
|
||||||
Iris.addPanic("read-chunk", "Chunk[" + i + "]");
|
Iris.addPanic("read-chunk", "Chunk[" + i + "]");
|
||||||
chunks.set(i, new MantleChunk(sectionHeight, din));
|
chunks.set(i, new MantleChunk(sectionHeight, din));
|
||||||
EnginePanic.saveLast();
|
EnginePanic.saveLast();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
long end = start + size;
|
||||||
|
Iris.error("Failed to read chunk, creating a new chunk instead.");
|
||||||
|
Iris.addPanic("read.byte.range", start + " " + end);
|
||||||
|
Iris.addPanic("read.byte.current", din.count() + "");
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
Iris.panic();
|
||||||
|
|
||||||
|
din.skipTo(end);
|
||||||
|
TectonicPlate.addError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TectonicPlate read(int worldHeight, File file) throws IOException, ClassNotFoundException {
|
public static TectonicPlate read(int worldHeight, File file) throws IOException {
|
||||||
FileInputStream fin = new FileInputStream(file);
|
try (FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.SYNC)) {
|
||||||
DataInputStream din;
|
fc.lock();
|
||||||
if (file.getName().endsWith("ttp.lz4b")) {
|
|
||||||
|
InputStream fin = Channels.newInputStream(fc);
|
||||||
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
||||||
din = new DataInputStream(new BufferedInputStream(lz4));
|
BufferedInputStream bis = new BufferedInputStream(lz4);
|
||||||
} else {
|
try (CountingDataInputStream din = CountingDataInputStream.wrap(bis)) {
|
||||||
GZIPInputStream gzi = new GZIPInputStream(fin);
|
return new TectonicPlate(worldHeight, din);
|
||||||
din = new DataInputStream(new BufferedInputStream(gzi));
|
|
||||||
}
|
}
|
||||||
TectonicPlate p = new TectonicPlate(worldHeight, din);
|
} finally {
|
||||||
din.close();
|
if (errors.remove(Thread.currentThread())) {
|
||||||
|
File dump = Iris.instance.getDataFolder("dump", file.getName() + ".bin");
|
||||||
|
try (FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.SYNC)) {
|
||||||
|
fc.lock();
|
||||||
|
|
||||||
return p;
|
InputStream fin = Channels.newInputStream(fc);
|
||||||
|
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
||||||
|
Files.copy(lz4, dump.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,19 +203,16 @@ public class TectonicPlate {
|
|||||||
*/
|
*/
|
||||||
public void write(File file) throws IOException {
|
public void write(File file) throws IOException {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
FileOutputStream fos = new FileOutputStream(file);
|
try (FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC)) {
|
||||||
DataOutputStream dos;
|
fc.lock();
|
||||||
if (file.getName().endsWith("ttp.lz4b")) {
|
|
||||||
LZ4BlockOutputStream lz4 = new LZ4BlockOutputStream(fos);
|
OutputStream fos = Channels.newOutputStream(fc);
|
||||||
dos = new DataOutputStream(lz4);
|
try (DataOutputStream dos = new DataOutputStream(new LZ4BlockOutputStream(fos))) {
|
||||||
} else {
|
|
||||||
GZIPOutputStream gzo = new GZIPOutputStream(fos);
|
|
||||||
dos = new DataOutputStream(gzo);
|
|
||||||
}
|
|
||||||
write(dos);
|
write(dos);
|
||||||
dos.close();
|
|
||||||
Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName().split("\\Q.\\E")[0] + C.RED + " in " + Form.duration(p.getMilliseconds(), 2));
|
Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName().split("\\Q.\\E")[0] + C.RED + " in " + Form.duration(p.getMilliseconds(), 2));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write this tectonic plate to a data stream
|
* Write this tectonic plate to a data stream
|
||||||
@ -197,15 +224,26 @@ public class TectonicPlate {
|
|||||||
dos.writeInt(x);
|
dos.writeInt(x);
|
||||||
dos.writeInt(z);
|
dos.writeInt(z);
|
||||||
|
|
||||||
|
var bytes = new ByteArrayOutputStream(8192);
|
||||||
|
var sub = new DataOutputStream(bytes);
|
||||||
for (int i = 0; i < chunks.length(); i++) {
|
for (int i = 0; i < chunks.length(); i++) {
|
||||||
MantleChunk chunk = chunks.get(i);
|
MantleChunk chunk = chunks.get(i);
|
||||||
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
dos.writeBoolean(true);
|
try {
|
||||||
chunk.write(dos);
|
chunk.write(sub);
|
||||||
|
dos.writeInt(bytes.size());
|
||||||
|
bytes.writeTo(dos);
|
||||||
|
} finally {
|
||||||
|
bytes.reset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dos.writeBoolean(false);
|
dos.writeInt(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addError() {
|
||||||
|
errors.add(Thread.currentThread());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import com.volmit.iris.engine.object.IrisObject;
|
|||||||
import com.volmit.iris.engine.object.IrisPosition;
|
import com.volmit.iris.engine.object.IrisPosition;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.hunk.Hunk;
|
import com.volmit.iris.util.hunk.Hunk;
|
||||||
|
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||||
|
import com.volmit.iris.util.mantle.TectonicPlate;
|
||||||
import com.volmit.iris.util.math.BlockPosition;
|
import com.volmit.iris.util.math.BlockPosition;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@ -96,18 +98,18 @@ public interface Matter {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Matter read(File f) throws IOException, ClassNotFoundException {
|
static Matter read(File f) throws IOException {
|
||||||
FileInputStream in = new FileInputStream(f);
|
FileInputStream in = new FileInputStream(f);
|
||||||
Matter m = read(in);
|
Matter m = read(in);
|
||||||
in.close();
|
in.close();
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Matter read(InputStream in) throws IOException, ClassNotFoundException {
|
static Matter read(InputStream in) throws IOException {
|
||||||
return read(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ()));
|
return read(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Matter readDin(DataInputStream in) throws IOException, ClassNotFoundException {
|
static Matter readDin(CountingDataInputStream in) throws IOException {
|
||||||
return readDin(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ()));
|
return readDin(in, (b) -> new IrisMatter(b.getX(), b.getY(), b.getZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,11 +122,11 @@ public interface Matter {
|
|||||||
* @return the matter object
|
* @return the matter object
|
||||||
* @throws IOException shit happens yo
|
* @throws IOException shit happens yo
|
||||||
*/
|
*/
|
||||||
static Matter read(InputStream in, Function<BlockPosition, Matter> matterFactory) throws IOException, ClassNotFoundException {
|
static Matter read(InputStream in, Function<BlockPosition, Matter> matterFactory) throws IOException {
|
||||||
return readDin(new DataInputStream(in), matterFactory);
|
return readDin(CountingDataInputStream.wrap(in), matterFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Matter readDin(DataInputStream din, Function<BlockPosition, Matter> matterFactory) throws IOException, ClassNotFoundException {
|
static Matter readDin(CountingDataInputStream din, Function<BlockPosition, Matter> matterFactory) throws IOException {
|
||||||
Matter matter = matterFactory.apply(new BlockPosition(
|
Matter matter = matterFactory.apply(new BlockPosition(
|
||||||
din.readInt(),
|
din.readInt(),
|
||||||
din.readInt(),
|
din.readInt(),
|
||||||
@ -137,17 +139,30 @@ public interface Matter {
|
|||||||
Iris.addPanic("read.matter.header", matter.getHeader().toString());
|
Iris.addPanic("read.matter.header", matter.getHeader().toString());
|
||||||
|
|
||||||
for (int i = 0; i < sliceCount; i++) {
|
for (int i = 0; i < sliceCount; i++) {
|
||||||
|
long size = din.readInt();
|
||||||
|
if (size == 0) continue;
|
||||||
|
long start = din.count();
|
||||||
|
|
||||||
Iris.addPanic("read.matter.slice", i + "");
|
Iris.addPanic("read.matter.slice", i + "");
|
||||||
|
try {
|
||||||
String cn = din.readUTF();
|
String cn = din.readUTF();
|
||||||
Iris.addPanic("read.matter.slice.class", cn);
|
Iris.addPanic("read.matter.slice.class", cn);
|
||||||
try {
|
|
||||||
Class<?> type = Class.forName(cn);
|
Class<?> type = Class.forName(cn);
|
||||||
MatterSlice<?> slice = matter.createSlice(type, matter);
|
MatterSlice<?> slice = matter.createSlice(type, matter);
|
||||||
slice.read(din);
|
slice.read(din);
|
||||||
matter.putSlice(type, slice);
|
matter.putSlice(type, slice);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
long end = start + size;
|
||||||
|
Iris.error("Failed to read matter slice, skipping it.");
|
||||||
|
Iris.addPanic("read.byte.range", start + " " + end);
|
||||||
|
Iris.addPanic("read.byte.current", din.count() + "");
|
||||||
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new IOException("Can't read class '" + cn + "' (slice count reverse at " + sliceCount + ")");
|
Iris.panic();
|
||||||
|
|
||||||
|
din.skipTo(end);
|
||||||
|
TectonicPlate.addError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,8 +429,16 @@ public interface Matter {
|
|||||||
dos.writeByte(getSliceTypes().size());
|
dos.writeByte(getSliceTypes().size());
|
||||||
getHeader().write(dos);
|
getHeader().write(dos);
|
||||||
|
|
||||||
|
var bytes = new ByteArrayOutputStream(1024);
|
||||||
|
var sub = new DataOutputStream(bytes);
|
||||||
for (Class<?> i : getSliceTypes()) {
|
for (Class<?> i : getSliceTypes()) {
|
||||||
getSlice(i).write(dos);
|
try {
|
||||||
|
getSlice(i).write(sub);
|
||||||
|
dos.writeInt(bytes.size());
|
||||||
|
bytes.writeTo(dos);
|
||||||
|
} finally {
|
||||||
|
bytes.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user