From 41d39ac23481acbe919e895a2f7842c95458013c Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Sun, 26 Aug 2018 10:02:41 +0300 Subject: [PATCH 01/11] Removed config tab from debug page --- .../plan/utilities/html/pages/DebugPage.java | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/DebugPage.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/DebugPage.java index ad8af1497..aaf0c69e2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/DebugPage.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/DebugPage.java @@ -14,7 +14,6 @@ import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.info.server.properties.ServerProperties; import com.djrapitops.plan.system.webserver.cache.ResponseCache; -import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plan.utilities.html.Html; import com.djrapitops.plan.utilities.html.HtmlStructure; import com.djrapitops.plan.utilities.html.icon.Icon; @@ -23,11 +22,9 @@ import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.utility.log.ErrorLogger; import com.djrapitops.plugin.api.utility.log.Log; -import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; -import java.nio.charset.Charset; import java.util.*; /** @@ -52,10 +49,9 @@ public class DebugPage implements Page { TabsElement.Tab info = new TabsElement.Tab(Icon.called("server") + " Server Information", createServerInfoContent()); TabsElement.Tab errors = new TabsElement.Tab(Icon.called("exclamation-circle") + " Errors", createErrorContent()); TabsElement.Tab debugLog = new TabsElement.Tab(Icon.called("bug") + " Debug Log", createDebugLogContent()); - TabsElement.Tab config = new TabsElement.Tab(Icon.called("cogs") + " Plan Config", createConfigContent()); TabsElement.Tab caches = new TabsElement.Tab(Icon.called("archive") + " Plan Caches", createCacheContent()); - TabsElement tabs = new TabsElement(info, errors, debugLog, config, caches); + TabsElement tabs = new TabsElement(info, errors, debugLog, caches); return preContent + tabs.toHtmlFull(); } @@ -105,12 +101,6 @@ public class DebugPage implements Page { } } - private String createConfigContent() { - StringBuilder content = new StringBuilder(); - appendConfig(content); - return content.toString(); - } - private String createDebugLogContent() { StringBuilder content = new StringBuilder(); appendDebugLog(content); @@ -221,21 +211,6 @@ public class DebugPage implements Page { content.append(""); } - private void appendConfig(StringBuilder content) { - try { - File configFile = new File(PlanPlugin.getInstance().getDataFolder(), "config.yml"); - if (configFile.exists()) { - content.append("
### config.yml
```
"); - FileUtil.lines(configFile, Charset.forName("UTF-8")) - .stream().filter(line -> !line.toLowerCase().contains("pass") && !line.toLowerCase().contains("secret")) - .forEach(line -> content.append(line).append("
")); - content.append("```
"); - } - } catch (IOException e) { - Log.toLog(this.getClass(), e); - } - } - private void appendBenchmarks(StringBuilder content) { content.append("
### Benchmarks
```
"); try { From 5295d56f3c9d0d6b3593bbd801a9a8027dd533ad Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Sun, 26 Aug 2018 18:15:51 +0300 Subject: [PATCH 02/11] Updated PlanPluginBridge dependencies to latest versions --- PlanPluginBridge/pom.xml | 205 +++++++----------- .../plan/react/ReactDataTask.java | 2 +- 2 files changed, 83 insertions(+), 124 deletions(-) diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml index cc4e6edba..ad44b12b0 100644 --- a/PlanPluginBridge/pom.xml +++ b/PlanPluginBridge/pom.xml @@ -54,7 +54,7 @@ http://nexus.hc.to/content/repositories/pub_releases - jitpack.io + jitpack.io (GriefPrevention) https://jitpack.io @@ -82,14 +82,14 @@ 4.3.0-SNAPSHOT provided - + + com.destroystokyo.paper paper-api 1.12.2-R0.1-SNAPSHOT provided - org.spigotmc spigot-api @@ -97,6 +97,9 @@ jar provided + + + com.hm.achievement advanced-achievements-api @@ -104,39 +107,21 @@ provided - com.earth2me - essentials - 2.0.1 + com.github.TechFortress + GriefPrevention + 16.8 provided - com.massivecraft - factions - 2.10.0 + me.clip + placeholderapi + 2.9.1 provided - com.gamingmesh - jobs - 4.0.1 - provided - - - com.massivecraft - mcore - 2.10.0 - provided - - - com.gmail.nossr50 - mcMMO - 1.5.07 - provided - - - com.palmergames - towny - 0.91.4.0 + br.net.fabiozumbi12.RedProtect + RedProtect-Spigot + 7.5.3 provided @@ -146,18 +131,56 @@ provided - com.wasteofplastic.askyblock - ASkyBlock - 3.0.6.8 + us.myles + viaversion + 1.5.0 + provided + + + + + + me.konsolas + AAC + 3.5.0 provided - com.github.TechFortress - GriefPrevention - 16.7.1 + me.leoko + advancedban + 2.1.5 + provided + + + com.wasteofplastic.askyblock + ASkyBlock + 3.0.9.4 + provided + + + me.confuser + banmanager + 5.15.0 + provided + + + net.ess3 + EssentialsX + 2.15.0.1 + provided + + + com.massivecraft + factions + 2.14.0 + provided + + + com.massivecraft + mcore + 2.14.0 provided - net.kaikk.mc GriefPreventionPlus @@ -165,21 +188,9 @@ provided - litebans - api - 0.2 - provided - - - io.minimum - minecraft.superbvote - 0.4.1 - provided - - - us.myles - viaversion - 1.1.1 + com.gamingmesh + jobs + 4.7.4 provided @@ -189,51 +200,39 @@ provided - me.confuser - banmanager - 5.15.0 + litebans + api + 0.3 + provided + + + com.gmail.nossr50 + mcMMO + 1.6.0 provided - - - - - - com.github.ProtocolSupport ProtocolSupport 4.28 provided - - br.net.fabiozumbi12.RedProtect - RedProtect-Spigot - RELEASE - provided - - - me.konsolas - AAC - 3.3.5 - provided - - - me.clip - placeholderapi - LATEST - provided - com.volmit react - 6.549 + 6.573 provided - me.leoko - advancedban - 2.1.5 + io.minimum + minecraft.superbvote + 0.5.3 + provided + + + com.palmergames + towny + 0.92.0.0 provided @@ -245,46 +244,6 @@ maven-install-plugin 2.5.2 - org.jacoco jacoco-maven-plugin diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/react/ReactDataTask.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/react/ReactDataTask.java index 7510e0c88..2a44728a2 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/react/ReactDataTask.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/react/ReactDataTask.java @@ -7,8 +7,8 @@ import com.djrapitops.plugin.task.AbsRunnable; import com.volmit.react.React; import com.volmit.react.api.GraphSampleLine; import com.volmit.react.api.SampledType; -import com.volmit.react.util.GMap; import com.volmit.react.util.M; +import com.volmit.react.volume.lang.collections.GMap; import java.util.ArrayList; import java.util.EnumMap; From af2eed4d88228832355a0e49a315211424e3d8ed Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 10:33:21 +0300 Subject: [PATCH 03/11] Added Bungee PluginData rendering support #571 Added Bungee Plugin Support: AdvancedBan, BuyCraft, LiteBans, ViaVersion Added Sponge Plugin support: BuyCraft --- Plan/dependency-reduced-pom.xml | 38 +++++----- .../store/containers/NetworkContainer.java | 3 + .../plan/system/info/BungeeInfoSystem.java | 7 +- .../connection/BungeeConnectionSystem.java | 9 ++- .../utilities/html/pages/NetworkPage.java | 8 +++ Plan/src/main/resources/bungeeconfig.yml | 7 +- Plan/src/main/resources/web/network.html | 10 +++ PlanPluginBridge/pom.xml | 12 +++- .../djrapitops/pluginbridge/plan/Bridge.java | 31 ++++++--- ...eBansHook.java => LiteBansBukkitHook.java} | 8 ++- .../plan/litebans/LiteBansBungeeHook.java | 69 +++++++++++++++++++ .../litebans/LiteBansDatabaseQueries.java | 4 +- ....java => BukkitPlayerVersionListener.java} | 4 +- .../BungeePlayerVersionListener.java | 46 +++++++++++++ .../plan/viaversion/Protocol.java | 2 + ...ionHook.java => ViaVersionBukkitHook.java} | 6 +- .../plan/viaversion/ViaVersionBungeeHook.java | 48 +++++++++++++ 17 files changed, 269 insertions(+), 43 deletions(-) rename PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/{LiteBansHook.java => LiteBansBukkitHook.java} (83%) create mode 100644 PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBungeeHook.java rename PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/{PlayerVersionListener.java => BukkitPlayerVersionListener.java} (92%) create mode 100644 PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BungeePlayerVersionListener.java rename PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/{ViaVersionHook.java => ViaVersionBukkitHook.java} (89%) create mode 100644 PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBungeeHook.java diff --git a/Plan/dependency-reduced-pom.xml b/Plan/dependency-reduced-pom.xml index f5d762d20..a8ec7baba 100644 --- a/Plan/dependency-reduced-pom.xml +++ b/Plan/dependency-reduced-pom.xml @@ -87,10 +87,10 @@ org.slf4j.Logger - - org.bstats - com.djrapitops.plan.utilities.metrics - + + org.bstats + com.djrapitops.plan.utilities.metrics + @@ -149,14 +149,14 @@ sponge-repo https://repo.spongepowered.org/maven - - md_5-snapshots - http://repo.md-5.net/content/repositories/snapshots/ - - - bstats-repo - http://repo.bstats.org/content/repositories/releases/ - + + md_5-snapshots + http://repo.md-5.net/content/repositories/snapshots/ + + + bstats-repo + http://repo.bstats.org/content/repositories/releases/ + @@ -359,12 +359,12 @@ - - com.imaginarycode.minecraft - RedisBungee - 0.3.8-SNAPSHOT - provided - + + com.imaginarycode.minecraft + RedisBungee + 0.3.8-SNAPSHOT + provided + org.mockito mockito-core @@ -388,7 +388,7 @@ org.xerial sqlite-jdbc - 3.23.1 + 3.23.1 test diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/containers/NetworkContainer.java b/Plan/src/main/java/com/djrapitops/plan/data/store/containers/NetworkContainer.java index 12b14fc28..dab7aae04 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/containers/NetworkContainer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/containers/NetworkContainer.java @@ -173,4 +173,7 @@ public class NetworkContainer extends DataContainer { putSupplier(NetworkKeys.PLAYERS_MONTH, () -> getUnsafe(uniqueMonth).count()); } + public ServerContainer getBungeeContainer() { + return bungeeContainer; + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java index c9e5e1d56..527597f46 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java @@ -10,6 +10,7 @@ import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.system.info.connection.BungeeConnectionSystem; import com.djrapitops.plan.system.info.request.CacheRequest; import com.djrapitops.plan.system.info.request.GenerateInspectPageRequest; +import com.djrapitops.plan.system.info.request.GenerateInspectPluginsTabRequest; import com.djrapitops.plan.system.info.request.InfoRequest; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.webserver.cache.PageId; @@ -30,8 +31,10 @@ public class BungeeInfoSystem extends InfoSystem { @Override public void runLocally(InfoRequest infoRequest) throws WebException { - if (infoRequest instanceof CacheRequest || - infoRequest instanceof GenerateInspectPageRequest) { + if (infoRequest instanceof CacheRequest + || infoRequest instanceof GenerateInspectPageRequest + || infoRequest instanceof GenerateInspectPluginsTabRequest + ) { infoRequest.runLocally(); } else { // runLocally is called when ConnectionSystem has no servers. diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java index 96aa03587..ae9516525 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java @@ -7,6 +7,7 @@ package com.djrapitops.plan.system.info.connection; import com.djrapitops.plan.api.exceptions.connection.NoServersException; import com.djrapitops.plan.api.exceptions.database.DBOpException; import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; import com.djrapitops.plan.system.info.request.*; import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plan.system.info.server.ServerInfo; @@ -44,7 +45,9 @@ public class BungeeConnectionSystem extends ConnectionSystem { protected Server selectServerForRequest(InfoRequest infoRequest) throws NoServersException { refreshServerMap(); Server server = null; - if (infoRequest instanceof CacheRequest || infoRequest instanceof GenerateInspectPageRequest) { + if (infoRequest instanceof CacheRequest + || infoRequest instanceof GenerateInspectPageRequest + || infoRequest instanceof GenerateInspectPluginsTabRequest) { // Run locally return ServerInfo.getServer(); } else if (infoRequest instanceof GenerateAnalysisPageRequest) { @@ -66,6 +69,10 @@ public class BungeeConnectionSystem extends ConnectionSystem { for (Server server : bukkitServers.values()) { WebExceptionLogger.logIfOccurs(this.getClass(), () -> sendInfoRequest(infoRequest, server)); } + // Quick hack + if (infoRequest instanceof GenerateInspectPluginsTabRequest) { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> InfoSystem.getInstance().sendRequest(infoRequest)); + } } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/NetworkPage.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/NetworkPage.java index 16175b197..073cafbd0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/NetworkPage.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/pages/NetworkPage.java @@ -13,6 +13,7 @@ import com.djrapitops.plan.system.webserver.cache.PageId; import com.djrapitops.plan.system.webserver.cache.ResponseCache; import com.djrapitops.plan.system.webserver.response.pages.parts.NetworkPageContent; import com.djrapitops.plan.utilities.file.FileUtil; +import com.djrapitops.plan.utilities.html.structure.AnalysisPluginsTabContentCreator; import static com.djrapitops.plan.data.store.keys.NetworkKeys.*; @@ -51,6 +52,13 @@ public class NetworkPage implements Page { ResponseCache.loadResponse(PageId.NETWORK_CONTENT.id(), NetworkPageContent::new); placeholderReplacer.put("tabContentServers", networkPageContent.getContents()); + String[] content = AnalysisPluginsTabContentCreator.createContent(networkContainer.getUnsafe(NetworkKeys.PLAYERS_MUTATOR), null); + String nav = content[0]; + String tabs = content[1]; + + placeholderReplacer.put("navPluginsTabs", nav); + placeholderReplacer.put("tabsPlugins", tabs); + return placeholderReplacer.apply(FileUtil.getStringFromResource("web/network.html")); } catch (Exception e) { throw new ParseException(e); diff --git a/Plan/src/main/resources/bungeeconfig.yml b/Plan/src/main/resources/bungeeconfig.yml index 02d582993..0a659ed81 100644 --- a/Plan/src/main/resources/bungeeconfig.yml +++ b/Plan/src/main/resources/bungeeconfig.yml @@ -148,4 +148,9 @@ Servers: Example: WebServerPort: 8034 ServerName: Example - ThemeBase: Default \ No newline at end of file + ThemeBase: Default +# ----------------------------------------------------- +Plugins: + BuyCraft: + # http://help.buycraft.net/article/36-where-to-find-the-secret-key + Secret: "-" \ No newline at end of file diff --git a/Plan/src/main/resources/web/network.html b/Plan/src/main/resources/web/network.html index 77dfe6b25..869b50233 100644 --- a/Plan/src/main/resources/web/network.html +++ b/Plan/src/main/resources/web/network.html @@ -130,6 +130,15 @@ Network Players +
  • + + extension + Plugins + +
      + ${navPluginsTabs} +
    +
  • @@ -487,6 +496,7 @@ + ${tabsPlugins} diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml index ad44b12b0..eb7c024dc 100644 --- a/PlanPluginBridge/pom.xml +++ b/PlanPluginBridge/pom.xml @@ -41,6 +41,10 @@ + + bungeecord-repo + https://oss.sonatype.org/content/repositories/snapshots + spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ @@ -97,7 +101,13 @@ jar provided
    - + + net.md-5 + bungeecord-api + 1.12-SNAPSHOT + jar + provided + diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java index 809783300..6659fdb50 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java @@ -16,14 +16,16 @@ import com.djrapitops.pluginbridge.plan.griefprevention.GriefPreventionHook; import com.djrapitops.pluginbridge.plan.griefprevention.plus.GriefPreventionPlusHook; import com.djrapitops.pluginbridge.plan.jobs.JobsHook; import com.djrapitops.pluginbridge.plan.kingdoms.KingdomsHook; -import com.djrapitops.pluginbridge.plan.litebans.LiteBansHook; +import com.djrapitops.pluginbridge.plan.litebans.LiteBansBukkitHook; +import com.djrapitops.pluginbridge.plan.litebans.LiteBansBungeeHook; import com.djrapitops.pluginbridge.plan.mcmmo.McmmoHook; import com.djrapitops.pluginbridge.plan.protocolsupport.ProtocolSupportHook; import com.djrapitops.pluginbridge.plan.redprotect.RedProtectHook; import com.djrapitops.pluginbridge.plan.superbvote.SuperbVoteHook; import com.djrapitops.pluginbridge.plan.towny.TownyHook; import com.djrapitops.pluginbridge.plan.vault.VaultHook; -import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionHook; +import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionBukkitHook; +import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionBungeeHook; /** * Manages connection to other plugins. @@ -56,17 +58,30 @@ public class Bridge { private static Hook[] getHooks(HookHandler h) { Hook[] hooks; - if (Check.isBukkitAvailable()) { - hooks = getBukkitHooks(h); - } else { + if (Check.isBungeeAvailable()) { hooks = getBungeeHooks(h); + } else if (Check.isBukkitAvailable()) { + hooks = getBukkitHooks(h); + } else if (Check.isSpongeAvailable()) { + hooks = getSpongeHooks(h); + } else { + return new Hook[0]; } return hooks; } + private static Hook[] getSpongeHooks(HookHandler h) { + return new Hook[]{ + new BuyCraftHook(h) + }; + } + private static Hook[] getBungeeHooks(HookHandler h) { return new Hook[]{ - new AdvancedBanHook(h) + new AdvancedBanHook(h), + new BuyCraftHook(h), + new LiteBansBungeeHook(h), + new ViaVersionBungeeHook(h) }; } @@ -84,7 +99,7 @@ public class Bridge { new GriefPreventionPlusHook(h), new JobsHook(h), new KingdomsHook(h), - new LiteBansHook(h), + new LiteBansBukkitHook(h), new McmmoHook(h), new SuperbVoteHook(h), new ProtocolSupportHook(h), @@ -92,7 +107,7 @@ public class Bridge { new RedProtectHook(h), new TownyHook(h), new VaultHook(h), - new ViaVersionHook(h)//, + new ViaVersionBukkitHook(h)//, // new PlaceholderAPIHook(h) }; } diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBukkitHook.java similarity index 83% rename from PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansHook.java rename to PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBukkitHook.java index 67dfc0544..516d3241c 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansHook.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBukkitHook.java @@ -5,6 +5,7 @@ import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.pluginbridge.plan.Hook; import litebans.api.Database; +import org.bukkit.Bukkit; /** * A Class responsible for hooking to LiteBans and registering data @@ -13,7 +14,7 @@ import litebans.api.Database; * @author Rsl1122 * @since 3.5.0 */ -public class LiteBansHook extends Hook { +public class LiteBansBukkitHook extends Hook { /** * Hooks the plugin and registers it's PluginData objects. @@ -24,7 +25,7 @@ public class LiteBansHook extends Hook { * @throws NoClassDefFoundError when the plugin class can not be found. */ @SuppressWarnings("ResultOfMethodCallIgnored") - public LiteBansHook(HookHandler hookH) { + public LiteBansBukkitHook(HookHandler hookH) { super(hookH); try { Database.get(); @@ -39,7 +40,8 @@ public class LiteBansHook extends Hook { public void hook() throws NoClassDefFoundError { if (enabled) { - LiteBansDatabaseQueries db = new LiteBansDatabaseQueries(); + String tablePrefix = Bukkit.getPluginManager().getPlugin("LiteBans").getConfig().getString("sql.table_prefix"); + LiteBansDatabaseQueries db = new LiteBansDatabaseQueries(tablePrefix); addPluginDataSource(new LiteBansData(db)); } } diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBungeeHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBungeeHook.java new file mode 100644 index 000000000..3cfe62196 --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansBungeeHook.java @@ -0,0 +1,69 @@ +package com.djrapitops.pluginbridge.plan.litebans; + +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.pluginbridge.plan.Hook; +import litebans.api.Database; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A Class responsible for hooking to LiteBans and registering data + * sources. + * + * @author Rsl1122 + * @since 3.5.0 + */ +public class LiteBansBungeeHook extends Hook { + + /** + * Hooks the plugin and registers it's PluginData objects. + *

    + * API#addPluginDataSource uses the same method from HookHandler. + * + * @param hookH HookHandler instance for registering the data sources. + * @throws NoClassDefFoundError when the plugin class can not be found. + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + public LiteBansBungeeHook(HookHandler hookH) { + super(hookH); + try { + Database.get(); + enabled = true; + } catch (NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError | Exception e) { + if (Settings.DEV_MODE.isTrue()) { + Log.toLog(this.getClass(), e); + } + enabled = false; + } + } + + public void hook() throws NoClassDefFoundError { + if (enabled) { + LiteBansDatabaseQueries db = new LiteBansDatabaseQueries(getTablePrefix()); + addPluginDataSource(new LiteBansData(db)); + } + } + + private String getTablePrefix() { + String tablePrefix = "libeans_"; + try { + File litebansDataFolder = ProxyServer.getInstance().getPluginManager().getPlugin("LiteBans").getDataFolder(); + File configFile = new File(litebansDataFolder, "config.yml"); + + Configuration configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); + tablePrefix = configuration.getString("sql.table_prefix"); + } catch (NullPointerException | IOException e) { + Logger.getLogger("Plan").log(Level.WARNING, "Could not get Litebans table prefix, using default (litebans_). " + e.toString()); + } + return tablePrefix; + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansDatabaseQueries.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansDatabaseQueries.java index 3c9f90332..f11cfb0b2 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansDatabaseQueries.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansDatabaseQueries.java @@ -5,7 +5,6 @@ import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStat import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; import com.djrapitops.plan.system.database.databases.sql.tables.Table; import litebans.api.Database; -import org.bukkit.Bukkit; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -30,10 +29,9 @@ public class LiteBansDatabaseQueries extends Table { private final String selectSQL; - public LiteBansDatabaseQueries() { + public LiteBansDatabaseQueries(String tablePrefix) { super("litebans", null); database = Database.get(); - String tablePrefix = Bukkit.getPluginManager().getPlugin("LiteBans").getConfig().getString("sql.table_prefix"); banTable = tablePrefix + "bans"; mutesTable = tablePrefix + "mutes"; warningsTable = tablePrefix + "warnings"; diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/PlayerVersionListener.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BukkitPlayerVersionListener.java similarity index 92% rename from PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/PlayerVersionListener.java rename to PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BukkitPlayerVersionListener.java index da82d60f8..ca41fbd7e 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/PlayerVersionListener.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BukkitPlayerVersionListener.java @@ -24,11 +24,11 @@ import java.util.UUID; * @author Rsl1122 * @since 3.5.0 */ -public class PlayerVersionListener implements Listener { +public class BukkitPlayerVersionListener implements Listener { private ViaAPI viaAPI; - public PlayerVersionListener(ViaAPI viaAPI) { + public BukkitPlayerVersionListener(ViaAPI viaAPI) { this.viaAPI = viaAPI; } diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BungeePlayerVersionListener.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BungeePlayerVersionListener.java new file mode 100644 index 000000000..382fedc1d --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/BungeePlayerVersionListener.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.djrapitops.pluginbridge.plan.viaversion; + +import com.djrapitops.plan.api.exceptions.database.DBOpException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.processing.Processing; +import com.djrapitops.plugin.api.utility.log.Log; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; +import us.myles.ViaVersion.api.ViaAPI; + +import java.util.UUID; + +/** + * Class responsible for listening join events for Version protocol. + * + * @author Rsl1122 + * @since 3.5.0 + */ +public class BungeePlayerVersionListener implements Listener { + + private ViaAPI viaAPI; + + public BungeePlayerVersionListener(ViaAPI viaAPI) { + this.viaAPI = viaAPI; + } + + @EventHandler + public void onJoin(PostLoginEvent event) { + UUID uuid = event.getPlayer().getUniqueId(); + int playerVersion = viaAPI.getPlayerVersion(uuid); + Processing.submitNonCritical(() -> { + try { + new ProtocolTable((SQLDB) Database.getActive()).saveProtocolVersion(uuid, playerVersion); + } catch (DBOpException e) { + Log.toLog(this.getClass(), e); + } + }); + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/Protocol.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/Protocol.java index b99764fb7..a98417036 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/Protocol.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/Protocol.java @@ -25,6 +25,8 @@ public class Protocol { */ public static String getMCVersion(int protocolVersion) { switch (protocolVersion) { + case 401: + return "1.13.1"; case 390: case 391: case 392: diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBukkitHook.java similarity index 89% rename from PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionHook.java rename to PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBukkitHook.java index bcaaa9f12..4db2dc27e 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionHook.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBukkitHook.java @@ -16,7 +16,7 @@ import us.myles.ViaVersion.api.ViaAPI; * @author Rsl1122 * @since 3.1.0 */ -public class ViaVersionHook extends Hook { +public class ViaVersionBukkitHook extends Hook { /** * Hooks the plugin and registers it's PluginData objects. @@ -25,7 +25,7 @@ public class ViaVersionHook extends Hook { * * @param hookH HookHandler instance for registering the data sources. */ - public ViaVersionHook(HookHandler hookH) { + public ViaVersionBukkitHook(HookHandler hookH) { super("us.myles.ViaVersion.ViaVersionPlugin", hookH); } @@ -42,7 +42,7 @@ public class ViaVersionHook extends Hook { Log.toLog(this.getClass().getName(), e); return; } - plan.registerListener(new PlayerVersionListener(api)); + plan.registerListener(new BukkitPlayerVersionListener(api)); addPluginDataSource(new ViaVersionData(table)); } } \ No newline at end of file diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBungeeHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBungeeHook.java new file mode 100644 index 000000000..41addff02 --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/viaversion/ViaVersionBungeeHook.java @@ -0,0 +1,48 @@ +package com.djrapitops.pluginbridge.plan.viaversion; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.pluginbridge.plan.Hook; +import us.myles.ViaVersion.api.Via; +import us.myles.ViaVersion.api.ViaAPI; + +/** + * A Class responsible for hooking to ViaVersion and registering data sources. + * + * @author Rsl1122 + * @since 3.1.0 + */ +public class ViaVersionBungeeHook extends Hook { + + /** + * Hooks the plugin and registers it's PluginData objects. + *

    + * API#addPluginDataSource uses the same method from HookHandler. + * + * @param hookH HookHandler instance for registering the data sources. + */ + public ViaVersionBungeeHook(HookHandler hookH) { + super("us.myles.ViaVersion.BungeePlugin", hookH); + } + + public void hook() throws NoClassDefFoundError { + if (!enabled) { + return; + } + PlanBungee plan = PlanBungee.getInstance(); + ViaAPI api = Via.getAPI(); + ProtocolTable table = new ProtocolTable((SQLDB) Database.getActive()); + try { + table.createTable(); + } catch (DBException e) { + Log.toLog(this.getClass().getName(), e); + return; + } + plan.registerListener(new BungeePlayerVersionListener(api)); + addPluginDataSource(new ViaVersionData(table)); + } +} \ No newline at end of file From 58512dbd19f82701a68553d9dd747014f58f74ec Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 11:36:37 +0300 Subject: [PATCH 04/11] Fixed uninstalled subcommand --- .../plan/command/commands/manage/ManageUninstalledCommand.java | 3 +-- .../plan/system/database/databases/sql/tables/ServerTable.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageUninstalledCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageUninstalledCommand.java index e42715f52..456f388f0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageUninstalledCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageUninstalledCommand.java @@ -3,7 +3,6 @@ package com.djrapitops.plan.command.commands.manage; import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.api.exceptions.database.DBOpException; import com.djrapitops.plan.system.database.databases.Database; -import com.djrapitops.plan.system.info.connection.ConnectionSystem; import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.locale.Locale; @@ -69,7 +68,7 @@ public class ManageUninstalledCommand extends CommandNode { } private Optional getServer(String[] args) { - if (args.length >= 1 && ConnectionSystem.getInstance().isServerAvailable()) { + if (args.length >= 1) { Map bukkitServers = Database.getActive().fetch().getBukkitServers(); String serverIdentifier = getGivenIdentifier(args); for (Map.Entry entry : bukkitServers.entrySet()) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java index 6df2a8a83..d9a3aaf18 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java @@ -367,7 +367,7 @@ public class ServerTable extends Table { } public void setAsUninstalled(UUID serverUUID) { - String sql = "UPDATE " + tableName + " SET (" + Col.INSTALLED + "=?) WHERE " + Col.SERVER_UUID + "=?"; + String sql = "UPDATE " + tableName + " SET " + Col.INSTALLED + "=? WHERE " + Col.SERVER_UUID + "=?"; execute(new ExecStatement(sql) { @Override From f5b6b43aec905fd2171b83d852e4e4befbc6f0e4 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 11:37:22 +0300 Subject: [PATCH 05/11] Added a progress bar utility --- .../utilities/html/graphs/ProgressBar.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ProgressBar.java diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ProgressBar.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ProgressBar.java new file mode 100644 index 000000000..a29ebc932 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ProgressBar.java @@ -0,0 +1,39 @@ +package com.djrapitops.plan.utilities.html.graphs; + +import com.djrapitops.plan.data.store.mutators.formatting.Formatters; + +/** + * Utility for creating ProgressBars. + * + * @author Rsl1122 + */ +public class ProgressBar { + + private final int obtained; + private final int max; + + private final String color; + + public ProgressBar(int obtained, int max) { + this(obtained, max, "teal"); + } + + public ProgressBar(int obtained, int max, String color) { + this.obtained = obtained; + this.max = max; + this.color = color; + } + + public String toHtml() { + double percentage = obtained * 1.0 / max; + int percentageRounded = (int) percentage; + + return "

    " + + obtained + " / " + max + " (" + Formatters.percentage().apply(percentage) + ")" + + "
    "; + } + +} \ No newline at end of file From 870b929a9e7befcc8aa3f465c0786677dd85868d Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 11:37:57 +0300 Subject: [PATCH 06/11] Added ASkyBlock challenges to player page #686 --- .../plan/askyblock/ASkyBlockData.java | 36 ++++++++++++++++++- .../plan/litebans/LiteBansData.java | 2 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/askyblock/ASkyBlockData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/askyblock/ASkyBlockData.java index 08516f12d..fc3640f07 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/askyblock/ASkyBlockData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/askyblock/ASkyBlockData.java @@ -6,14 +6,18 @@ package com.djrapitops.pluginbridge.plan.askyblock; import com.djrapitops.plan.data.element.AnalysisContainer; import com.djrapitops.plan.data.element.InspectContainer; +import com.djrapitops.plan.data.element.TableContainer; import com.djrapitops.plan.data.plugin.ContainerSize; import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.utilities.html.graphs.ProgressBar; import com.djrapitops.plan.utilities.html.icon.Color; import com.djrapitops.plan.utilities.html.icon.Family; import com.djrapitops.plan.utilities.html.icon.Icon; +import com.djrapitops.plugin.utilities.Format; import com.wasteofplastic.askyblock.ASkyBlockAPI; import java.util.Collection; +import java.util.Map; import java.util.UUID; /** @@ -35,7 +39,7 @@ public class ASkyBlockData extends PluginData { public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) { if (api.hasIsland(uuid)) { String islandName = api.getIslandName(uuid); - int level = api.getIslandLevel(uuid); + long level = api.getLongIslandLevel(uuid); int resetsLeft = api.getResetsLeft(uuid); inspectContainer.addValue(getWithIcon("Island Name", Icon.called("street-view").of(Color.GREEN)), islandName); @@ -45,9 +49,39 @@ public class ASkyBlockData extends PluginData { inspectContainer.addValue(getWithIcon("Island Name", Icon.called("street-view").of(Color.GREEN)), "No Island"); } + Map challengeCompletion = api.getChallengeTimes(uuid); + int obtained = (int) challengeCompletion.values().stream().filter(value -> value != 0).count(); + int max = challengeCompletion.size(); + + inspectContainer.addValue(getWithIcon("Challenge Progress", Icon.called("bookmark").of(Color.LIGHT_BLUE)), obtained + " / " + max); + ProgressBar challengeProgress = new ProgressBar(obtained, max, "light-blue"); + inspectContainer.addHtml("challenge-progress", challengeProgress.toHtml()); + + addTable(inspectContainer, challengeCompletion); + return inspectContainer; } + private void addTable(InspectContainer inspectContainer, Map challengeCompletion) { + TableContainer challenges = new TableContainer( + getWithIcon("Challenge", Icon.called("bookmark")), + getWithIcon("Times completed", Icon.called("check")) + ); + challenges.setColor("light-blue"); + challengeCompletion.entrySet().stream() + .sorted((one, two) -> Integer.compare(two.getValue(), one.getValue())) + .forEach(entry -> { + String challenge = new Format(entry.getKey()).capitalize().toString(); + Integer completionTimes = entry.getValue(); + boolean complete = completionTimes > 0; + challenges.addRow( + "" + challenge + "", + completionTimes + ); + }); + inspectContainer.addTable("challenge-table", challenges); + } + @Override public AnalysisContainer getServerData(Collection uuids, AnalysisContainer analysisContainer) { int islandCount = api.getIslandCount(); diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java index 48cde675c..f58704be9 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java @@ -44,7 +44,7 @@ public class LiteBansData extends PluginData implements BanData { public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) { inspectContainer.addValue(Icon.called("balance-scale").of(Color.RED) + - "Hover over 'What' column entry for offence reasons", ""); + " Hover over 'What' column entry for offence reasons", ""); String what = getWithIcon("Effect", Icon.called("times-circle").of(Family.REGULAR)); String by = getWithIcon("By", Icon.called("gavel")); From f610e014c10dd39fb8405c92cfa7bdfeed50fa65 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 11:45:51 +0300 Subject: [PATCH 07/11] Cleaned up AdvancedBanData class --- .../plan/advancedban/AdvancedBanData.java | 94 +++++++++---------- 1 file changed, 42 insertions(+), 52 deletions(-) diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/advancedban/AdvancedBanData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/advancedban/AdvancedBanData.java index 31f4bfae2..377083f1a 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/advancedban/AdvancedBanData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/advancedban/AdvancedBanData.java @@ -9,7 +9,6 @@ import com.djrapitops.plan.data.element.AnalysisContainer; import com.djrapitops.plan.data.element.InspectContainer; import com.djrapitops.plan.data.plugin.ContainerSize; import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.data.store.keys.AnalysisKeys; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.html.Html; import com.djrapitops.plan.utilities.html.HtmlUtils; @@ -17,15 +16,13 @@ import com.djrapitops.plan.utilities.html.icon.Color; import com.djrapitops.plan.utilities.html.icon.Family; import com.djrapitops.plan.utilities.html.icon.Icon; import com.djrapitops.plan.utilities.html.icon.Icons; -import com.djrapitops.plugin.api.utility.log.Log; -import java.util.Collection; -import java.util.HashMap; -import java.util.UUID; import me.leoko.advancedban.manager.PunishmentManager; -import me.leoko.advancedban.manager.UUIDManager; import me.leoko.advancedban.utils.Punishment; import me.leoko.advancedban.utils.PunishmentType; +import java.util.Collection; +import java.util.UUID; + /** * PluginData for AdvancedBan plugin. * @@ -45,59 +42,52 @@ public class AdvancedBanData extends PluginData { return inspectContainer; } - Punishment ban = PunishmentManager.get().getBan(abUuid); - Punishment mute = PunishmentManager.get().getMute(abUuid); - long warnings = PunishmentManager.get().getWarns(abUuid).stream().filter(warning -> !warning.isExpired()).count(); + PunishmentManager punishmentManager = PunishmentManager.get(); + Punishment ban = punishmentManager.getBan(abUuid); + Punishment mute = punishmentManager.getMute(abUuid); + long warnings = punishmentManager.getWarns(abUuid).stream().filter(warning -> !warning.isExpired()).count(); inspectContainer.addValue(getWithIcon("Banned", Icons.BANNED), ban != null ? "Yes" : "No"); - inspectContainer.addValue(getWithIcon("Muted", Icon.called("bell-slash").of(Color.DEEP_ORANGE)), mute != null ? "Yes" : "No"); + if (ban != null) { + addPunishment(inspectContainer, ban, "Permanent ban"); + } + + inspectContainer.addValue(getWithIcon("Muted", Icon.called("bell-slash").of(Color.DEEP_ORANGE)), mute != null ? "Yes" : "No"); + if (mute != null) { + addPunishment(inspectContainer, mute, "Permanent mute"); + } + inspectContainer.addValue(getWithIcon("Warnings", Icon.called("flag").of(Color.YELLOW)), warnings); - if (ban != null) { - String operator = ban.getOperator(); - String link = Html.LINK.parse(PlanAPI.getInstance().getPlayerInspectPageLink(operator), operator); - String reason = HtmlUtils.swapColorsToSpan(ban.getReason()); - long start = ban.getStart(); - String end = FormatUtils.formatTimeStampYear(ban.getEnd()); - - if (ban.getType() == PunishmentType.BAN || ban.getType() == PunishmentType.IP_BAN) { // Permanent - end = "Permanent ban"; - } - - if (operator.equals("CONSOLE")) { - link = "CONSOLE"; - } - - inspectContainer.addValue(" " + getWithIcon("Operator", Icon.called("user").of(Color.RED)), link); - inspectContainer.addValue(" " + getWithIcon("Date", Icon.called("calendar").of(Color.RED).of(Family.REGULAR)), FormatUtils.formatTimeStampYear(start)); - inspectContainer.addValue(" " + getWithIcon("Ends", Icon.called("calendar-check").of(Color.RED).of(Family.REGULAR)), end); - inspectContainer.addValue(" " + getWithIcon("Reason", Icon.called("comment").of(Color.RED).of(Family.REGULAR)), reason); - } - - if (mute != null) { - String operator = mute.getOperator(); - String link = Html.LINK.parse(PlanAPI.getInstance().getPlayerInspectPageLink(operator), operator); - String reason = HtmlUtils.swapColorsToSpan(mute.getReason()); - long start = mute.getStart(); - String end = FormatUtils.formatTimeStampYear(mute.getEnd()); - - if (mute.getType() == PunishmentType.MUTE) { // Permanent - end = "Permanent mute"; - } - - if (operator.equals("CONSOLE")) { - link = "CONSOLE"; - } - - inspectContainer.addValue(" " + getWithIcon("Operator", Icon.called("user").of(Color.DEEP_ORANGE)), link); - inspectContainer.addValue(" " + getWithIcon("Date", Icon.called("calendar").of(Color.DEEP_ORANGE).of(Family.REGULAR)), FormatUtils.formatTimeStampYear(start)); - inspectContainer.addValue(" " + getWithIcon("Ends", Icon.called("calendar-check").of(Color.DEEP_ORANGE).of(Family.REGULAR)), end); - inspectContainer.addValue(" " + getWithIcon("Reason", Icon.called("comment").of(Color.DEEP_ORANGE).of(Family.REGULAR)), reason); - } - return inspectContainer; } + private void addPunishment(InspectContainer inspectContainer, Punishment punishment, String identifier) { + String operator = punishment.getOperator(); + String link = Html.LINK.parse(PlanAPI.getInstance().getPlayerInspectPageLink(operator), operator); + String reason = HtmlUtils.swapColorsToSpan(punishment.getReason()); + String start = FormatUtils.formatTimeStampYear(punishment.getStart()); + String end = FormatUtils.formatTimeStampYear(punishment.getEnd()); + + PunishmentType type = punishment.getType(); + // Permanent + if (type == PunishmentType.BAN + || type == PunishmentType.IP_BAN + || type == PunishmentType.MUTE + ) { + end = identifier; + } + + if (operator.equals("CONSOLE")) { + link = "CONSOLE"; + } + + inspectContainer.addValue(" " + getWithIcon("Operator", Icon.called("user").of(Color.RED)), link); + inspectContainer.addValue(" " + getWithIcon("Date", Icon.called("calendar").of(Color.RED).of(Family.REGULAR)), start); + inspectContainer.addValue(" " + getWithIcon("Ends", Icon.called("calendar-check").of(Color.RED).of(Family.REGULAR)), end); + inspectContainer.addValue(" " + getWithIcon("Reason", Icon.called("comment").of(Color.RED).of(Family.REGULAR)), reason); + } + @Override public AnalysisContainer getServerData(Collection uuids, AnalysisContainer analysisContainer) { return analysisContainer; From e09f821071137e25aeb934bca248026f2a5b7ed2 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 11:49:41 +0300 Subject: [PATCH 08/11] Updated PluginBridge jar --- PlanPluginBridge/PlanPluginBridge-4.4.0.jar | Bin 145435 -> 156141 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PlanPluginBridge/PlanPluginBridge-4.4.0.jar b/PlanPluginBridge/PlanPluginBridge-4.4.0.jar index fdf51327bee2e47098a5e8b434de4d999e93c4cf..c39acfceac167d6b506b941bceb939e4417443ae 100644 GIT binary patch delta 41620 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 From 86f99cbe1beed83e2b17c537c0bbd222cd0daa5a Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 12:02:00 +0300 Subject: [PATCH 09/11] Fixed Sponge CPU usage gathering --- .../plan/system/tasks/TPSCountTimer.java | 25 +++++++++++++++++++ .../tasks/bungee/BungeeTPSCountTimer.java | 4 +++ .../tasks/server/BukkitTPSCountTimer.java | 24 +----------------- .../tasks/server/SpongeTPSCountTimer.java | 16 ++---------- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java index ba94523c3..93fe4cd32 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java @@ -7,6 +7,8 @@ import com.djrapitops.plan.system.processing.processors.TPSInsertProcessor; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.task.AbsRunnable; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; import java.util.ArrayList; import java.util.List; @@ -52,4 +54,27 @@ public abstract class TPSCountTimer extends AbsRunnable { public int getLatestPlayersOnline() { return latestPlayersOnline; } + + protected long getUsedMemory() { + Runtime runtime = Runtime.getRuntime(); + long totalMemory = runtime.totalMemory(); + return (totalMemory - runtime.freeMemory()) / 1000000; + } + + protected double getCPUUsage() { + double averageCPUUsage; + + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + if (osBean instanceof com.sun.management.OperatingSystemMXBean) { + com.sun.management.OperatingSystemMXBean nativeOsBean = (com.sun.management.OperatingSystemMXBean) osBean; + averageCPUUsage = nativeOsBean.getSystemCpuLoad(); + } else { + int availableProcessors = osBean.getAvailableProcessors(); + averageCPUUsage = osBean.getSystemLoadAverage() / availableProcessors; + } + if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 + averageCPUUsage = -1; + } + return averageCPUUsage * 100.0; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java index 2d5edb328..dda2d8233 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java @@ -19,6 +19,10 @@ public class BungeeTPSCountTimer extends TPSCountTimer { .date(now) .skipTPS() .playersOnline(onlineCount) + .usedCPU(getCPUUsage()) + .usedMemory(getUsedMemory()) + .entities(-1) + .chunksLoaded(-1) .toTPS(); history.add(tps); diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/BukkitTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/BukkitTPSCountTimer.java index 7ace91d0a..1017dea99 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/BukkitTPSCountTimer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/BukkitTPSCountTimer.java @@ -7,9 +7,6 @@ import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.api.utility.log.Log; import org.bukkit.World; -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; - public class BukkitTPSCountTimer extends TPSCountTimer { private long lastCheckNano; @@ -43,10 +40,7 @@ public class BukkitTPSCountTimer extends TPSCountTimer { private TPS calculateTPS(long diff, long now) { double averageCPUUsage = getCPUUsage(); - Runtime runtime = Runtime.getRuntime(); - - long totalMemory = runtime.totalMemory(); - long usedMemory = (totalMemory - runtime.freeMemory()) / 1000000; + long usedMemory = getUsedMemory(); int playersOnline = plugin.getServer().getOnlinePlayers().size(); latestPlayersOnline = playersOnline; @@ -58,22 +52,6 @@ public class BukkitTPSCountTimer extends TPSCountTimer { return getTPS(diff, now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); } - private double getCPUUsage() { - double averageCPUUsage; - - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - if (osBean instanceof com.sun.management.OperatingSystemMXBean) { - com.sun.management.OperatingSystemMXBean nativeOsBean = (com.sun.management.OperatingSystemMXBean) osBean; - averageCPUUsage = nativeOsBean.getSystemCpuLoad(); - } else { - int availableProcessors = osBean.getAvailableProcessors(); - averageCPUUsage = osBean.getSystemLoadAverage() / availableProcessors; - } - if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 - averageCPUUsage = -1; - } - return averageCPUUsage * 100.0; - } /** * Gets the TPS for Spigot / Bukkit diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/SpongeTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/SpongeTPSCountTimer.java index 2e3356bab..a3ce43333 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/SpongeTPSCountTimer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/server/SpongeTPSCountTimer.java @@ -9,9 +9,6 @@ import com.djrapitops.plugin.api.utility.log.Log; import org.spongepowered.api.Sponge; import org.spongepowered.api.world.World; -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; - public class SpongeTPSCountTimer extends TPSCountTimer { private long lastCheckNano; @@ -42,18 +39,9 @@ public class SpongeTPSCountTimer extends TPSCountTimer { * @return the TPS */ private TPS calculateTPS(long now) { - OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); - int availableProcessors = operatingSystemMXBean.getAvailableProcessors(); - double averageCPUUsage = operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0; + double averageCPUUsage = getCPUUsage(); - if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 - averageCPUUsage = -1; - } - - Runtime runtime = Runtime.getRuntime(); - - long totalMemory = runtime.totalMemory(); - long usedMemory = (totalMemory - runtime.freeMemory()) / 1000000; + long usedMemory = getUsedMemory(); double tps = Sponge.getGame().getServer().getTicksPerSecond(); int playersOnline = ServerInfo.getServerProperties().getOnlinePlayers(); From a21b91fae8d8230009185ee838434f1c55be18a2 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 12:02:12 +0300 Subject: [PATCH 10/11] Version bump to 4.4.5 --- Plan/src/main/java/com/djrapitops/plan/PlanSponge.java | 2 +- Plan/src/main/resources/bungee.yml | 2 +- Plan/src/main/resources/plugin.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java b/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java index 60ece7eba..543b60759 100644 --- a/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java +++ b/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java @@ -25,7 +25,7 @@ import org.spongepowered.api.plugin.Plugin; import java.io.File; import java.io.InputStream; -@Plugin(id = "plan", name = "Plan", version = "4.4.4", description = "Player Analytics Plugin by Rsl1122", authors = {"Rsl1122"}) +@Plugin(id = "plan", name = "Plan", version = "4.4.5", description = "Player Analytics Plugin by Rsl1122", authors = {"Rsl1122"}) public class PlanSponge extends SpongePlugin implements PlanPlugin { @Inject diff --git a/Plan/src/main/resources/bungee.yml b/Plan/src/main/resources/bungee.yml index 365f2b64d..0b1e9b6f6 100644 --- a/Plan/src/main/resources/bungee.yml +++ b/Plan/src/main/resources/bungee.yml @@ -1,4 +1,4 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.PlanBungee -version: 4.4.4 \ No newline at end of file +version: 4.4.5 \ No newline at end of file diff --git a/Plan/src/main/resources/plugin.yml b/Plan/src/main/resources/plugin.yml index 8583e4134..55c0b3fe7 100644 --- a/Plan/src/main/resources/plugin.yml +++ b/Plan/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.Plan -version: 4.4.4 +version: 4.4.5 softdepend: - EssentialsX - Towny From 9898bf8264d4716bf2cd7a7936020ef744ddbc8e Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 27 Aug 2018 15:23:46 +0300 Subject: [PATCH 11/11] Bukkit/Bungee pom - comment relocation & uncomment ignore for Sponge pom --- Plan/dependency-reduced-pom.xml | 3 --- Plan/pom.xml | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Plan/dependency-reduced-pom.xml b/Plan/dependency-reduced-pom.xml index a8ec7baba..7b3d46293 100644 --- a/Plan/dependency-reduced-pom.xml +++ b/Plan/dependency-reduced-pom.xml @@ -83,9 +83,6 @@ org.slf4j plan.org.slf4j - - org.slf4j.Logger - org.bstats diff --git a/Plan/pom.xml b/Plan/pom.xml index baf436b60..9f16f2e25 100644 --- a/Plan/pom.xml +++ b/Plan/pom.xml @@ -223,6 +223,7 @@ org.mockito:* org.easymock:* junit:* + @@ -248,9 +249,6 @@ org.slf4j plan.org.slf4j - - org.slf4j.Logger - org.bstats