diff --git a/core/src/main/java/tc/oc/pgm/listeners/ChatDispatcher.java b/core/src/main/java/tc/oc/pgm/listeners/ChatDispatcher.java index fcd4f279db..5c54dc26d9 100644 --- a/core/src/main/java/tc/oc/pgm/listeners/ChatDispatcher.java +++ b/core/src/main/java/tc/oc/pgm/listeners/ChatDispatcher.java @@ -12,6 +12,8 @@ import com.google.common.cache.CacheBuilder; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -31,6 +33,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.incendo.cloud.annotation.specifier.Greedy; import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; @@ -52,7 +55,6 @@ import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.Players; import tc.oc.pgm.util.bukkit.BukkitUtils; -import tc.oc.pgm.util.bukkit.OnlinePlayerMapAdapter; import tc.oc.pgm.util.channels.Channel; import tc.oc.pgm.util.event.ChannelMessageEvent; import tc.oc.pgm.util.named.NameStyle; @@ -69,7 +71,7 @@ public static ChatDispatcher get() { } private final MatchManager manager; - private final OnlinePlayerMapAdapter lastMessagedBy; + private final Map lastMessagedBy; public static final TextComponent ADMIN_CHAT_PREFIX = text() .append(text("[", NamedTextColor.WHITE)) @@ -94,7 +96,7 @@ public static ChatDispatcher get() { public ChatDispatcher() { this.manager = PGM.get().getMatchManager(); - this.lastMessagedBy = new OnlinePlayerMapAdapter<>(PGM.get()); + this.lastMessagedBy = new HashMap<>(); PGM.get().getServer().getPluginManager().registerEvents(this, PGM.get()); } @@ -439,13 +441,17 @@ private Component getChatFormat(@Nullable Component prefix, MatchPlayer player, .build(); } + @EventHandler(ignoreCancelled = true) + public void onPlayerQuit(PlayerQuitEvent event) { + this.lastMessagedBy.remove(event.getPlayer().getUniqueId()); + } + private void trackMessage(Player receiver, Player sender) { - MessageSenderIdentity senderIdent = new MessageSenderIdentity(receiver, sender); - this.lastMessagedBy.put(receiver, senderIdent); + this.lastMessagedBy.put(receiver.getUniqueId(), new MessageSenderIdentity(receiver, sender)); } private UUID getLastMessagedId(Player sender) { - MessageSenderIdentity targetIdent = lastMessagedBy.get(sender); + MessageSenderIdentity targetIdent = lastMessagedBy.get(sender.getUniqueId()); if (targetIdent == null) return null; MatchPlayer target = manager.getPlayer(targetIdent.getPlayerId()); @@ -466,10 +472,9 @@ private UUID getLastMessagedId(Player sender) { return null; } - private class MessageSenderIdentity { - - private UUID playerId; - private String name; + private static class MessageSenderIdentity { + private final UUID playerId; + private final String name; public MessageSenderIdentity(Player viewer, Player player) { this.playerId = player.getUniqueId(); diff --git a/core/src/main/java/tc/oc/pgm/listeners/MatchAnnouncer.java b/core/src/main/java/tc/oc/pgm/listeners/MatchAnnouncer.java index 6e013a580c..3b45f4e56e 100644 --- a/core/src/main/java/tc/oc/pgm/listeners/MatchAnnouncer.java +++ b/core/src/main/java/tc/oc/pgm/listeners/MatchAnnouncer.java @@ -53,8 +53,7 @@ public void onMatchLoad(final MatchLoadEvent event) { final Match match = event.getMatch(); match .getExecutor(MatchScope.LOADED) - .scheduleWithFixedDelay( - () -> match.getPlayers().forEach(this::sendCurrentlyPlaying), 0, 5, TimeUnit.MINUTES); + .scheduleWithFixedDelay(() -> sendCurrentlyPlaying(match), 0, 5, TimeUnit.MINUTES); } @EventHandler(priority = EventPriority.MONITOR) @@ -83,12 +82,11 @@ public void onMatchEnd(final MatchFinishEvent event) { title = translatable("broadcast.gameOver"); } else { if (singleWinner) { - title = - translatable( - Iterables.getOnlyElement(winners).isNamePlural() - ? "broadcast.gameOver.teamWinners" - : "broadcast.gameOver.teamWinner", - TextFormatter.nameList(winners, NameStyle.FANCY, NamedTextColor.WHITE)); + title = translatable( + Iterables.getOnlyElement(winners).isNamePlural() + ? "broadcast.gameOver.teamWinners" + : "broadcast.gameOver.teamWinner", + TextFormatter.nameList(winners, NameStyle.FANCY, NamedTextColor.WHITE)); } // Use stream here instead of #contains to avoid unchecked cast @@ -156,13 +154,11 @@ public void sendWelcomeMessage(MatchPlayer viewer, List extraLines) { Collection authors = mapInfo.getAuthors(); if (!authors.isEmpty()) { - viewer.sendMessage( - space() - .append( - translatable( - "misc.createdBy", - NamedTextColor.GRAY, - TextFormatter.nameList(authors, NameStyle.FANCY, NamedTextColor.GRAY)))); + viewer.sendMessage(space() + .append(translatable( + "misc.createdBy", + NamedTextColor.GRAY, + TextFormatter.nameList(authors, NameStyle.FANCY, NamedTextColor.GRAY)))); } // Send extra info from other plugins @@ -173,11 +169,10 @@ public void sendWelcomeMessage(MatchPlayer viewer, List extraLines) { viewer.sendMessage(TextFormatter.horizontalLine(NamedTextColor.WHITE, 200)); } - private void sendCurrentlyPlaying(MatchPlayer viewer) { - viewer.sendMessage( - translatable( - "misc.playing", - NamedTextColor.DARK_PURPLE, - viewer.getMatch().getMap().getStyledName(MapNameStyle.COLOR_WITH_AUTHORS))); + private void sendCurrentlyPlaying(Match match) { + match.sendMessage(translatable( + "misc.playing", + NamedTextColor.DARK_PURPLE, + match.getMap().getStyledName(MapNameStyle.COLOR_WITH_AUTHORS))); } } diff --git a/core/src/main/java/tc/oc/pgm/loot/LootableMatchModule.java b/core/src/main/java/tc/oc/pgm/loot/LootableMatchModule.java index 3e2abf7d25..3f0736bc8b 100644 --- a/core/src/main/java/tc/oc/pgm/loot/LootableMatchModule.java +++ b/core/src/main/java/tc/oc/pgm/loot/LootableMatchModule.java @@ -57,18 +57,16 @@ public LootableMatchModule( this.fillers = fillers; this.match = match; this.caches = caches; - this.filledAt = new InstantMap<>(new WorldTickClock(match.getWorld())); + this.filledAt = new InstantMap<>(match.getClock()); this.immm = match.getModule(ItemModifyMatchModule.class); final FilterMatchModule fmm = match.needModule(FilterMatchModule.class); - fillers.forEach( - filler -> { - fmm.onRise( - Match.class, - filler.getRefillTrigger(), - m -> this.filledAt.keySet().removeIf(f -> filler.equals(f.getRight()))); - }); + fillers.forEach(filler -> { + fmm.onRise(Match.class, filler.getRefillTrigger(), m -> this.filledAt + .keySet() + .removeIf(f -> filler.equals(f.getRight()))); + }); } /** @@ -78,9 +76,10 @@ public LootableMatchModule( private static @Nullable Predicate filterPredicate(InventoryHolder holder) { if (holder instanceof DoubleChest) { final DoubleChest doubleChest = (DoubleChest) holder; - return filter -> - !filter.query(new BlockQuery((Chest) doubleChest.getLeftSide())).isDenied() - || !filter.query(new BlockQuery((Chest) doubleChest.getRightSide())).isDenied(); + return filter -> !filter + .query(new BlockQuery((Chest) doubleChest.getLeftSide())) + .isDenied() + || !filter.query(new BlockQuery((Chest) doubleChest.getRightSide())).isDenied(); } else if (holder instanceof BlockState) { return filter -> !filter.query(new BlockQuery((BlockState) holder)).isDenied(); } else if (holder instanceof Player) { @@ -104,25 +103,17 @@ public void onInventoryOpen(InventoryOpenEvent event) { final Predicate filterPredicate = filterPredicate(inventory.getHolder()); if (filterPredicate == null) return; - logger.fine( - () -> - opener.getNameLegacy() - + " opened a " - + inventory.getHolder().getClass().getSimpleName()); + logger.fine(() -> + opener.getNameLegacy() + " opened a " + inventory.getHolder().getClass().getSimpleName()); // Find all Fillers that apply to the holder of the opened inventory - final List fillers = - this.fillers.stream() - .filter(filler -> filterPredicate.test(filler.getFilter())) - .collect(Collectors.toList()); + final List fillers = this.fillers.stream() + .filter(filler -> filterPredicate.test(filler.getFilter())) + .collect(Collectors.toList()); if (fillers.isEmpty()) return; - logger.fine( - () -> - "Found fillers " - + fillers.stream() - .map(FillerDefinition::toString) - .collect(Collectors.joining(", "))); + logger.fine(() -> "Found fillers " + + fillers.stream().map(FillerDefinition::toString).collect(Collectors.joining(", "))); // Find all Caches that the opened inventory is part of final List fillables = new ArrayList<>(); @@ -145,67 +136,54 @@ abstract class Fillable { void fill(MatchPlayer opener, List fillers) { // Build a short list of Fillers that are NOT cooling down from a previous fill - final List coolFillers = - fillers.stream() - .filter( - filler -> - filledAt.putUnlessNewer(new Pair<>(this, filler), filler.getRefillInterval()) - == null) - .collect(Collectors.toList()); + final List coolFillers = fillers.stream() + .filter(filler -> + filledAt.putUnlessNewer(new Pair<>(this, filler), filler.getRefillInterval()) == null) + .collect(Collectors.toList()); // Find all the Inventories for this Fillable, and build a map of Fillers to the subset // of Inventories that they are allowed to fill, based on the filter of each Filler. // Note how duplicate inventories are skipped. final SetMultimap fillerInventories = HashMultimap.create(); - inventories() - .distinct() - .forEach( - inventory -> { - final Predicate passes = filterPredicate(inventory.getHolder()); - if (passes == null) return; - for (FillerDefinition filler : coolFillers) { - if (passes.test(filler.getFilter())) { - fillerInventories.put(filler, inventory); - } - } - }); - - fillerInventories - .asMap() - .forEach( - (filler, inventories) -> { - if (filler.cleanBeforeRefill()) { - inventories().forEach(Inventory::clear); - } - }); + inventories().distinct().forEach(inventory -> { + final Predicate passes = filterPredicate(inventory.getHolder()); + if (passes == null) return; + for (FillerDefinition filler : coolFillers) { + if (passes.test(filler.getFilter())) { + fillerInventories.put(filler, inventory); + } + } + }); + + fillerInventories.asMap().forEach((filler, inventories) -> { + if (filler.cleanBeforeRefill()) { + inventories().forEach(Inventory::clear); + } + }); final Random random = new Random(); - fillerInventories - .asMap() - .forEach( - (filler, inventories) -> { - // For each Filler, build a mutable list of slots that it can fill. - // (27 is the standard size for single chests) - final List slots = new ArrayList<>(inventories.size() * 27); - for (Inventory inv : inventories) { - for (int index = 0; index < inv.getSize(); index++) { - if (inv.getItem(index) == null) { - slots.add(new InventorySlot(index, inv)); - } - } - } - - filler - .getLoot() - .elements(opener) - .limit(slots.size()) - .peek( - i -> { - if (immm != null) immm.applyRules(i); - }) - .forEachOrdered(i -> slots.remove(random.nextInt(slots.size())).putItem(i)); - }); + fillerInventories.asMap().forEach((filler, inventories) -> { + // For each Filler, build a mutable list of slots that it can fill. + // (27 is the standard size for single chests) + final List slots = new ArrayList<>(inventories.size() * 27); + for (Inventory inv : inventories) { + for (int index = 0; index < inv.getSize(); index++) { + if (inv.getItem(index) == null) { + slots.add(new InventorySlot(index, inv)); + } + } + } + + filler + .getLoot() + .elements(opener) + .limit(slots.size()) + .peek(i -> { + if (immm != null) immm.applyRules(i); + }) + .forEachOrdered(i -> slots.remove(random.nextInt(slots.size())).putItem(i)); + }); } } @@ -256,13 +234,11 @@ Stream inventories() { .region() .getChunkPositions() .map(cp -> cp.getChunk(match.getWorld())) - .flatMap( - ch -> - Stream.concat( - Stream.of(ch.getTileEntities()).map(BlockQuery::new), - Stream.of(ch.getEntities()) - .filter(e -> !(e instanceof Player)) - .map(EntityQuery::new))) + .flatMap(ch -> Stream.concat( + Stream.of(ch.getTileEntities()).map(BlockQuery::new), + Stream.of(ch.getEntities()) + .filter(e -> !(e instanceof Player)) + .map(EntityQuery::new))) .filter(q -> cache.jointFilter().query(q).isAllowed()) .map(InventoryQuery::getInventory) .filter(Objects::nonNull); diff --git a/core/src/main/java/tc/oc/pgm/loot/WorldTickClock.java b/core/src/main/java/tc/oc/pgm/loot/WorldTickClock.java index 7bffd72d12..4fa332bd27 100644 --- a/core/src/main/java/tc/oc/pgm/loot/WorldTickClock.java +++ b/core/src/main/java/tc/oc/pgm/loot/WorldTickClock.java @@ -5,7 +5,7 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneId; -import org.bukkit.World; +import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.time.Tick; import tc.oc.pgm.util.collection.InstantMap; @@ -18,11 +18,11 @@ */ public class WorldTickClock extends Clock { - private final World world; + private final Match match; private Tick tick; - public WorldTickClock(World world) { - this.world = world; + public WorldTickClock(Match match) { + this.match = match; } @Override @@ -45,7 +45,7 @@ public Tick getTick() { } private Tick now() { - long tick = NMS_HACKS.getMonotonicTime(this.world); + long tick = NMS_HACKS.getMonotonicTime(match.getWorld()); if (this.tick == null || tick != this.tick.tick) { this.tick = new Tick(tick, Instant.now()); } diff --git a/core/src/main/java/tc/oc/pgm/match/MatchImpl.java b/core/src/main/java/tc/oc/pgm/match/MatchImpl.java index 254a951302..193674d8da 100644 --- a/core/src/main/java/tc/oc/pgm/match/MatchImpl.java +++ b/core/src/main/java/tc/oc/pgm/match/MatchImpl.java @@ -124,7 +124,7 @@ protected MatchImpl(String id, MapContext map, World world) { this.world = new WeakReference<>(assertNotNull(world)); this.matchModules = new ConcurrentHashMap<>(); - this.clock = new WorldTickClock(world); + this.clock = new WorldTickClock(this); this.logger = ClassLogger.get(PGM.get().getLogger(), getClass()); this.random = new Random(); this.tickRandoms = new HashMap<>(); diff --git a/util/src/main/java/tc/oc/pgm/util/concurrent/TaskExecutorService.java b/util/src/main/java/tc/oc/pgm/util/concurrent/TaskExecutorService.java index f2f1e7faf0..dbc6e8d1d1 100644 --- a/util/src/main/java/tc/oc/pgm/util/concurrent/TaskExecutorService.java +++ b/util/src/main/java/tc/oc/pgm/util/concurrent/TaskExecutorService.java @@ -17,6 +17,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.jetbrains.annotations.NotNull; import tc.oc.pgm.util.TimeUtils; /** An executor service that is backed by a runnable executor. */ @@ -64,7 +65,7 @@ public List shutdownNow() { if (!isShutdown()) shutdown(); List pending = ImmutableList.copyOf(tasks); - for (Task task : tasks) { + for (var task : tasks) { task.cancel(true); } @@ -234,49 +235,35 @@ public void run() { @Override public boolean complete(V value) { - return complete(value, null); + return !periodic && cleanup(super.complete(value)); } @Override public boolean completeExceptionally(Throwable ex) { - return complete(null, ex); + return cleanup(super.completeExceptionally(ex)); } @Override public boolean cancel(boolean mayInterruptIfRunning) { - if (super.cancel(mayInterruptIfRunning)) { - tasks.remove(this); - if (terminated != null) { - terminated.countDown(); - } - cancelTask(taskId); - return true; - } - - return false; + return cleanup(super.cancel(mayInterruptIfRunning)); } @Override - public long getDelay(TimeUnit unit) { + public long getDelay(@NotNull TimeUnit unit) { return 0; } @Override - public int compareTo(Delayed o) { - if (!(o instanceof Task)) return 0; - return isDone() ? 1 : 0; + public int compareTo(@NotNull Delayed other) { + if (!(other instanceof Task ot)) return -1; + return Integer.compare(taskId, ot.taskId); } - private boolean complete(V value, Throwable ex) { - boolean done = false; - - if (!periodic && value != null) { - done = super.complete(value); - } else if (ex != null) { - done = super.completeExceptionally(ex); - } - - return !done || cancel(true); + private boolean cleanup(boolean triggered) { + if (terminated != null) terminated.countDown(); + cancelTask(taskId); + tasks.remove(this); + return triggered; } } }