From 6dedc3e6cb9120671412a3129e3ba6723d32d8c4 Mon Sep 17 00:00:00 2001 From: len <40720638+destro174@users.noreply.github.com> Date: Mon, 5 Apr 2021 00:01:18 +0200 Subject: [PATCH] Add afkcheck command --- .gitignore | 38 +++ pom.xml | 47 +++ .../com/alttd/afkdectector/AFKCheckTimer.java | 75 +++++ .../com/alttd/afkdectector/AFKDetector.java | 292 ++++++++++++++++++ .../java/com/alttd/afkdectector/Lang.java | 66 ++++ .../com/alttd/afkdectector/MessageTimer.java | 70 +++++ .../afkdectector/afkplayer/AFKPlayer.java | 77 +++++ .../afkdectector/command/AFKCheckCommand.java | 55 ++++ .../afkdectector/command/AFKListCommand.java | 50 +++ src/main/resources/changelog.txt | 0 src/main/resources/config.yml | 62 ++++ src/main/resources/lang.yml | 19 ++ src/main/resources/plugin.yml | 42 +++ 13 files changed, 893 insertions(+) create mode 100755 .gitignore create mode 100755 pom.xml create mode 100755 src/main/java/com/alttd/afkdectector/AFKCheckTimer.java create mode 100755 src/main/java/com/alttd/afkdectector/AFKDetector.java create mode 100755 src/main/java/com/alttd/afkdectector/Lang.java create mode 100755 src/main/java/com/alttd/afkdectector/MessageTimer.java create mode 100755 src/main/java/com/alttd/afkdectector/afkplayer/AFKPlayer.java create mode 100755 src/main/java/com/alttd/afkdectector/command/AFKCheckCommand.java create mode 100755 src/main/java/com/alttd/afkdectector/command/AFKListCommand.java create mode 100755 src/main/resources/changelog.txt create mode 100755 src/main/resources/config.yml create mode 100755 src/main/resources/lang.yml create mode 100755 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..e884074 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Plugin +.idea +testserver +run + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Maven +target/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..18fd552 --- /dev/null +++ b/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + groupId + AFKDetector + 2.1.3 + AFKDetector + + ${project.artifactId} + clean package install + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 11 + 11 + + + + + + src/main/resources + + + + + + + papermc + https://papermc.io/repo/repository/maven-public/ + + + + + + com.destroystokyo.paper + paper-api + 1.16.5-R0.1-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/src/main/java/com/alttd/afkdectector/AFKCheckTimer.java b/src/main/java/com/alttd/afkdectector/AFKCheckTimer.java new file mode 100755 index 0000000..e484457 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/AFKCheckTimer.java @@ -0,0 +1,75 @@ +package com.alttd.afkdectector; + +import java.util.UUID; + +import com.alttd.afkdectector.afkplayer.AFKPlayer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + + +public class AFKCheckTimer extends BukkitRunnable{ + + private AFKDetector plugin; + + public AFKCheckTimer(AFKDetector plugin) { + this.plugin = plugin; + } + + public void init() { + runTaskTimer(plugin, 0, 20); + } + + @Override + public void run() { + for (UUID uuid : plugin.players.keySet()) { + Player player = Bukkit.getPlayer(uuid); + AFKPlayer afkplayer = plugin.players.get(uuid); + if(player == null || player.hasPermission("afkdetector.bypass")) { + continue; + } + Location pastLocation = afkplayer.getplayerToSphereCenter(); + if(pastLocation == null || !player.getLocation().getWorld().getName().equals(pastLocation.getWorld().getName())) { + pastLocation = player.getLocation(); + afkplayer.setplayerToSphereCenter(pastLocation); + } + if (player.getLocation().distanceSquared(pastLocation) > plugin.radius * plugin.radius) { + if(player.getLocation().getYaw() != pastLocation.getYaw() && player.getLocation().getPitch() != pastLocation.getPitch()) { + afkplayer.setplayerToSphereCenter(pastLocation); + afkplayer.setstandingTime(System.currentTimeMillis()); + player.setSleepingIgnored(false); + //player.setCanPickupItems(true); + plugin.AFKPlayers.removeEntry(player.getName()); + afkplayer.ResetAFK(); + MessageTimer currentTimer = plugin.messageTimers.get(player.getUniqueId()); + if (currentTimer != null) { + plugin.messageTimers.remove(player.getUniqueId()); + } + continue; + } + } + long standingTime = afkplayer.getstandingTime(); + if(System.currentTimeMillis() - standingTime > plugin.toggletime * 60 * 1000 && !afkplayer.isafk()) { + afkplayer.setafk(true); + player.setSleepingIgnored(true); + //player.setCanPickupItems(false); + plugin.AFKPlayers.addEntry(player.getName()); + Bukkit.broadcast(player.getName() + " is now afk.", "afkdetector.notify"); + } + if(System.currentTimeMillis() - standingTime > afkplayer.getafkTime() * 60 * 1000) { + MessageTimer currentTimer = plugin.messageTimers.get(uuid); + if(currentTimer == null) { + currentTimer = new MessageTimer(plugin, uuid, plugin.messageRepeats); + plugin.messageTimers.put(uuid, currentTimer); + new MessageTimer(plugin, uuid, plugin.messageRepeats).init(); + } + } else { + MessageTimer currentTimer = plugin.messageTimers.get(uuid); + if(currentTimer != null) { + plugin.messageTimers.remove(player.getUniqueId()); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/alttd/afkdectector/AFKDetector.java b/src/main/java/com/alttd/afkdectector/AFKDetector.java new file mode 100755 index 0000000..2f0eb49 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/AFKDetector.java @@ -0,0 +1,292 @@ +package com.alttd.afkdectector; + +import com.alttd.afkdectector.afkplayer.AFKPlayer; +import com.alttd.afkdectector.command.AFKCheckCommand; +import com.alttd.afkdectector.command.AFKListCommand; +import net.kyori.adventure.audience.Audience; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.ScoreboardManager; +import org.bukkit.scoreboard.Team; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.permissions.PermissionAttachmentInfo; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +public class AFKDetector extends JavaPlugin implements Listener{ + + public HashMap players = new HashMap<>(); + public HashMap messageTimers = new HashMap<>(); + public HashMap PlayerAfkTime = new HashMap<>(); + + public boolean sleepignore, serverfull, countdownenabled, fulloverride; + public int radius, flagTime, messageDelay, messageRepeats, defaultafkTime, maxafkTime, toggletime, commandcooldown, playerlimit; + public int fadein, stay, fadeout = 0; + public String title, subtitle, message, title1, title2 = ""; + public String kickCommand = "kick ${ChatColor.RED}You have been kicked for being AFK."; + /** + * Adventure + */ + private Audience audience; + + /** + * events that cancel + */ + public boolean chatWillCancel, commandWillCancel; + + /** + * afkplayers need to be added to a team. + */ + Team AFKPlayers; + + /** + * Messages.yml + */ + public static YamlConfiguration LANG; + public static File LANG_FILE; + + + @Override + public void onEnable() { + try { + loadSettings(); + settupAfkState(); + getServer().getPluginManager().registerEvents(this, this); + //getCommand("afk").setExecutor(new AFKCommand(this)); + getCommand("afklist").setExecutor(new AFKListCommand(this)); + getCommand("afkcheck").setExecutor(new AFKCheckCommand(this)); + new AFKCheckTimer(this).init(); + } catch (Throwable t) { + getLogger().severe("An error has occured while loading AFKDetector"); + if (!(t instanceof ExceptionInInitializerError)) { + t.printStackTrace(); + } + getServer().getPluginManager().disablePlugin(this); + } + } + + @Override + public void onDisable() { + ScoreboardManager manager = Bukkit.getScoreboardManager(); + Scoreboard board = manager.getMainScoreboard(); + board.getTeam("AFKPlayers").unregister(); + this.getServer().getScheduler().cancelTasks(this); + } + + public AFKPlayer getPlayer(Player player) { + if (!players.containsKey(player.getUniqueId())) { + players.put(player.getUniqueId(), new AFKPlayer(player, this)); + } + return players.get(player.getUniqueId()); + } + + private void settupAfkState() { + if (Bukkit.getScoreboardManager().getMainScoreboard().getTeam("AFKPlayers") == null) { + AFKPlayers = Bukkit.getScoreboardManager().getMainScoreboard().registerNewTeam("AFKPlayers"); + } else { + AFKPlayers = Bukkit.getScoreboardManager().getMainScoreboard().getTeam("AFKPlayers"); + } + AFKPlayers.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); + //AFKPlayers.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.NEVER); + } + + /** + * Load the config.yml file. + * @return The config.yml config. + */ + private void loadSettings() { + saveDefaultConfig(); + + /** + * Player section + */ + sleepignore = getConfig().getBoolean("player.sleep" ,false); + radius = getConfig().getInt("player.radius", 4); + toggletime = getConfig().getInt("player.toggle-time", 5); + defaultafkTime = getConfig().getInt("player.afk-time", 5); + maxafkTime = getConfig().getInt("player.maxafk-time", 5); + serverfull = getConfig().getBoolean("player.serverfull" ,false); + playerlimit = Math.round(Bukkit.getMaxPlayers() * 90 / 100); + commandcooldown = getConfig().getInt("player.commandcooldown"); + /** + * Countdown section + */ + countdownenabled = getConfig().getBoolean("countdown.enabled" ,false); + message = getConfig().getString("countdown.message"); + title1 = getConfig().getString("countdown.title1"); + title2 = getConfig().getString("countdown.title2"); + fadein = getConfig().getInt("countdown.fadein", 10); + stay = getConfig().getInt("countdown.stay", 50); + fadeout = getConfig().getInt("countdown.fadeout", 10); + messageDelay = getConfig().getInt("countdown.message-delay", 30); + messageRepeats = getConfig().getInt("countdown.message-repeats", 4); + kickCommand = getConfig().getString("countdown.kick-command"); + /** + * events + */ + chatWillCancel = getConfig().getBoolean("events.chat", true); + commandWillCancel = getConfig().getBoolean("events.commands", true); + loadLang(); + } + + /** + * Load the lang.yml file. + * @return + * @return The lang.yml config. + */ + public YamlConfiguration loadLang() { + File lang = new File(getDataFolder(), "lang.yml"); + if (!lang.exists()) { + try { + getDataFolder().mkdir(); + lang.createNewFile(); + InputStreamReader defConfigStream = new InputStreamReader(this.getResource("lang.yml")); + if (defConfigStream != null) { + YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); + defConfig.save(lang); + Lang.setFile(defConfig); + return defConfig; + } + } catch(IOException e) { + e.printStackTrace(); // So they notice + this.setEnabled(false); // Without it loaded, we can't send them messages + } + } + YamlConfiguration conf = YamlConfiguration.loadConfiguration(lang); + for(Lang item:Lang.values()) { + if (conf.getString(item.getPath()) == null) { + conf.set(item.getPath(), item.getDefault()); + } + } + Lang.setFile(conf); + LANG = conf; + LANG_FILE = lang; + try { + conf.save(getLangFile()); + } catch(IOException e) { + e.printStackTrace(); + } + return conf; + } + + /** + * Gets the lang.yml config. + * @return The lang.yml config. + */ + public YamlConfiguration getLang() { + return LANG; + } + + /** + * Get the lang.yml file. + * @return The lang.yml file. + */ + public File getLangFile() { + return LANG_FILE; + } + + /** + * Get the afk time for a player + */ + public int getaAllowedAfktime(Player player) { + if(fulloverride) { + return defaultafkTime; + } + return PlayerAfkTime.get(player.getUniqueId()); + } + + public int getPlayerAfktime(Player player) { + String permissionPrefix = "afkdetector.afktime."; + for (PermissionAttachmentInfo attachmentInfo : player.getEffectivePermissions()) { + if (attachmentInfo.getPermission().startsWith(permissionPrefix)) { + String perm = attachmentInfo.getPermission(); + int Time = Integer.parseInt(perm.substring(perm.lastIndexOf(".") + 1)); + if(Time >= maxafkTime) { + return maxafkTime; + } else if(Time < maxafkTime) { + return Time; + } + } + } + return defaultafkTime; + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + if (player != null) { + PlayerAfkTime.put(player.getUniqueId(), getPlayerAfktime(player)); + players.put(player.getUniqueId(), new AFKPlayer(player, this)); + } + if(Bukkit.getOnlinePlayers().size() >= playerlimit && !fulloverride) { + fulloverride = true; + } + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + // Remove the players from the timer if they logout + if (player != null) { + players.remove(player.getUniqueId()); + } + if(Bukkit.getOnlinePlayers().size() < playerlimit && fulloverride){ + fulloverride = false; + } + } + + @EventHandler + public void onTalkCancel(AsyncPlayerChatEvent event) { + if (!chatWillCancel) { + return; + } + Player player = event.getPlayer(); + if (player != null) { + getPlayer(player).ResetAFK(); + } + } + + @EventHandler + public void oncommandCancel(PlayerCommandPreprocessEvent event) { + if (!commandWillCancel) { + return; + } + Player player = event.getPlayer(); + if (player != null) { + getPlayer(player).ResetAFK(); + } + } + + public Audience getAudience() { + return audience; + } + + /* @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + if (player != null) { + if (!player.hasPermission("afkdetect.bypass")) { + if(!player.isInsideVehicle()) { + float yawDif = Math.abs(event.getFrom().getYaw() - event.getTo().getYaw()); + float pitchDif = Math.abs(event.getFrom().getPitch() - event.getTo().getPitch()); + if (yawDif != 0.0F || pitchDif != 0.0F) { + //getPlayer(player).ResetAFK(); + } + } + } + } + }*/ + +} diff --git a/src/main/java/com/alttd/afkdectector/Lang.java b/src/main/java/com/alttd/afkdectector/Lang.java new file mode 100755 index 0000000..1405003 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/Lang.java @@ -0,0 +1,66 @@ +package com.alttd.afkdectector; + +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.YamlConfiguration; + +/** +* An enum for requesting strings from the language file. +*/ +public enum Lang { + TITLE("title-name", "&4[&fAFKDetector&4]:"), + COOLDOWN("cooldown-message", "You need to wait %timeleft% seconds before using this command."), + INVALID_PLAYER("invalid-args", "&cInvalid args!usage: -p:playername"), + INVALID_REASON("invalid-reason" , "&cInvalid args! usage: -r:reason"), + NOT_ONLINE("player-notonline", "&cInvalid args! player not online"), + PLAYER_ONLY("player-only", "Teri have you ever seen an afk console?"), + NO_PERMS("no-permissions", "&cYou don''t have permission for that!"), + AFK_LIST("afk-list", "There are %afkplayers% afk."), + AFK_PREFIX("afk-prefix", "[AFK]"), + AFKCHECKTITLE("afkcheck-title", "AFK CHECK"), + AFKCHECKSUBTITLE("afkcheck-subtitle", "Please respond to the dm from staff!"), + AFKCHECKCMESSAGE("afkcheck-message", "Hey, since you're near a farm and not moving I'm making sure you aren't afk. Please respond to me if you're not AFK."); + + + private String path; + private String def; + private static YamlConfiguration LANG; + + /** + * Lang enum constructor. + * @param path The string path. + * @param start The default string. + */ + Lang(String path, String start) { + this.path = path; + this.def = start; + } + + /** + * Set the {@code YamlConfiguration} to use. + * @param config The config to set. + */ + public static void setFile(YamlConfiguration config) { + LANG = config; + } + + @Override + public String toString() { + return ChatColor.translateAlternateColorCodes('&', LANG.getString(this.path, def)); + } + + /** + * Get the default value of the path. + * @return The default value of the path. + */ + public String getDefault() { + return this.def; + } + + /** + * Get the path to the string. + * @return The path to the string. + */ + public String getPath() { + return this.path; + } +} \ No newline at end of file diff --git a/src/main/java/com/alttd/afkdectector/MessageTimer.java b/src/main/java/com/alttd/afkdectector/MessageTimer.java new file mode 100755 index 0000000..3c539d8 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/MessageTimer.java @@ -0,0 +1,70 @@ +package com.alttd.afkdectector; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +public class MessageTimer extends BukkitRunnable { + + private AFKDetector plugin; + private UUID uuid = null; + private int repeats; + + public MessageTimer(AFKDetector plugin, UUID uuid, int repeats) { + this.plugin = plugin; + this.uuid = uuid; + this.repeats = repeats; + } + + public void init() { + runTaskTimer(plugin, 0, plugin.messageDelay * 20); + } + + // TODO get a better string builder + /* + private String return_placeholders(Param String ... string) + */ + private String return_placeholders(String s, Player p) { + s = s.replaceAll("%player%", p.getName()).replaceAll("%afktime%", (int) Math.floor((System.currentTimeMillis() - plugin.getPlayer(p).getstandingTime()) / 60 / 1000) +""); + return s; + } + + @Override + public void run() { + Player player = Bukkit.getPlayer(uuid); + if(plugin.messageTimers.containsKey(uuid)) { + if (player == null || player.hasPermission("afkdetector.kickexempt")) { + cancel(); + return; + } + if(plugin.countdownenabled) { + player.sendTitle(ChatColor.translateAlternateColorCodes('&', plugin.title1), + ChatColor.translateAlternateColorCodes('&', plugin.title2), plugin.fadein, plugin.stay, plugin.fadeout); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', plugin.message)); + } + repeats = repeats - 1; + + if (repeats <= 0) { + if(player.isInsideVehicle()) { + player.leaveVehicle(); + } + //Bukkit.dispatchCommand(Bukkit.getConsoleSender(), plugin.kickCommand.replace("%player%", player.getName())); + plugin.messageTimers.remove(player.getUniqueId()); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), return_placeholders(plugin.kickCommand, player)); + cancel(); + } + } else { + if(player != null) { + if(!plugin.messageTimers.isEmpty()) { + if(plugin.messageTimers.containsKey(player.getUniqueId())) { + plugin.messageTimers.remove(player.getUniqueId()); + } + } + cancel(); + } + } + } +} diff --git a/src/main/java/com/alttd/afkdectector/afkplayer/AFKPlayer.java b/src/main/java/com/alttd/afkdectector/afkplayer/AFKPlayer.java new file mode 100755 index 0000000..1d8a492 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/afkplayer/AFKPlayer.java @@ -0,0 +1,77 @@ +package com.alttd.afkdectector.afkplayer; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import com.alttd.afkdectector.AFKDetector; + +public class AFKPlayer { + + private final String playerName; + private final UUID uuid; + + private Location playerToSphereCenter; + private long standingTime; + private final int afkTime; + private boolean isafk; + + public AFKPlayer(Player player, AFKDetector plugin) { + this.playerName = player.getName(); + this.uuid = player.getUniqueId(); + this.playerToSphereCenter = player.getLocation(); + this.standingTime = System.currentTimeMillis(); + this.afkTime = plugin.getaAllowedAfktime(player); + this.isafk = false; + //plugin.getLogger().info("Loading " + playerName + ", Time " + standingTime + ", allowed afktime " + afkTime); + + } + + public String getPlayerName() { + return this.playerName; + } + + public UUID getPlayerUuid() { + return this.uuid; + } + + public Location getplayerToSphereCenter() { + return playerToSphereCenter; + } + + public void setplayerToSphereCenter(Location playerlocation) { + playerToSphereCenter = playerlocation; + } + + public long getstandingTime() { + return standingTime; + } + + public void setstandingTime(long Time) { + standingTime = Time; + } + + public int getafkTime() { + return this.afkTime; + } + + public void setafk(boolean bool) { + isafk = bool; + } + + public boolean isafk() { + return isafk; + } + + public void ResetAFK() { + if(isafk) { + Bukkit.broadcast(playerName + " is no longer afk.", "afkdetector.notify"); + } + standingTime = System.currentTimeMillis(); + playerToSphereCenter = Bukkit.getPlayer(getPlayerUuid()).getLocation(); + isafk = false; + } + +} diff --git a/src/main/java/com/alttd/afkdectector/command/AFKCheckCommand.java b/src/main/java/com/alttd/afkdectector/command/AFKCheckCommand.java new file mode 100755 index 0000000..6f958b8 --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/command/AFKCheckCommand.java @@ -0,0 +1,55 @@ +package com.alttd.afkdectector.command; + +import com.alttd.afkdectector.AFKDetector; +import com.alttd.afkdectector.Lang; +import com.alttd.afkdectector.afkplayer.AFKPlayer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.title.Title; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.checkerframework.checker.units.qual.A; + +import java.util.List; + +public class AFKCheckCommand implements CommandExecutor, TabCompleter { + + private AFKDetector plugin; + + public AFKCheckCommand(AFKDetector plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(args.length > 0)) { + sender.sendMessage(Component.text(command.getUsage(), NamedTextColor.RED)); + return true; + } + Player target = Bukkit.getPlayer(args[0]); + if (target == null) { + sender.sendMessage(Component.text(command.getUsage(), NamedTextColor.RED)); + return true; + } + if (!(target instanceof Audience)) { + sender.sendMessage(Component.text(command.getUsage(), NamedTextColor.RED)); + return true; + } + target.showTitle(Title.title(Component.text(Lang.AFKCHECKTITLE.toString(), NamedTextColor.RED), + Component.text(Lang.AFKCHECKSUBTITLE.toString(), NamedTextColor.RED))); + Bukkit.dispatchCommand(sender, "msg " + target + " " + Lang.AFKCHECKCMESSAGE.toString()); + return true; + } + + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/alttd/afkdectector/command/AFKListCommand.java b/src/main/java/com/alttd/afkdectector/command/AFKListCommand.java new file mode 100755 index 0000000..0cff69d --- /dev/null +++ b/src/main/java/com/alttd/afkdectector/command/AFKListCommand.java @@ -0,0 +1,50 @@ +package com.alttd.afkdectector.command; + +import com.alttd.afkdectector.AFKDetector; +import com.alttd.afkdectector.Lang; +import com.alttd.afkdectector.afkplayer.AFKPlayer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.List; + +public class AFKListCommand implements CommandExecutor, TabCompleter { + + private AFKDetector plugin; + + public AFKListCommand(AFKDetector plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + int afkplayers = 0; + Component message = Component.text(""); + for (AFKPlayer afkplayer : plugin.players.values()) { + long standingTime = afkplayer.getstandingTime(); + if(System.currentTimeMillis() - standingTime > plugin.toggletime * 60 * 1000) { + afkplayers += 1; + message.append(Component.newline()); + Component userinfo = Component.text(afkplayer.getPlayerName(), NamedTextColor.DARK_PURPLE); + userinfo.append(Component.text(" has been afk for " + (System.currentTimeMillis() - standingTime) / 1000 + " seconds.")); + userinfo.hoverEvent(Component.text("Click here to send an afkcheck to " + afkplayer.getPlayerName() + "!" , NamedTextColor.GRAY).asHoverEvent()); + userinfo.clickEvent(net.kyori.adventure.text.event.ClickEvent.runCommand("/afkcheck " + afkplayer.getPlayerName())); + message.append(userinfo); + } + } + Component component = Component.text(Lang.AFK_LIST.toString().replaceAll("%afkplayers%", Integer.toString(afkplayers)), NamedTextColor.YELLOW, TextDecoration.BOLD); + component.append(message); + sender.sendMessage(component); + return true; + } + + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { + return null; + } +} \ No newline at end of file diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt new file mode 100755 index 0000000..e69de29 diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100755 index 0000000..c8af00a --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,62 @@ +# / \ | | | |_ (_) | |_ _ _ __| | ___ +# / _ \ | | | __| | | | __| | | | | / _` | / _ \ +# / ___ \ | | | |_ | | | |_ | |_| | | (_| | | __/ +# /_/ \_\ |_| \__| |_| \__| \__,_| \__,_| \___| + +# Options for afk player +player: + # Whether or not players in AFK mode should be exempt from sleeping to skip the night + sleep: true + # The range in which the player has to move to not be tagged afk + # ran + radius: 4 + # Time it takes for the player to be AFK toggled + toggle-time: 1 + # Total time in minutes a player is allowed afk + afk-time: 15 + # The maximum allowed afk time in minutes for players using adkdetector.afktime. + # this is a hardset maximum, if the players permission is higher then this it'll be this value + maxafk-time: 30 + # Ignore custom afk time if the server is full(90%) + serverfull: false + # Cooldown for /afk command in seconds + commandcooldown: 60 + +# Options for countdown message +countdown: + # Enable the message, this is only for the message, the player will still be kicked wether this is true or false. + enabled: true + # The messages to be send + message: '&7You need to move around to avoid being kicked' + #title message stuff + #title(title1, title2, fadein, stay, fadeout) + title1: '&7You need to move around to avoid being kicked' + title2: '&7You need to move around to avoid being kicked' + #time in ticks + fadein: 10 + stay: 50 + fadeout: 10 + + # delay in seconds between afk warning messages + message-delay: 15 + + # amount of times the message will be sent with the message delay before they are kicked + # this starts after the flag-time has been reached + message-repeats: 4 + + # command ran by console when player should be kicked (omit /) + # placeholders: %player% - will be replaced by player's name + kick-command: "kick %player% &cYou have been afk for %afktime% minutes." + +# Options for tablist prefix +tablist: + # By default, tablist prefix is enabled + enabled: true + # Prefix itself + prefix: '[AFK] ' + +events: + # if true using this event will reset the timer + chat: true + # if true using this event will reset the timer + commands: true \ No newline at end of file diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml new file mode 100755 index 0000000..b938856 --- /dev/null +++ b/src/main/resources/lang.yml @@ -0,0 +1,19 @@ +# / \ | | | |_ (_) | |_ _ _ __| | ___ +# / _ \ | | | __| | | | __| | | | | / _` | / _ \ +# / ___ \ | | | |_ | | | |_ | |_| | | (_| | | __/ +# /_/ \_\ |_| \__| |_| \__| \__,_| \__,_| \___| + +# Use & color codes are supported + +title-name: "&4[&fAFKDetector&4]:" +cooldown-message: "You need to wait %timeleft% seconds before using this command." +player-only: "Teri have you ever seen an afk console?" +must-be-number: "&cYou need to specify a number, not a word." +invalid-player: "&cInvalid args! usage: -p playername" +invalid-reason: "&cInvalid args! usage: -r reason" +player-notonline: "&cInvalid args! player not online" +no-permissions: "&cYou don't have permission for that!" +afk-list: "There are %afkplayers% afk." +afk-on: "You are now afk." +afk-off: "You are no longer afk." +afk-prefix: "&4[AFK]" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100755 index 0000000..70c2399 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,42 @@ +main: com.alttd.afkdectector.AFKDetector +name: AFKDetector +version: 2.0 +api-version: 1.16 +author: Destro174 + +description: Checks if a player is afk. + +commands: + afklist: + description: Gives a list of all afk players + permission: afkdetector.afklist + permission-message: You do not have permission! + usage: /afklist + afkcheck: + description: Sends and afkcheck message to the target + permission: afkdetector.afkcheck + permission-message: You do not have permission! + usage: /afkcheck + +permissions: + afkdetector.admin: + default: op + description: Implies all permissions. + children: + afkdetector.bypass: true + afkdetector.afklist: true + afkdetector.bypass: + description: Bypass the AFKplugin. + default: op + children: + afkdetector.kickexempt: true + afkdetector.kickexempt: + description: Doesn't kick you automatically for AFK. + default: op + afkdetector.afktime: + description: Master permission for custom times. + default: false + afkdetector.afklist: + description: Allows the usage of /afklist command. + default: false +