Document and clean up StatsManager

This commit is contained in:
samczsun 2016-11-30 21:41:59 -05:00 committed by cnr
parent d291521ad1
commit 87eaeabd7f
12 changed files with 400 additions and 457 deletions

View File

@ -1,6 +1,7 @@
package mineplex.core.achievement.command; package mineplex.core.achievement.command;
import mineplex.core.stats.PlayerStats; import mineplex.core.stats.PlayerStats;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import mineplex.core.achievement.AchievementManager; import mineplex.core.achievement.AchievementManager;
@ -59,35 +60,17 @@ public class StatsCommand extends CommandBase<AchievementManager>
UtilPlayer.message(caller, F.main("Stats", "Attempting to look up offline stats...")); UtilPlayer.message(caller, F.main("Stats", "Attempting to look up offline stats..."));
final String playerName = args[0]; final String playerName = args[0];
Plugin.runAsync(() -> { Plugin.getStatsManager().getOfflinePlayerStats(args[0], stats ->
try
{ {
PlayerStats stats = Plugin.getStatsManager().getOfflinePlayerStats(playerName);
if (stats == null) if (stats == null)
{ {
Plugin.runSync(() -> offlinePlayerNotFound(caller, playerName)); UtilPlayer.message(caller, F.main("Stats", "Offline Player " + F.elem(playerName) + " not found."));
} }
else else
{ {
Plugin.runSync(() -> openShop(caller, playerName, stats)); Plugin.openShop(caller, playerName, stats);
}
} catch (SQLException e)
{
Plugin.runSync(() -> UtilPlayer.message(caller, F.main("Stats", "There was an error trying to look up offline player " + F.elem(playerName))));
e.printStackTrace();
} }
}); });
} }
} }
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);
}
} }

View File

@ -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 playerName The player name
* @param salesPackageId The package id * @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 playerName The name of the player
* @param packageName The name of the unknown package * @param packageName The name of the unknown package

View File

@ -1,41 +1,72 @@
package mineplex.core.stats; package mineplex.core.stats;
import java.util.Set; import java.util.Collections;
import java.util.HashMap;
import mineplex.core.common.util.NautHashMap; import java.util.Map;
/**
* Represents a player's statistic information. This object is thread-safe
*/
public class PlayerStats public class PlayerStats
{ {
private NautHashMap<String, Long> _statHash = new NautHashMap<String,Long>(); private final Object lock = new Object();
public long addStat(String statName, long value) private Map<String, Long> _stats = new HashMap<>();
{
value = Math.max(0L, value);
if (!_statHash.containsKey(statName)) /**
* 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)
{ {
_statHash.put(statName, 0L); synchronized (lock)
{
return _stats.merge(statName, Math.max(0, value), Long::sum);
}
} }
_statHash.put(statName, _statHash.get(statName) + value); /**
* Sets the value of the specified stat
return _statHash.get(statName); *
} * @param statName The name of the stat
* @param value The value, must be positive
public long setStat(String statName, long value) * @return The new value for the specified stat
*/
long setStat(String statName, long value)
{ {
_statHash.put(statName, value); synchronized (lock)
{
return _statHash.get(statName); _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) public long getStat(String statName)
{ {
return _statHash.containsKey(statName) ? _statHash.get(statName) : 0L; synchronized (lock)
{
return _stats.getOrDefault(statName, 0L);
}
} }
public Set<String> getStatsNames() /**
* Returns a view of the all the stats. This view will not be updated
*/
public Map<String, Long> getStats()
{ {
return _statHash.keySet(); 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));
}
} }
} }

View File

@ -2,6 +2,22 @@ package mineplex.core.stats;
public class Stat public class Stat
{ {
public int Id; private int id;
public String Name; 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;
}
} }

View File

