Trace Refactor #233

Zusammengeführt
YoyoNow hat 121 Commits von TracerGUI nach master 2024-04-21 16:03:26 +02:00 zusammengeführt
9 geänderte Dateien mit 503 neuen und 236 gelöschten Zeilen
Nur Änderungen aus Commit d13c415565 werden angezeigt - Alle Commits anzeigen

10
.gitignore vendored
Datei anzeigen

@ -1,5 +1,7 @@
# Package Files
# Build files
*.jar
**/bin
**/build
# Gradle
.gradle
@ -10,6 +12,10 @@ steamwar.properties
# IntelliJ IDEA
.idea
*.iml
plugin.yml
# Other
lib
lib
#linkage
LinkageUtils.java

Datei anzeigen

@ -24,7 +24,7 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.TraceRecorder;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.utils.FlatteningWrapper;
import org.bukkit.Location;
@ -59,7 +59,7 @@ public class ProcessingTracesState implements LaufbauState {
this.factor = factor;
// TODO: Optimize only retrieving traces inside of the affected regions!
TNTPoints = TraceRecorder.instance.manager.getAll()
TNTPoints = TraceManager.instance.getAll()
.stream()
.flatMap(trace -> trace.getHistories().stream())
.flatMap(Collection::stream)

Datei anzeigen

@ -23,73 +23,81 @@ import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.utils.RegionExtensionType;
import de.steamwar.bausystem.region.utils.RegionType;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.util.Vector;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;
import java.util.Optional;
@Getter
public class TNTPoint {
public class TNTPoint implements Externalizable {
/**
* Unique number to identify records being of the same tnt
*/
private final int tntId;
private int tntId;
/**
* Whether this is a record of a tnt explosion or an entity
*/
private final boolean explosion;
private boolean explosion;
/**
* Whether this is a record of a tnt that was in water
*/
private final boolean inWater;
private boolean inWater;
/**
* Whether this record was taken after the first tnt exploded
*/
private final boolean afterFirstExplosion;
private boolean afterFirstExplosion;
/**
* Whether this record has destroyed blocks in build area
*/
private final boolean destroyedBuildArea;
private boolean destroyedBuildArea;
/**
* Whether this record has destroyed blocks in testblock area
*/
private final boolean destroyedTestBlock;
private boolean destroyedTestBlock;
/**
* Tick offset, from this record being taken to the start of the trace
*/
private final long ticksSinceStart;
private long ticksSinceStart;
/**
* Fuse ticks of the recorded tnt (0 if this is an explosion)
*/
private final int fuse;
private int fuse;
/**
* Location of the recorded tnt
*/
private final Location location;
private Location location;
/**
* Velocity of the recorded tnt
*/
private final Vector velocity;
private Vector velocity;
/**
* List of all tnt records, that are represent the same tnt
*/
private final List<TNTPoint> history;
private List<TNTPoint> history;
public TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart, List<TNTPoint> history, List<Block> destroyedBlocks) {
public TNTPoint() {
}
public TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart,
List<TNTPoint> history, List<Block> destroyedBlocks) {
this.tntId = tntId;
this.explosion = explosion;
this.inWater = tnt.isInWater();
@ -103,10 +111,12 @@ public class TNTPoint {
boolean buildDestroy = false;
boolean testblockDestroy = false;
for (Block destroyedBlock : destroyedBlocks) {
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(), RegionType.BUILD, RegionExtensionType.EXTENSION)) {
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(), RegionType.BUILD,
RegionExtensionType.EXTENSION)) {
buildDestroy = true;
}
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) {
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(),
RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) {
testblockDestroy = true;
}
}
@ -125,6 +135,50 @@ public class TNTPoint {
return index == 0 ? Optional.empty() : Optional.of(history.get(index - 1));
}
void setHistory(List<TNTPoint> history) {
this.history = history;
}
@Override
public void writeExternal(ObjectOutput objectOutput) throws IOException {
objectOutput.writeInt(tntId);
objectOutput.writeBoolean(explosion);
objectOutput.writeBoolean(inWater);
objectOutput.writeBoolean(afterFirstExplosion);
objectOutput.writeBoolean(destroyedBuildArea);
objectOutput.writeBoolean(destroyedTestBlock);
objectOutput.writeLong(ticksSinceStart);
objectOutput.writeInt(fuse);
objectOutput.writeUTF(location.getWorld().getName());
objectOutput.writeDouble(location.getX());
objectOutput.writeDouble(location.getY());
objectOutput.writeDouble(location.getZ());
objectOutput.writeDouble(velocity.getX());
objectOutput.writeDouble(velocity.getY());
objectOutput.writeDouble(velocity.getZ());
}
@Override
public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException {
tntId = objectInput.readInt();
explosion = objectInput.readBoolean();
inWater = objectInput.readBoolean();
afterFirstExplosion = objectInput.readBoolean();
destroyedBuildArea = objectInput.readBoolean();
destroyedTestBlock = objectInput.readBoolean();
ticksSinceStart = objectInput.readLong();
fuse = objectInput.readInt();
String worldName = objectInput.readUTF();
double locX = objectInput.readDouble();
double locY = objectInput.readDouble();
double locZ = objectInput.readDouble();
location = new Location(Bukkit.getWorld(worldName), locX, locY, locZ);
double velX = objectInput.readDouble();
double velY = objectInput.readDouble();
double velZ = objectInput.readDouble();
velocity = new Vector(velX, velY, velZ);
}
@Override
public String toString() {
return "TNTRecord{" +
@ -138,11 +192,15 @@ public class TNTPoint {
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TNTPoint)) return false;
if (!(obj instanceof TNTPoint))
return false;
TNTPoint record = (TNTPoint) obj;
if (record.isExplosion() != explosion) return false;
if (!record.getLocation().equals(location)) return false;
if (!record.getVelocity().equals(velocity)) return false;
if (record.isExplosion() != explosion)
return false;
if (!record.getLocation().equals(location))
return false;
if (!record.getVelocity().equals(velocity))
return false;
return true;
}
}

