diff --git a/changelog.txt b/changelog.txt index f9d9e8d..530a6b0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,7 @@ === v7.10 === -* Added permissions for maximum particles, groups, and fixed effects (values in the config are now the lower bounds) ++ Added command '/pp reset ' to be able to reset the particles of an offline player + - Permission: 'playerparticles.reset.others' ++ Added permissions for maximum particles, groups, and fixed effects (values in the config are now the lower bounds) - playerparticles.particles.max. - playerparticles.groups.max. - playerparticles.fixed.max. diff --git a/src/main/java/dev/esophose/playerparticles/api/PlayerParticlesAPI.java b/src/main/java/dev/esophose/playerparticles/api/PlayerParticlesAPI.java index 0c1159a..f48146b 100644 --- a/src/main/java/dev/esophose/playerparticles/api/PlayerParticlesAPI.java +++ b/src/main/java/dev/esophose/playerparticles/api/PlayerParticlesAPI.java @@ -23,7 +23,9 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.stream.Collectors; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -442,6 +444,7 @@ public final class PlayerParticlesAPI { * @param player The player to remove from * @return The number of particles removed or null if failed */ + @Nullable public Integer resetActivePlayerParticles(@NotNull Player player) { DataManager dataManager = this.playerParticles.getManager(DataManager.class); PPlayer pplayer = this.getPPlayer(player); @@ -454,6 +457,28 @@ public final class PlayerParticlesAPI { return amount; } + /** + * Attempts to reset the active particles for the given player name. + * This works even if the player is offline. + * + * @param playerName The name of the player to reset the active particles for + * @param successConsumer The callback to execute when finished + */ + public void resetActivePlayerParticles(@NotNull String playerName, @Nullable Consumer successConsumer) { + Objects.requireNonNull(playerName); + + if (successConsumer == null) + successConsumer = success -> {}; + + Player player = Bukkit.getPlayer(playerName); + if (player != null) { + this.resetActivePlayerParticles(player); + successConsumer.accept(true); + } else { + this.playerParticles.getManager(DataManager.class).resetActiveParticleGroup(playerName, successConsumer); + } + } + /** * Gets all active particles from a player * diff --git a/src/main/java/dev/esophose/playerparticles/command/ResetCommandModule.java b/src/main/java/dev/esophose/playerparticles/command/ResetCommandModule.java index d56210d..07c83c4 100644 --- a/src/main/java/dev/esophose/playerparticles/command/ResetCommandModule.java +++ b/src/main/java/dev/esophose/playerparticles/command/ResetCommandModule.java @@ -3,21 +3,49 @@ package dev.esophose.playerparticles.command; import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.api.PlayerParticlesAPI; import dev.esophose.playerparticles.manager.LocaleManager; +import dev.esophose.playerparticles.manager.PermissionManager; import dev.esophose.playerparticles.particles.PPlayer; -import dev.esophose.playerparticles.particles.ParticleGroup; import dev.esophose.playerparticles.util.StringPlaceholders; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; public class ResetCommandModule implements CommandModule { public void onCommandExecute(PPlayer pplayer, String[] args) { - int particleCount = pplayer.getActiveParticles().size(); - PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), ParticleGroup.getDefaultGroup()); - PlayerParticles.getInstance().getManager(LocaleManager.class).sendMessage(pplayer, "reset-success", StringPlaceholders.single("amount", particleCount)); + LocaleManager localeManager = PlayerParticles.getInstance().getManager(LocaleManager.class); + + boolean isConsole = pplayer.getPlayer() == null; + if (isConsole && args.length == 0) { + localeManager.sendCustomMessage(Bukkit.getConsoleSender(), "&cOnly players can use this command. Did you mean to use '/pp reset [other]'?"); + return; + } + + if (args.length == 0 || !PlayerParticles.getInstance().getManager(PermissionManager.class).canResetOthers(pplayer)) { + Integer particleCount = PlayerParticlesAPI.getInstance().resetActivePlayerParticles(pplayer.getPlayer()); + if (particleCount != null) + localeManager.sendMessage(pplayer, "reset-success", StringPlaceholders.single("amount", particleCount)); + } else { + PlayerParticlesAPI.getInstance().resetActivePlayerParticles(args[0], success -> { + if (success) { + localeManager.sendMessage(pplayer, "reset-others-success", StringPlaceholders.single("other", args[0])); + } else { + localeManager.sendMessage(pplayer, "reset-others-none", StringPlaceholders.single("other", args[0])); + } + }); + } } public List onTabComplete(PPlayer pplayer, String[] args) { + if (args.length == 1 && PlayerParticles.getInstance().getManager(PermissionManager.class).canResetOthers(pplayer)) { + List replacements = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList()); + List suggestions = new ArrayList<>(); + StringUtil.copyPartialMatches(args[0], replacements, suggestions); + return suggestions; + } return new ArrayList<>(); } @@ -30,7 +58,7 @@ public class ResetCommandModule implements CommandModule { } public String getArguments() { - return ""; + return "[other]"; } public boolean requiresEffectsAndStyles() { @@ -38,7 +66,7 @@ public class ResetCommandModule implements CommandModule { } public boolean canConsoleExecute() { - return false; + return true; } } diff --git a/src/main/java/dev/esophose/playerparticles/locale/EnglishLocale.java b/src/main/java/dev/esophose/playerparticles/locale/EnglishLocale.java index 7ae6048..e7bdd2d 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/EnglishLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/EnglishLocale.java @@ -166,6 +166,8 @@ public class EnglishLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&aRemoved &b%amount% &aactive particle(s)!"); + this.put("reset-others-success", "&aRemoved particles for &b%other%&a!"); + this.put("reset-others-none", "&eNo particles were removed for &b%other%&e."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&cUnable to create fixed effect, you are missing &b%amount% &crequired arguments!"); diff --git a/src/main/java/dev/esophose/playerparticles/locale/FrenchLocale.java b/src/main/java/dev/esophose/playerparticles/locale/FrenchLocale.java index 63d441f..5c1824a 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/FrenchLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/FrenchLocale.java @@ -166,6 +166,8 @@ public class FrenchLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&b%amount% &aparticule(s) actives supprimées !"); + this.put("reset-others-success", "&aParticules enlevées pour &b%other%&a !"); + this.put("reset-others-none", "&eAucune particule n'a été enlevée pour &b%other%&e."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&cImpossible de créer un effet fixe, vous oubliez des arguments : &b%amount%"); diff --git a/src/main/java/dev/esophose/playerparticles/locale/GermanLocale.java b/src/main/java/dev/esophose/playerparticles/locale/GermanLocale.java index d89d46d..f97320e 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/GermanLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/GermanLocale.java @@ -166,6 +166,8 @@ public class GermanLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&b%amount% &aaktive Partikel entfernt!"); + this.put("reset-others-success", "&aEntfertigte Partikel für &b%other%&a!"); + this.put("reset-others-none", "&eFür &b%other%&e wurden keine Partikel entfernt."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&cFixer Effekt kann nicht erstellt werden, es fehlen &b%amount% &cerforderliche Argumente!"); diff --git a/src/main/java/dev/esophose/playerparticles/locale/RussianLocale.java b/src/main/java/dev/esophose/playerparticles/locale/RussianLocale.java index 4e14781..8a52fc6 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/RussianLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/RussianLocale.java @@ -166,6 +166,8 @@ public class RussianLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&aУдалено &aактивных частиц - &b%amount%!"); + this.put("reset-others-success", "&aУдаленные частицы для &b%other%&a!"); + this.put("reset-others-none", "&eНикакие частицы не были удалены для &b%other% &e."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&cНевозможно создать эффект, не введено запрашиваемых аргументов - &b%amount%!"); diff --git a/src/main/java/dev/esophose/playerparticles/locale/SimplifiedChineseLocale.java b/src/main/java/dev/esophose/playerparticles/locale/SimplifiedChineseLocale.java index ee8d27f..e503847 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/SimplifiedChineseLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/SimplifiedChineseLocale.java @@ -166,6 +166,8 @@ public class SimplifiedChineseLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&a已删除&b%amount%个&a激活的粒子特效!"); + this.put("reset-others-success", "&a已删除&b%other%&a的颗粒!"); + this.put("reset-others-none", "&e没有除去&b%other%&e的颗粒."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&c无法创建定点特效, 缺少 &b%amount% &c必要参数!"); diff --git a/src/main/java/dev/esophose/playerparticles/locale/VietnameseLocale.java b/src/main/java/dev/esophose/playerparticles/locale/VietnameseLocale.java index 864d576..1c80a8e 100644 --- a/src/main/java/dev/esophose/playerparticles/locale/VietnameseLocale.java +++ b/src/main/java/dev/esophose/playerparticles/locale/VietnameseLocale.java @@ -166,6 +166,8 @@ public class VietnameseLocale implements Locale { this.put("#17", "Reset Message"); this.put("reset-success", "&aĐã xóa &b%amount% &aHạt hiệu ứng hoạt động!"); + this.put("reset-others-success", "&aCác hạt bị loại bỏ cho &b%other%&a!"); + this.put("reset-others-none", "&eKhông có hạt nào được loại bỏ cho &b%other%&e."); this.put("#18", "Fixed Create Messages"); this.put("fixed-create-missing-args", "&cKhông thể tạo Hiệu ứng cố định, bạn đã quên &b%amount% &cđối số yêu cầu!"); diff --git a/src/main/java/dev/esophose/playerparticles/manager/DataManager.java b/src/main/java/dev/esophose/playerparticles/manager/DataManager.java index 7f196a2..d511676 100644 --- a/src/main/java/dev/esophose/playerparticles/manager/DataManager.java +++ b/src/main/java/dev/esophose/playerparticles/manager/DataManager.java @@ -26,6 +26,7 @@ import java.util.function.Consumer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.World; /** @@ -400,6 +401,27 @@ public class DataManager extends Manager { })); } + /** + * Attempts to reset the active particle group for the given player name. + * This works even if the player is offline. + * + * @param playerName The name of the player to reset the active particle group for + * @param callback The callback to execute when finished + */ + public void resetActiveParticleGroup(String playerName, Consumer callback) { + this.async(() -> this.databaseConnector.connect((connection) -> { + @SuppressWarnings("deprecation") + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName); + + String query = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid IN (SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?)"; + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setString(1, offlinePlayer.getUniqueId().toString()); + statement.setString(2, ParticleGroup.DEFAULT_NAME); + callback.accept(statement.execute()); + } + })); + } + /** * Saves a fixed effect to save data * Does not perform a check to see if a fixed effect with this id already exists diff --git a/src/main/java/dev/esophose/playerparticles/manager/PermissionManager.java b/src/main/java/dev/esophose/playerparticles/manager/PermissionManager.java index b694bc7..fdcd7ae 100644 --- a/src/main/java/dev/esophose/playerparticles/manager/PermissionManager.java +++ b/src/main/java/dev/esophose/playerparticles/manager/PermissionManager.java @@ -37,6 +37,7 @@ public class PermissionManager extends Manager { RELOAD("reload"), OVERRIDE("override"), + RESET_OTHERS("reset.others"), GUI("gui"), @@ -129,6 +130,7 @@ public class PermissionManager extends Manager { // Misc pluginManager.addPermission(new Permission("playerparticles.reload")); pluginManager.addPermission(new Permission("playerparticles.override")); + pluginManager.addPermission(new Permission("playerparticles.reset.others")); pluginManager.addPermission(new Permission("playerparticles.gui")); pluginManager.addPermission(new Permission("playerparticles.particles.max")); @@ -267,6 +269,16 @@ public class PermissionManager extends Manager { return Setting.DISABLED_WORLDS.getStringList(); } + /** + * Checks if a player can reset another offline player's particles + * + * @param player The player to check the permission for + * @return True if the player has permission, otherwise false + */ + public boolean canResetOthers(PPlayer player) { + return PPermission.RESET_OTHERS.check(player.getUnderlyingExecutor()); + } + /** * Checks if a player has permission to use an effect *