Improved trace serialisation through versioning

This commit is contained in:
D4rkr34lm
2024-08-08 15:33:01 +02:00
committed by D4rkr34lm
parent a9393f878f
commit be848ac67a
5 changed files with 86 additions and 101 deletions
@@ -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,
@@ -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<List<TNTPoint>> 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<TNTPoint> 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<TraceEntity> entities = new LinkedList<>();
for (List<TNTPoint> 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<TNTPoint> 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<Integer, List<TNTPoint>> histories = new HashMap<>();
for (TNTPoint record : records) {
int tntId = record.getTntId();
List<TNTPoint> 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<TNTPoint> getRecords() {
@@ -58,7 +58,7 @@ public class TraceManager implements Listener {
if (traceFile.getName().contains(".records"))
continue;
add(new Trace(traceFile));
add(TraceRepository.readTrace(traceFile));
}
}
@@ -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<TNTPoint> recordsToAdd;
private final List<TNTPoint> 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);
}
}
@@ -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<TNTPoint> 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<TNTPoint> 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();