Datei anzeigen

@ -19,102 +19,104 @@
package de.steamwar.bausystem.features.tracer;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
import de.steamwar.bausystem.features.tracer.rendering.TraceEntity;
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 org.bukkit.entity.Player;
import java.io.*;
import java.lang.ref.SoftReference;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Trace { // TODO: Add UUID for file saving and so on!
public class Trace {
/**
* UUID of the trace used for
*/
@Getter
private final UUID uuid;
/**
* Region this trace has been recorded in
* File the records are saved in
*/
@Getter
private final File recordsSaveFile;
/**
* File the metadata are saved in
*/
@Getter
private final File metadataSaveFile;
/**
* Region the trace was recorded in
*/
@Getter
private final Region region;
/**
* Tick the recording started at
* Date the trace was recorded at
*/
@Getter
private final long startTime = TPSUtils.currentTick.get();
/**
*
*/
@Getter
private final Date date = new Date();
private final Date date;
/**
* Records of TNTs, making up the trace
*/
@Getter
private List<TNTPoint> records = new ArrayList<>();
/**
* ID that should be assigned to the next record of a unique tnt
*/
@Getter
private int nextOpenRecordId = -1;
private SoftReference<List<TNTPoint>> records;
private final Map<Player, REntityServer> entityServerMap = new HashMap<>();
/**
* List of all used ids
*/
public List<String> getUsedIds() {
return getRecords()
.stream()
.map(TNTPoint::getTntId)
.map(i -> i + "")
.collect(Collectors.toList());
}
public Trace(Region region) {
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();
records = new SoftReference<>(recordList);
metadataSaveFile = new File(TraceManager.tracesFolder, uuid + ".meta");
/**
* Gets and increments the next open record id
*
* @return next open record id
*/
protected int getAndIncrementNextOpenRecordId() {
return ++nextOpenRecordId;
}
/**
* Adds the given records and updates potential trace renderings
*/
protected void addAll(List<TNTPoint> records, Function<Player, PlayerTraceShowData> getter) {
this.getRecords().addAll(records);
Iterator<Player> keySetIterator = entityServerMap.keySet().iterator();
while (keySetIterator.hasNext()) {
Player player = keySetIterator.next();
PlayerTraceShowData playerTraceShowData = getter.apply(player);
if (playerTraceShowData == null) {
keySetIterator.remove();
continue;
}
render(records, entityServerMap.get(player), playerTraceShowData);
try {
@Cleanup
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(metadataSaveFile));
outputStream.writeUTF(uuid.toString());
outputStream.writeUTF(region.getName());
outputStream.writeObject(date);
} catch (IOException | ClassCastException e) {
e.printStackTrace();
}
}
/**
* Internal methode to make records immutable after recording is finished
*
* @param records immutable records list
*/
protected void setRecords(List<TNTPoint> records) {
this.records = records;
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();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
this.uuid = UUID.fromString(uuid);
this.region = region;
this.date = date;
recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records");
this.records = new SoftReference<>(null);
}
System.out.println(this);
}
/**
@ -132,6 +134,17 @@ public class Trace { // TODO: Add UUID for file saving and so on!
return histories;
}
/**
* List of all used ids
*/
public List<String> getUsedIds() {
return getRecords()
.stream()
.map(TNTPoint::getTntId)
.map(i -> i + "")
.collect(Collectors.toList());
}
/**
* Renders this traces
*
@ -150,34 +163,41 @@ public class Trace { // TODO: Add UUID for file saving and so on!
render(getRecords(), entityServer, playerTraceShowData);
}
protected void render(List<TNTPoint> records, Player player, PlayerTraceShowData playerTraceShowData) {
render(records, entityServerMap.get(player), playerTraceShowData);
}
/**
* Internal methode to render records to a REntityServer
*
* @param records Records to render
* @param entityServer The show server the trace will be renderd to
* @param playerTraceShowData The showData for modifying the rendering
*/
private void render(List<TNTPoint> records, REntityServer entityServer, PlayerTraceShowData playerTraceShowData) {
if (records.isEmpty()) return;
if (records.isEmpty())
return;
List<TNTPoint> workingRecords = new ArrayList<>(records);
Set<ViewFlag> flagList = playerTraceShowData.getEffectiveViewFlags();
//Apply filters
// Apply filters
for (ViewFlag flag : flagList) {
workingRecords = flag.filter(workingRecords);
}
//Bundle records at unique positions
// Bundle records at unique positions
List<List<TNTPoint>> bundles = bundleRecords(workingRecords, playerTraceShowData.getBundleFilter());
//Render bundled records
// Render bundled records
List<TraceEntity> entities = new LinkedList<>();
for (List<TNTPoint> bundle : bundles) {
entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle));
entities.add(
new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle));
}
//Apply modifiers
// Apply modifiers
for (ViewFlag flag : flagList) {
flag.modify(entityServer, entities);
}
@ -195,13 +215,13 @@ public class Trace { // TODO: Add UUID for file saving and so on!
* Bundles the passed TNTRecords based on whether they are at the same location
*
* @param records The TNTRecords that are supposed to be bundled
* @param filter A filter specefieng whether records can be bundled
* @return A list of bundles
*/
private List<List<TNTPoint>> bundleRecords(List<TNTPoint> records, BundleFilter filter) {
List<List<TNTPoint>> bundles = new ArrayList<>();
recordsLoop:
for (TNTPoint record : records) {
recordsLoop: for (TNTPoint record : records) {
if (bundles.isEmpty()) {
List<TNTPoint> firstBundle = new ArrayList<>();
firstBundle.add(record);
@ -226,6 +246,26 @@ public class Trace { // TODO: Add UUID for file saving and so on!
return bundles;
}
/**
* Makes the first passed player follow the trace render of the second passed
* player
*
* @param player
* @param toFollow
*/
public void follow(Player player, Player toFollow) {
throw new UnsupportedOperationException();
}
/**
* Makes the passed player stop following any other players trace render
*
* @param player
*/
public void unfollow(Player player) {
throw new UnsupportedOperationException();
}
/**
* Hides this trail for the given player
*
@ -233,8 +273,11 @@ public class Trace { // TODO: Add UUID for file saving and so on!
*/
public void hide(Player player) {
REntityServer entityServer = entityServerMap.remove(player);
if (entityServer == null) return;
entityServer.close();
if (entityServer == null)
return;
entityServer.removePlayer(player);
if (entityServer.getPlayers().isEmpty())
entityServer.close();
}
public void hide() {
@ -244,12 +287,47 @@ public class Trace { // TODO: Add UUID for file saving and so on!
entityServerMap.clear();
}
private void loadRecords() {
try {
List<TNTPoint> records = new ArrayList<>();
@Cleanup
FileInputStream fileInputStream = new FileInputStream(recordsSaveFile);
@Cleanup
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
while (fileInputStream.getChannel().position() < recordsSaveFile.length()) {
records.add((TNTPoint) inputStream.readObject());
}
System.out.println("Loaded... " + records);
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);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public List<TNTPoint> getRecords() {
if (records.get() == null)
loadRecords();
return records.get();
}
@Override
public String toString() {
return "Trace{" +
"region=" + region +
", startTime=" + startTime +
", records=" + records +
"uuid=" + uuid +
", region=" + region +
", creationTime=" + date +
", recordsSaveFile=" + recordsSaveFile.getName() +
", records=" + getRecords() +
'}';
}
}

Datei anzeigen

@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.tracer;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.AtFlag;
import de.steamwar.bausystem.region.Region;
@ -28,7 +29,6 @@ import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -41,12 +41,6 @@ import java.util.stream.Stream;
@Linked
public class TraceCommand extends SWCommand {
@LinkedInstance
public TraceRecorder traceRecorder;
@LinkedInstance
public TraceManager manager;
public TraceCommand() {
super("trace", "trail");
}
@ -54,21 +48,21 @@ public class TraceCommand extends SWCommand {
@Register(value = "start", description = "TRACE_COMMAND_HELP_START")
public void start(@Validator Player player) {
Region region = Region.getRegion(player.getLocation());
traceRecorder.startRecording(region);
TraceRecorder.instance.startRecording(region);
BauSystem.MESSAGE.send("TRACE_MESSAGE_START", player);
}
@Register(value = "stop", description = "TRACE_COMMAND_HELP_STOP")
public void stop(@Validator Player player) {
Region region = Region.getRegion(player.getLocation());
traceRecorder.stopRecording(region);
TraceRecorder.instance.stopRecording(region);
BauSystem.MESSAGE.send("TRACE_MESSAGE_STOP", player);
}
@Register(value = "auto", description = "TRACE_COMMAND_HELP_AUTO")
public void auto(@Validator Player player) {
Region region = Region.getRegion(player.getLocation());
traceRecorder.toggleAutoTrace(region);
TraceRecorder.instance.toggleAutoTrace(region);
// TODO: Add Auto toggle Message!
}
@ -78,20 +72,24 @@ public class TraceCommand extends SWCommand {
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW", player);
}
@Register(value = {"show", "at"}, description = "TRACE_COMMAND_HELP_SHOW_AT_WITH")
public void showAt(@Validator Player player, @Min(intValue = 0) int time, @StaticValue("with") String with, @OptionalValue("STRICT") BundleFilter bundleFilter, @ArrayLength(min = 1) ViewFlag... flags) {
@Register(value = { "show", "at" }, description = "TRACE_COMMAND_HELP_SHOW_AT_WITH")
public void showAt(@Validator Player player, @Min(intValue = 0) int time, @StaticValue("with") String with,
@OptionalValue("STRICT") BundleFilter bundleFilter, @ArrayLength(min = 1) ViewFlag... flags) {
showInternal(player, time, time, bundleFilter, flags);
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_AT", player, time);
}
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_WITH")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("with") String with, @OptionalValue("STRICT") BundleFilter bundleFilter, @ArrayLength(min = 1) ViewFlag... flags) {
@Register(value = { "show", "from" }, description = "TRACE_COMMAND_HELP_SHOW_FROM_WITH")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("with") String with,
@OptionalValue("STRICT") BundleFilter bundleFilter, @ArrayLength(min = 1) ViewFlag... flags) {
showInternal(player, from, Integer.MAX_VALUE, bundleFilter, flags);
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM", player, from);
}
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO_WITH")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString, int to, @StaticValue("with") String with, @OptionalValue("STRICT") BundleFilter bundleFilter, @ArrayLength(min = 1) ViewFlag... flags) {
@Register(value = { "show", "from" }, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO_WITH")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString,
int to, @StaticValue("with") String with, @OptionalValue("STRICT") BundleFilter bundleFilter,
@ArrayLength(min = 1) ViewFlag... flags) {
if (to < from) {
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_TO_SMALLER", player);
return;
@ -103,71 +101,73 @@ public class TraceCommand extends SWCommand {
private void showInternal(Player player, int from, int to, BundleFilter bundleFilter, ViewFlag... flags) {
PlayerTraceShowData playerTraceShowData = new PlayerTraceShowData(bundleFilter, flags);
playerTraceShowData.addViewFlag(new AtFlag(from, to));
manager.show(player, playerTraceShowData);
TraceManager.instance.show(player, playerTraceShowData);
}
@Register(value = {"show", "at"}, description = "TRACE_COMMAND_HELP_SHOW_AT")
@Register(value = { "show", "at" }, description = "TRACE_COMMAND_HELP_SHOW_AT")
public void showAt(@Validator Player player, @Min(intValue = 0) int time) {
manager.renderAt(player, time, time);
TraceManager.instance.renderAt(player, time, time);
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_AT", player, time);
}
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM")
@Register(value = { "show", "from" }, description = "TRACE_COMMAND_HELP_SHOW_FROM")
public void showFrom(@Validator Player player, @Min(intValue = 0) int from) {
manager.renderAt(player, from, Integer.MAX_VALUE);
TraceManager.instance.renderAt(player, from, Integer.MAX_VALUE);
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM", player, from);
}
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString, int to) {
manager.renderAt(player, from, to);
@Register(value = { "show", "from" }, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO")
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString,
int to) {
TraceManager.instance.renderAt(player, from, to);
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM_TO", player, from, to);
}
@Register(value = "hide", description = "TRACE_COMMAND_HELP_HIDE")
public void hide(@Validator Player player) {
manager.hide(player);
TraceManager.instance.hide(player);
BauSystem.MESSAGE.send("TRACE_MESSAGE_HIDE", player);
}
@Register(value = "delete", description = "TRACE_COMMAND_HELP_DELETE")
@Register(value = "clear")
public void delete(@Validator Player player) {
manager.clear();
TraceManager.instance.clear();
BauSystem.MESSAGE.send("TRACE_MESSAGE_DELETE", player);
}
@Register(value = "delete")
public void delete(@Validator Player player, Trace trace) {
manager.remove(trace);
TraceManager.instance.remove(trace);
BauSystem.MESSAGE.send("TRACE_MESSAGE_DELETE_SPECIFIC", player);
}
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
manager.isolate(player, records);
public void isolate(@Validator Player player, Trace trace,
@ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
TraceManager.instance.isolate(player, records);
// TODO: Add Message!
}
@Register(value = "share", description = "TRACE_COMMAND_HELP_SHOW")
public void share(@Validator Player player) {
//TODO Rücksprache
// TODO Rücksprache
}
@Register(value = "follow", description = "TRACE_COMMAND_HELP_SHOW")
public void follow(@Validator Player player, Player toFollow) {
if (player == toFollow) {
// TODO: Implement message
return;
// TODO: Implement
for (Trace trace : TraceManager.instance.getAll()) {
trace.follow(player, toFollow);
}
manager.follow(player, toFollow);
// TODO: Implement message
}
@Register(value = "unfollow", description = "TRACE_COMMAND_HELP_SHOW")
public void unfollow(@Validator Player player) {
manager.unfollow(player);
// TODO: Implement message
// TODO: Implement
for (Trace trace : TraceManager.instance.getAll()) {
trace.unfollow(player);
}
}
@ClassMapper(value = Trace.class, local = true)
@ -175,12 +175,13 @@ public class TraceCommand extends SWCommand {
return new TypeMapper<>() {
@Override
public Trace map(CommandSender commandSender, String[] previousArguments, String s) {
return manager.get(Integer.parseInt(s)).orElse(null);
return TraceManager.instance.get(Integer.parseInt(s)).orElse(null);
}
@Override
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
return manager.getAllIds().stream()
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments,
String s) {
return TraceManager.instance.getAllIds().stream()
.map(Object::toString)
.collect(Collectors.toList());
}
@ -193,7 +194,8 @@ public class TraceCommand extends SWCommand {
@Override
public TNTPoint map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
Trace trace = previousArguments.getFirst(Trace.class).orElse(null);
if (trace == null) return null;
if (trace == null)
return null;
int id = Integer.parseInt(s);
return trace.getRecords().stream()
@ -202,11 +204,13 @@ public class TraceCommand extends SWCommand {
.orElse(null);
}
//TODO change when new command framework update
// TODO change when new command framework update
@Override
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments,
String s) {
Trace trace = previousArguments.getFirst(Trace.class).orElse(null);
if (trace == null) return null;
if (trace == null)
return null;
return trace.getUsedIds();
}
};
@ -226,7 +230,8 @@ public class TraceCommand extends SWCommand {
}
@Override
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments,
String s) {
if (s.length() == 0) {
return new ArrayList<>();
}
@ -258,7 +263,8 @@ public class TraceCommand extends SWCommand {
}
@Override
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments,
String s) {
return ViewFlag.flags.stream()
.flatMap(viewFlag -> Stream.concat(Stream.of("--" + viewFlag.name),
Arrays.stream(viewFlag.aliases).map(name -> "-" + name)))

Datei anzeigen

@ -20,19 +20,47 @@
package de.steamwar.bausystem.features.tracer;
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.AtFlag;
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.IsolateFlag;
import de.steamwar.bausystem.region.Region;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import java.io.File;
import java.util.*;
@Linked
public class TraceManager implements Listener {
public static TraceManager instance;
{
instance = this;
}
public static File tracesFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "traces");
public TraceManager() {
if (!tracesFolder.exists())
tracesFolder.mkdir();
File[] traceFiles = tracesFolder.listFiles();
if (traceFiles == null)
return;
for (File traceFile : traceFiles) {
if (traceFile.getName().contains(".records"))
continue;
add(new Trace(traceFile));
}
}
/**
* List of all current traces
*/
@ -56,31 +84,15 @@ public class TraceManager implements Listener {
* @return id of the created trace
*/
protected int add(Trace trace) {
showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).forEach((player, playerTraceShowData) -> {
trace.render(player, playerTraceShowData);
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
trace.render(follower, playerTraceShowData);
});
});
showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).forEach(trace::render);
traces.put(nextOpenId, trace);
tracesByRegion.computeIfAbsent(trace.getRegion(), region -> new HashMap<>()).put(nextOpenId, trace);
nextOpenId++;
return nextOpenId;
}
protected void addAll(Trace trace, List<TNTPoint> TNTPoints) {
trace.addAll(TNTPoints, player -> {
Map.Entry<Player, Set<Player>> entry = followerMap.entrySet()
.stream()
.filter(playerSetEntry -> playerSetEntry.getValue().contains(player))
.findFirst()
.orElse(null);
if (entry == null) {
return showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).get(player);
} else {
return showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).get(entry.getKey());
}
});
protected Map<Player, PlayerTraceShowData> getTraceShowDataPlayerMapping(Region region) {
return showDataPerRegionPerPlayer.getOrDefault(region, new HashMap<>());
}
/**
@ -94,7 +106,8 @@ public class TraceManager implements Listener {
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
if (traceId == null) return false;
if (traceId == null)
return false;
traces.remove(traceId);
tracesByRegion.getOrDefault(trace.getRegion(), Collections.emptyMap()).remove(traceId);
trace.hide();
@ -116,6 +129,10 @@ public class TraceManager implements Listener {
players.forEach(trace::hide);
});
});
traces.forEach((i, trace) -> {
trace.getMetadataSaveFile().delete();
trace.getRecordsSaveFile().delete();
});
traces.clear();
tracesByRegion.clear();
nextOpenId = 0;
@ -135,7 +152,7 @@ public class TraceManager implements Listener {
* Methode to get the trace with specific id
*
* @param index index of the trace
* @return the trace with given id or null if no trace with id is found
* @return the trace with given id
*/
public Optional<Trace> get(int index) {
return Optional.ofNullable(traces.get(index));
@ -185,16 +202,19 @@ public class TraceManager implements Listener {
unfollow(player);
Region region = Region.getRegion(player.getLocation());
PlayerTraceShowData previous = showDataPerRegionPerPlayer.getOrDefault(region, Collections.emptyMap()).remove(player);
if (previous == null) return;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
PlayerTraceShowData previous = showDataPerRegionPerPlayer.getOrDefault(region, Collections.emptyMap())
.remove(player);
if (previous == null)
return;
tracesByRegion.getOrDefault(player, Collections.emptyMap()).forEach((integer, trace) -> {
trace.hide(player);
followerMap.getOrDefault(player, Collections.emptySet()).forEach(trace::hide);
});
}
public boolean follow(Player follower, Player following) {
if (followerMap.containsKey(follower)) return false;
if (followerMap.containsKey(follower))
return false;
if (followerMap.entrySet().stream().anyMatch(playerSetEntry -> playerSetEntry.getValue().contains(follower))) {
unfollow(follower);
}
@ -209,7 +229,8 @@ public class TraceManager implements Listener {
}
PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(following);
if (playerTraceShowData == null) return;
if (playerTraceShowData == null)
return;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
trace.render(follower, playerTraceShowData);
});
@ -218,25 +239,30 @@ public class TraceManager implements Listener {
}
public void unfollow(Player follower) {
if (followerMap.containsKey(follower)) return;
if (followerMap.containsKey(follower))
return;
List<Player> toRemove = new ArrayList<>();
Set<Player> toHide = new HashSet<>();
followerMap.forEach((player, players) -> {
if (players.remove(follower)) toHide.add(follower);
if (players.isEmpty()) toRemove.add(player);
if (players.remove(follower))
toHide.add(follower);
if (players.isEmpty())
toRemove.add(player);
});
toRemove.forEach(followerMap::remove);
showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> {
toHide.forEach(player -> {
if (!playerPlayerTraceShowDataMap.containsKey(player)) return;
if (!playerPlayerTraceShowDataMap.containsKey(player))
return;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
trace.hide(follower);
});
});
PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(follower);
if (playerTraceShowData == null) return;
if (playerTraceShowData == null)
return;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
trace.render(follower, playerTraceShowData);
});
@ -244,7 +270,8 @@ public class TraceManager implements Listener {
}
/**
* Modifies the render for the given player, to only show tnts at the given time interval
* Modifies the render for the given player, to only show tnts at the given time
* interval
*
* @param player
* @param from start of time interval
@ -254,7 +281,9 @@ public class TraceManager implements Listener {
unfollow(player);
Region region = Region.getRegion(player.getLocation());
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT));
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer
.computeIfAbsent(region, ignored -> new HashMap<>())
.computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT));
AtFlag atFlag = playerTraceShowData.getViewFlag(AtFlag.class);
if (atFlag == null) {
@ -282,7 +311,9 @@ public class TraceManager implements Listener {
unfollow(player);
Region region = Region.getRegion(player.getLocation());
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT));
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer
.computeIfAbsent(region, ignored -> new HashMap<>())
.computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT));
IsolateFlag isolateFlag;
if (playerTraceShowData.hasViewFlagOnly(IsolateFlag.class)) {

Datei anzeigen

@ -23,7 +23,6 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.region.Region;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import org.bukkit.block.Block;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
@ -43,16 +42,10 @@ public class TraceRecorder implements Listener {
instance = this;
}
/**
* Linked instance of TraceManager
*/
@LinkedInstance
public TraceManager manager;
/**
* Map for all traces being actively recorded
*/
private final Map<Region, Trace> activeTraces = new HashMap<>();
private final Map<Region, TraceRecordingWrapper> activeTraces = new HashMap<>();
/**
* Map for all TNTs being traced, by region
@ -64,16 +57,6 @@ public class TraceRecorder implements Listener {
*/
private final Map<TNTPrimed, Region> tntSpawnRegion = new HashMap<>();
/**
* Set of all active traces that no explosion has been recorded on
*/
private final Set<Trace> noExplosionRecorded = new HashSet<>();
/**
* A map for records that have been taken in the same tick and now have to be added to the traces
*/
private final Map<Trace, List<TNTPoint>> recordsToAddMap = new HashMap<>();
/**
* Maps a tracked tnt entity to its entire recording history
*/
@ -109,7 +92,8 @@ public class TraceRecorder implements Listener {
*/
public void checkForAutoTraceFinish() {
for (Region region : autoTraceRegions) {
if (autoTraceRegions.contains(region) && trackedTNT.getOrDefault(region, Collections.emptyList()).size() == 0) {
if (autoTraceRegions.contains(region)
&& trackedTNT.getOrDefault(region, Collections.emptyList()).size() == 0) {
stopRecording(region);
}
}
@ -121,12 +105,12 @@ public class TraceRecorder implements Listener {
* @param region region to be recorded
*/
public int startRecording(Region region) {
if (activeTraces.containsKey(region)) return -1;
Trace trace = new Trace(region);
noExplosionRecorded.add(trace);
activeTraces.put(region, trace);
recordsToAddMap.put(trace, new ArrayList<>());
return manager.add(trace);
if (activeTraces.containsKey(region))
return -1;
TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region);
activeTraces.put(region, wrappedTrace);
return TraceManager.instance.add(wrappedTrace.getTrace());
}
/**
@ -135,17 +119,14 @@ public class TraceRecorder implements Listener {
* @param region region to stop recording
*/
public void stopRecording(Region region) {
Trace trace = activeTraces.getOrDefault(region, null);
if (trace == null) return;
trace.setRecords(Collections.unmodifiableList(trace.getRecords()));
TraceRecordingWrapper wrappedTrace = activeTraces.getOrDefault(region, null);
if (wrappedTrace == null)
return;
noExplosionRecorded.remove(trace);
activeTraces.remove(region);
for (TNTPrimed tnt : trackedTNT.getOrDefault(region, Collections.emptyList())) {
historyMap.remove(tnt);
}
recordsToAddMap.remove(trace);
trackedTNT.put(region, new ArrayList<>());
}
@ -154,45 +135,45 @@ public class TraceRecorder implements Listener {
*/
private void record() {
for (Region region : activeTraces.keySet()) {
Trace trace = activeTraces.get(region);
TraceRecordingWrapper wrappedTrace = activeTraces.get(region);
for (TNTPrimed tnt : trackedTNT.getOrDefault(region, Collections.emptyList())) {
record(tnt, trace, Collections.emptyList());
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
wrappedTrace.addRecord(record);
}
List<TNTPoint> TNTPoints = recordsToAddMap.get(trace);
manager.addAll(trace, TNTPoints);
TNTPoints.clear();
wrappedTrace.commitRecorded();
}
}
/**
* Internal methode to record exploded tnt
*
* @param tntPrimed tnt exploding
* @param trace trace to record the tnt for
* @param tntPrimed tnt exploding
* @param wrappedTrace the trace to record the tnt for wrapped with metadata
* @param destroyedBlocks the blocks destoryed by the passed tnt
* @return the record creaded of the passed tnt
*/
private void record(TNTPrimed tntPrimed, Trace trace, List<Block> destroyedBlocks) {
private TNTPoint record(TNTPrimed tntPrimed, TraceRecordingWrapper wrappedTrace, List<Block> destroyedBlocks) {
List<TNTPoint> history = historyMap.getOrDefault(tntPrimed, new ArrayList<>());
int tntID;
if (history.size() == 0) {
historyMap.put(tntPrimed, history);
tntID = trace.getAndIncrementNextOpenRecordId();
tntID = wrappedTrace.getNextOpenRecordIdAndIncrement();
} else {
tntID = history.get(0).getTntId();
}
boolean isExplosion = tntPrimed.getFuseTicks() == 0;
if (isExplosion) {
noExplosionRecorded.remove(trace);
wrappedTrace.activateExplosionRecorded();
}
boolean afterFirstExplosion = noExplosionRecorded.contains(trace);
boolean afterFirstExplosion = wrappedTrace.isExplosionRecorded();
TNTPoint record = new TNTPoint(tntID, tntPrimed, isExplosion, afterFirstExplosion, TPSUtils.currentTick.get() - trace.getStartTime(), history, destroyedBlocks);
TNTPoint record = new TNTPoint(tntID, tntPrimed, isExplosion, afterFirstExplosion,
TPSUtils.currentTick.get() - wrappedTrace.getStartTick(), history, destroyedBlocks);
history.add(record);
recordsToAddMap.get(trace).add(record);
return record;
}
/**
@ -203,7 +184,8 @@ public class TraceRecorder implements Listener {
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onTNTSpawn(EntitySpawnEvent event) {
if (!(event.getEntity() instanceof TNTPrimed)) return;
if (!(event.getEntity() instanceof TNTPrimed))
return;
Region region = Region.getRegion(event.getLocation());
@ -219,7 +201,8 @@ public class TraceRecorder implements Listener {
trackedTNT.get(region).add((TNTPrimed) event.getEntity());
tntSpawnRegion.put((TNTPrimed) event.getEntity(), region);
record((TNTPrimed) event.getEntity(), activeTraces.get(region), Collections.emptyList());
activeTraces.get(region).addRecord(
record((TNTPrimed) event.getEntity(), activeTraces.get(region), Collections.emptyList()));
}
}
@ -231,13 +214,16 @@ public class TraceRecorder implements Listener {
*/
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onTNTExplode(EntityExplodeEvent event) {
if (!(event.getEntity() instanceof TNTPrimed)) return;
if (!(event.getEntity() instanceof TNTPrimed))
return;
Region region = tntSpawnRegion.getOrDefault((TNTPrimed) event.getEntity(), null);
if (region == null) return;
if (region == null)
return;
trackedTNT.get(region).remove((TNTPrimed) event.getEntity());
tntSpawnRegion.remove((TNTPrimed) event.getEntity());
record((TNTPrimed) event.getEntity(), activeTraces.get(region), event.blockList());
activeTraces.get(region)
.addRecord(record((TNTPrimed) event.getEntity(), activeTraces.get(region), event.blockList()));
}
}

Datei anzeigen

@ -0,0 +1,102 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.features.tracer;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.region.Region;
import lombok.Getter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
//TODO Rename ?
public class TraceRecordingWrapper {
private final Region region;
@Getter
private final long startTick;
private final List<TNTPoint> recordsToAdd;
private final List<TNTPoint> recordList;
private ObjectOutputStream recordsOutputStream;
private int nextOpenRecordId = 0;
@Getter
private boolean explosionRecorded = false;
@Getter
private final Trace trace;
public TraceRecordingWrapper(Region region) {
this.region = region;
startTick = TPSUtils.currentTick.get();
recordsToAdd = new ArrayList<>();
recordList = new ArrayList<>();
trace = new Trace(region, recordList);
TraceManager.instance.add(trace);
File recordsSaveFile = new File(TraceManager.tracesFolder, trace.getUuid() + ".records");
try {
recordsOutputStream = new ObjectOutputStream(new FileOutputStream(recordsSaveFile));
} catch (IOException e) {
e.printStackTrace();
}
}
public int getNextOpenRecordIdAndIncrement() {
return nextOpenRecordId++;
}
public void activateExplosionRecorded() {
explosionRecorded = true;
}
public void addRecord(TNTPoint record) {
recordsToAdd.add(record);
}
public void commitRecorded() {
TraceManager.instance.getTraceShowDataPlayerMapping(region).forEach((key, value) -> trace.render(recordsToAdd, key, value));
recordsToAdd.forEach(record -> {
try {
recordsOutputStream.writeObject(record);
} catch (IOException e) {
e.printStackTrace();
}
});
recordList.addAll(recordsToAdd);
recordsToAdd.clear();
System.out.println(recordList);
}
protected void finalizeRecording() {
try {
recordsOutputStream.flush();
recordsOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Datei anzeigen

@ -17,10 +17,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.features.tracer;
package de.steamwar.bausystem.features.tracer.rendering;
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
import lombok.Getter;
import lombok.Setter;
@ -42,7 +40,7 @@ public class PlayerTraceShowData {
}
public Set<ViewFlag> getEffectiveViewFlags() {
//Manage flags and required flags
// Manage flags and required flags
Set<ViewFlag> flagList = new HashSet<>();
for (ViewFlag flag : viewFlags.values()) {
flagList.add(flag);
@ -51,7 +49,7 @@ public class PlayerTraceShowData {
}
}
//Manage inverse flags
// Manage inverse flags
ViewFlag.inverseFlags.forEach(viewFlag -> {
if (!flagList.remove(viewFlag)) {
flagList.add(viewFlag);
@ -73,6 +71,8 @@ public class PlayerTraceShowData {
return viewFlags.containsKey(clazz) && viewFlags.size() == 1;
}
// TODO ?
@SuppressWarnings("unchecked")
public <T extends ViewFlag> T getViewFlag(Class<T> clazz) {
return (T) viewFlags.get(clazz);
}