diff --git a/pom.xml b/pom.xml
index c68f5e2..79b030e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,26 +78,9 @@
provided
-
- org.mcstats.bukkit
- metrics
- R8-SNAPSHOT
- compile
-
-
- org.bukkit
- bukkit
-
-
- org.bukkit
- craftbukkit
-
-
-
-
org.bstats
- bstats-bukkit-lite
+ bstats-bukkit
1.7
compile
@@ -326,6 +309,24 @@
${project.name}
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+ true
+
+
+ true
+
+
+ ${buildType}
+ ${maven.build.timestamp}
+ ${java.runtime.version}
+
+
+
+
maven-compiler-plugin
3.6.1
@@ -347,7 +348,6 @@
- org.mcstats.bukkit
org.bstats:*
net.gravitydevelopment.updater
com.j256.ormlite
@@ -356,10 +356,6 @@
-
- org.mcstats
- com.Acrobot.ChestShop.Metrics.MCStats
-
org.bstats
com.Acrobot.ChestShop.Metrics.BStats
@@ -394,6 +390,7 @@
UTF-8
${buildNumber}
+ ${buildType}
${project.version} ${buildDescription}
@@ -463,6 +460,7 @@
+ manual
0
(compiled at ${maven.build.timestamp})
@@ -476,6 +474,7 @@
+ jenkins
${env.BUILD_NUMBER}
(build ${env.BUILD_NUMBER})
diff --git a/src/main/java/com/Acrobot/Breeze/Utils/NumberUtil.java b/src/main/java/com/Acrobot/Breeze/Utils/NumberUtil.java
index 8cc0d7f..c775ff7 100644
--- a/src/main/java/com/Acrobot/Breeze/Utils/NumberUtil.java
+++ b/src/main/java/com/Acrobot/Breeze/Utils/NumberUtil.java
@@ -154,4 +154,14 @@ public class NumberUtil {
return Integer.toString(number);
}
}
+
+ /**
+ * Convert a long to an integer while not overflowing but returning Integer.MAX_VALUE
+ *
+ * @param number The long to convert
+ * @return The integer value or Integer.MAX_VALUE on overflow
+ */
+ public static int toInt(long number) {
+ return number > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) number;
+ }
}
diff --git a/src/main/java/com/Acrobot/ChestShop/ChestShop.java b/src/main/java/com/Acrobot/ChestShop/ChestShop.java
index 90f4bae..18334e5 100644
--- a/src/main/java/com/Acrobot/ChestShop/ChestShop.java
+++ b/src/main/java/com/Acrobot/ChestShop/ChestShop.java
@@ -19,6 +19,7 @@ import com.Acrobot.ChestShop.Listeners.AuthMeChestShopListener;
import com.Acrobot.ChestShop.Listeners.GarbageTextListener;
import com.Acrobot.ChestShop.Listeners.Item.ItemMoveListener;
import com.Acrobot.ChestShop.Listeners.ItemInfoListener;
+import com.Acrobot.ChestShop.Listeners.Modules.MetricsModule;
import com.Acrobot.ChestShop.Listeners.SignParseListener;
import com.Acrobot.ChestShop.Listeners.Modules.DiscountModule;
import com.Acrobot.ChestShop.Listeners.Modules.PriceRestrictionModule;
@@ -41,6 +42,7 @@ import com.Acrobot.ChestShop.UUIDs.NameManager;
import com.Acrobot.ChestShop.Updater.JenkinsBuildsNotifier;
import com.Acrobot.ChestShop.Updater.Updater;
+import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
@@ -53,7 +55,9 @@ import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
+import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
+import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
@@ -67,9 +71,15 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.jar.JarFile;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
/**
* Main file of the plugin
@@ -111,6 +121,7 @@ public class ChestShop extends JavaPlugin {
registerCommand("iteminfo", new ItemInfo(), Permission.ITEMINFO);
registerCommand("csVersion", new Version(), Permission.ADMIN);
+ registerCommand("csMetrics", new com.Acrobot.ChestShop.Commands.Metrics(), Permission.ADMIN);
registerCommand("csGive", new Give(), Permission.ADMIN);
registerCommand("cstoggle", new Toggle(), Permission.NOTIFY_TOGGLE);
registerCommand("csaccess", new AccessToggle(), Permission.ACCESS_TOGGLE);
@@ -376,6 +387,7 @@ public class ChestShop extends JavaPlugin {
private void registerModules() {
registerEvent(new DiscountModule());
+ registerEvent(new MetricsModule());
registerEvent(new PriceRestrictionModule());
registerEconomicalModules();
@@ -397,12 +409,49 @@ public class ChestShop extends JavaPlugin {
}
private void startStatistics() {
+ Metrics bStats = new Metrics(this, 1109);
try {
- new org.mcstats.Metrics(this).start();
- } catch (IOException ex) {
- ChestShop.getBukkitLogger().severe("There was an error while submitting MCStats statistics.");
- }
- new org.bstats.bukkit.MetricsLite(this, 1109);
+ String dist = new JarFile(this.getFile()).getManifest().getMainAttributes().getValue("Distribution-Type");
+ bStats.addCustomChart(new Metrics.SimplePie("distributionType", () -> dist));
+ } catch (IOException ignored) {}
+
+ bStats.addCustomChart(new Metrics.SingleLineChart("shopAccounts", NameManager::getAccountCount));
+ bStats.addCustomChart(new Metrics.MultiLineChart("transactionCount", () -> ImmutableMap.of(
+ "total", MetricsModule.getTotalTransactions(),
+ "buy", MetricsModule.getBuyTransactions(),
+ "sell", MetricsModule.getSellTransactions()
+ )));bStats.addCustomChart(new Metrics.MultiLineChart("itemCount", () -> ImmutableMap.of(
+ "total", MetricsModule.getTotalItemsCount(),
+ "buy", MetricsModule.getSoldItemsCount(),
+ "sell", MetricsModule.getBoughtItemsCount()
+ )));
+
+ bStats.addCustomChart(new Metrics.SimplePie("includeSettingsInMetrics", () -> Properties.INCLUDE_SETTINGS_IN_METRICS ? "enabled" : "disabled"));
+ if (!Properties.INCLUDE_SETTINGS_IN_METRICS) return;
+
+ bStats.addCustomChart(new Metrics.AdvancedBarChart("pluginProperties", () -> {
+ Map map = new LinkedHashMap<>();
+ map.put("reverse-buttons", getChartArray(Properties.REVERSE_BUTTONS));
+ map.put("shift-sells-in-stacks", getChartArray(Properties.SHIFT_SELLS_IN_STACKS));
+ map.put("shift-sells-everything", getChartArray(Properties.SHIFT_SELLS_EVERYTHING));
+ map.put("allow-sign-chest-open", getChartArray(!Properties.ALLOW_SIGN_CHEST_OPEN));
+ map.put("remove-empty-shops", getChartArray(!Properties.REMOVE_EMPTY_SHOPS));
+ map.put("remove-empty-chests", getChartArray(!Properties.REMOVE_EMPTY_CHESTS));
+ map.put("uses-server-economy-account", getChartArray(!Properties.SERVER_ECONOMY_ACCOUNT.isEmpty()));
+ map.put("uses-server-economy-account-uuid", getChartArray(!Properties.SERVER_ECONOMY_ACCOUNT_UUID.equals(new UUID(0, 0))));
+ map.put("allow-multiple-shops-at-one-block", getChartArray(Properties.ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK));
+ map.put("allow-partial-transactions", getChartArray(Properties.ALLOW_PARTIAL_TRANSACTIONS));
+ map.put("bungeecord-messages", getChartArray(Properties.BUNGEECORD_MESSAGES));
+ map.put("log-to-console", getChartArray(Properties.LOG_TO_CONSOLE));
+ map.put("log-to-file", getChartArray(Properties.LOG_TO_FILE));
+ return map;
+ }));
+ bStats.addCustomChart(new Metrics.SimpleBarChart("shopContainers",
+ () -> Properties.SHOP_CONTAINERS.stream().map(Material::name).collect(Collectors.toMap(k -> k, k -> 1))));
+ }
+
+ private int[] getChartArray(boolean value) {
+ return new int[]{value ? 1 : 0, value ? 0 : 1};
}
private static final int PROJECT_BUKKITDEV_ID = 31263;
diff --git a/src/main/java/com/Acrobot/ChestShop/Commands/Metrics.java b/src/main/java/com/Acrobot/ChestShop/Commands/Metrics.java
new file mode 100644
index 0000000..b5f5340
--- /dev/null
+++ b/src/main/java/com/Acrobot/ChestShop/Commands/Metrics.java
@@ -0,0 +1,26 @@
+package com.Acrobot.ChestShop.Commands;
+
+import com.Acrobot.ChestShop.Configuration.Messages;
+import com.Acrobot.ChestShop.Listeners.Modules.MetricsModule;
+import com.Acrobot.ChestShop.UUIDs.NameManager;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author Acrobot
+ */
+public class Metrics implements CommandExecutor {
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ sender.sendMessage(Messages.replace(Messages.METRICS,
+ "accounts", String.valueOf(NameManager.getAccountCount()),
+ "totalTransactions", String.valueOf(MetricsModule.getTotalTransactions()),
+ "buyTransactions", String.valueOf(MetricsModule.getBuyTransactions()),
+ "sellTransactions", String.valueOf(MetricsModule.getSellTransactions()),
+ "totalItems", String.valueOf(MetricsModule.getTotalItemsCount()),
+ "boughtItems", String.valueOf(MetricsModule.getBoughtItemsCount()),
+ "soldItems", String.valueOf(MetricsModule.getSoldItemsCount())
+ ));
+ return true;
+ }
+}
diff --git a/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java b/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java
index 25b3c4c..abd5426 100644
--- a/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java
+++ b/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java
@@ -16,6 +16,12 @@ public class Messages {
public static String iteminfo_book_generatopm = "&fBook Generation: &7%generation";
public static String iteminfo_lore = "&fLore: \n&r%lore";
+ @PrecededBySpace
+ public static String METRICS = "&a[Shop] &fMetrics:\n" +
+ "&fAccounts: &7%accounts\n" +
+ "&fAverage transactions: &7%totalTransactions &f(buy: &7%buyTransactions &fsell: &7%sellTransactions&f)\n" +
+ "&fAverage items traded: &7%totalItems &f(bought: &7%boughtItems &fsold: &7%soldItems&f)";
+
@PrecededBySpace
public static String ACCESS_DENIED = "You don't have permission to access that shop's storage container!";
public static String TRADE_DENIED = "You don't have permission to trade with that shop!";
diff --git a/src/main/java/com/Acrobot/ChestShop/Configuration/Properties.java b/src/main/java/com/Acrobot/ChestShop/Configuration/Properties.java
index c4b6c3b..0f732c6 100644
--- a/src/main/java/com/Acrobot/ChestShop/Configuration/Properties.java
+++ b/src/main/java/com/Acrobot/ChestShop/Configuration/Properties.java
@@ -105,6 +105,9 @@ public class Properties {
@ConfigurationComment("Do you want to turn off the automatic notifications for new development builds?")
public static boolean TURN_OFF_DEV_UPDATE_NOTIFIER = false;
+ @ConfigurationComment("Do you want to include some values of this config in the metrics? (This will not leak sensitive data but help in the development process)")
+ public static boolean INCLUDE_SETTINGS_IN_METRICS = true;
+
@PrecededBySpace
@ConfigurationComment("How large should the internal caches be?")
public static int CACHE_SIZE = 1000;
diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Modules/MetricsModule.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Modules/MetricsModule.java
new file mode 100644
index 0000000..4bf7754
--- /dev/null
+++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Modules/MetricsModule.java
@@ -0,0 +1,92 @@
+package com.Acrobot.ChestShop.Listeners.Modules;
+
+import com.Acrobot.Breeze.Utils.NumberUtil;
+import com.Acrobot.ChestShop.Events.TransactionEvent;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.inventory.ItemStack;
+
+/**
+ * @author Acrobot
+ */
+public class MetricsModule implements Listener {
+
+ private static final long RESET_MINUTES = 30;
+
+ private static long lastReset = System.currentTimeMillis();
+
+ private static int buyTransactionsLast = 0;
+ private static int sellTransactionsLast = 0;
+ private static long buyTransactionsCurrent = 0;
+ private static long sellTransactionsCurrent = 0;
+
+ private static int boughtItemsLast = 0;
+ private static int soldItemsLast = 0;
+ private static long boughtItemsCurrent = 0;
+ private static long soldItemsCurrent = 0;
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public static void onTransaction(final TransactionEvent event) {
+ checkReset();
+ switch (event.getTransactionType()) {
+ case BUY:
+ buyTransactionsCurrent++;
+ for (ItemStack itemStack : event.getStock()) {
+ boughtItemsCurrent += itemStack.getAmount();
+ }
+ break;
+ case SELL:
+ sellTransactionsCurrent++;
+ for (ItemStack itemStack : event.getStock()) {
+ soldItemsCurrent += itemStack.getAmount();
+ }
+ break;
+ }
+ }
+
+ public static int getBuyTransactions() {
+ checkReset();
+ return buyTransactionsLast;
+ }
+
+ public static int getSellTransactions() {
+ checkReset();
+ return sellTransactionsLast;
+ }
+
+ public static int getTotalTransactions() {
+ checkReset();
+ return buyTransactionsLast + sellTransactionsLast;
+ }
+
+ public static int getBoughtItemsCount() {
+ checkReset();
+ return boughtItemsLast;
+ }
+
+ public static int getSoldItemsCount() {
+ checkReset();
+ return soldItemsLast;
+ }
+
+ public static int getTotalItemsCount() {
+ checkReset();
+ return boughtItemsLast + soldItemsLast;
+ }
+
+ private static void checkReset() {
+ if (lastReset + RESET_MINUTES * 60 * 1000 < System.currentTimeMillis()) {
+ lastReset = System.currentTimeMillis();
+ buyTransactionsLast = NumberUtil.toInt(buyTransactionsCurrent);
+ buyTransactionsCurrent = 0;
+ sellTransactionsLast = NumberUtil.toInt(sellTransactionsCurrent);
+ sellTransactionsCurrent = 0;
+
+ boughtItemsLast = NumberUtil.toInt(boughtItemsCurrent);
+ boughtItemsCurrent = 0;
+ soldItemsLast = NumberUtil.toInt(soldItemsCurrent);
+ soldItemsCurrent = 0;
+ }
+ }
+}
diff --git a/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java b/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java
index 1f3aff4..f17bc78 100644
--- a/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java
+++ b/src/main/java/com/Acrobot/ChestShop/UUIDs/NameManager.java
@@ -3,6 +3,7 @@ package com.Acrobot.ChestShop.UUIDs;
import com.Acrobot.Breeze.Utils.Encoding.Base62;
import com.Acrobot.Breeze.Utils.NameUtil;
import com.Acrobot.Breeze.Collection.SimpleCache;
+import com.Acrobot.Breeze.Utils.NumberUtil;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Database.Account;
@@ -48,6 +49,14 @@ public class NameManager implements Listener {
private static Account serverEconomyAccount;
private static int uuidVersion = -1;
+ public static int getAccountCount() {
+ try {
+ return NumberUtil.toInt(accounts.queryBuilder().countOf() - 1);
+ } catch (SQLException e) {
+ return 0;
+ }
+ }
+
/**
* Get or create an account for a player
*
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index db7625b..cb473a9 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -22,6 +22,9 @@ commands:
aliases: [chestshop]
description: Shows the ChestShop's version
usage: /
+ csMetrics:
+ description: Shows ChestShop's metrics
+ usage: /
cstoggle:
description: Toggle messages to the owner of a shop
usage: /