From 87eaeabd7f90427f9505ae4a1c34b41a90c9829f Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 30 Nov 2016 21:41:59 -0500 Subject: [PATCH] Document and clean up StatsManager --- .../achievement/command/StatsCommand.java | 35 +- .../repository/DonationRepository.java | 4 +- .../src/mineplex/core/stats/PlayerStats.java | 89 ++-- .../src/mineplex/core/stats/Stat.java | 20 +- .../src/mineplex/core/stats/StatsManager.java | 486 +++++++++--------- .../mineplex/core/stats/StatsRepository.java | 135 ++--- .../core/stats/command/GiveStatCommand.java | 2 +- .../stats/command/MasterBuilderUnban.java | 2 +- .../core/stats/command/TimeCommand.java | 36 +- .../mineplex/core/utils/UtilScheduler.java | 6 + .../playtime/command/PlayTimeCommand.java | 36 +- .../customerSupport/CustomerSupport.java | 6 +- 12 files changed, 400 insertions(+), 457 deletions(-) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/achievement/command/StatsCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/achievement/command/StatsCommand.java index 384bdf996..f25cb32ce 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/achievement/command/StatsCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/achievement/command/StatsCommand.java @@ -1,6 +1,7 @@ package mineplex.core.achievement.command; import mineplex.core.stats.PlayerStats; + import org.bukkit.entity.Player; import mineplex.core.achievement.AchievementManager; @@ -35,7 +36,7 @@ public class StatsCommand extends CommandBase if (Plugin.getClientManager().hasRank(caller, Rank.MODERATOR)) attemptOffline(caller, args); return; } - + if (/* StaffServer special case */Plugin.getIncognito() != null && Plugin.getIncognito().Get(target).Hidden) { UtilPlayer.message(caller, @@ -59,35 +60,17 @@ public class StatsCommand extends CommandBase UtilPlayer.message(caller, F.main("Stats", "Attempting to look up offline stats...")); final String playerName = args[0]; - Plugin.runAsync(() -> { - try + Plugin.getStatsManager().getOfflinePlayerStats(args[0], stats -> + { + if (stats == null) { - PlayerStats stats = Plugin.getStatsManager().getOfflinePlayerStats(playerName); - - if (stats == null) - { - Plugin.runSync(() -> offlinePlayerNotFound(caller, playerName)); - } - else - { - Plugin.runSync(() -> openShop(caller, playerName, stats)); - } - } catch (SQLException e) + UtilPlayer.message(caller, F.main("Stats", "Offline Player " + F.elem(playerName) + " not found.")); + } + else { - Plugin.runSync(() -> UtilPlayer.message(caller, F.main("Stats", "There was an error trying to look up offline player " + F.elem(playerName)))); - e.printStackTrace(); + Plugin.openShop(caller, playerName, stats); } }); } } - - private void offlinePlayerNotFound(Player caller, String searchName) - { - UtilPlayer.message(caller, F.main("Stats", "Offline Player " + F.elem(searchName) + " not found.")); - } - - private void openShop(Player caller, String searchName, PlayerStats playerStats) - { - Plugin.openShop(caller, searchName, playerStats); - } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/donation/repository/DonationRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/donation/repository/DonationRepository.java index 80b4beb8b..6363d018b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/donation/repository/DonationRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/donation/repository/DonationRepository.java @@ -35,7 +35,7 @@ public class DonationRepository extends MinecraftRepository } /** - * Purchases a known sales package.. whatever that means + * Purchases a known sales package * * @param playerName The player name * @param salesPackageId The package id @@ -58,7 +58,7 @@ public class DonationRepository extends MinecraftRepository } /** - * Purchases an unknown sales package... or something + * Purchases an unknown sales package * * @param playerName The name of the player * @param packageName The name of the unknown package diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/PlayerStats.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/PlayerStats.java index 8bf28aa5b..8b9f4e229 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/PlayerStats.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/PlayerStats.java @@ -1,41 +1,72 @@ package mineplex.core.stats; -import java.util.Set; - -import mineplex.core.common.util.NautHashMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +/** + * Represents a player's statistic information. This object is thread-safe + */ public class PlayerStats { - private NautHashMap _statHash = new NautHashMap(); - - public long addStat(String statName, long value) + private final Object lock = new Object(); + + private Map _stats = new HashMap<>(); + + /** + * Add a value to the specified stat + * + * @param statName The name of the stat + * @param value The value, must be positive + * @return The new value for the specified stat + */ + long addStat(String statName, long value) { - value = Math.max(0L, value); - - if (!_statHash.containsKey(statName)) + synchronized (lock) { - _statHash.put(statName, 0L); + return _stats.merge(statName, Math.max(0, value), Long::sum); } - - _statHash.put(statName, _statHash.get(statName) + value); - - return _statHash.get(statName); - } - - public long setStat(String statName, long value) - { - _statHash.put(statName, value); - - return _statHash.get(statName); - } - - public long getStat(String statName) - { - return _statHash.containsKey(statName) ? _statHash.get(statName) : 0L; } - public Set getStatsNames() - { - return _statHash.keySet(); + /** + * Sets the value of the specified stat + * + * @param statName The name of the stat + * @param value The value, must be positive + * @return The new value for the specified stat + */ + long setStat(String statName, long value) + { + synchronized (lock) + { + _stats.put(statName, value); + return value; + } + } + + /** + * Gets the value for the specified stat + * + * @param statName The name of the stat + * @return The value of the stat if it exists, or 0 if it does not + */ + public long getStat(String statName) + { + synchronized (lock) + { + return _stats.getOrDefault(statName, 0L); + } + } + + /** + * Returns a view of the all the stats. This view will not be updated + */ + public Map getStats() + { + synchronized (lock) + { + // make it unmodifiable so that people who try to edit it will get an exception instead of silently failing + return Collections.unmodifiableMap(new HashMap<>(_stats)); + } } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/Stat.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/Stat.java index 534251521..a2dcec041 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/Stat.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/Stat.java @@ -2,6 +2,22 @@ package mineplex.core.stats; public class Stat { - public int Id; - public String Name; + private int id; + private String name; + + public Stat(int id, String name) + { + this.id = id; + this.name = name; + } + + public int getId() + { + return id; + } + + public String getName() + { + return name; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsManager.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsManager.java index 8b52886cb..05c2bad00 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsManager.java @@ -2,317 +2,270 @@ package mineplex.core.stats; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Iterator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.Future; +import java.util.function.Consumer; -import mineplex.cache.player.PlayerInfo; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.cache.player.PlayerCache; import mineplex.core.MiniDbClientPlugin; +import mineplex.core.account.CoreClient; import mineplex.core.account.CoreClientManager; -import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTasks; import mineplex.core.stats.command.GiveStatCommand; import mineplex.core.stats.command.MasterBuilderUnban; import mineplex.core.stats.command.TimeCommand; import mineplex.core.stats.event.StatChangeEvent; +import mineplex.core.thread.ThreadPool; +import mineplex.core.updater.UpdateType; +import mineplex.core.utils.UtilScheduler; +/** + * This manager handles player statistics + */ public class StatsManager extends MiniDbClientPlugin { - private static final Object _statSync = new Object(); - - private StatsRepository _repository; - - private NautHashMap _stats = new NautHashMap(); - private NautHashMap> _statUploadQueue = new NautHashMap<>(); - private NautHashMap> _statUploadQueueOverRidable = new NautHashMap<>(); + private static final Object STATS_LOCK = new Object(); - private Runnable _saveRunnable; - - public StatsManager(JavaPlugin plugin, CoreClientManager clientManager) + private final CoreClientManager _coreClientManager; + private final StatsRepository _repository; + + private final Map _stats = new HashMap<>(); + private final Map> _statUploadQueue = new HashMap<>(); + private final Map> _statUploadQueueOverRidable = new HashMap<>(); + + public StatsManager(JavaPlugin plugin, CoreClientManager clientManager) { super("Stats Manager", plugin, clientManager); - _repository = new StatsRepository(plugin); - - if (_saveRunnable == null) + _repository = new StatsRepository(); + _coreClientManager = clientManager; + + UtilScheduler.runAsyncEvery(UpdateType.SEC, () -> { - _saveRunnable = new Runnable() - { - public void run() - { - saveStats(); - overRidableSaveStats(); - } - }; - - plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, _saveRunnable, 20L, 20L); - } - + save(_statUploadQueue, _repository::saveStats, "normal"); + save(_statUploadQueueOverRidable, map -> _repository.saveStats(map, true), "override"); + }); + for (Stat stat : _repository.retrieveStats()) { - _stats.put(stat.Name, stat.Id); + _stats.put(stat.getName(), stat.getId()); } } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) + + /** + * Gets offline stats for the specified player name + * + * @return A Future to listen to, if you are already off the main thread + */ + public Future getOfflinePlayerStats(String playerName) { - PlayerStats playerStats = Get(event.getPlayer()); - - final int accountId = getClientManager().getAccountId(event.getPlayer()); - - for (String statName : playerStats.getStatsNames()) + return getOfflinePlayerStats(playerName, null); + } + + /** + * Gets offline stats for the specified player name + * + * @param action The action to perform with the fetched PlayerStats. This action will be performed on the main thread. Can be null + * @return A Future to listen to, should you already be off the main thread + */ + public Future getOfflinePlayerStats(String playerName, Consumer action) + { + return ThreadPool.ASYNC.submit(() -> { - if (!_stats.containsKey(statName)) - continue; - - final int statId = _stats.get(statName); - - if (playerStats.getStat(statName) == -1) + PlayerStats stats = _repository.loadOfflinePlayerStats(playerName); + UtilTasks.onMainThread(action).accept(stats); + return stats; + }); + } + + + /** + * Increments a stat for the given player by the specified amount + * + * @param value The value, must be greater or equal to zero + */ + public void incrementStat(Player player, String statName, long value) + { + if (value < 0) + return; + + long oldValue = Get(player).getStat(statName); + long newValue = Get(player).addStat(statName, value); + + UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, oldValue, newValue)); + registerNewStat(statName, () -> addToQueue(statName, player, value)); + } + + + /** + * Sets the value of a stat for the given player + * + * @param value The value, must be greater or equal to zero + */ + public void setStat(Player player, String statName, long value) + { + if (value < 0) + return; + + long oldValue = Get(player).getStat(statName); + Get(player).setStat(statName, value); + + UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, oldValue, value)); + registerNewStat(statName, () -> addToOverRidableQueue(statName, player, value)); + } + + /** + * Increments a stat for the given account ID of an offline player by the specified amount + */ + public void incrementStat(final int accountId, final String statName, final long value) + { + registerNewStat(statName, () -> + { + Map> uploadQueue = new HashMap<>(); + uploadQueue.computeIfAbsent(accountId, key -> new HashMap<>()).put(_stats.get(statName), value); + + _repository.saveStats(uploadQueue, false); + }); + } + + /** + * Sets the value of a stat for the given account ID of an offline player + * + * @param value The value, must be greater or equal to zero + */ + public void setStat(final int accountId, final String statName, final long value) + { + if (value < 0) + return; + + registerNewStat(statName, () -> + { + Map> uploadQueue = new HashMap<>(); + uploadQueue.computeIfAbsent(accountId, key -> new HashMap<>()).put(_stats.get(statName), value); + + _repository.saveStats(uploadQueue, true); + }); + } + + private void addToOverRidableQueue(String statName, Player player, long value) + { + synchronized (STATS_LOCK) + { + _statUploadQueueOverRidable + .computeIfAbsent(_coreClientManager.Get(player), key -> new HashMap<>()) + .put(statName, value); + } + } + + private void addToQueue(String statName, Player player, long value) + { + synchronized (STATS_LOCK) + { + _statUploadQueue + .computeIfAbsent(_coreClientManager.Get(player), key -> new HashMap<>()) + .merge(statName, value, Long::sum); + } + } + + protected void save(Map> statsMap, Consumer>> action, String type) + { + if (statsMap.isEmpty()) + return; + + Map> uploadQueue = new HashMap<>(); + + try + { + synchronized (STATS_LOCK) { - runAsync(new Runnable() + statsMap.entrySet().removeIf(entry -> { - public void run() + CoreClient client = entry.getKey(); + if (Bukkit.getPlayer(client.getUniqueId()) != null) + return false; + + Map uploadStats = uploadQueue.computeIfAbsent(client.getAccountId(), key -> new HashMap<>()); + + entry.getValue().forEach((statName, amount) -> { - _repository.setStat(accountId, statId, 0); - } + // Sanity check + if (_stats.containsKey(statName)) + { + uploadStats.merge(_stats.get(statName), amount, Long::sum); + System.out.println(String.format("Saving stat '%s' for '%s', value '%s', type '%s'", statName, client.getName(), uploadStats.get(_stats.get(statName)), type)); + } + }); + + return true; }); } } - } - - public void incrementStat(final Player player, final String statName, final long value) - { - incrementStat(player, statName, value, false); - } - - public void incrementStat(final Player player, final String statName, final long value, boolean overRide) - { - if (value <= 0) - return; - - long newValue = Get(player).addStat(statName, value); - - //Event - UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, newValue - value, newValue)); - - // Verify stat is in our local cache, if not add it remotely. - registerNewStat(statName, new Runnable() - { - @Override - public void run() - { - if(overRide) - { - addToOverRidableQueue(statName, player, value); - } - else - { - addToQueue(statName, player, value); - } - } - }); - } - - private void addToOverRidableQueue(String statName, Player player, long value) - { - synchronized (_statSync) - { - if (!_statUploadQueueOverRidable.containsKey(player.getUniqueId())) - _statUploadQueueOverRidable.put(player.getUniqueId(), new NautHashMap()); - - if (!_statUploadQueueOverRidable.get(player.getUniqueId()).containsKey(statName)) - _statUploadQueueOverRidable.get(player.getUniqueId()).put(statName, 0L); - - _statUploadQueueOverRidable.get(player.getUniqueId()).put(statName, _statUploadQueueOverRidable.get(player.getUniqueId()).get(statName) + value); - } - } - - protected void overRidableSaveStats() - { - if (_statUploadQueueOverRidable.isEmpty()) - return; - - try - { - NautHashMap> uploadQueue = new NautHashMap>(); - - synchronized (_statSync) - { - for (Iterator statIterator = _statUploadQueueOverRidable.keySet().iterator(); statIterator.hasNext();) - { - UUID player = statIterator.next(); - - if (Bukkit.getPlayer(player) != null) - continue; - - try - { - PlayerInfo info = PlayerCache.getInstance().getPlayer(player); - - uploadQueue.put(info.getAccountId(), new NautHashMap<>()); - - for (String statName : _statUploadQueueOverRidable.get(player).keySet()) - { - int statId = _stats.get(statName); - uploadQueue.get(info.getAccountId()).put(statId, _statUploadQueueOverRidable.get(player).get(statName)); - System.out.println(info.getName() + " saving stat : " + statName + " overriding " + _statUploadQueueOverRidable.get(player).get(statName)); - } - - statIterator.remove(); - } - catch (Exception e) - { - //System.out.println("[StatsManager] AccountId was not set for " + player.getName()); - } - } - } - - _repository.saveStats(uploadQueue, true); - } catch (Exception exception) { exception.printStackTrace(); } - } - - private void addToQueue(String statName, Player player, long value) - { - synchronized (_statSync) + finally { - if (!_statUploadQueue.containsKey(player.getUniqueId())) - _statUploadQueue.put(player.getUniqueId(), new NautHashMap()); - - if (!_statUploadQueue.get(player.getUniqueId()).containsKey(statName)) - _statUploadQueue.get(player.getUniqueId()).put(statName, 0L); - - _statUploadQueue.get(player.getUniqueId()).put(statName, _statUploadQueue.get(player.getUniqueId()).get(statName) + value); + action.accept(uploadQueue); } } - protected void saveStats() - { - if (_statUploadQueue.isEmpty()) - return; - - try - { - NautHashMap> uploadQueue = new NautHashMap>(); - - synchronized (_statSync) - { - for (Iterator statIterator = _statUploadQueue.keySet().iterator(); statIterator.hasNext();) - { - UUID player = statIterator.next(); - - if (Bukkit.getPlayer(player) != null) - continue; - - try - { - PlayerInfo info = PlayerCache.getInstance().getPlayer(player); - - uploadQueue.put(info.getAccountId(), new NautHashMap()); - - for (String statName : _statUploadQueue.get(player).keySet()) - { - int statId = _stats.get(statName); - uploadQueue.get(info.getAccountId()).put(statId, _statUploadQueue.get(player).get(statName)); - System.out.println(info.getName() + " saving stat : " + statName + " adding " + _statUploadQueue.get(player).get(statName)); - } - - statIterator.remove(); - } - catch (Exception e) - { - //System.out.println("[StatsManager] AccountId was not set for " + player.getName()); - } - } - } - - _repository.saveStats(uploadQueue); - } - catch (Exception exception) - { - exception.printStackTrace(); - } - } - - public boolean incrementStat(final int accountId, final String statName, final long value) - { - return incrementStat(accountId, statName, value, false); - } - - public boolean incrementStat(final int accountId, final String statName, final long value, boolean overRide) - { - // This will register a new stat if we don't have one, otherwise it will just run the callback - registerNewStat(statName, new Runnable() - { - @Override - public void run() - { - final NautHashMap> uploadQueue = new NautHashMap>(); - uploadQueue.put(accountId, new NautHashMap()); - uploadQueue.get(accountId).put(_stats.get(statName), value); - - _repository.saveStats(uploadQueue, overRide); - } - }); - - return true; - } - private void registerNewStat(final String statName, final Runnable callback) { - runAsync(new Runnable() + runAsync(() -> { - public void run() + synchronized (STATS_LOCK) { - synchronized (_statSync) + if (_stats.containsKey(statName)) { - if (_stats.containsKey(statName)) - { - if (callback != null) callback.run(); - return; - } - - _repository.addStat(statName); - - _stats.clear(); - - for (Stat stat : _repository.retrieveStats()) - { - _stats.put(stat.Name, stat.Id); - } - if (callback != null) callback.run(); + return; } + + _repository.registerNewStat(statName); + + _stats.clear(); + + for (Stat stat : _repository.retrieveStats()) + { + _stats.put(stat.getName(), stat.getId()); + } + + if (callback != null) callback.run(); } }); } - - - - public int getStatId(String statName) - { - return _stats.get(statName); - } - @Override - protected PlayerStats addPlayer(UUID uuid) + @EventHandler + private void onPlayerJoin(PlayerJoinEvent event) { - return new PlayerStats(); - } + Set statsToReset = new HashSet<>(); - public PlayerStats getOfflinePlayerStats(String playerName) throws SQLException - { - return _repository.loadOfflinePlayerStats(playerName); + Get(event.getPlayer()).getStats().forEach((stat, amount) -> + { + if (!_stats.containsKey(stat)) + return; + + if (amount == -1) + { + statsToReset.add(stat); + } + }); + + statsToReset.forEach(stat -> + { + setStat(event.getPlayer(), stat, 0); + }); } @Override @@ -323,10 +276,31 @@ public class StatsManager extends MiniDbClientPlugin addCommand(new MasterBuilderUnban(this)); } + @Override + protected PlayerStats addPlayer(UUID uuid) + { + return new PlayerStats(); + } + @Override public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException { - Set(uuid, _repository.loadClientInformation(resultSet)); + PlayerStats playerStats = new PlayerStats(); + + while (resultSet.next()) + { + try + { + playerStats.addStat(resultSet.getString(1), resultSet.getLong(2)); + } + catch (Exception ex) + { + ex.printStackTrace(); + playerStats.addStat(resultSet.getString(1), -1); + } + } + + Set(uuid, playerStats); } @Override diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsRepository.java index c52804ceb..72574fce9 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/StatsRepository.java @@ -1,19 +1,10 @@ package mineplex.core.stats; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; -import mineplex.core.common.util.NautHashMap; -import mineplex.core.database.MinecraftRepository; -import mineplex.serverdata.database.DBPool; -import mineplex.serverdata.database.ResultSetCallable; -import mineplex.serverdata.database.column.ColumnVarChar; -import mineplex.database.Tables; - -import org.bukkit.plugin.java.JavaPlugin; import org.jooq.DSLContext; import org.jooq.Insert; import org.jooq.Record2; @@ -23,53 +14,68 @@ import org.jooq.Update; import org.jooq.impl.DSL; import org.jooq.types.ULong; +import mineplex.core.database.MinecraftRepository; +import mineplex.database.Tables; +import mineplex.serverdata.database.DBPool; +import mineplex.serverdata.database.column.ColumnVarChar; + public class StatsRepository extends MinecraftRepository { - private static String RETRIEVE_STATS = "SELECT id, name FROM stats;"; - private static String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);"; + private static final String RETRIEVE_STATS = "SELECT id, name FROM stats;"; + private static final String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);"; - - public StatsRepository(JavaPlugin plugin) + public StatsRepository() { super(DBPool.getAccount()); } - + + /** + * Retrieves all the remote registered stats + * + * @return The list of stats + */ public List retrieveStats() { - final List stats = new ArrayList(); - - executeQuery(RETRIEVE_STATS, new ResultSetCallable() - { - public void processResultSet(ResultSet resultSet) throws SQLException - { - while (resultSet.next()) - { - Stat stat = new Stat(); - - stat.Id = resultSet.getInt(1); - stat.Name = resultSet.getString(2); + List stats = new ArrayList<>(); - stats.add(stat); - } + executeQuery(RETRIEVE_STATS, resultSet -> + { + while (resultSet.next()) + { + stats.add(new Stat(resultSet.getInt(1), resultSet.getString(2))); } }); - + return stats; } - - public void addStat(String name) + + /** + * Registers a stat with the remote server + * + * @param name The name of the stat + */ + public void registerNewStat(String name) { executeUpdate(INSERT_STAT, new ColumnVarChar("name", 100, name)); } - - public void saveStats(NautHashMap> uploadQueue) + + /** + * Saves the given stats + * + * @param uploadQueue A map of account ID to a map of stat IDS to values + */ + public void saveStats(Map> uploadQueue) { saveStats(uploadQueue, false); } - - @SuppressWarnings("rawtypes") - public void saveStats(NautHashMap> uploadQueue, boolean overRideStat) + /** + * Saves the given stats + * + * @param uploadQueue A map of account ID to a map of stat IDS to values + * @param overrideStat Whether to replace the remote value, or to add to it + */ + public void saveStats(Map> uploadQueue, boolean overrideStat) { try { @@ -82,22 +88,22 @@ public class StatsRepository extends MinecraftRepository { for (Integer statId : uploadQueue.get(accountId).keySet()) { - if(overRideStat) + if (overrideStat) { Update update = context .update(Tables.accountStat) .set(Tables.accountStat.value, ULong.valueOf(uploadQueue.get(accountId).get(statId))) .where(Tables.accountStat.accountId.eq(accountId)) .and(Tables.accountStat.statId.eq(statId)); - updates.add(update); + updates.add(update); } else { Update update = context - .update(Tables.accountStat) - .set(Tables.accountStat.value, Tables.accountStat.value.plus(uploadQueue.get(accountId).get(statId))) - .where(Tables.accountStat.accountId.eq(accountId)) - .and(Tables.accountStat.statId.eq(statId)); + .update(Tables.accountStat) + .set(Tables.accountStat.value, Tables.accountStat.value.plus(uploadQueue.get(accountId).get(statId))) + .where(Tables.accountStat.accountId.eq(accountId)) + .and(Tables.accountStat.statId.eq(statId)); updates.add(update); } @@ -129,6 +135,10 @@ public class StatsRepository extends MinecraftRepository } } + + /** + * Gets offline stats for the specified player name. This performs SQL on the current thread + */ public PlayerStats loadOfflinePlayerStats(String playerName) { PlayerStats playerStats = null; @@ -161,43 +171,4 @@ public class StatsRepository extends MinecraftRepository return playerStats; } - - public PlayerStats loadClientInformation(ResultSet resultSet) throws SQLException - { - final PlayerStats playerStats = new PlayerStats(); - - while (resultSet.next()) - { - try - { - playerStats.addStat(resultSet.getString(1), resultSet.getLong(2)); - } - catch (Exception ex) - { - ex.printStackTrace(); - playerStats.addStat(resultSet.getString(1), -1); - } - } - - return playerStats; - } - - public void setStat(int accountId, int statId, long value) - { - try - { - DSLContext context = DSL.using(getConnectionPool(), SQLDialect.MYSQL); - - context - .update(Tables.accountStat) - .set(Tables.accountStat.value, ULong.valueOf(value)) - .where(Tables.accountStat.accountId.eq(accountId)) - .and(Tables.accountStat.statId.eq(statId)) - .execute(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/GiveStatCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/GiveStatCommand.java index 688a8aaa8..2e584379b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/GiveStatCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/GiveStatCommand.java @@ -53,7 +53,7 @@ public class GiveStatCommand extends CommandBase Plugin.incrementStat(player, statName, Integer.parseInt(args[args.length - 1])); } - UtilPlayer.message(caller, F.main("Stats", "Applied " + F.elem(Integer.parseInt(args[args.length - 1]) + " " + statName) + " to " + F.elem(player.getName()) + ".")); + UtilPlayer.message(caller, F.main("Stats", "Applied " + F.elem(Integer.parseInt(args[args.length - 1]) + " " + statName) + " to " + F.elem(player == null ? args[0] : player.getName()) + ".")); } catch (Exception e) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/MasterBuilderUnban.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/MasterBuilderUnban.java index a5784bd2d..ab22079ea 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/MasterBuilderUnban.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/MasterBuilderUnban.java @@ -72,7 +72,7 @@ public class MasterBuilderUnban extends CommandBase { if(theClient != null) { - Plugin.incrementStat(theClient.getAccountId(), "Global.Build Draw Abuse", 0, true); // True = Resets the stat + Plugin.setStat(theClient.getAccountId(), "Global.Build Draw Abuse", 0); caller.sendMessage(F.main("MasterBuilder Unban", "The user " + target + " has been unbanned from Master Builders")); } else diff --git a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/TimeCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/TimeCommand.java index 42fe8b841..4b616c9e4 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/stats/command/TimeCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/stats/command/TimeCommand.java @@ -35,36 +35,16 @@ public class TimeCommand extends CommandBase if (target == null) { - Plugin.getPlugin().getServer().getScheduler().runTaskAsynchronously(Plugin.getPlugin(), new Runnable() + Plugin.getOfflinePlayerStats(args[0], stats -> { - @Override - public void run() + if (stats == null) { - try - { - final PlayerStats stats = Plugin.getOfflinePlayerStats(args[0]); - - Plugin.getPlugin().getServer().getScheduler().runTask(Plugin.getPlugin(), new Runnable() - { - @Override - public void run() - { - if (stats == null) - { - UtilPlayer.message(caller, F.main("Time", "Player " + F.elem(args[0]) + " not found!")); - } - else - { - long time = stats.getStat("Global.TimeInGame"); - UtilPlayer.message(caller, F.main("Time", F.name(args[0]) + " has spent " + F.elem(UtilTime.convertString(time * 1000L, 1, UtilTime.TimeUnit.FIT)) + " in game")); - } - } - }); - } - catch (SQLException e) - { - e.printStackTrace(); - } + UtilPlayer.message(caller, F.main("Time", "Player " + F.elem(args[0]) + " not found!")); + } + else + { + long time = stats.getStat("Global.TimeInGame"); + UtilPlayer.message(caller, F.main("Time", F.name(args[0]) + " has spent " + F.elem(UtilTime.convertString(time * 1000L, 1, UtilTime.TimeUnit.FIT)) + " in game")); } }); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/utils/UtilScheduler.java b/Plugins/Mineplex.Core/src/mineplex/core/utils/UtilScheduler.java index 32b96489d..d83cda20f 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/utils/UtilScheduler.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/utils/UtilScheduler.java @@ -12,4 +12,10 @@ public class UtilScheduler Plugin plugin = UtilServer.getPlugin(); plugin.getServer().getScheduler().runTaskTimer(plugin, action, 0, (int) Math.ceil(speed.getMilliseconds() / 50.0)); } + + public static void runAsyncEvery(UpdateType speed, Runnable action) + { + Plugin plugin = UtilServer.getPlugin(); + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, action, 0, (int) Math.ceil(speed.getMilliseconds() / 50.0)); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/playtime/command/PlayTimeCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/playtime/command/PlayTimeCommand.java index 30b82b248..61b9fc451 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/playtime/command/PlayTimeCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/playtime/command/PlayTimeCommand.java @@ -38,36 +38,16 @@ public class PlayTimeCommand extends CommandBase if (target == null) { - Plugin.getPlugin().getServer().getScheduler().runTaskAsynchronously(Plugin.getPlugin(), new Runnable() + Plugin.getOfflinePlayerStats(args[0], stats -> { - @Override - public void run() + if (stats == null) { - try - { - final PlayerStats stats = Plugin.getOfflinePlayerStats(args[0]); - - Plugin.getPlugin().getServer().getScheduler().runTask(Plugin.getPlugin(), new Runnable() - { - @Override - public void run() - { - if (stats == null) - { - UtilPlayer.message(caller, F.main("Clans", "Player " + F.elem(args[0]) + " not found!")); - } - else - { - long time = stats.getStat(ClansPlayerStats.PLAY_TIME.id()); - UtilPlayer.message(caller, F.main("Clans", F.name(args[0]) + " has spent " + F.elem(UtilTime.convertString(time * 1000L, 1, UtilTime.TimeUnit.FIT)) + " playing Clans.")); - } - } - }); - } - catch (SQLException e) - { - UtilPlayer.message(caller, F.main("Clans", F.name(target.getName()) + " does not have any play time in Clans.")); - } + UtilPlayer.message(caller, F.main("Clans", "Player " + F.elem(args[0]) + " not found!")); + } + else + { + long time = stats.getStat(ClansPlayerStats.PLAY_TIME.id()); + UtilPlayer.message(caller, F.main("Clans", F.name(args[0]) + " has spent " + F.elem(UtilTime.convertString(time * 1000L, 1, UtilTime.TimeUnit.FIT)) + " playing Clans.")); } }); } diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java index a51055ca9..f9cd84940 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java @@ -10,6 +10,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.UUID; +import java.util.concurrent.ExecutionException; import org.bukkit.Bukkit; import org.bukkit.GameMode; @@ -342,12 +343,13 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable { try { - PlayerStats playerStats = statsManager.getOfflinePlayerStats(playerName); + PlayerStats playerStats = statsManager.getOfflinePlayerStats(playerName).get(); if (playerStats != null) { hauntedChestsOpened = (int) playerStats.getStat("Global.Treasure.Haunted"); } - } catch (SQLException e) + } + catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }