From 89ced70bde74c2bd30134d04afc22bf3c15a77fb Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Sun, 7 Apr 2024 20:22:15 +0300 Subject: [PATCH 1/3] Improved data fetching, Folia support; --- .../expansion/pinger/PingerExpansion.java | 170 +++++++++--------- 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java index 9a13260..9bee4d5 100644 --- a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java +++ b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java @@ -1,12 +1,14 @@ package com.extendedclip.papi.expansion.pinger; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import me.clip.placeholderapi.expansion.Cacheable; import me.clip.placeholderapi.expansion.Configurable; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.Taskable; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.net.InetSocketAddress; @@ -14,134 +16,114 @@ import java.net.SocketException; import java.nio.charset.Charset; import java.util.HashMap; +import java.util.Locale; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.*; +@SuppressWarnings("unused") public class PingerExpansion extends PlaceholderExpansion implements Cacheable, Taskable, Configurable { - private BukkitTask pingTask = null; private String online = "&aOnline"; private String offline = "&cOffline"; - private final Map servers = new ConcurrentHashMap<>(); - - private final Map toPing = new ConcurrentHashMap<>(); + private LoadingCache> cache; private int interval = 60; public Map getDefaults() { Map defaults = new HashMap<>(); - defaults.put("check_interval", Integer.valueOf(30)); + defaults.put("check_interval", 30); defaults.put("online", "&aOnline"); defaults.put("offline", "&cOffline"); return defaults; } public void start() { - String on = getString("online", "&aOnline"); - this.online = (on != null) ? on : "&aOnline"; - String off = getString("offline", "&cOffline"); - this.offline = (off != null) ? off : "&cOffline"; + this.online = getString("online", this.online); + this.offline = getString("offline", this.offline); + int time = getInt("check_interval", 60); - if (time > 0) - this.interval = time; - this.pingTask = (new BukkitRunnable() { - public void run() { - if (PingerExpansion.this.toPing.isEmpty()) - return; - for (Map.Entry address : PingerExpansion.this.toPing.entrySet()) { - PingerExpansion.Pinger r; - try { - r = new PingerExpansion.Pinger(address.getValue().getHostName(), address.getValue().getPort()); - if (r.fetchData()) { - PingerExpansion.this.servers.put(address.getKey(), r); - continue; - } - if (PingerExpansion.this.servers.containsKey(address.getKey())) - PingerExpansion.this.servers.remove(address.getKey()); - } catch (Exception exception) { - } - } - } - }).runTaskTimerAsynchronously(getPlaceholderAPI(), 20L, 20L * this.interval); + if (time > 0) this.interval = time; + + this.cache = CacheBuilder.newBuilder() + .concurrencyLevel(1) + .refreshAfterWrite(this.interval, TimeUnit.SECONDS) + .build(new PingerCacheLoader()); } public void stop() { - try { - this.pingTask.cancel(); - } catch (Exception exception) { - } - this.pingTask = null; + this.cache.asMap().values().forEach(future -> future.cancel(true)); + this.cache = null; } public void clear() { - this.servers.clear(); - this.toPing.clear(); + this.cache.cleanUp(); } public boolean canRegister() { return true; } - public String getAuthor() { + public @NotNull String getAuthor() { return "clip"; } - public String getIdentifier() { + public @NotNull String getIdentifier() { return "pinger"; } - public String getPlugin() { - return null; - } - - public String getVersion() { - return "1.0.1"; + public @NotNull String getVersion() { + return "1.0.2"; } public String onPlaceholderRequest(Player p, String identifier) { - int place = identifier.indexOf("_"); + final int place = identifier.indexOf("_"); if (place == -1) return null; - String type = identifier.substring(0, place); - String address = identifier.substring(place + 1); - Pinger r = null; - for (String a : this.servers.keySet()) { - if (a.equalsIgnoreCase(address)) { - r = this.servers.get(a); - break; + + final String type = identifier.substring(0, place).toLowerCase(Locale.ROOT); + final String address = identifier.substring(place + 1); + + try { + final Future pinger = this.cache.get(address); + switch (type) { + case "motd": + if (pinger == null || !pinger.isDone()) return ""; + return pinger.get().getMotd(); + + case "count": + case "players": + if (pinger == null || !pinger.isDone()) return "0"; + return String.valueOf(pinger.get().getPlayersOnline()); + + case "max": + case "maxplayers": + if (pinger == null || !pinger.isDone()) return "0"; + return String.valueOf(pinger.get().getMaxPlayers()); + + case "pingversion": + case "pingv": + if (pinger == null || !pinger.isDone()) return "-1"; + return String.valueOf(pinger.get().getPingVersion()); + + case "gameversion": + case "version": + if (pinger == null || !pinger.isDone()) return ""; + return pinger.get().getGameVersion(); + + case "online": + case "isonline": + if (pinger == null || !pinger.isDone()) return this.offline; + return this.online; } + } catch (InterruptedException | ExecutionException ignored) { } - if (r == null) - if (!this.toPing.containsKey(address)) { - int port = 25565; - String add = address; - if (address.contains(":")) { - add = address.substring(0, address.indexOf(":")); - try { - port = Integer.parseInt(address.substring(address.indexOf(":") + 1)); - } catch (Exception exception) { - } - } - this.toPing.put(address, new InetSocketAddress(add, port)); - } - if (type.equalsIgnoreCase("motd")) - return (r != null) ? r.getMotd() : ""; - if (type.equalsIgnoreCase("count") || type.equalsIgnoreCase("players")) - return (r != null) ? String.valueOf(r.getPlayersOnline()) : "0"; - if (type.equalsIgnoreCase("max") || type.equalsIgnoreCase("maxplayers")) - return (r != null) ? String.valueOf(r.getMaxPlayers()) : "0"; - if (type.equalsIgnoreCase("pingversion") || type.equalsIgnoreCase("pingv")) - return (r != null) ? String.valueOf(r.getPingVersion()) : "-1"; - if (type.equalsIgnoreCase("gameversion") || type.equalsIgnoreCase("version")) - return (r != null && r.getGameVersion() != null) ? r.getGameVersion() : ""; - if (type.equalsIgnoreCase("online") || type.equalsIgnoreCase("isonline")) - return (r != null) ? this.online : this.offline; + return null; } - public final class Pinger { + private static class Pinger { private String address = "localhost"; private int port = 25565; @@ -321,4 +303,28 @@ public boolean fetchData() { return true; } } + + private static class PingerCacheLoader extends CacheLoader> { + @Override + public Future load(final String key) { + final InetSocketAddress address = this.address(key); + final Pinger pinger = new Pinger(address.getHostName(), address.getPort()); + + return CompletableFuture.supplyAsync(() -> { + if (!pinger.fetchData()) return null; + + return pinger; + }); + } + + private InetSocketAddress address(final String key) { + final int index = key.indexOf(":"); + if (index == -1) return new InetSocketAddress(key, 25565); + + final String host = key.substring(0, index); + final int port = Integer.parseInt(key.substring(index + 1)); + + return new InetSocketAddress(host, port); + } + } } From 5af3517e461421e3bfe004311d201e3bbe798d1b Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Sun, 7 Apr 2024 20:28:41 +0300 Subject: [PATCH 2/3] Fix a potential Null-like exception; --- .../expansion/pinger/PingerExpansion.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java index 9bee4d5..5579389 100644 --- a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java +++ b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java @@ -86,35 +86,37 @@ public String onPlaceholderRequest(Player p, String identifier) { final String address = identifier.substring(place + 1); try { - final Future pinger = this.cache.get(address); + final Future future = this.cache.get(address); + final Pinger pinger = future.isDone() ? future.get() : null; + switch (type) { case "motd": - if (pinger == null || !pinger.isDone()) return ""; - return pinger.get().getMotd(); + if (pinger == null) return ""; + return pinger.getMotd(); case "count": case "players": - if (pinger == null || !pinger.isDone()) return "0"; - return String.valueOf(pinger.get().getPlayersOnline()); + if (pinger == null) return "0"; + return String.valueOf(pinger.getPlayersOnline()); case "max": case "maxplayers": - if (pinger == null || !pinger.isDone()) return "0"; - return String.valueOf(pinger.get().getMaxPlayers()); + if (pinger == null) return "0"; + return String.valueOf(pinger.getMaxPlayers()); case "pingversion": case "pingv": - if (pinger == null || !pinger.isDone()) return "-1"; - return String.valueOf(pinger.get().getPingVersion()); + if (pinger == null) return "-1"; + return String.valueOf(pinger.getPingVersion()); case "gameversion": case "version": - if (pinger == null || !pinger.isDone()) return ""; - return pinger.get().getGameVersion(); + if (pinger == null) return ""; + return pinger.getGameVersion(); case "online": case "isonline": - if (pinger == null || !pinger.isDone()) return this.offline; + if (pinger == null) return this.offline; return this.online; } } catch (InterruptedException | ExecutionException ignored) { From 72cbcb425e40b4677a2551e21a782c4f36435267 Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:41:20 +0300 Subject: [PATCH 3/3] Fix NullPointerException for uninitialized cache; --- .../papi/expansion/pinger/PingerExpansion.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java index 5579389..bf9a588 100644 --- a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java +++ b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java @@ -9,6 +9,7 @@ import me.clip.placeholderapi.expansion.Taskable; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.net.InetSocketAddress; @@ -27,6 +28,7 @@ public class PingerExpansion extends PlaceholderExpansion implements Cacheable, private String offline = "&cOffline"; + @Nullable private LoadingCache> cache; private int interval = 60; @@ -53,11 +55,13 @@ public void start() { } public void stop() { + if (this.cache == null) return; this.cache.asMap().values().forEach(future -> future.cancel(true)); this.cache = null; } public void clear() { + if (this.cache == null) return; this.cache.cleanUp(); } @@ -85,6 +89,7 @@ public String onPlaceholderRequest(Player p, String identifier) { final String type = identifier.substring(0, place).toLowerCase(Locale.ROOT); final String address = identifier.substring(place + 1); + if (this.cache == null) return null; try { final Future future = this.cache.get(address); final Pinger pinger = future.isDone() ? future.get() : null; @@ -319,7 +324,7 @@ public Future load(final String key) { }); } - private InetSocketAddress address(final String key) { + private InetSocketAddress address(final String key) { final int index = key.indexOf(":"); if (index == -1) return new InetSocketAddress(key, 25565);