Solved How to create a command of temp ban

Discussion in 'Spigot Plugin Development' started by craftmen0202, Oct 5, 2019.

  1. Hello everyone, I would like to know how it is possible to create a temp ban command, I know I need something to count the expiration time, but I would like to be shown something for me to base on. Remember that even if the server is restarted, keep counting the time.
     
  2. drives_a_ford

    Moderator

    What you do is you ban the person and calculate the date/time at which the unbanning is supposed to happen. You then write this to a file and check the file whether or not there's anyone to unban every now and again. If/when that time comes, you unban and remove the information from the file.
     
  3. For safety sake, rather then banning/unbanning the player you might want to make it so that the player is kicked & notified about still being banned rather then awaiting the date of the unban. Things might turn bad if the server somehow crashes without saving the unban, leaving the banned player without a way to be unbanned.
     
  4. Alternatively, you could save the UUID, the unban date (for your own convenience that should be in milliseconds) and probably a reason (passed on by the command) and then cancel the PlayerJoinEvent every time someone from that list tries to join, giving the player the specified reason. Upside, you don't need to have a scheduler that unbans players, downside, you check every joining player and read your storage on it.
     
  5. Additionally to that, I really don't how often someone gets banned but I feel like storing the equivalent of three long values per player (2 for an uuid, 1 for the timestamp) should be pretty affordable and not require unloading the information into a per-player file. And temp bans are not exactly the longest lived ones either, it will be nowhere near the point of exhausting your resources even if you have a few thousand bans active and pending.
     
  6. Hey, I wrote a little temp-ban system :D

    Code (Java):
    public final class Main extends JavaPlugin {

        public static Main INSTANCE;
        private BufferedReader in;
        private Bans bans;
        private String prefix = "§8[§cBans§8] §r";

        @Override
        public void onEnable() {
            INSTANCE = this;
            this.bans = new Bans(this);

            this.getCommand("tempban").setExecutor(new tempbanCMD());
            Bukkit.getPluginManager().registerEvents(new PlayerJoinListener(), this);
        }

        public static Main getInstance() {
            return INSTANCE;
        }

        public Bans getBans() {
            return bans;
        }

        public String getPrefix() {
            return prefix;
        }

        public String getUUID(String name) {
            String uuid = "";
            try {
                in = new BufferedReader(new InputStreamReader(new URL("https://api.mojang.com/users/profiles/minecraft/" + name).openStream()));
                uuid = (((JsonObject)new JsonParser().parse(in)).get("id")).toString().replaceAll("\"", "");
                uuid = uuid.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
                in.close();
            } catch (Exception e) {
                System.out.println("Unable to get UUID of: " + name + "!");
                uuid = "er";
            }
            return uuid;
        }
    }

    Code (Java):
    public class Bans {

        private File file;
        private YamlConfiguration cfg;

        private Plugin plugin;

        public Bans(Plugin plugin) {
            this.plugin = plugin;
            file = new File("plugins/" + plugin.getName() + "/bans.yml");
            cfg = YamlConfiguration.loadConfiguration(file);

            try {
                if(!file.exists()) {
                    file.createNewFile();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void ban(String uuid, String reason, long seconds) {
            if(isBanned(uuid)) {
                return;
            }
            long time = 0;
            long current = System.currentTimeMillis();
            long millis = seconds*1000;
            time = current + millis;

            if(seconds == -1) {
                time = -1;
            }

            cfg.set("Bans." + uuid + ".time", time);
            cfg.set("Bans." + uuid + ".reason", reason);
            saveFile();
        }

        public void sendBanScreen(Player p) {
            p.kickPlayer("§cYou have been banned!\n\n" +
                    "§7Reason: §c" + getReason(p.getUniqueId().toString()) + "\n\n" +
                    "§7Unban date: §c" + getUnbanDate(p.getUniqueId().toString()));
        }

        public String getReason(String uuid) {
            return cfg.getString("Bans." + uuid + ".reason");
        }


        public String getUnbanDate(String uuid) {
            long time = cfg.getLong("Bans." + uuid + ".time");
            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
            sdf.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
            Date date = new Date(time);
            return sdf.format(date);
        }

        public void unban(String uuid) {
            cfg.set("Bans." + uuid + ".time", null);
            cfg.set("Bans." + uuid + ".reason", null);
            saveFile();
        }

        public long getBanMillis(String uuid) {
            return cfg.getLong("Bans." + uuid + ".time");
        }

        public boolean isBanned(String uuid) {
            return cfg.getString("Bans." + uuid + ".reason") != null;
        }

        public void saveFile() {
            try {
                cfg.save(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    Code (Java):
    public enum BanUnit {

        SECOND("Second(s)", 1, "sec"),
        MINUTE("Minute(s)", 60, "min"),
        HOUR("Hour(s)", 60*60, "hour"),
        DAY("Day(s)", 24*60*60, "day"),
        WEEK("Week(s)", 7*24*60*60, "week"),
        MONTH("Month(s)", 4*7*24*60*60, "month"),
        YEAR("Year(s)", 12*4*7*24*60*60, "year");

        private String name;
        private int toSecond;
        private String shortcut;

        BanUnit(String name, int toSecond, String shortcut) {
            this.name = name;
            this.toSecond = toSecond;
            this.shortcut = shortcut;
        }

        public int getToSecond() {
            return toSecond;
        }

        public String getName() {
            return name;
        }

        public String getShortcut() {
            return shortcut;
        }

        public static List<String> getUnitsAsString() {
            List<String> units = new ArrayList<String>();
            for(BanUnit unit : BanUnit.values()) {
                units.add(unit.getShortcut().toLowerCase());
            }
            return units;
        }

        public static BanUnit getUnit(String unit) {
            for(BanUnit units : BanUnit.values()) {
                if(units.getShortcut().toLowerCase().equals(unit.toLowerCase())) {
                    return units;
                }
            }
            return null;
        }


    }
     

    Code (Java):
    public class PlayerJoinListener implements Listener {

        @EventHandler
        public void onPlayerJoinEvent(PlayerJoinEvent event) {
            Player player = event.getPlayer();

            if(Main.getInstance().getBans().isBanned(player.getUniqueId().toString())) {
                if(Main.getInstance().getBans().getBanMillis(player.getUniqueId().toString()) <= System.currentTimeMillis()) {
                    Main.getInstance().getBans().unban(player.getUniqueId().toString());
                } else {
                    Main.getInstance().getBans().sendBanScreen(player);
                }
            }

        }
    }
     

    Code (Java):
    public class tempbanCMD implements CommandExecutor {

        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if (sender instanceof Player) {
                Player player = (Player) sender;

                if(player.hasPermission("bans.tempban")) {

                    if (args.length >= 4) {
                        String name = args[0];
                        String uuid = Main.getInstance().getUUID(args[0]);

                        if (Main.getInstance().getBans().isBanned(uuid)) {
                            player.sendMessage(Main.getInstance().getPrefix() + "§cThis player is already banned.");
                            return true;
                        }

                        long value = 0;
                        try {
                            value = Integer.valueOf(args[1]);
                        } catch (NumberFormatException e) {
                            player.sendMessage(Main.getInstance().getPrefix() + "§cPlease enter a number at <Value>");
                        }

                        String unitString = args[2];
                        String reason = "";
                        for (int i = 3; i < args.length; i++) {
                            reason += args[i] + " ";
                        }

                        List<String> unitList = BanUnit.getUnitsAsString();
                        if (unitList.contains(unitString.toLowerCase())) {

                            BanUnit unit = BanUnit.getUnit(unitString);
                            long seconds = value * unit.getToSecond();
                            Main.getInstance().getBans().ban(uuid, reason, seconds);
                            player.sendMessage(Main.getInstance().getPrefix() + "§7" + name + " has been banned for " + value + " " + unit.getName() + "!");

                            if(Bukkit.getPlayer(name) != null) {
                                Main.getInstance().getBans().sendBanScreen(Bukkit.getPlayer(name));
                            }
                        }
                    } else {
                        player.sendMessage(Main.getInstance().getPrefix() + "§7Use: §b/tempban <Name> <Value> <BanUnit>");
                    }

                } else {
                    player.sendMessage(Main.getInstance().getPrefix() + "§cNo permissions.");
                }

            } else {
                sender.sendMessage("§cYou need to be a player to use this command!");
            }
            return false;
        }

    }
     

    Please try to understand this code. If you don't, don't copy it and try to do something else first.
    Thanks :)
     
    #6 bayerntvplay, Oct 5, 2019
    Last edited: Oct 6, 2019
  7. drives_a_ford

    Moderator

    There's a number of issues with this.

    For instance, I can see issues with lack of encapsulation.
    I also see you breaking the DRY principles.
    You really shouldn't be using the "§" character, either, you should be using the ChatColor enum instead.
    While it's great that you've based your bans on UUID, you really should be enforcing that by accepting UUIDs as arguments to your methods instead of allowing any old String.
    Naming your plugin Main is not exactly good practice, but I would consider naming a class tempbanCMD to be a worse offense on the naming convention (for reference see link below).

    But the most horrendous thing I see is your Main#getUUID. You should never call web services from the main thread. This can and will clog up your server.

    All in all, I suggest you take a look at the Beginner Programming Mistakes and Why You're Making Them.
     
    • Agree Agree x 1
  8. Thanks dude! I'll take a look at it :)
     
  9. It is not a huge issue but you never close the BufferedReader and why do you save the Player in your command class as a field and not as a local variable?
     
    #9 patri9ck, Oct 5, 2019
    Last edited: Oct 5, 2019
  10. I close the BufferedReader :4

    Because I do not create the object "player" again and again, I just define it.
    Correct me if I'm wrong :)
     
  11. I am sorry, I missed that you close the BufferedReader.

    You never create a Player object in Bukkit, it is a interface, Bukkit creates it for you. You just initialize a field. That is a difference. You would also not create a Player object if you simply delcared and intialized a local variable.

    Normally you use a field when you need a variable over multiple methods. But in this case it just messes up your class and it does not make sense.
     
  12. Oh ok, thank you for the info :) Imma correct this quickly :3