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
+