@ -2,279 +2,229 @@ package mineplex.core.stats;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; 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.UUID;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import mineplex.cache.player.PlayerInfo;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import mineplex.cache.player.PlayerCache;
import mineplex.core.MiniDbClientPlugin; import mineplex.core.MiniDbClientPlugin;
import mineplex.core.account.CoreClient;
import mineplex.core.account.CoreClientManager; import mineplex.core.account.CoreClientManager;
import mineplex.core.common.util.NautHashMap;
import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTasks;
import mineplex.core.stats.command.GiveStatCommand; import mineplex.core.stats.command.GiveStatCommand;
import mineplex.core.stats.command.MasterBuilderUnban; import mineplex.core.stats.command.MasterBuilderUnban;
import mineplex.core.stats.command.TimeCommand; import mineplex.core.stats.command.TimeCommand;
import mineplex.core.stats.event.StatChangeEvent; 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<PlayerStats> public class StatsManager extends MiniDbClientPlugin<PlayerStats>
{ {
private static final Object _statSync = new Object(); private static final Object STATS_LOCK = new Object();
private StatsRepository _repository; private final CoreClientManager _coreClientManager;
private final StatsRepository _repository;
private NautHashMap<String, Integer> _stats = new NautHashMap<String, Integer>(); private final Map<String, Integer> _stats = new HashMap<>();
private NautHashMap<UUID, NautHashMap<String, Long>> _statUploadQueue = new NautHashMap<>(); private final Map<CoreClient, Map<String, Long>> _statUploadQueue = new HashMap<>();
private NautHashMap<UUID, NautHashMap<String, Long>> _statUploadQueueOverRidable = new NautHashMap<>(); private final Map<CoreClient, Map<String, Long>> _statUploadQueueOverRidable = new HashMap<>();
private Runnable _saveRunnable;
public StatsManager(JavaPlugin plugin, CoreClientManager clientManager) public StatsManager(JavaPlugin plugin, CoreClientManager clientManager)
{ {
super("Stats Manager", plugin, clientManager); super("Stats Manager", plugin, clientManager);
_repository = new StatsRepository(plugin); _repository = new StatsRepository();
_coreClientManager = clientManager;
if (_saveRunnable == null) UtilScheduler.runAsyncEvery(UpdateType.SEC, () ->
{ {
_saveRunnable = new Runnable() save(_statUploadQueue, _repository::saveStats, "normal");
{ save(_statUploadQueueOverRidable, map -> _repository.saveStats(map, true), "override");
public void run() });
{
saveStats();
overRidableSaveStats();
}
};
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, _saveRunnable, 20L, 20L);
}
for (Stat stat : _repository.retrieveStats()) 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<PlayerStats> getOfflinePlayerStats(String playerName)
{ {
PlayerStats playerStats = Get(event.getPlayer()); return getOfflinePlayerStats(playerName, null);
final int accountId = getClientManager().getAccountId(event.getPlayer());
for (String statName : playerStats.getStatsNames())
{
if (!_stats.containsKey(statName))
continue;
final int statId = _stats.get(statName);
if (playerStats.getStat(statName) == -1)
{
runAsync(new Runnable()
{
public void run()
{
_repository.setStat(accountId, statId, 0);
} }
/**
* 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<PlayerStats> getOfflinePlayerStats(String playerName, Consumer<PlayerStats> action)
{
return ThreadPool.ASYNC.submit(() ->
{
PlayerStats stats = _repository.loadOfflinePlayerStats(playerName);
UtilTasks.onMainThread(action).accept(stats);
return stats;
}); });
} }
}
}
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) /**
* 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) if (value < 0)
return; return;
long oldValue = Get(player).getStat(statName);
long newValue = Get(player).addStat(statName, value); long newValue = Get(player).addStat(statName, value);
//Event UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, oldValue, newValue));
UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, newValue - value, newValue)); registerNewStat(statName, () -> addToQueue(statName, player, value));
}
// Verify stat is in our local cache, if not add it remotely.
registerNewStat(statName, new Runnable() /**
* 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)
{ {
@Override if (value < 0)
public void run() return;
{
if(overRide) long oldValue = Get(player).getStat(statName);
{ Get(player).setStat(statName, value);
addToOverRidableQueue(statName, player, value);
UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player.getName(), statName, oldValue, value));
registerNewStat(statName, () -> addToOverRidableQueue(statName, player, value));
} }
else
/**
* Increments a stat for the given account ID of an <b>offline player</b> by the specified amount
*/
public void incrementStat(final int accountId, final String statName, final long value)
{ {
addToQueue(statName, player, value); registerNewStat(statName, () ->
} {
Map<Integer, Map<Integer, Long>> 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 <b>offline player</b>
*
* @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<Integer, Map<Integer, Long>> 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) private void addToOverRidableQueue(String statName, Player player, long value)
{ {
synchronized (_statSync) synchronized (STATS_LOCK)
{ {
if (!_statUploadQueueOverRidable.containsKey(player.getUniqueId())) _statUploadQueueOverRidable
_statUploadQueueOverRidable.put(player.getUniqueId(), new NautHashMap<String, Long>()); .computeIfAbsent(_coreClientManager.Get(player), key -> new HashMap<>())
.put(statName, value);
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<Integer, NautHashMap<Integer, Long>> uploadQueue = new NautHashMap<Integer, NautHashMap<Integer, Long>>();
synchronized (_statSync)
{
for (Iterator<UUID> 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) private void addToQueue(String statName, Player player, long value)
{ {
synchronized (_statSync) synchronized (STATS_LOCK)
{ {
if (!_statUploadQueue.containsKey(player.getUniqueId())) _statUploadQueue
_statUploadQueue.put(player.getUniqueId(), new NautHashMap<String, Long>()); .computeIfAbsent(_coreClientManager.Get(player), key -> new HashMap<>())
.merge(statName, value, Long::sum);
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);
} }
} }
protected void saveStats() protected void save(Map<CoreClient, Map<String, Long>> statsMap, Consumer<Map<Integer, Map<Integer, Long>>> action, String type)
{ {
if (_statUploadQueue.isEmpty()) if (statsMap.isEmpty())
return; return;
try Map<Integer, Map<Integer, Long>> uploadQueue = new HashMap<>();
{
NautHashMap<Integer, NautHashMap<Integer, Long>> uploadQueue = new NautHashMap<Integer, NautHashMap<Integer, Long>>();
synchronized (_statSync)
{
for (Iterator<UUID> statIterator = _statUploadQueue.keySet().iterator(); statIterator.hasNext();)
{
UUID player = statIterator.next();
if (Bukkit.getPlayer(player) != null)
continue;
try try
{ {
PlayerInfo info = PlayerCache.getInstance().getPlayer(player); synchronized (STATS_LOCK)
uploadQueue.put(info.getAccountId(), new NautHashMap<Integer, Long>());
for (String statName : _statUploadQueue.get(player).keySet())
{ {
int statId = _stats.get(statName); statsMap.entrySet().removeIf(entry ->
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()); CoreClient client = entry.getKey();
} if (Bukkit.getPlayer(client.getUniqueId()) != null)
} return false;
}
_repository.saveStats(uploadQueue); Map<Integer, Long> uploadStats = uploadQueue.computeIfAbsent(client.getAccountId(), key -> new HashMap<>());
entry.getValue().forEach((statName, amount) ->
{
// 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;
});
}
} }
catch (Exception exception) catch (Exception exception)
{ {
exception.printStackTrace(); exception.printStackTrace();
} }
finally
{
action.accept(uploadQueue);
} }
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<Integer, NautHashMap<Integer, Long>> uploadQueue = new NautHashMap<Integer, NautHashMap<Integer, Long>>();
uploadQueue.put(accountId, new NautHashMap<Integer, Long>());
uploadQueue.get(accountId).put(_stats.get(statName), value);
_repository.saveStats(uploadQueue, overRide);
}
});
return true;
} }
private void registerNewStat(final String statName, final Runnable callback) 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))
{ {
@ -282,37 +232,40 @@ public class StatsManager extends MiniDbClientPlugin<PlayerStats>
return; return;
} }
_repository.addStat(statName); _repository.registerNewStat(statName);
_stats.clear(); _stats.clear();
for (Stat stat : _repository.retrieveStats()) for (Stat stat : _repository.retrieveStats())
{ {
_stats.put(stat.Name, stat.Id); _stats.put(stat.getName(), stat.getId());
} }
if (callback != null) callback.run(); if (callback != null) callback.run();
} }
}
}); });
} }
@EventHandler
private void onPlayerJoin(PlayerJoinEvent event)
public int getStatId(String statName)
{ {
return _stats.get(statName); Set<String> statsToReset = new HashSet<>();
Get(event.getPlayer()).getStats().forEach((stat, amount) ->
{
if (!_stats.containsKey(stat))
return;
if (amount == -1)
{
statsToReset.add(stat);
} }
});
@Override statsToReset.forEach(stat ->
protected PlayerStats addPlayer(UUID uuid)
{ {
return new PlayerStats(); setStat(event.getPlayer(), stat, 0);
} });
public PlayerStats getOfflinePlayerStats(String playerName) throws SQLException
{
return _repository.loadOfflinePlayerStats(playerName);
} }
@Override @Override
@ -323,10 +276,31 @@ public class StatsManager extends MiniDbClientPlugin<PlayerStats>
addCommand(new MasterBuilderUnban(this)); addCommand(new MasterBuilderUnban(this));
} }
@Override
protected PlayerStats addPlayer(UUID uuid)
{
return new PlayerStats();
}
@Override @Override
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException 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 @Override

