diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java new file mode 100644 index 00000000..20c21969 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java @@ -0,0 +1,37 @@ +package net.william278.husksync.listener; + +import net.william278.husksync.config.Settings; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.jetbrains.annotations.NotNull; + +public interface BukkitDeathEventListener extends Listener { + + boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + default void onPlayerDeathHighest(@NotNull PlayerDeathEvent event) { + if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.HIGHEST)) { + handlePlayerDeath(event); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + default void onPlayerDeath(@NotNull PlayerDeathEvent event) { + if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerDeath(event); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + default void onPlayerDeathLowest(@NotNull PlayerDeathEvent event) { + if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerDeath(event); + } + } + + void handlePlayerDeath(@NotNull PlayerDeathEvent player); + +} diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java index b7efd3de..94654d35 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java @@ -1,6 +1,7 @@ package net.william278.husksync.listener; import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.config.Settings; import net.william278.husksync.data.BukkitInventoryMap; import net.william278.husksync.data.BukkitSerializer; import net.william278.husksync.data.ItemData; @@ -19,8 +20,6 @@ import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.WorldSaveEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -28,35 +27,31 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -public class BukkitEventListener extends EventListener implements Listener { +public class BukkitEventListener extends EventListener implements BukkitJoinEventListener, BukkitQuitEventListener, + BukkitDeathEventListener, Listener { public BukkitEventListener(@NotNull BukkitHuskSync huskSync) { super(huskSync); Bukkit.getServer().getPluginManager().registerEvents(this, huskSync); } - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(@NotNull PlayerJoinEvent event) { - super.handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + @Override + public boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority) { + return plugin.getSettings().getEventPriority(type).equals(priority); } - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerQuit(@NotNull PlayerQuitEvent event) { - super.handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + @Override + public void handlePlayerQuit(@NotNull BukkitPlayer player) { + super.handlePlayerQuit(player); } - @EventHandler(ignoreCancelled = true) - public void onWorldSave(@NotNull WorldSaveEvent event) { - // Handle saving player data snapshots when the world saves - if (!plugin.getSettings().saveOnWorldSave) return; - - CompletableFuture.runAsync(() -> super.saveOnWorldSave(event.getWorld().getPlayers() - .stream().map(BukkitPlayer::adapt) - .collect(Collectors.toList()))); + @Override + public void handlePlayerJoin(@NotNull BukkitPlayer player) { + super.handlePlayerJoin(player); } - @EventHandler(ignoreCancelled = true) - public void onPlayerDeath(PlayerDeathEvent event) { + @Override + public void handlePlayerDeath(@NotNull PlayerDeathEvent event) { final OnlineUser user = BukkitPlayer.adapt(event.getEntity()); // If the player is locked or the plugin disabling, clear their drops @@ -77,6 +72,16 @@ public class BukkitEventListener extends EventListener implements Listener { .thenAccept(serializedDrops -> super.saveOnPlayerDeath(user, new ItemData(serializedDrops))); } + @EventHandler(ignoreCancelled = true) + public void onWorldSave(@NotNull WorldSaveEvent event) { + // Handle saving player data snapshots when the world saves + if (!plugin.getSettings().saveOnWorldSave) return; + + CompletableFuture.runAsync(() -> super.saveOnWorldSave(event.getWorld().getPlayers() + .stream().map(BukkitPlayer::adapt) + .collect(Collectors.toList()))); + } + /* * Events to cancel if the player has not been set yet diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java new file mode 100644 index 00000000..d9df8669 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java @@ -0,0 +1,38 @@ +package net.william278.husksync.listener; + +import net.william278.husksync.config.Settings; +import net.william278.husksync.player.BukkitPlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.jetbrains.annotations.NotNull; + +public interface BukkitJoinEventListener extends Listener { + + boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + default void onPlayerJoinHighest(@NotNull PlayerJoinEvent event) { + if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.HIGHEST)) { + handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + default void onPlayerJoin(@NotNull PlayerJoinEvent event) { + if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + default void onPlayerJoinLowest(@NotNull PlayerJoinEvent event) { + if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + } + } + + void handlePlayerJoin(@NotNull BukkitPlayer player); + +} diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java new file mode 100644 index 00000000..04f3ac65 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java @@ -0,0 +1,38 @@ +package net.william278.husksync.listener; + +import net.william278.husksync.config.Settings; +import net.william278.husksync.player.BukkitPlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.jetbrains.annotations.NotNull; + +public interface BukkitQuitEventListener extends Listener { + + boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + default void onPlayerQuitHighest(@NotNull PlayerQuitEvent event) { + if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.HIGHEST)) { + handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + default void onPlayerQuit(@NotNull PlayerQuitEvent event) { + if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + default void onPlayerQuitLowest(@NotNull PlayerQuitEvent event) { + if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.NORMAL)) { + handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + } + } + + void handlePlayerQuit(@NotNull BukkitPlayer player); + +} diff --git a/common/src/main/java/net/william278/husksync/config/Settings.java b/common/src/main/java/net/william278/husksync/config/Settings.java index d725b919..d6f3c483 100644 --- a/common/src/main/java/net/william278/husksync/config/Settings.java +++ b/common/src/main/java/net/william278/husksync/config/Settings.java @@ -20,7 +20,7 @@ import java.util.Optional; ┣╸ Information: https://william278.net/project/husksync ┗╸ Documentation: https://william278.net/docs/husksync""", - versionField = "config_version", versionNumber = 2) + versionField = "config_version", versionNumber = 3) public class Settings { // Top-level settings @@ -125,6 +125,15 @@ public class Settings { .orElse(feature.enabledByDefault); } + @YamlKey("synchronization.event_priorities") + public Map synchronizationEventPriorities = EventType.getDefaults(); + + @NotNull + public EventPriority getEventPriority(@NotNull Settings.EventType eventType) { + return Optional.ofNullable(synchronizationEventPriorities.get(eventType.name().toLowerCase())) + .orElse(EventPriority.NORMAL); + } + /** * Represents the names of tables in the database @@ -143,6 +152,7 @@ public class Settings { return Map.entry(name().toLowerCase(), defaultName); } + @SuppressWarnings("unchecked") private static Map getDefaults() { return Map.ofEntries(Arrays.stream(values()) .map(TableName::toEntry) @@ -178,6 +188,8 @@ public class Settings { return Map.entry(name().toLowerCase(), enabledByDefault); } + + @SuppressWarnings("unchecked") private static Map getDefaults() { return Map.ofEntries(Arrays.stream(values()) .map(SynchronizationFeature::toEntry) @@ -185,4 +197,49 @@ public class Settings { } } + /** + * Represents events that HuskSync listens to, with a configurable priority listener + */ + public enum EventType { + JOIN_LISTENER(EventPriority.LOWEST), + QUIT_LISTENER(EventPriority.LOWEST), + DEATH_LISTENER(EventPriority.NORMAL); + + private final EventPriority defaultPriority; + + EventType(@NotNull EventPriority defaultPriority) { + this.defaultPriority = defaultPriority; + } + + private Map.Entry toEntry() { + return Map.entry(name(), defaultPriority); + } + + + @SuppressWarnings("unchecked") + private static Map getDefaults() { + return Map.ofEntries(Arrays.stream(values()) + .map(EventType::toEntry) + .toArray(Map.Entry[]::new)); + } + } + + /** + * Represents priorities for events that HuskSync listens to + */ + public enum EventPriority { + /** + * Listens and processes the event execution last + */ + HIGHEST, + /** + * Listens in between {@link #HIGHEST} and {@link #LOWEST} priority marked + */ + NORMAL, + /** + * Listens and processes the event execution first + */ + LOWEST + } + } \ No newline at end of file