diff --git a/Plan/build.gradle b/Plan/build.gradle
index accbb25ae..2cf6a8d6f 100644
--- a/Plan/build.gradle
+++ b/Plan/build.gradle
@@ -78,6 +78,7 @@ subprojects {
ext.gsonVersion = "2.8.5"
ext.guavaVersion = "28.0-jre"
ext.bstatsVersion = "1.4"
+ ext.placeholderapiVersion = "2.9.2"
repositories {
mavenCentral()
diff --git a/Plan/bukkit/build.gradle b/Plan/bukkit/build.gradle
index 654966f0e..ef98b864b 100644
--- a/Plan/bukkit/build.gradle
+++ b/Plan/bukkit/build.gradle
@@ -1,16 +1,18 @@
+repositories {
+ maven { // Placeholder API repository
+ url = "http://repo.extendedclip.com/content/repositories/placeholderapi/"
+ }
+}
+
dependencies {
compile project(path: ":common", configuration: 'shadow')
compileOnly project(":api")
compile "com.djrapitops:AbstractPluginFramework-bukkit:$abstractPluginFrameworkVersion"
compile "org.bstats:bstats-bukkit:$bstatsVersion"
+ compileOnly "me.clip:placeholderapi:$placeholderapiVersion"
-// compileOnly "org.spigotmc:spigot-api:$spigotVersion"
-// compileOnly "org.bukkit:bukkit:$bukkitVersion"
compileOnly "com.destroystokyo.paper:paper-api:$paperVersion"
-
-// testCompile "org.spigotmc:spigot-api:$spigotVersion"
-// testCompile "org.bukkit:bukkit:$bukkitVersion"
testCompile "com.destroystokyo.paper:paper-api:$paperVersion"
testCompile project(path: ":common", configuration: 'testArtifacts')
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/Plan.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/Plan.java
index 7631164ee..faeb02dcd 100644
--- a/Plan/bukkit/src/main/java/com/djrapitops/plan/Plan.java
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/Plan.java
@@ -16,6 +16,7 @@
*/
package com.djrapitops.plan;
+import com.djrapitops.plan.addons.placeholderapi.PlaceholderRegistrar;
import com.djrapitops.plan.commands.PlanCommand;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.gathering.ServerShutdownSave;
@@ -26,6 +27,7 @@ import com.djrapitops.plugin.BukkitPlugin;
import com.djrapitops.plugin.benchmarking.Benchmark;
import com.djrapitops.plugin.command.ColorScheme;
import com.djrapitops.plugin.task.AbsRunnable;
+import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.logging.Level;
@@ -53,6 +55,7 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
system.enable();
registerMetrics();
+ registerPlaceholderAPIExtension();
logger.debug("Verbose debug messages are enabled.");
String benchTime = " (" + timings.end("Enable").map(Benchmark::toDurationString).orElse("-") + ")";
@@ -79,6 +82,16 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
}
}
+ private void registerPlaceholderAPIExtension() {
+ try {
+ if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+ PlaceholderRegistrar.register(system, errorHandler);
+ }
+ } catch (Exception | NoClassDefFoundError | NoSuchMethodError failed) {
+ logger.warn("Failed to register PlaceholderAPI placeholders: " + failed.toString());
+ }
+ }
+
private void registerMetrics() {
Plan plugin = this;
// Spigot 1.14 requires Sync events to be fired from a server thread.
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlaceholderRegistrar.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlaceholderRegistrar.java
new file mode 100644
index 000000000..170f86999
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlaceholderRegistrar.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi;
+
+import com.djrapitops.plan.PlanSystem;
+import com.djrapitops.plugin.logging.error.ErrorHandler;
+
+/**
+ * Additional wrapper to register PlaceholderAPI placeholders.
+ *
+ * @author Rsl1122
+ */
+public class PlaceholderRegistrar {
+
+ private PlaceholderRegistrar() {
+ }
+
+ public static void register(PlanSystem system, ErrorHandler errorHandler) {
+ new PlanPlaceHolders(system, errorHandler).register();
+ }
+
+}
\ No newline at end of file
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceHolders.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceHolders.java
new file mode 100644
index 000000000..3104d8dad
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceHolders.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi;
+
+import com.djrapitops.plan.PlanSystem;
+import com.djrapitops.plan.addons.placeholderapi.placeholders.*;
+import com.djrapitops.plan.delivery.domain.keys.ServerKeys;
+import com.djrapitops.plan.delivery.formatting.Formatters;
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.settings.config.PlanConfig;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.version.VersionCheckSystem;
+import com.djrapitops.plugin.logging.L;
+import com.djrapitops.plugin.logging.error.ErrorHandler;
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Placeholder expansion used to provide data from Plan.
+ *
+ *
+ * Current used services for placeholders:
+ *
+ * - {@link ServerPlaceHolders}:
+ * {@link ServerKeys#TPS},{@link ServerKeys#NAME},
+ * {@link ServerKeys#SERVER_UUID}
+ * - {@link OperatorPlaceholders}: {@link ServerKeys#OPERATORS}
+ * - {@link WorldTimePlaceHolder}: {@link ServerKeys#WORLD_TIMES}
+ * - {@link SessionPlaceHolder}: {@link ServerKeys#SESSIONS},
+ * {@link ServerKeys#PLAYERS},{@link ServerKeys#PING},{@link ServerKeys#ALL_TIME_PEAK_PLAYERS},
+ * {@link ServerKeys#RECENT_PEAK_PLAYERS}
+ *
+ *
+ * @author aidn5
+ */
+public class PlanPlaceHolders extends PlaceholderExpansion {
+ public final ErrorHandler errorHandler;
+
+ private final Collection placeholders = new ArrayList<>();
+ private final VersionCheckSystem versionCheckSystem;
+
+ public PlanPlaceHolders(
+ PlanSystem system,
+ ErrorHandler errorHandler
+ ) {
+ this.versionCheckSystem = system.getVersionCheckSystem();
+ this.errorHandler = errorHandler;
+
+ PlanConfig config = system.getConfigSystem().getConfig();
+ DBSystem databaseSystem = system.getDatabaseSystem();
+ ServerInfo serverInfo = system.getServerInfo();
+ Formatters formatters = system.getDeliveryUtilities().getFormatters();
+
+ placeholders.add(new ServerPlaceHolders(databaseSystem, serverInfo, formatters));
+ placeholders.add(new OperatorPlaceholders(databaseSystem, serverInfo));
+ placeholders.add(new WorldTimePlaceHolder(databaseSystem, serverInfo, formatters));
+ placeholders.add(new SessionPlaceHolder(config, databaseSystem, serverInfo, formatters));
+ placeholders.add(new PlayerPlaceHolder(databaseSystem, serverInfo, formatters));
+ }
+
+ @Override
+ public boolean persist() {
+ return true;
+ }
+
+ @Override
+ public boolean canRegister() {
+ return true;
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "plan";
+ }
+
+ @Override
+ public String getPlugin() {
+ return "Plan";
+ }
+
+ @Override
+ public String getAuthor() {
+ return "Rsl1122";
+ }
+
+ @Override
+ public String getVersion() {
+ return versionCheckSystem.getCurrentVersion();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) {
+ try {
+ for (AbstractPlanPlaceHolder placeholder : placeholders) {
+ String value = placeholder.onPlaceholderRequest(p, params);
+ if (value == null) continue;
+
+ return value;
+
+ }
+ } catch (Exception e) {
+ errorHandler.log(L.WARN, getClass(), e);
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/AbstractPlanPlaceHolder.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/AbstractPlanPlaceHolder.java
new file mode 100644
index 000000000..04000f0ef
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/AbstractPlanPlaceHolder.java
@@ -0,0 +1,75 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.addons.placeholderapi.PlanPlaceHolders;
+import com.djrapitops.plan.identification.ServerInfo;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * abstract class used for plan placeholders list. This class contains most used
+ * methods (static methods and non-static one). It is also used as a universe
+ * interface for the Plan-placeholders instances
+ * {@link #onPlaceholderRequest(Player, String)}. Check {@link PlanPlaceHolders}
+ * to learn more how it is used.
+ *
+ * @author aidn5
+ * @see PlanPlaceHolders
+ */
+public abstract class AbstractPlanPlaceHolder {
+
+ protected final ServerInfo serverInfo;
+
+ AbstractPlanPlaceHolder(ServerInfo serverInfo) {
+ this.serverInfo = serverInfo;
+ }
+
+ static long now() {
+ return System.currentTimeMillis();
+ }
+
+ static long dayAgo() {
+ return now() - TimeUnit.DAYS.toMillis(1L);
+ }
+
+ static long weekAgo() {
+ return now() - (TimeUnit.DAYS.toMillis(7L));
+ }
+
+ static long monthAgo() {
+ return now() - (TimeUnit.DAYS.toMillis(30L));
+ }
+
+ UUID serverUUID() {
+ return serverInfo.getServerUUID();
+ }
+
+ /**
+ * Look up the placeholder and check if it is registered in this instance.
+ *
+ * @param p the player who is viewing the placeholder
+ * @param params the placeholder to look up to.
+ * @return the value of the placeholder if found, or empty {@link String} if no
+ * value found but the placeholder is registered,
+ * otherwise {@code null}
+ * @throws Exception if any error occurs
+ */
+ public abstract String onPlaceholderRequest(Player p, String params) throws Exception;
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/OperatorPlaceholders.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/OperatorPlaceholders.java
new file mode 100644
index 000000000..c2b6898be
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/OperatorPlaceholders.java
@@ -0,0 +1,46 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
+import org.bukkit.entity.Player;
+
+/**
+ * Placeholders about operators.
+ *
+ * @author aidn5, Rsl1122
+ */
+public class OperatorPlaceholders extends AbstractPlanPlaceHolder {
+
+ private final DBSystem dbSystem;
+
+ public OperatorPlaceholders(DBSystem dbSystem, ServerInfo serverInfo) {
+ super(serverInfo);
+ this.dbSystem = dbSystem;
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) throws Exception {
+ if ("operators_total".equalsIgnoreCase(params)) {
+ return dbSystem.getDatabase().query(PlayerCountQueries.operators(serverUUID())).toString();
+ }
+
+ return null;
+ }
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/PlayerPlaceHolder.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/PlayerPlaceHolder.java
new file mode 100644
index 000000000..6fa52aefd
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/PlayerPlaceHolder.java
@@ -0,0 +1,134 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
+import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
+import com.djrapitops.plan.delivery.domain.mutators.PingMutator;
+import com.djrapitops.plan.delivery.domain.mutators.PvpInfoMutator;
+import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
+import com.djrapitops.plan.delivery.formatting.Formatter;
+import com.djrapitops.plan.delivery.formatting.Formatters;
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries;
+import com.djrapitops.plan.utilities.Predicates;
+import me.clip.placeholderapi.PlaceholderAPIPlugin;
+import org.bukkit.entity.Player;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Placeholders about a player.
+ *
+ * @author aidn5, Rsl1122
+ */
+public class PlayerPlaceHolder extends AbstractPlanPlaceHolder {
+
+ private final DBSystem dbSystem;
+ private Formatter year;
+
+ public PlayerPlaceHolder(
+ DBSystem dbSystem,
+ ServerInfo serverInfo,
+ Formatters formatters
+ ) {
+ super(serverInfo);
+ this.dbSystem = dbSystem;
+ year = formatters.yearLong();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) throws Exception {
+ Serializable got = get(params, p.getUniqueId());
+ return got != null ? got.toString() : null;
+ }
+
+ // Checkstyle.OFF: CyclomaticComplexity
+
+ public Serializable get(String params, UUID playerUUID) {
+ PlayerContainer player = getPlayer(playerUUID);
+
+ switch (params.toLowerCase()) {
+ case "player_banned":
+ return player.getValue(PlayerKeys.BANNED)
+ .orElse(Boolean.FALSE) ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse();
+ case "player_operator":
+ return player.getValue(PlayerKeys.OPERATOR)
+ .orElse(Boolean.FALSE) ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse();
+
+ case "player_sessions_count":
+ return SessionsMutator.forContainer(player).count();
+
+ case "player_kick_count":
+ return player.getValue(PlayerKeys.KICK_COUNT).orElse(0);
+ case "player_death_count":
+ return player.getValue(PlayerKeys.DEATH_COUNT).orElse(0);
+ case "player_mob_kill_count":
+ return player.getValue(PlayerKeys.MOB_KILL_COUNT).orElse(0);
+ case "player_player_kill_count":
+ return player.getValue(PlayerKeys.PLAYER_KILL_COUNT).orElse(0);
+ case "player_kill_death_ratio":
+ return PvpInfoMutator.forContainer(player).killDeathRatio();
+
+ case "player_ping_average_day":
+ return PingMutator.forContainer(player).filterBy(Predicates.within(dayAgo(), now())).average();
+ case "player_ping_average_week":
+ return PingMutator.forContainer(player).filterBy(Predicates.within(weekAgo(), now())).average();
+
+ case "player_ping_average_month":
+ return PingMutator.forContainer(player).filterBy(Predicates.within(monthAgo(), now())).average();
+
+ case "player_lastseen":
+ return year.apply(player.getValue(PlayerKeys.LAST_SEEN).orElse((long) 0));
+ case "player_registered":
+ return year.apply(player.getValue(PlayerKeys.REGISTERED).orElse((long) 0));
+
+ case "player_time_active":
+ return year.apply(SessionsMutator.forContainer(player)
+ .toActivePlaytime());
+ case "player_time_afk":
+ return year.apply(SessionsMutator.forContainer(player)
+ .toAfkTime());
+
+ case "player_time_total":
+ return year.apply(SessionsMutator.forContainer(player)
+ .toPlaytime());
+ case "player_time_day":
+ return year.apply(SessionsMutator.forContainer(player)
+ .filterSessionsBetween(dayAgo(), now())
+ .toPlaytime());
+ case "player_time_week":
+ return year.apply(SessionsMutator.forContainer(player)
+ .filterSessionsBetween(weekAgo(), now())
+ .toPlaytime());
+ case "player_time_month":
+ return year.apply(SessionsMutator.forContainer(player)
+ .filterSessionsBetween(monthAgo(), now())
+ .toPlaytime());
+
+ }
+ return null;
+ }
+
+ // Checkstyle.ON: CyclomaticComplexity
+
+ private PlayerContainer getPlayer(UUID playerUUID) {
+ return dbSystem.getDatabase().query(ContainerFetchQueries.fetchPlayerContainer(playerUUID));
+ }
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/ServerPlaceHolders.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/ServerPlaceHolders.java
new file mode 100644
index 000000000..e93f7e620
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/ServerPlaceHolders.java
@@ -0,0 +1,131 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.delivery.formatting.Formatter;
+import com.djrapitops.plan.delivery.formatting.Formatters;
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.storage.database.Database;
+import com.djrapitops.plan.storage.database.queries.objects.TPSQueries;
+import org.bukkit.entity.Player;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Placeholders about a servers.
+ *
+ * @author aidn5, Rsl1122
+ */
+public class ServerPlaceHolders extends AbstractPlanPlaceHolder {
+
+ private final DBSystem dbSystem;
+ private Formatter decimals;
+ private Formatter percentage;
+
+ public ServerPlaceHolders(
+ DBSystem dbSystem,
+ ServerInfo serverInfo,
+ Formatters formatters
+ ) {
+ super(serverInfo);
+ this.dbSystem = dbSystem;
+ decimals = formatters.decimals();
+ percentage = formatters.percentage();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) throws Exception {
+ Database database = dbSystem.getDatabase();
+ UUID serverUUID = serverUUID();
+ Serializable got = get(params, database, serverUUID);
+ return got != null ? got.toString() : null;
+ }
+
+ // Checkstyle.OFF: CyclomaticComplexity
+
+ public Serializable get(String params, Database database, UUID serverUUID) {
+ switch (params.toLowerCase()) {
+ case "server_tps_day":
+ return decimals.apply(database.query(TPSQueries.averageTPS(dayAgo(), now(), serverUUID)));
+ case "server_tps_week":
+ return decimals.apply(database.query(TPSQueries.averageTPS(weekAgo(), now(), serverUUID)));
+ case "server_tps_month":
+ return decimals.apply(database.query(TPSQueries.averageTPS(monthAgo(), now(), serverUUID)));
+
+ case "server_cpu_day":
+ return percentage.apply(database.query(TPSQueries.averageCPU(dayAgo(), now(), serverUUID)));
+ case "server_cpu_week":
+ return percentage.apply(database.query(TPSQueries.averageCPU(weekAgo(), now(), serverUUID)));
+ case "server_cpu_month":
+ return percentage.apply(database.query(TPSQueries.averageCPU(monthAgo(), now(), serverUUID)));
+
+ case "server_ram_day":
+ return database.query(TPSQueries.averageRAM(dayAgo(), now(), serverUUID)) + " MB";
+ case "server_ram_week":
+ return database.query(TPSQueries.averageRAM(weekAgo(), now(), serverUUID)) + " MB";
+ case "server_ram_month":
+ return database.query(TPSQueries.averageRAM(monthAgo(), now(), serverUUID)) + " MB";
+
+ case "server_chunks_day":
+ return database.query(TPSQueries.averageChunks(dayAgo(), now(), serverUUID));
+ case "server_chunks_week":
+ return database.query(TPSQueries.averageChunks(weekAgo(), now(), serverUUID));
+ case "server_chunks_month":
+ return database.query(TPSQueries.averageChunks(monthAgo(), now(), serverUUID));
+
+ case "server_entities_day":
+ return database.query(TPSQueries.averageEntities(dayAgo(), now(), serverUUID));
+ case "server_entities_week":
+ return database.query(TPSQueries.averageEntities(weekAgo(), now(), serverUUID));
+ case "server_entities_month":
+ return database.query(TPSQueries.averageEntities(monthAgo(), now(), serverUUID));
+
+ case "server_max_free_disk_day":
+ return database.query(TPSQueries.maxFreeDisk(dayAgo(), now(), serverUUID));
+ case "server_max_free_disk_week":
+ return database.query(TPSQueries.maxFreeDisk(weekAgo(), now(), serverUUID));
+ case "server_max_free_disk_month":
+ return database.query(TPSQueries.maxFreeDisk(monthAgo(), now(), serverUUID));
+
+ case "server_min_free_disk_day":
+ return database.query(TPSQueries.minFreeDisk(dayAgo(), now(), serverUUID));
+ case "server_min_free_disk_week":
+ return database.query(TPSQueries.minFreeDisk(weekAgo(), now(), serverUUID));
+ case "server_min_free_disk_month":
+ return database.query(TPSQueries.minFreeDisk(monthAgo(), now(), serverUUID));
+
+ case "server_average_free_disk_day":
+ return database.query(TPSQueries.averageFreeDisk(dayAgo(), now(), serverUUID));
+ case "server_average_free_disk_week":
+ return database.query(TPSQueries.averageFreeDisk(weekAgo(), now(), serverUUID));
+ case "server_average_free_disk_month":
+ return database.query(TPSQueries.averageFreeDisk(monthAgo(), now(), serverUUID));
+
+ case "server_name":
+ return serverInfo.getServer().getName();
+ case "server_uuid":
+ return serverInfo.getServerUUID();
+
+ default:
+ return null;
+ }
+ }
+
+ // Checkstyle.ON: CyclomaticComplexity
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/SessionPlaceHolder.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/SessionPlaceHolder.java
new file mode 100644
index 000000000..a6a196452
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/SessionPlaceHolder.java
@@ -0,0 +1,195 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.delivery.domain.DateHolder;
+import com.djrapitops.plan.delivery.domain.DateObj;
+import com.djrapitops.plan.delivery.formatting.Formatter;
+import com.djrapitops.plan.delivery.formatting.Formatters;
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.settings.config.PlanConfig;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.storage.database.Database;
+import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
+import com.djrapitops.plan.storage.database.queries.objects.KillQueries;
+import com.djrapitops.plan.storage.database.queries.objects.PingQueries;
+import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
+import com.djrapitops.plan.storage.database.queries.objects.TPSQueries;
+import org.bukkit.entity.Player;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Placeholders about a sessions.
+ *
+ * @author aidn5, Rsl1122
+ */
+public class SessionPlaceHolder extends AbstractPlanPlaceHolder {
+
+ private final DBSystem dbSystem;
+ private Formatter timeAmount;
+ private int tzOffsetMs;
+ private Formatter year;
+
+ public SessionPlaceHolder(
+ PlanConfig config,
+ DBSystem dbSystem,
+ ServerInfo serverInfo,
+ Formatters formatters
+ ) {
+ super(serverInfo);
+ this.dbSystem = dbSystem;
+
+ tzOffsetMs = config.getTimeZone().getOffset(System.currentTimeMillis());
+ timeAmount = formatters.timeAmount();
+ year = formatters.year();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) throws Exception {
+ Serializable got = get(params);
+ return got != null ? got.toString() : null;
+ }
+
+ // Checkstyle.OFF: CyclomaticComplexity
+
+ public Serializable get(String params) {
+ Database database = dbSystem.getDatabase();
+ UUID serverUUID = serverUUID();
+
+ switch (params.toLowerCase()) {
+
+ case "sessions_play_time_total":
+ return timeAmount.apply(database.query(SessionQueries.playtime(0L, now(), serverUUID)));
+ case "sessions_play_time_day":
+ return timeAmount.apply(database.query(SessionQueries.playtime(dayAgo(), now(), serverUUID)));
+ case "sessions_play_time_week":
+ return timeAmount.apply(database.query(SessionQueries.playtime(weekAgo(), now(), serverUUID)));
+ case "sessions_play_time_month":
+ return timeAmount.apply(database.query(SessionQueries.playtime(monthAgo(), now(), serverUUID)));
+
+ case "sessions_active_time_total":
+ return timeAmount.apply(database.query(SessionQueries.activePlaytime(0L, now(), serverUUID)));
+ case "sessions_active_time_day":
+ return timeAmount.apply(database.query(SessionQueries.activePlaytime(dayAgo(), now(), serverUUID)));
+ case "sessions_active_time_week":
+ return timeAmount.apply(database.query(SessionQueries.activePlaytime(weekAgo(), now(), serverUUID)));
+ case "sessions_active_time_month":
+ return timeAmount.apply(database.query(SessionQueries.activePlaytime(monthAgo(), now(), serverUUID)));
+
+ case "sessions_afk_time_total":
+ return timeAmount.apply(database.query(SessionQueries.afkTime(0L, now(), serverUUID)));
+ case "sessions_afk_time_day":
+ return timeAmount.apply(database.query(SessionQueries.afkTime(dayAgo(), now(), serverUUID)));
+ case "sessions_afk_time_week":
+ return timeAmount.apply(database.query(SessionQueries.afkTime(weekAgo(), now(), serverUUID)));
+ case "sessions_afk_time_month":
+ return timeAmount.apply(database.query(SessionQueries.afkTime(monthAgo(), now(), serverUUID)));
+
+ case "sessions_unique_players_total":
+ case "sessions_new_players_total":
+ return database.query(PlayerCountQueries.newPlayerCount(0L, now(), serverUUID));
+ case "sessions_unique_players_day":
+ return database.query(PlayerCountQueries.uniquePlayerCount(dayAgo(), now(), serverUUID));
+ case "sessions_unique_players_week":
+ return database.query(PlayerCountQueries.uniquePlayerCount(weekAgo(), now(), serverUUID));
+ case "sessions_unique_players_month":
+ return database.query(PlayerCountQueries.uniquePlayerCount(monthAgo(), now(), serverUUID));
+
+ case "sessions_players_death_total":
+ return database.query(KillQueries.deathCount(0L, now(), serverUUID));
+ case "sessions_players_death_day":
+ return database.query(KillQueries.deathCount(dayAgo(), now(), serverUUID));
+ case "sessions_players_death_week":
+ return database.query(KillQueries.deathCount(weekAgo(), now(), serverUUID));
+ case "sessions_players_death_month":
+ return database.query(KillQueries.deathCount(monthAgo(), now(), serverUUID));
+
+ case "sessions_players_kill_total":
+ return database.query(KillQueries.playerKillCount(0L, now(), serverUUID));
+ case "sessions_players_kill_day":
+ return database.query(KillQueries.playerKillCount(dayAgo(), now(), serverUUID));
+ case "sessions_players_kill_week":
+ return database.query(KillQueries.playerKillCount(weekAgo(), now(), serverUUID));
+ case "sessions_players_kill_month":
+ return database.query(KillQueries.playerKillCount(monthAgo(), now(), serverUUID));
+
+ case "sessions_mob_kill_total":
+ return database.query(KillQueries.mobKillCount(0L, now(), serverUUID));
+ case "sessions_mob_kill_day":
+ return database.query(KillQueries.mobKillCount(dayAgo(), now(), serverUUID));
+ case "sessions_mob_kill_week":
+ return database.query(KillQueries.mobKillCount(weekAgo(), now(), serverUUID));
+ case "sessions_mob_kill_month":
+ return database.query(KillQueries.mobKillCount(monthAgo(), now(), serverUUID));
+
+ case "sessions_average_session_length_total":
+ return getPlaytime(database, 0L, now(), serverUUID);
+ case "sessions_average_session_length_day":
+ return getPlaytime(database, dayAgo(), now(), serverUUID);
+ case "sessions_average_session_length_week":
+ return getPlaytime(database, weekAgo(), now(), serverUUID);
+ case "sessions_average_session_length_month":
+ return getPlaytime(database, monthAgo(), now(), serverUUID);
+
+ case "sessions_average_unique_players_total":
+ return database.query(PlayerCountQueries.averageUniquePlayerCount(0L, now(), tzOffsetMs, serverUUID));
+ case "sessions_average_unique_players_day":
+ return database.query(PlayerCountQueries.averageUniquePlayerCount(dayAgo(), now(), tzOffsetMs, serverUUID));
+ case "sessions_average_unique_players_week":
+ return database.query(PlayerCountQueries.averageUniquePlayerCount(weekAgo(), now(), tzOffsetMs, serverUUID));
+ case "sessions_average_unique_players_month":
+ return database.query(PlayerCountQueries.averageUniquePlayerCount(monthAgo(), now(), tzOffsetMs, serverUUID));
+ case "sessions_new_players_day":
+ return database.query(PlayerCountQueries.newPlayerCount(dayAgo(), now(), serverUUID));
+ case "sessions_new_players_week":
+ return database.query(PlayerCountQueries.newPlayerCount(weekAgo(), now(), serverUUID));
+ case "sessions_new_players_month":
+ return database.query(PlayerCountQueries.newPlayerCount(monthAgo(), now(), serverUUID));
+
+ case "ping_total":
+ return database.query(PingQueries.averagePing(0L, now(), serverUUID));
+ case "ping_day":
+ return database.query(PingQueries.averagePing(dayAgo(), now(), serverUUID));
+ case "ping_week":
+ return database.query(PingQueries.averagePing(weekAgo(), now(), serverUUID));
+ case "ping_month":
+ return database.query(PingQueries.averagePing(monthAgo(), now(), serverUUID));
+
+ case "sessions_peak_count":
+ return database.query(TPSQueries.fetchAllTimePeakPlayerCount(serverUUID)).map(DateObj::getValue).orElse(0);
+ case "sessions_peak_date":
+ return database.query(TPSQueries.fetchAllTimePeakPlayerCount(serverUUID)).map(year).orElse("-");
+
+ case "sessions_recent_peak_count":
+ return database.query(TPSQueries.fetchPeakPlayerCount(serverUUID, dayAgo() * 2L)).map(DateObj::getValue).orElse(0);
+ case "sessions_recent_peak_date":
+ return database.query(TPSQueries.fetchPeakPlayerCount(serverUUID, dayAgo() * 2L)).map(year).orElse("-");
+
+ default:
+ return null;
+ }
+ }
+ // Checkstyle.ON: CyclomaticComplexity
+
+ private String getPlaytime(Database database, long after, long before, UUID serverUUID) {
+ Long playtime = database.query(SessionQueries.playtime(after, before, serverUUID));
+ Long sessionCount = database.query(SessionQueries.sessionCount(after, before, serverUUID));
+ return timeAmount.apply(sessionCount != 0 ? playtime / sessionCount : playtime);
+ }
+}
diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/WorldTimePlaceHolder.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/WorldTimePlaceHolder.java
new file mode 100644
index 000000000..30708de07
--- /dev/null
+++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/placeholders/WorldTimePlaceHolder.java
@@ -0,0 +1,66 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see .
+ */
+package com.djrapitops.plan.addons.placeholderapi.placeholders;
+
+import com.djrapitops.plan.delivery.formatting.Formatter;
+import com.djrapitops.plan.delivery.formatting.Formatters;
+import com.djrapitops.plan.gathering.domain.WorldTimes;
+import com.djrapitops.plan.identification.ServerInfo;
+import com.djrapitops.plan.storage.database.DBSystem;
+import com.djrapitops.plan.storage.database.queries.objects.WorldTimesQueries;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.entity.Player;
+
+/**
+ * Placeholders about a world times.
+ *
+ * @author aidn5, Rsl1122
+ */
+public class WorldTimePlaceHolder extends AbstractPlanPlaceHolder {
+
+ private final DBSystem dbSystem;
+ private Formatter timeAmount;
+
+ public WorldTimePlaceHolder(
+ DBSystem dbSystem,
+ ServerInfo serverInfo,
+ Formatters formatters
+ ) {
+ super(serverInfo);
+ this.dbSystem = dbSystem;
+ timeAmount = formatters.timeAmount();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String params) throws Exception {
+ String string = params.toLowerCase();
+
+ if (StringUtils.startsWith(string, "worlds_playtime_total_")) {
+ // get world total play time
+ // e.g. "plan_worlds_playtime_total_%worldname%"
+ // where %worldname% is "world_nether"
+
+ String worldName = StringUtils.removeStart(string, "worlds_playtime_total_");
+ WorldTimes worldTimes = dbSystem.getDatabase().query(WorldTimesQueries.fetchServerTotalWorldTimes(serverUUID()));
+
+ return timeAmount.apply(worldTimes.getWorldPlaytime(worldName));
+ }
+
+ return null;
+ }
+
+}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/PingMutator.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/PingMutator.java
index 3e1ff7727..faaccb675 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/PingMutator.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/PingMutator.java
@@ -20,7 +20,7 @@ import com.djrapitops.plan.delivery.domain.container.DataContainer;
import com.djrapitops.plan.delivery.domain.keys.CommonKeys;
import com.djrapitops.plan.gathering.domain.Ping;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.SortedMap;
import java.util.UUID;
@@ -36,7 +36,7 @@ public class PingMutator {
}
public static PingMutator forContainer(DataContainer container) {
- return new PingMutator(container.getValue(CommonKeys.PING).orElse(new ArrayList<>()));
+ return new PingMutator(container.getValue(CommonKeys.PING).orElse(Collections.emptyList()));
}
public PingMutator filterBy(Predicate predicate) {
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/PlayerCountQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/PlayerCountQueries.java
index a22eeebda..7bfa09ca2 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/PlayerCountQueries.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/PlayerCountQueries.java
@@ -432,4 +432,22 @@ public class PlayerCountQueries {
}
};
}
+
+ public static Query operators(UUID serverUUID) {
+ String sql = SELECT + "COUNT(1) as player_count" + FROM + UserInfoTable.TABLE_NAME +
+ WHERE + UserInfoTable.SERVER_UUID + "=?" +
+ AND + UserInfoTable.OP + "=?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setBoolean(2, true);
+ }
+
+ @Override
+ public Integer processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getInt("player_count") : 0;
+ }
+ };
+ }
}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/PingQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/PingQueries.java
index 0a820fe68..c0af918de 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/PingQueries.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/PingQueries.java
@@ -293,4 +293,25 @@ public class PingQueries {
}
};
}
+
+ public static Query averagePing(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + PingTable.AVG_PING + ") as average" + FROM + PingTable.TABLE_NAME +
+ WHERE + PingTable.SERVER_UUID + "=?" +
+ AND + PingTable.DATE + ">=?" +
+ AND + PingTable.DATE + "<=?";
+
+ return new QueryStatement(sql, 1000) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, after);
+ statement.setLong(3, before);
+ }
+
+ @Override
+ public Double processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getDouble("average") : -1.0;
+ }
+ };
+ }
}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java
index 7cd034b1b..2afa7dc24 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java
@@ -829,4 +829,26 @@ public class SessionQueries {
}
};
}
+
+ public static Query activePlaytime(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME +
+ ") as playtime" +
+ FROM + SessionsTable.TABLE_NAME +
+ WHERE + SessionsTable.SERVER_UUID + "=?" +
+ AND + SessionsTable.SESSION_END + ">=?" +
+ AND + SessionsTable.SESSION_START + "<=?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, after);
+ statement.setLong(3, before);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("playtime") : 0L;
+ }
+ };
+ }
}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java
index 4361223d8..40fd98886 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java
@@ -277,4 +277,164 @@ public class TPSQueries {
}
};
}
+
+ public static Query averageTPS(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + TPS + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Double processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getDouble("average") : -1.0;
+ }
+ };
+ }
+
+ public static Query averageCPU(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + CPU_USAGE + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Double processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getDouble("average") : -1.0;
+ }
+ };
+ }
+
+ public static Query averageRAM(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + RAM_USAGE + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("average") : -1L;
+ }
+ };
+ }
+
+ public static Query averageChunks(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + CHUNKS + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("average") : -1L;
+ }
+ };
+ }
+
+ public static Query averageEntities(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + ENTITIES + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("average") : -1L;
+ }
+ };
+ }
+
+ public static Query maxFreeDisk(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "MAX(" + FREE_DISK + ") as free" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("free") : -1L;
+ }
+ };
+ }
+
+ public static Query minFreeDisk(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "MIN(" + FREE_DISK + ") as free" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("free") : -1L;
+ }
+ };
+ }
+
+ public static Query averageFreeDisk(long after, long before, UUID serverUUID) {
+ String sql = SELECT + "AVG(" + FREE_DISK + ") as average" + FROM + TABLE_NAME +
+ WHERE + SERVER_ID + '=' + ServerTable.STATEMENT_SELECT_SERVER_ID +
+ AND + DATE + "" +
+ AND + DATE + ">?";
+ return new QueryStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, serverUUID.toString());
+ statement.setLong(2, before);
+ statement.setLong(3, after);
+ }
+
+ @Override
+ public Long processResults(ResultSet set) throws SQLException {
+ return set.next() ? set.getLong("average") : -1L;
+ }
+ };
+ }
}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/Predicates.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/Predicates.java
index 030f7543b..2117b067f 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/Predicates.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/Predicates.java
@@ -31,7 +31,7 @@ public class Predicates {
/* static method class */
}
- public static Predicate within(long after, long before) {
+ public static Predicate within(long after, long before) {
return holder -> {
long date = holder.getDate();
return after < date && date <= before;
diff --git a/Plan/common/src/main/resources/assets/plan/web/error.html b/Plan/common/src/main/resources/assets/plan/web/error.html
index f7ed77f1d..e45166375 100644
--- a/Plan/common/src/main/resources/assets/plan/web/error.html
+++ b/Plan/common/src/main/resources/assets/plan/web/error.html
@@ -188,6 +188,7 @@
Player Analytics is developed by Rsl1122.
In addition following awesome people have contributed:
+ - aidn5
- Argetan
- BrainStone
- CyanTech
diff --git a/Plan/common/src/main/resources/assets/plan/web/network.html b/Plan/common/src/main/resources/assets/plan/web/network.html
index 30307fc8b..58e98f3b3 100644
--- a/Plan/common/src/main/resources/assets/plan/web/network.html
+++ b/Plan/common/src/main/resources/assets/plan/web/network.html
@@ -730,6 +730,7 @@
Player Analytics is developed by Rsl1122.
In addition following awesome people have contributed:
+ - aidn5
- Argetan
- Aurelien
- BrainStone
diff --git a/Plan/common/src/main/resources/assets/plan/web/player.html b/Plan/common/src/main/resources/assets/plan/web/player.html
index 3f979d3b7..63e4a5fc6 100644
--- a/Plan/common/src/main/resources/assets/plan/web/player.html
+++ b/Plan/common/src/main/resources/assets/plan/web/player.html
@@ -655,6 +655,7 @@
Player Analytics is developed by Rsl1122.
In addition following awesome people have contributed:
+ - aidn5
- Argetan
- Aurelien
- BrainStone
diff --git a/Plan/common/src/main/resources/assets/plan/web/players.html b/Plan/common/src/main/resources/assets/plan/web/players.html
index 06db87740..2cc813bcf 100644
--- a/Plan/common/src/main/resources/assets/plan/web/players.html
+++ b/Plan/common/src/main/resources/assets/plan/web/players.html
@@ -197,6 +197,7 @@
Player Analytics is developed by Rsl1122.
In addition following awesome people have contributed:
+ - aidn5
- Argetan
- Aurelien
- BrainStone
diff --git a/Plan/common/src/main/resources/assets/plan/web/server.html b/Plan/common/src/main/resources/assets/plan/web/server.html
index 7083ac2df..f1f757eb1 100644
--- a/Plan/common/src/main/resources/assets/plan/web/server.html
+++ b/Plan/common/src/main/resources/assets/plan/web/server.html
@@ -1201,6 +1201,7 @@
Player Analytics is developed by Rsl1122.
In addition following awesome people have contributed:
+ - aidn5
- Argetan
- Aurelien
- BrainStone
diff --git a/Plan/common/src/main/resources/plugin.yml b/Plan/common/src/main/resources/plugin.yml
index ddebc4394..57e091636 100644
--- a/Plan/common/src/main/resources/plugin.yml
+++ b/Plan/common/src/main/resources/plugin.yml
@@ -27,6 +27,7 @@ softdepend:
- Towny
- Vault
- ViaVersion
+ - PlaceholderAPI
commands:
plan:
diff --git a/Plan/config/checkstyle/checkstyle.xml b/Plan/config/checkstyle/checkstyle.xml
index c832d6569..b43afdfe9 100644
--- a/Plan/config/checkstyle/checkstyle.xml
+++ b/Plan/config/checkstyle/checkstyle.xml
@@ -16,6 +16,12 @@
+
+
+
+
+
+