diff --git a/CHANGELOG.md b/CHANGELOG.md index 33867fb..a84363d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.6.0 +Improve performances. +Save user settings on the Minecraft world. +Add an option to disable the light lock message. + # 1.5.0 Fix translation & add French translation. diff --git a/build.gradle.kts b/build.gradle.kts index 6391c86..86a6685 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "github.xCykrix" -version = "1.5.1" +version = "1.6.0" description="Dynamic Lights for Minecraft Servers without requiring Modding." val mainMinecraftVersion = "1.21.11" val supportedMinecraftVersions = "1.21.11 - 1.21.11" diff --git a/src/main/java/github/xCykrix/dynamicLights/command/DynamicLightsCommand.java b/src/main/java/github/xCykrix/dynamicLights/command/DynamicLightsCommand.java index c4102b6..32c001d 100644 --- a/src/main/java/github/xCykrix/dynamicLights/command/DynamicLightsCommand.java +++ b/src/main/java/github/xCykrix/dynamicLights/command/DynamicLightsCommand.java @@ -5,6 +5,7 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Subcommand; import github.xCykrix.dynamicLights.DynamicLights; +import github.xCykrix.dynamicLights.util.PlayerUtil; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; @@ -16,6 +17,7 @@ @CommandAlias("dynamiclights|dynamiclight|dl") public class DynamicLightsCommand extends co.aikar.commands.BaseCommand {// extends DevkitSimpleState { + private static JavaPlugin plugin; public DynamicLightsCommand(JavaPlugin plugin) { this.plugin = plugin; } @@ -52,15 +54,13 @@ public static String getStackTrace(Throwable throwable) { @CommandPermission("dynamiclights.toggle") public static void onToggle(CommandSender commandSender) { if (commandSender instanceof Player player) { - String uuid = player.getUniqueId().toString(); - boolean current = DynamicLights.manager.toggles.getOrDefault(uuid, DynamicLights.manager.toggle); - if (!current) { - player.sendMessage(DynamicLights.translate("toggle-on")); - DynamicLights.manager.toggles.put(uuid, true); - } else { + if (PlayerUtil.getToggleStatus(player)) { player.sendMessage(DynamicLights.translate("toggle-off")); - DynamicLights.manager.toggles.put(uuid, false); + } else { + player.sendMessage(DynamicLights.translate("toggle-on")); } + + PlayerUtil.switchToggleStatus(player); } } @@ -69,15 +69,27 @@ public static void onToggle(CommandSender commandSender) { @CommandPermission("dynamiclights.lock") public static void onLock(CommandSender commandSender) { if (commandSender instanceof Player player) { - String uuid = player.getUniqueId().toString(); - boolean current = DynamicLights.manager.locks.getOrDefault(uuid, true); - if (!current) { + if (PlayerUtil.getLockStatus(player)) { + player.sendMessage(DynamicLights.translate("disable-lock")); + } else { player.sendMessage(DynamicLights.translate("enable-lock")); - DynamicLights.manager.locks.put(uuid, true); + } + + PlayerUtil.switchLockStatus(player); + } + } + @Subcommand("lockverbose") + @Description("Make the warning lock message go away") + @CommandPermission("dynamiclights.lock") + public static void onLockVerbose(CommandSender commandSender) { + if (commandSender instanceof Player player) { + if (PlayerUtil.getLockStatus(player)) { + player.sendMessage(DynamicLights.translate("disable-lock-verbose")); } else { - player.sendMessage(DynamicLights.translate("disable-lock")); - DynamicLights.manager.locks.put(uuid, false); + player.sendMessage(DynamicLights.translate("enable-lock-verbose")); } + + PlayerUtil.switchLockVerboseStatus(player); } } } diff --git a/src/main/java/github/xCykrix/dynamicLights/event/PlayerHandler.java b/src/main/java/github/xCykrix/dynamicLights/event/PlayerHandler.java index 51b52d7..9a7000b 100644 --- a/src/main/java/github/xCykrix/dynamicLights/event/PlayerHandler.java +++ b/src/main/java/github/xCykrix/dynamicLights/event/PlayerHandler.java @@ -1,10 +1,13 @@ package github.xCykrix.dynamicLights.event; import github.xCykrix.dynamicLights.DynamicLights; +import github.xCykrix.dynamicLights.util.PlayerUtil; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.plugin.java.JavaPlugin; @@ -22,21 +25,30 @@ public void playerBlockPlaceEvent(BlockPlaceEvent event) { if (!DynamicLights.source.isProtectedLight(event.getItemInHand().getType())) { return; } - if (DynamicLights.manager.locks.getOrDefault(event.getPlayer().getUniqueId().toString(), DynamicLights.manager.toggle)) { - event.getPlayer().sendMessage(DynamicLights.translate("prevent-block-place")); + if (PlayerUtil.getLockStatus(event.getPlayer())) { + // send a text to the player to explain why the block place event was cancelled + if (PlayerUtil.getLockVerboseStatus(event.getPlayer())) { + event.getPlayer().sendMessage(DynamicLights.translate("prevent-block-place")); + } + // cancel the event event.setCancelled(true); } } } - // No need we do it for each online player - // @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - // public void onPlayerJoinEvent(PlayerJoinEvent event) { - // DynamicLights.manager.addPlayer(event.getPlayer()); - // } - @EventHandler(priority = EventPriority.MONITOR) public void onPlayerQuitEvent(PlayerQuitEvent event) { - DynamicLights.manager.removeLightFromLocationRegion(event.getPlayer().getUniqueId()); + DynamicLights.manager.removePlayerLightEnabled(event.getPlayer().getUniqueId()); + // DynamicLights.manager.removeLightFromLocationRegion(event.getPlayer().getUniqueId()); + } + + @EventHandler(ignoreCancelled = true) + public void onPlayerGameModeChangeEvent(PlayerGameModeChangeEvent event) { + DynamicLights.manager.updatePlayerState(event.getPlayer(), event.getNewGameMode()); + } + + @EventHandler + public void onPlayerJoinEvent(PlayerJoinEvent event) { + DynamicLights.manager.updatePlayerState(event.getPlayer(), event.getPlayer().getGameMode()); } } diff --git a/src/main/java/github/xCykrix/dynamicLights/util/LightManager.java b/src/main/java/github/xCykrix/dynamicLights/util/LightManager.java index 8fa301a..8e10897 100644 --- a/src/main/java/github/xCykrix/dynamicLights/util/LightManager.java +++ b/src/main/java/github/xCykrix/dynamicLights/util/LightManager.java @@ -1,13 +1,12 @@ package github.xCykrix.dynamicLights.util; import github.xCykrix.dynamicLights.DynamicLights; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import org.bukkit.Bukkit; import org.bukkit.GameMode; @@ -25,38 +24,38 @@ public class LightManager { private final LightSource source; private final Map lastLightLocation = new ConcurrentHashMap<>(200); - public final ConcurrentMap toggles; - public final ConcurrentMap locks; - private final long refresh; - public final boolean toggle; + private final Set playerLightEnabled; private JavaPlugin plugin; public LightManager(JavaPlugin plugin) { this.plugin = plugin; - // YamlDocument config = DynamicLights.configuration.getYAMLFile("config.yml"); - // if (config == null) { - // throw new RuntimeException("config.yml is corrupted or contains invalid formatting. Failed to load plugin."); - // } - this.source = DynamicLights.source; - // TODO reenable file storing of toggles & locks - // this.toggles = DynamicLights.h2.get().openMap("lightToggleStatus"); - // this.locks = DynamicLights.h2.get().openMap("lightLockStatus"); - this.toggles = new ConcurrentHashMap<>(); - this.locks = new ConcurrentHashMap<>(); - this.refresh = plugin.getConfig().getLong("update-rate"); - this.toggle = plugin.getConfig().getBoolean("default-toggle-state"); - // this.lights = Collections.synchronizedList(new LinkedList<>()); + playerLightEnabled = ConcurrentHashMap.newKeySet(); - Bukkit.getAsyncScheduler().runAtFixedRate(plugin, st -> tick(), 0L, refresh, TimeUnit.MILLISECONDS); + Bukkit.getAsyncScheduler().runAtFixedRate(plugin, st -> tick(), 0L, plugin.getConfig().getLong("update-rate"), TimeUnit.MILLISECONDS); } // @Override public void shutdown() { clearAllLights(); } + public void addPlayerLightEnabled(UUID uuid) { playerLightEnabled.add(uuid); } + + public void removePlayerLightEnabled(UUID uuid) { playerLightEnabled.remove(uuid); } + + public boolean isPlayerLightEnabled(UUID uuid) { return playerLightEnabled.contains(uuid); } + + // Player emit light if (SURVIVAL or ADVENTURE) and they have it enabled. + public void updatePlayerState(Player player, GameMode mode) { + if ((mode == GameMode.SURVIVAL || mode == GameMode.ADVENTURE) && PlayerUtil.getToggleStatus(player)) { + addPlayerLightEnabled(player.getUniqueId()); + } else { + removePlayerLightEnabled(player.getUniqueId()); + // removeLightFromLocationRegion(player.getUniqueId()); + } + } public void tick() { if (!plugin.isEnabled()) { @@ -64,13 +63,20 @@ public void tick() { return; } - // For each online player, check if we should add a light or move the existing one - Collection players = Bukkit.getOnlinePlayers(); - for (Player targetPlayer : players) { - updatePlayerLight(targetPlayer); + // For each online player that have the right game mode, check if we should add a light or move the existing one + for (UUID targetPlayerUUID : playerLightEnabled) { + updatePlayerLight(Bukkit.getPlayer(targetPlayerUUID)); } - // Removing player light when the player quit is now done in player quit event. + // Remove each light that should not be there + // With a short delay between each tick(), the light is added back when removed from somewhere else, + // so we need to remove it after the main for loop. + // It might call to remove the light many time if the region scheduler is not fast enough, but it's fine I guess. + for (UUID targetPlayerUUID : lastLightLocation.keySet()) { + if (!playerLightEnabled.contains(targetPlayerUUID)) { + this.removeLightFromLocationRegion(targetPlayerUUID); + } + } } public void clearAllLights() { @@ -88,17 +94,6 @@ public void updatePlayerLight(Player player) { * Find the best location to place a light and update the light if needed. */ private Optional updateLightToNewLocation(Player player, Location eyeLocation) { - if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { - // plugin.getLogger().info("creative or spectator"); - this.removeLightFromLocationRegion(player.getUniqueId()); - return Optional.empty(); - } - if (!(this.toggles.getOrDefault(player.getUniqueId().toString(), this.toggle))) { - this.removeLightFromLocationRegion(player.getUniqueId()); - return Optional.empty(); - } - - Material mainHand = getMaterialOrAir(player.getInventory().getItemInMainHand()); Material offHand = getMaterialOrAir(player.getInventory().getItemInOffHand()); Material helmet = getMaterialOrAir(player.getInventory().getHelmet()); @@ -201,7 +196,8 @@ private void removeLight(UUID playerUuid, Location location) { } } } - // Remove only if its the current last location, else we want to keep that value to remove it later when we will have to remove the light. + // Remove only if its the current last location, else we want to keep that value to remove it later when we will have to remove the + // light. lastLightLocation.remove(playerUuid, location); // DynamicLights.getInstance().getLogger().info("Removed light at " + location); } diff --git a/src/main/java/github/xCykrix/dynamicLights/util/PlayerUtil.java b/src/main/java/github/xCykrix/dynamicLights/util/PlayerUtil.java new file mode 100644 index 0000000..e6c756c --- /dev/null +++ b/src/main/java/github/xCykrix/dynamicLights/util/PlayerUtil.java @@ -0,0 +1,37 @@ +package github.xCykrix.dynamicLights.util; + +import github.xCykrix.dynamicLights.DynamicLights; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataType; + +public class PlayerUtil { + private static NamespacedKey lightToggleStatusKey = new NamespacedKey("dynamiclights", "toggle-state"); + private static NamespacedKey lightLockStatusKey = new NamespacedKey("dynamiclights", "lock-state"); + private static NamespacedKey lightLockVerboseStatusKey = new NamespacedKey("dynamiclights", "lock-verbose-state"); + public static boolean getToggleStatus(Player player) { + return player.getPersistentDataContainer().getOrDefault(lightToggleStatusKey, PersistentDataType.BOOLEAN, + DynamicLights.getInstance().getConfig().getBoolean("default-toggle-state", true)); + } + public static void switchToggleStatus(Player player) { + player.getPersistentDataContainer().set(lightToggleStatusKey, PersistentDataType.BOOLEAN, !getToggleStatus(player)); + } + + public static boolean getLockStatus(Player player) { + return player.getPersistentDataContainer().getOrDefault(lightLockStatusKey, PersistentDataType.BOOLEAN, + DynamicLights.getInstance().getConfig().getBoolean("default-lock-state", false)); + } + + public static void switchLockStatus(Player player) { + player.getPersistentDataContainer().set(lightLockStatusKey, PersistentDataType.BOOLEAN, !getLockStatus(player)); + } + + public static boolean getLockVerboseStatus(Player player) { + return player.getPersistentDataContainer().getOrDefault(lightLockVerboseStatusKey, PersistentDataType.BOOLEAN, + DynamicLights.getInstance().getConfig().getBoolean("default-lock-verbose-state", true)); + } + + public static void switchLockVerboseStatus(Player player) { + player.getPersistentDataContainer().set(lightLockVerboseStatusKey, PersistentDataType.BOOLEAN, !getLockVerboseStatus(player)); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5405e6d..fe254c7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -7,6 +7,9 @@ default-toggle-state: true # Default Locking State: Controls if player's offhand are automatically locked by default. default-lock-state: false +# Default warn player when locked that they can unlock it with a command. +default-lock-verbose-state: true + # DO NOT EDIT THE VERSION. Manual edits may corrupt or reset configuration files. # version: 3 diff --git a/src/main/resources/locale/en.yml b/src/main/resources/locale/en.yml index 5309186..954ecaa 100644 --- a/src/main/resources/locale/en.yml +++ b/src/main/resources/locale/en.yml @@ -14,9 +14,11 @@ ### prefix: "[DynamicLights]" -prevent-block-place: " Light locking mode is currently enabled. You must sneak to place light sources from your Off Hand. This can be toggled with \"/dl lock\"." +prevent-block-place: " Light locking mode is currently enabled. You must sneak to place light sources from your Off Hand. This can be toggled with \"/dl lock\". (Disable this message with \"/dl lockverbose\".)" enable-lock: " Enabled light lock mode." disable-lock: " Disabled light lock mode." +enable-lock-verbose: " Enabled light lock mode warning message." +disable-lock-verbose: " Disabled light lock mode warning message." toggle-on: " Light rendering enabled." toggle-off: " Light rendering disabled." reload: " Reloaded lights.yml configuration." diff --git a/src/main/resources/locale/fr.yml b/src/main/resources/locale/fr.yml index a1d6bf8..76d0482 100644 --- a/src/main/resources/locale/fr.yml +++ b/src/main/resources/locale/fr.yml @@ -14,9 +14,11 @@ ### prefix: "[DynamicLights]" -prevent-block-place: " Le mode de verrouillage des sources lumineuses est actuellement activé. Vous devez vous accroupir pour placer des sources lumineuses depuis votre main secondaire. Ce mode peut être désactivé avec la commande « /dl lock »." -enable-lock: " Mode de verrouillage lumineux activé." -disable-lock: " Mode de verrouillage lumineux désactivé." +prevent-block-place: " Le mode de verrouillage des sources lumineuses est actuellement activé. Vous devez vous accroupir pour placer des sources lumineuses depuis votre main secondaire. Ce mode peut être désactivé avec « /dl lock ». (Désactivez ce message avec « /dl lockverbose ».)" +enable-lock: " Mode de verrouillage de la lumière activé." +disable-lock: " Mode de verrouillage de la lumière désactivé." +enable-lock-verbose: " Message d'avertissement du mode de verrouillage de la lumière activé." +disable-lock-verbose: " Message d'avertissement du mode de verrouillage de la lumière désactivé." toggle-on: " Rendu de la lumière activé." toggle-off: " Rendu de la lumière désactivé." reload: " Configuration lights.yml rechargée."