diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java index 84d58fac..0e7033aa 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java @@ -34,6 +34,7 @@ import java.util.function.Function; import java.util.stream.Collectors; public class Trace { // TODO: Add UUID for file saving and so on! + /** * Region this trace has been recorded in */ @@ -225,25 +226,6 @@ 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 * @@ -252,8 +234,7 @@ 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.removePlayer(player); - if (entityServer.getPlayers().isEmpty()) entityServer.close(); + entityServer.close(); } @Override diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java index bfeb1a79..fba84cc0 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java @@ -155,18 +155,18 @@ public class TraceCommand extends SWCommand { @Register(value = "follow", description = "TRACE_COMMAND_HELP_SHOW") public void follow(@Validator Player player, Player toFollow) { - // TODO: Implement - for (Trace trace : manager.getAll()) { - trace.follow(player, toFollow); + if (player == toFollow) { + // TODO: Implement message + return; } + manager.follow(player, toFollow); + // TODO: Implement message } @Register(value = "unfollow", description = "TRACE_COMMAND_HELP_SHOW") public void unfollow(@Validator Player player) { - // TODO: Implement - for (Trace trace : manager.getAll()) { - trace.unfollow(player); - } + manager.unfollow(player); + // TODO: Implement message } @ClassMapper(value = Trace.class, local = true) diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java index e275b0ce..ac36428e 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java @@ -40,6 +40,8 @@ public class TraceManager implements Listener { private final Map> showDataPerRegionPerPlayer = new HashMap<>(); + private final Map> followerMap = new HashMap<>(); + /** * Utility variable to keep track of the next open trace id; */ @@ -54,6 +56,9 @@ public class TraceManager implements Listener { 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); + }); }); traces.put(nextOpenId, trace); tracesByRegion.computeIfAbsent(trace.getRegion(), region -> new HashMap<>()).put(nextOpenId, trace); @@ -63,7 +68,16 @@ public class TraceManager implements Listener { protected void addAll(Trace trace, List TNTPoints) { trace.addAll(TNTPoints, player -> { - return showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).get(player); + Map.Entry> 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()); + } }); } @@ -78,6 +92,7 @@ public class TraceManager implements Listener { Trace trace = traces.remove(id); showDataPerRegionPerPlayer.get(trace.getRegion()).forEach((player, playerTraceShowData) -> { trace.hide(player); + followerMap.getOrDefault(player, Collections.emptySet()).forEach(trace::hide); }); tracesByRegion.get(trace.getRegion()).remove(id); return true; @@ -92,8 +107,10 @@ public class TraceManager implements Listener { .flatMap(map -> map.entrySet().stream()) .map(Map.Entry::getKey) .forEach(player -> { + Set players = followerMap.getOrDefault(player, Collections.emptySet()); traces.values().forEach(trace -> { trace.hide(player); + players.forEach(trace::hide); }); }); traces.clear(); @@ -144,10 +161,15 @@ public class TraceManager implements Listener { * @param playerTraceShowData */ public void show(Player player, PlayerTraceShowData playerTraceShowData) { + unfollow(player); + Region region = Region.getRegion(player.getLocation()); showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).put(player, playerTraceShowData); tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { trace.render(player, playerTraceShowData); + followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> { + trace.render(follower, playerTraceShowData); + }); }); } @@ -157,11 +179,56 @@ public class TraceManager implements Listener { * @param player */ public void hide(Player player) { + unfollow(player); + Region region = Region.getRegion(player.getLocation()); PlayerTraceShowData previous = showDataPerRegionPerPlayer.getOrDefault(region, Collections.emptyMap()).remove(player); if (previous == null) return; - tracesByRegion.getOrDefault(player, Collections.emptyMap()).forEach((integer, trace) -> { + tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { trace.hide(player); + followerMap.getOrDefault(player, Collections.emptySet()).forEach(trace::hide); + }); + } + + public boolean hasFollower(Player player) { + return followerMap.containsKey(player); + } + + public boolean follow(Player follower, Player following) { + if (followerMap.containsKey(follower)) return false; + followerMap.computeIfAbsent(following, ignored -> new HashSet<>()).add(follower); + + showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> { + if (playerPlayerTraceShowDataMap.containsKey(follower)) { + tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { + trace.hide(follower); + }); + } + + PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(following); + if (playerTraceShowData == null) return; + tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { + trace.render(follower, playerTraceShowData); + }); + }); + return true; + } + + public void unfollow(Player follower) { + if (followerMap.containsKey(follower)) return; + List toRemove = new ArrayList<>(); + followerMap.forEach((player, players) -> { + players.remove(player); + if (players.isEmpty()) toRemove.add(player); + }); + toRemove.forEach(followerMap::remove); + + showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> { + PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(follower); + if (playerTraceShowData == null) return; + tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { + trace.render(follower, playerTraceShowData); + }); }); } @@ -173,6 +240,8 @@ public class TraceManager implements Listener { * @param to end of time interval */ public void renderAt(Player player, int from, int to) { + unfollow(player); + Region region = Region.getRegion(player.getLocation()); PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT)); @@ -186,6 +255,9 @@ public class TraceManager implements Listener { tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { trace.render(player, playerTraceShowData); + followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> { + trace.render(follower, playerTraceShowData); + }); }); } @@ -196,6 +268,8 @@ public class TraceManager implements Listener { * @param records the record for which isolation is toggled */ public void isolate(Player player, TNTPoint... records) { + unfollow(player); + Region region = Region.getRegion(player.getLocation()); PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.STRICT)); @@ -219,6 +293,9 @@ public class TraceManager implements Listener { PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData; tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> { trace.render(player, finalPlayerTraceShowData); + followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> { + trace.render(follower, finalPlayerTraceShowData); + }); }); } }