From be848ac67a638f596ca383758123fba48b09036d Mon Sep 17 00:00:00 2001 From: D4rkr34lm Date: Thu, 8 Aug 2024 15:33:01 +0200 Subject: [PATCH] Improved trace serialisation through versioning --- .../bausystem/features/tracer/TNTPoint.java | 20 +++- .../bausystem/features/tracer/Trace.java | 94 +++++-------------- .../features/tracer/TraceManager.java | 2 +- .../tracer/TraceRecordingWrapper.java | 25 +---- .../features/tracer/TraceRepository.java | 46 ++++++++- 5 files changed, 86 insertions(+), 101 deletions(-) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java index ed0f1306..432241c2 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java @@ -99,7 +99,25 @@ public class TNTPoint implements Externalizable { /** * Constructor for deserialization only !! Do not Call !! */ - public TNTPoint() { + protected TNTPoint(int tntId, boolean explosion, + boolean inWater, + boolean afterFirstExplosion, + boolean destroyedBuildArea, + boolean destroyedTestBlock, + long ticksSinceStart, + int fuse, + Location location, + Vector velocity) { + this.tntId = tntId; + this.explosion = explosion; + this.inWater = inWater; + this.afterFirstExplosion = afterFirstExplosion; + this.destroyedBuildArea = destroyedBuildArea; + this.destroyedTestBlock = destroyedTestBlock; + this.ticksSinceStart = ticksSinceStart; + this.fuse = fuse; + this.location = location; + this.velocity = velocity; } public TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart, diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java index e3305def..a637a181 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java @@ -26,20 +26,15 @@ import de.steamwar.bausystem.features.tracer.rendering.ViewFlag; import de.steamwar.bausystem.region.Region; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; -import lombok.Cleanup; import lombok.Getter; import lombok.SneakyThrows; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import java.io.*; +import java.io.File; import java.lang.ref.SoftReference; import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.zip.GZIPInputStream; public class Trace { /** @@ -77,6 +72,9 @@ public class Trace { */ private SoftReference> records; + @Getter + private final int recordsCount; + /** * A map of all REntityServers rendering this trace */ @@ -91,46 +89,26 @@ public class Trace { @SneakyThrows public Trace(Region region, List recordList) { this.uuid = UUID.randomUUID(); - recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records"); this.region = region; this.date = new Date(); + recordsCount = recordList.size(); records = new SoftReference<>(recordList); + recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records"); metadataSaveFile = new File(TraceManager.tracesFolder, uuid + ".meta"); - - @Cleanup - ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(metadataSaveFile)); - outputStream.writeUTF(uuid.toString()); - outputStream.writeUTF(region.getName()); - outputStream.writeObject(date); } /** - * Constructor for serialising a trace from the file system - * - * @param metadataSaveFile the file for this traces metadata + * Constructor for deserialising a trace from the file system */ @SneakyThrows - public Trace(File metadataSaveFile) { - String uuid = null; - Region region = null; - Date date = null; - - this.metadataSaveFile = metadataSaveFile; - - try { - @Cleanup - ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(metadataSaveFile)); - uuid = inputStream.readUTF(); - region = Region.getREGION_MAP().get(inputStream.readUTF()); - date = (Date) inputStream.readObject(); - inputStream.close(); - } finally { - this.uuid = UUID.fromString(uuid); - this.region = region; - this.date = date; - recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records"); - this.records = new SoftReference<>(null); - } + protected Trace(UUID uuid, Region region, Date date, File metadataFile, File recordsFile, int recordsCount) { + this.metadataSaveFile = metadataFile; + recordsSaveFile = recordsFile; + this.uuid = uuid; + this.region = region; + this.date = date; + this.records = new SoftReference<>(null); + this.recordsCount = recordsCount; } /** @@ -173,7 +151,8 @@ public class Trace { entityServer = new REntityServer(); entityServer.addPlayer(player); entityServer.setCallback((p, rEntity, entityAction) -> { - if (entityAction != REntityServer.EntityAction.INTERACT) return; + if (entityAction != REntityServer.EntityAction.INTERACT) + return; if (rEntity instanceof TraceEntity) { ((TraceEntity) rEntity).printIntoChat(p); } @@ -195,7 +174,8 @@ public class Trace { REntityServer newEntityServer = new REntityServer(); newEntityServer.addPlayer(k); newEntityServer.setCallback((p, rEntity, entityAction) -> { - if (entityAction != REntityServer.EntityAction.INTERACT) return; + if (entityAction != REntityServer.EntityAction.INTERACT) + return; if (rEntity instanceof TraceEntity) { ((TraceEntity) rEntity).printIntoChat(p); } @@ -234,7 +214,8 @@ public class Trace { List entities = new LinkedList<>(); for (List bundle : bundles) { - entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle, this)); + entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle, + this)); } // Apply modifiers @@ -312,38 +293,7 @@ public class Trace { * Loads the records of this trace from storage to memory */ private void loadRecords() { - List records = new ArrayList<>(); - long readBytes = 0; - try { - FileInputStream fileInputStream = new FileInputStream(recordsSaveFile); - - @Cleanup - ObjectInputStream inputStream = new ObjectInputStream(new GZIPInputStream(fileInputStream)); - long fileLenght = recordsSaveFile.length(); - while (fileInputStream.getChannel().position() < fileLenght) { - records.add((TNTPoint) inputStream.readObject()); - readBytes = fileInputStream.getChannel().position(); - } - } catch (EOFException e) { - Logger logger = Bukkit.getLogger(); - logger.log(Level.WARNING, "EOF in trace read detected in " + uuid); - logger.log(Level.WARNING, "Read " + readBytes + "/" + recordsSaveFile.length() + " Bytes"); - logger.log(Level.WARNING, "Read so far: " + records); - - e.printStackTrace(); - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } - - Map> histories = new HashMap<>(); - for (TNTPoint record : records) { - int tntId = record.getTntId(); - List history = histories.computeIfAbsent(tntId, id -> new ArrayList<>()); - history.add(record); - record.setHistory(history); - } - - this.records = new SoftReference<>(records); + records = new SoftReference<>(TraceRepository.readTraceRecords(this)); } public synchronized List getRecords() { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java index 8ab7437c..6596d46d 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java @@ -58,7 +58,7 @@ public class TraceManager implements Listener { if (traceFile.getName().contains(".records")) continue; - add(new Trace(traceFile)); + add(TraceRepository.readTrace(traceFile)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java index 7f23bb32..c7d2a043 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java @@ -24,28 +24,21 @@ import de.steamwar.bausystem.region.Region; import lombok.Getter; import lombok.SneakyThrows; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; -import java.util.zip.GZIPOutputStream; public class TraceRecordingWrapper { + private final Trace trace; + @Getter private final long startTick; private final List recordsToAdd; private final List recordList; - private final ObjectOutputStream recordsOutputStream; private int nextOpenRecordId = 0; @Getter private boolean explosionRecorded = false; - @Getter - private final Trace trace; - @SneakyThrows public TraceRecordingWrapper(Region region) { startTick = TPSUtils.currentRealTick.get(); @@ -53,8 +46,6 @@ public class TraceRecordingWrapper { recordList = new ArrayList<>(); trace = new Trace(region, recordList); - File recordsSaveFile = new File(TraceManager.tracesFolder, trace.getUuid() + ".records"); - recordsOutputStream = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(recordsSaveFile))); } public int getNextOpenRecordIdAndIncrement() { @@ -72,23 +63,13 @@ public class TraceRecordingWrapper { public void commitRecorded() { TraceManager.instance.showPartial(trace, recordsToAdd); - recordsToAdd.forEach(record -> { - try { - recordsOutputStream.writeObject(record); - recordsOutputStream.flush(); - } catch (IOException e) { - e.printStackTrace(); - } - }); - recordList.addAll(recordsToAdd); recordsToAdd.clear(); } @SneakyThrows protected void finalizeRecording() { - recordsOutputStream.flush(); - recordsOutputStream.close(); + TraceRepository.writeTrace(trace, recordList); TraceManager.instance.add(trace); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java index de33bfef..424472d3 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java @@ -7,10 +7,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.util.Vector; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.ObjectInputStream; +import java.io.*; import java.util.*; import java.util.zip.GZIPInputStream; @@ -37,7 +34,7 @@ public class TraceRepository { } @SneakyThrows - protected static Trace readTrace(File metadataFile) { + public static Trace readTrace(File metadataFile) { @Cleanup ObjectInputStream reader = new ObjectInputStream(new FileInputStream(metadataFile)); UUID uuid = UUID.fromString(reader.readUTF()); @@ -49,6 +46,43 @@ public class TraceRepository { return new Trace(uuid, region, date, metadataFile, recordsFile, recordsCount); } + @SneakyThrows + protected static void writeTrace(Trace trace, List records) { + @Cleanup + ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(trace.getMetadataSaveFile())); + outputStream.writeUTF(trace.getUuid().toString()); + outputStream.writeUTF(trace.getRegion().getName()); + outputStream.writeObject(trace.getDate()); + outputStream.writeInt(SERIALISATION_VERSION); + outputStream.writeInt(records.size()); + + + writeTraceRecords(trace.getRecordsSaveFile(), records); + } + + @SneakyThrows + protected static void writeTraceRecords(File recordsFile, List records) { + ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(recordsFile)); + for (TNTPoint record : records) { + outputStream.writeInt(record.getTntId()); + outputStream.writeBoolean(record.isExplosion()); + outputStream.writeBoolean(record.isInWater()); + outputStream.writeBoolean(record.isAfterFirstExplosion()); + outputStream.writeBoolean(record.isDestroyedBuildArea()); + outputStream.writeBoolean(record.isDestroyedTestBlock()); + outputStream.writeLong(record.getTicksSinceStart()); + outputStream.writeInt(record.getFuse()); + Location location = record.getLocation(); + outputStream.writeDouble(location.getX()); + outputStream.writeDouble(location.getY()); + outputStream.writeDouble(location.getZ()); + Vector velocity = record.getVelocity(); + outputStream.writeDouble(velocity.getX()); + outputStream.writeDouble(velocity.getY()); + outputStream.writeDouble(velocity.getZ()); + } + } + @SneakyThrows protected static TNTPoint readTraceRecord(ObjectInputStream objectInput) { @@ -60,10 +94,12 @@ public class TraceRepository { boolean destroyedTestBlock = objectInput.readBoolean(); long ticksSinceStart = objectInput.readLong(); int fuse = objectInput.readInt(); + double locX = objectInput.readDouble(); double locY = objectInput.readDouble(); double locZ = objectInput.readDouble(); Location location = new Location(Bukkit.getWorlds().get(0), locX, locY, locZ); + double velX = objectInput.readDouble(); double velY = objectInput.readDouble(); double velZ = objectInput.readDouble();