View File

@ -1,19 +1,10 @@
package mineplex.core.stats; package mineplex.core.stats;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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.DSLContext;
import org.jooq.Insert; import org.jooq.Insert;
import org.jooq.Record2; import org.jooq.Record2;
@ -23,53 +14,68 @@ import org.jooq.Update;
import org.jooq.impl.DSL; import org.jooq.impl.DSL;
import org.jooq.types.ULong; 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 public class StatsRepository extends MinecraftRepository
{ {
private static String RETRIEVE_STATS = "SELECT id, name FROM stats;"; private static final String RETRIEVE_STATS = "SELECT id, name FROM stats;";
private static String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);"; private static final String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);";
public StatsRepository()
public StatsRepository(JavaPlugin plugin)
{ {
super(DBPool.getAccount()); super(DBPool.getAccount());
} }
/**
* Retrieves all the remote registered stats
*
* @return The list of stats
*/
public List<Stat> retrieveStats() public List<Stat> retrieveStats()
{ {
final List<Stat> stats = new ArrayList<Stat>(); List<Stat> stats = new ArrayList<>();
executeQuery(RETRIEVE_STATS, new ResultSetCallable() executeQuery(RETRIEVE_STATS, resultSet ->
{
public void processResultSet(ResultSet resultSet) throws SQLException
{ {
while (resultSet.next()) while (resultSet.next())
{ {
Stat stat = new Stat(); stats.add(new Stat(resultSet.getInt(1), resultSet.getString(2)));
stat.Id = resultSet.getInt(1);
stat.Name = resultSet.getString(2);
stats.add(stat);
}
} }
}); });
return stats; 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)); executeUpdate(INSERT_STAT, new ColumnVarChar("name", 100, name));
} }
public void saveStats(NautHashMap<Integer, NautHashMap<Integer, Long>> uploadQueue) /**
* Saves the given stats
*
* @param uploadQueue A map of account ID to a map of stat IDS to values
*/
public void saveStats(Map<Integer, Map<Integer, Long>> uploadQueue)
{ {
saveStats(uploadQueue, false); saveStats(uploadQueue, false);
} }
/**
@SuppressWarnings("rawtypes") * Saves the given stats
public void saveStats(NautHashMap<Integer, NautHashMap<Integer, Long>> uploadQueue, boolean overRideStat) *
* @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<Integer, Map<Integer, Long>> uploadQueue, boolean overrideStat)
{ {
try try
{ {
@ -82,7 +88,7 @@ public class StatsRepository extends MinecraftRepository
{ {
for (Integer statId : uploadQueue.get(accountId).keySet()) for (Integer statId : uploadQueue.get(accountId).keySet())
{ {
if(overRideStat) if (overrideStat)
{ {
Update update = context Update update = context
.update(Tables.accountStat) .update(Tables.accountStat)
@ -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) public PlayerStats loadOfflinePlayerStats(String playerName)
{ {
PlayerStats playerStats = null; PlayerStats playerStats = null;
@ -161,43 +171,4 @@ public class StatsRepository extends MinecraftRepository
return playerStats; 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();
}
}
} }

View File

@ -53,7 +53,7 @@ public class GiveStatCommand extends CommandBase<StatsManager>
Plugin.incrementStat(player, statName, Integer.parseInt(args[args.length - 1])); 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) catch (Exception e)
{ {

View File

@ -72,7 +72,7 @@ public class MasterBuilderUnban extends CommandBase<StatsManager>
{ {
if(theClient != null) 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")); caller.sendMessage(F.main("MasterBuilder Unban", "The user " + target + " has been unbanned from Master Builders"));
} }
else else

View File

@ -35,19 +35,7 @@ public class TimeCommand extends CommandBase<StatsManager>
if (target == null) if (target == null)
{ {
Plugin.getPlugin().getServer().getScheduler().runTaskAsynchronously(Plugin.getPlugin(), new Runnable() Plugin.getOfflinePlayerStats(args[0], stats ->
{
@Override
public void run()
{
try
{
final PlayerStats stats = Plugin.getOfflinePlayerStats(args[0]);
Plugin.getPlugin().getServer().getScheduler().runTask(Plugin.getPlugin(), new Runnable()
{
@Override
public void run()
{ {
if (stats == null) if (stats == null)
{ {
@ -58,14 +46,6 @@ public class TimeCommand extends CommandBase<StatsManager>
long time = stats.getStat("Global.TimeInGame"); 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")); 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();
}
}
}); });
} }
else else

View File

@ -12,4 +12,10 @@ public class UtilScheduler
Plugin plugin = UtilServer.getPlugin(); Plugin plugin = UtilServer.getPlugin();
plugin.getServer().getScheduler().runTaskTimer(plugin, action, 0, (int) Math.ceil(speed.getMilliseconds() / 50.0)); 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));
}
} }

View File

@ -38,19 +38,7 @@ public class PlayTimeCommand extends CommandBase<StatsManager>
if (target == null) if (target == null)
{ {
Plugin.getPlugin().getServer().getScheduler().runTaskAsynchronously(Plugin.getPlugin(), new Runnable() Plugin.getOfflinePlayerStats(args[0], stats ->
{
@Override
public void run()
{
try
{
final PlayerStats stats = Plugin.getOfflinePlayerStats(args[0]);
Plugin.getPlugin().getServer().getScheduler().runTask(Plugin.getPlugin(), new Runnable()
{
@Override
public void run()
{ {
if (stats == null) if (stats == null)
{ {
@ -61,14 +49,6 @@ public class PlayTimeCommand extends CommandBase<StatsManager>
long time = stats.getStat(ClansPlayerStats.PLAY_TIME.id()); 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.")); 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."));
}
}
}); });
} }
else else

View File

@ -10,6 +10,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@ -342,12 +343,13 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable
{ {
try try
{ {
PlayerStats playerStats = statsManager.getOfflinePlayerStats(playerName); PlayerStats playerStats = statsManager.getOfflinePlayerStats(playerName).get();
if (playerStats != null) if (playerStats != null)
{ {
hauntedChestsOpened = (int) playerStats.getStat("Global.Treasure.Haunted"); hauntedChestsOpened = (int) playerStats.getStat("Global.Treasure.Haunted");
} }
} catch (SQLException e) }
catch (InterruptedException | ExecutionException e)
{ {
e.printStackTrace(); e.printStackTrace();
} }