Update stats and leaderboard code to be cleaner and better organized
This commit is contained in:
parent
835b50c683
commit
0d708a99f4
@ -108,11 +108,6 @@ public class LeaderboardManager extends MiniPlugin
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleStatIncrease(Map<Integer, Map<Integer, Long>> stats)
|
|
||||||
{
|
|
||||||
_repo.insertStats(stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerIfNotExists(String identifier, LeaderboardDisplay display)
|
public void registerIfNotExists(String identifier, LeaderboardDisplay display)
|
||||||
{
|
{
|
||||||
if (_leaderboards.containsKey(identifier))
|
if (_leaderboards.containsKey(identifier))
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package mineplex.core.leaderboard;
|
package mineplex.core.leaderboard;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
@ -24,9 +23,6 @@ public class LeaderboardRepository extends RepositoryBase
|
|||||||
private static final String CREATE_DAILY = "CREATE TABLE accountStatsDaily (accountId INT NOT NULL, statId INT NOT NULL, date DATE NOT NULL, value BIGINT NOT NULL, PRIMARY KEY (accountId, statId), INDEX valueIndex (value DESC), INDEX dateIndex (date), FOREIGN KEY (accountId) REFERENCES accounts(id), FOREIGN KEY (statId) REFERENCES stats(id));";
|
private static final String CREATE_DAILY = "CREATE TABLE accountStatsDaily (accountId INT NOT NULL, statId INT NOT NULL, date DATE NOT NULL, value BIGINT NOT NULL, PRIMARY KEY (accountId, statId), INDEX valueIndex (value DESC), INDEX dateIndex (date), FOREIGN KEY (accountId) REFERENCES accounts(id), FOREIGN KEY (statId) REFERENCES stats(id));";
|
||||||
private static final String CREATE_SEASON = "CREATE TABLE statSeasons (id SMALLINT NOT NULL, seasonName VARCHAR(50) NOT NULL, startDate TIMESTAMP NOT NULL DEFAULT '1969-12-31 18:00:01', endDate TIMESTAMP NOT NULL DEFAULT '1969-12-31 18:00:01', PRIMARY KEY (id), UNIQUE INDEX seasonIndex (seasonName), INDEX startIndex (startDate), INDEX endIndex (endDate));";
|
private static final String CREATE_SEASON = "CREATE TABLE statSeasons (id SMALLINT NOT NULL, seasonName VARCHAR(50) NOT NULL, startDate TIMESTAMP NOT NULL DEFAULT '1969-12-31 18:00:01', endDate TIMESTAMP NOT NULL DEFAULT '1969-12-31 18:00:01', PRIMARY KEY (id), UNIQUE INDEX seasonIndex (seasonName), INDEX startIndex (startDate), INDEX endIndex (endDate));";
|
||||||
|
|
||||||
private static final String INSERT_STAT = "INSERT INTO accountStatsAllTime (accountId, statId, value) VALUES (?, ?, ?);";
|
|
||||||
private static final String UPDATE_STAT = "UPDATE accountStatsAllTime SET value=value + ? WHERE accountId=? AND statId=?;";
|
|
||||||
|
|
||||||
private static final String FETCH_STAT_ALL = "SELECT a.name, a.uuid, sl.value FROM (SELECT accountId, value FROM accountStatsAllTime WHERE statId=(SELECT id FROM stats WHERE name='%STAT%') ORDER BY value DESC LIMIT %START%,%LIMIT%) AS sl INNER JOIN accounts AS a ON a.id=sl.accountId;";
|
private static final String FETCH_STAT_ALL = "SELECT a.name, a.uuid, sl.value FROM (SELECT accountId, value FROM accountStatsAllTime WHERE statId=(SELECT id FROM stats WHERE name='%STAT%') ORDER BY value DESC LIMIT %START%,%LIMIT%) AS sl INNER JOIN accounts AS a ON a.id=sl.accountId;";
|
||||||
|
|
||||||
private static final String FETCH_STAT_YEARLY = "SELECT a.name, a.uuid, sl.value FROM (SELECT accountId, value FROM accountStatsYearly WHERE (date BETWEEN MAKEDATE(YEAR(CURDATE()),1) AND CURDATE()) AND statId=(SELECT id FROM stats WHERE name='%STAT%') ORDER BY value DESC LIMIT %START%,%LIMIT%) AS sl INNER JOIN accounts AS a ON a.id=sl.accountId;";
|
private static final String FETCH_STAT_YEARLY = "SELECT a.name, a.uuid, sl.value FROM (SELECT accountId, value FROM accountStatsYearly WHERE (date BETWEEN MAKEDATE(YEAR(CURDATE()),1) AND CURDATE()) AND statId=(SELECT id FROM stats WHERE name='%STAT%') ORDER BY value DESC LIMIT %START%,%LIMIT%) AS sl INNER JOIN accounts AS a ON a.id=sl.accountId;";
|
||||||
@ -41,90 +37,6 @@ public class LeaderboardRepository extends RepositoryBase
|
|||||||
super(DBPool.getAccount());
|
super(DBPool.getAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertStats(Map<Integer, Map<Integer, Long>> stats)
|
|
||||||
{
|
|
||||||
UtilServer.runAsync(() ->
|
|
||||||
{
|
|
||||||
try (
|
|
||||||
Connection c = getConnection();
|
|
||||||
PreparedStatement updateStat = c.prepareStatement(UPDATE_STAT);
|
|
||||||
PreparedStatement insertStat = c.prepareStatement(INSERT_STAT);
|
|
||||||
)
|
|
||||||
{
|
|
||||||
for (Integer accountId : stats.keySet())
|
|
||||||
{
|
|
||||||
for (Integer statId : stats.get(accountId).keySet())
|
|
||||||
{
|
|
||||||
updateStat.setLong(1, stats.get(accountId).get(statId));
|
|
||||||
updateStat.setInt(2, accountId);
|
|
||||||
updateStat.setInt(3, statId);
|
|
||||||
updateStat.addBatch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int[] rowsAffected = updateStat.executeBatch();
|
|
||||||
int i = 0;
|
|
||||||
for (Integer accountId : stats.keySet())
|
|
||||||
{
|
|
||||||
for (Integer statId : stats.get(accountId).keySet())
|
|
||||||
{
|
|
||||||
if (rowsAffected[i] < 1)
|
|
||||||
{
|
|
||||||
insertStat.setInt(1, accountId);
|
|
||||||
insertStat.setInt(2, statId);
|
|
||||||
insertStat.setLong(3, stats.get(accountId).get(statId));
|
|
||||||
insertStat.addBatch();
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
insertStat.executeBatch();
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertStats(int accountId, Map<Integer, Long> stats)
|
|
||||||
{
|
|
||||||
UtilServer.runAsync(() ->
|
|
||||||
{
|
|
||||||
try (
|
|
||||||
Connection c = getConnection();
|
|
||||||
PreparedStatement updateStat = c.prepareStatement(UPDATE_STAT);
|
|
||||||
PreparedStatement insertStat = c.prepareStatement(INSERT_STAT);
|
|
||||||
)
|
|
||||||
{
|
|
||||||
for (Integer statId : stats.keySet())
|
|
||||||
{
|
|
||||||
updateStat.setLong(1, stats.get(statId));
|
|
||||||
updateStat.setInt(2, accountId);
|
|
||||||
updateStat.setInt(3, statId);
|
|
||||||
updateStat.addBatch();
|
|
||||||
}
|
|
||||||
int[] rowsAffected = updateStat.executeBatch();
|
|
||||||
int i = 0;
|
|
||||||
for (Integer statId : stats.keySet())
|
|
||||||
{
|
|
||||||
if (rowsAffected[i] < 1)
|
|
||||||
{
|
|
||||||
insertStat.setInt(1, accountId);
|
|
||||||
insertStat.setInt(2, statId);
|
|
||||||
insertStat.setLong(3, stats.get(statId));
|
|
||||||
insertStat.addBatch();
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
insertStat.executeBatch();
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadLeaderboard(Leaderboard board, Consumer<Map<String, Long>> leaderboard)
|
public void loadLeaderboard(Leaderboard board, Consumer<Map<String, Long>> leaderboard)
|
||||||
{
|
{
|
||||||
UtilServer.runAsync(() ->
|
UtilServer.runAsync(() ->
|
||||||
|
@ -18,9 +18,6 @@ public class PlayerStats
|
|||||||
@GuardedBy("_lock")
|
@GuardedBy("_lock")
|
||||||
private Map<String, Long> _stats = new HashMap<>();
|
private Map<String, Long> _stats = new HashMap<>();
|
||||||
|
|
||||||
@GuardedBy("_lock")
|
|
||||||
private Map<String, Long> _statsOld = new HashMap<>();
|
|
||||||
|
|
||||||
private final boolean _temporary;
|
private final boolean _temporary;
|
||||||
|
|
||||||
public PlayerStats(boolean temporary)
|
public PlayerStats(boolean temporary)
|
||||||
@ -64,14 +61,6 @@ public class PlayerStats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStatOld(String statName, long value)
|
|
||||||
{
|
|
||||||
synchronized (_lock)
|
|
||||||
{
|
|
||||||
_statsOld.put(statName, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value for the specified stat
|
* Gets the value for the specified stat
|
||||||
*
|
*
|
||||||
@ -79,24 +68,6 @@ public class PlayerStats
|
|||||||
* @return The value of the stat if it exists, or 0 if it does not
|
* @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)
|
||||||
{
|
|
||||||
synchronized (_lock)
|
|
||||||
{
|
|
||||||
long cur = _stats.getOrDefault(statName, 0L);
|
|
||||||
long old = _statsOld.getOrDefault(statName, 0L);
|
|
||||||
return cur + (old > cur ? old - cur : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getStatOld(String statName)
|
|
||||||
{
|
|
||||||
synchronized (_lock)
|
|
||||||
{
|
|
||||||
return _statsOld.getOrDefault(statName, 0L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getJustCurrentStat(String statName)
|
|
||||||
{
|
{
|
||||||
synchronized (_lock)
|
synchronized (_lock)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ import mineplex.core.utils.UtilScheduler;
|
|||||||
/**
|
/**
|
||||||
* This manager handles player statistics
|
* This manager handles player statistics
|
||||||
*/
|
*/
|
||||||
public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlugin<PlayerStats>
|
public class StatsManager extends MiniClientPlugin<PlayerStats>
|
||||||
{
|
{
|
||||||
public enum Perm implements Permission
|
public enum Perm implements Permission
|
||||||
{
|
{
|
||||||
@ -52,63 +52,27 @@ public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlu
|
|||||||
|
|
||||||
private final CoreClientManager _coreClientManager;
|
private final CoreClientManager _coreClientManager;
|
||||||
private final StatsRepository _repository;
|
private final StatsRepository _repository;
|
||||||
private final LeaderboardManager _leaderboard;
|
|
||||||
|
|
||||||
private final Map<String, Integer> _stats = new HashMap<>();
|
private final Map<String, Integer> _stats = new HashMap<>();
|
||||||
private final Map<CoreClient, Map<String, Long>> _statUploadQueue = new HashMap<>();
|
private final Map<CoreClient, Map<String, Long>> _statUploadQueue = new HashMap<>();
|
||||||
private final Map<CoreClient, Map<String, Long>> _statUploadQueueOverRidable = new HashMap<>();
|
|
||||||
|
|
||||||
private final Set<UUID> _loading = Collections.synchronizedSet(new HashSet<>());
|
private final Set<UUID> _loading = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
public StatsManager(JavaPlugin plugin, CoreClientManager clientManager)
|
public StatsManager(JavaPlugin plugin, CoreClientManager clientManager)
|
||||||
{
|
{
|
||||||
//super("Stats Manager", plugin, clientManager);
|
|
||||||
super("Stats Manager", plugin);
|
super("Stats Manager", plugin);
|
||||||
|
|
||||||
_repository = new StatsRepository();
|
_repository = new StatsRepository();
|
||||||
_coreClientManager = clientManager;
|
_coreClientManager = clientManager;
|
||||||
|
|
||||||
_leaderboard = new LeaderboardManager(this);
|
new LeaderboardManager(this);
|
||||||
|
|
||||||
/*clientManager.addStoredProcedureLoginProcessor(new ILoginProcessor()
|
|
||||||
{
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return "Stat Old Selector";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
|
|
||||||
{
|
|
||||||
PlayerStats stats = Get(uuid);
|
|
||||||
|
|
||||||
while (resultSet.next())
|
|
||||||
{
|
|
||||||
stats.setStatOld(resultSet.getString(1), resultSet.getLong(2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getQuery(int accountId, String uuid, String name)
|
|
||||||
{
|
|
||||||
return "SELECT stats.name, value FROM accountStat INNER JOIN stats ON stats.id = accountStat.statId WHERE accountStat.accountId = '" + accountId + "';";
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
|
|
||||||
UtilScheduler.runAsyncEvery(UpdateType.SEC, () ->
|
UtilScheduler.runAsyncEvery(UpdateType.SEC, () ->
|
||||||
{
|
{
|
||||||
save(_statUploadQueue, map ->
|
save(_statUploadQueue, map ->
|
||||||
{
|
{
|
||||||
//_repository.saveStats(map);
|
_repository.insertStats(map);
|
||||||
_repository.saveOnlyExisting(map);
|
|
||||||
_leaderboard.handleStatIncrease(map);
|
|
||||||
}, "increment");
|
}, "increment");
|
||||||
save(_statUploadQueueOverRidable, map ->
|
|
||||||
{
|
|
||||||
//_repository.saveStats(map, true);
|
|
||||||
_repository.saveOnlyExisting(map);
|
|
||||||
_leaderboard.handleStatIncrease(map);
|
|
||||||
}, "override");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (Stat stat : _repository.retrieveStats())
|
for (Stat stat : _repository.retrieveStats())
|
||||||
@ -180,38 +144,13 @@ public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long oldCompositeValue = snapshot.getStat(statName);
|
long oldValue = snapshot.getStat(statName);
|
||||||
long newValue = snapshot.addStat(statName, value);
|
long newValue = snapshot.addStat(statName, value);
|
||||||
|
|
||||||
UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player, statName, oldCompositeValue, newValue));
|
UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player, statName, oldValue, newValue));
|
||||||
registerNewStat(statName, () -> addToQueue(statName, client, value));
|
registerNewStat(statName, () -> addToQueue(statName, client, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value of a stat for the given player
|
|
||||||
*
|
|
||||||
* @param value The value, must be greater or equal to zero
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setStat(Player player, String statName, long value)
|
|
||||||
{
|
|
||||||
if (value < 0)
|
|
||||||
return;
|
|
||||||
if (0 == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreClient client = _coreClientManager.Get(player);
|
|
||||||
|
|
||||||
long oldValue = Get(player).getStat(statName);
|
|
||||||
Get(player).setStat(statName, value);
|
|
||||||
|
|
||||||
UtilServer.getServer().getPluginManager().callEvent(new StatChangeEvent(player, statName, oldValue, value));
|
|
||||||
registerNewStat(statName, () -> addToOverRidableQueue(statName, client, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments a stat for the given account ID of an <b>offline player</b> by the specified amount
|
* Increments a stat for the given account ID of an <b>offline player</b> by the specified amount
|
||||||
*/
|
*/
|
||||||
@ -219,58 +158,13 @@ public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlu
|
|||||||
{
|
{
|
||||||
registerNewStat(statName, () ->
|
registerNewStat(statName, () ->
|
||||||
{
|
{
|
||||||
Map<Integer, Map<Integer, Long>> uploadQueue = new HashMap<>();
|
Map<Integer, Long> stats = new HashMap<>();
|
||||||
uploadQueue.computeIfAbsent(accountId, key -> new HashMap<>()).put(_stats.get(statName), value);
|
stats.put(_stats.get(statName), value);
|
||||||
|
|
||||||
_repository.saveStats(uploadQueue, false);
|
_repository.insertStats(accountId, stats);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setStat(final int accountId, final String statName, final long value)
|
|
||||||
{
|
|
||||||
if (value < 0)
|
|
||||||
return;
|
|
||||||
if (0 == 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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private void addToOverRidableQueue(String statName, CoreClient client, long value)
|
|
||||||
{
|
|
||||||
if (0 == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (client.getAccountId() == -1)
|
|
||||||
{
|
|
||||||
System.out.println(String.format("Error: Tried to add %s/%s to overridable queue with -1 account id", client.getName(), client.getUniqueId()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (STATS_LOCK)
|
|
||||||
{
|
|
||||||
_statUploadQueueOverRidable
|
|
||||||
.computeIfAbsent(client, key -> new HashMap<>())
|
|
||||||
.put(statName, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToQueue(String statName, CoreClient client, long value)
|
private void addToQueue(String statName, CoreClient client, long value)
|
||||||
{
|
{
|
||||||
if (client.getAccountId() == -1)
|
if (client.getAccountId() == -1)
|
||||||
@ -369,17 +263,13 @@ public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlu
|
|||||||
final UUID uuid = event.getPlayer().getUniqueId();
|
final UUID uuid = event.getPlayer().getUniqueId();
|
||||||
final int accountId = _coreClientManager.Get(event.getPlayer()).getAccountId();
|
final int accountId = _coreClientManager.Get(event.getPlayer()).getAccountId();
|
||||||
UtilPlayer.message(event.getPlayer(), F.main(getName(), "Loading your stats..."));
|
UtilPlayer.message(event.getPlayer(), F.main(getName(), "Loading your stats..."));
|
||||||
runAsync(() ->
|
runSyncLater(() ->
|
||||||
{
|
{
|
||||||
_repository.loadStatsFromOld(accountId, data ->
|
_repository.loadStats(accountId, data ->
|
||||||
{
|
{
|
||||||
PlayerStats stats = new PlayerStats(false);
|
PlayerStats stats = new PlayerStats(false);
|
||||||
|
|
||||||
data.forEach((stat, values) ->
|
data.forEach(stats::setStat);
|
||||||
{
|
|
||||||
stats.setStatOld(stat, values.getLeft());
|
|
||||||
stats.addStat(stat, values.getRight());
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_loading.remove(uuid))
|
if (_loading.remove(uuid))
|
||||||
{
|
{
|
||||||
@ -431,33 +321,4 @@ public class StatsManager extends MiniClientPlugin<PlayerStats>//MiniDbClientPlu
|
|||||||
{
|
{
|
||||||
return _coreClientManager;
|
return _coreClientManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @Override
|
|
||||||
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
|
|
||||||
{
|
|
||||||
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
|
|
||||||
public String getQuery(int accountId, String uuid, String name)
|
|
||||||
{
|
|
||||||
return "SELECT stats.name, value FROM accountStatsAllTime INNER JOIN stats ON stats.id = accountStatsAllTime.statId WHERE accountStatsAllTime.accountId = '" + accountId + "';";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
@ -2,36 +2,29 @@ package mineplex.core.stats;
|
|||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jooq.DSLContext;
|
|
||||||
import org.jooq.Insert;
|
|
||||||
import org.jooq.Record2;
|
|
||||||
import org.jooq.Result;
|
|
||||||
import org.jooq.SQLDialect;
|
|
||||||
import org.jooq.Update;
|
|
||||||
import org.jooq.impl.DSL;
|
|
||||||
import org.jooq.types.ULong;
|
|
||||||
|
|
||||||
import com.mysql.jdbc.exceptions.jdbc4.MySQLDataException;
|
import com.mysql.jdbc.exceptions.jdbc4.MySQLDataException;
|
||||||
|
|
||||||
import mineplex.core.common.Pair;
|
|
||||||
import mineplex.core.common.util.UtilServer;
|
import mineplex.core.common.util.UtilServer;
|
||||||
import mineplex.database.Tables;
|
|
||||||
import mineplex.serverdata.database.DBPool;
|
import mineplex.serverdata.database.DBPool;
|
||||||
import mineplex.serverdata.database.RepositoryBase;
|
import mineplex.serverdata.database.RepositoryBase;
|
||||||
|
import mineplex.serverdata.database.column.ColumnInt;
|
||||||
import mineplex.serverdata.database.column.ColumnVarChar;
|
import mineplex.serverdata.database.column.ColumnVarChar;
|
||||||
|
|
||||||
public class StatsRepository extends RepositoryBase
|
public class StatsRepository extends RepositoryBase
|
||||||
{
|
{
|
||||||
|
private static final String SELECT_ACCOUNT_STATS = "SELECT stats.name, accountStatsAllTime.value FROM accountStatsAllTime INNER JOIN stats ON stats.id = accountStatsAllTime.statId WHERE accountStatsAllTime.accountId=?;";
|
||||||
|
private static final String SELECT_USER_STATS = "SELECT stats.name, accountStatsAllTime.value FROM accountStatsAllTime INNER JOIN stats ON stats.id = accountStatsAllTime.statId WHERE accountStatsAllTime.accountId=(SELECT id FROM accounts WHERE name=? ORDER BY lastLogin DESC LIMIT 1);";
|
||||||
|
|
||||||
|
private static final String INSERT_ACCOUNT_STAT = "INSERT INTO accountStatsAllTime (accountId, statId, value) VALUES (?, ?, ?);";
|
||||||
|
private static final String UPDATE_ACCOUNT_STAT = "UPDATE accountStatsAllTime SET value=value + ? WHERE accountId=? AND statId=?;";
|
||||||
|
|
||||||
private static final String RETRIEVE_STATS = "SELECT id, name FROM stats;";
|
private static final String RETRIEVE_STATS = "SELECT id, name FROM stats;";
|
||||||
private static final String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);";
|
private static final String INSERT_STAT = "INSERT INTO stats (name) VALUES (?);";
|
||||||
|
|
||||||
@ -40,66 +33,6 @@ public class StatsRepository extends RepositoryBase
|
|||||||
super(DBPool.getAccount());
|
super(DBPool.getAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadStatsFromOld(int accountId, Consumer<Map<String, Pair<Long, Long>>> callback)
|
|
||||||
{
|
|
||||||
try (Connection c = getConnection();
|
|
||||||
PreparedStatement oldStatement = c.prepareStatement("SELECT stats.name, value FROM accountStat INNER JOIN stats ON stats.id = accountStat.statId WHERE accountStat.accountId=?;");
|
|
||||||
PreparedStatement newStatement = c.prepareStatement("SELECT stats.name, value FROM accountStatsAllTime INNER JOIN stats ON stats.id = accountStatsAllTime.statId WHERE accountStatsAllTime.accountId=?;");
|
|
||||||
)
|
|
||||||
{
|
|
||||||
oldStatement.setInt(1, accountId);
|
|
||||||
newStatement.setInt(1, accountId);
|
|
||||||
try (ResultSet oldSet = oldStatement.executeQuery();
|
|
||||||
ResultSet newSet = newStatement.executeQuery();
|
|
||||||
)
|
|
||||||
{
|
|
||||||
final Map<String, Pair<Long, Long>> statMap = new HashMap<>();
|
|
||||||
while (oldSet.next())
|
|
||||||
{
|
|
||||||
String statName = oldSet.getString(1);
|
|
||||||
long oldValue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
oldValue = oldSet.getLong(2);
|
|
||||||
}
|
|
||||||
catch (MySQLDataException ex)
|
|
||||||
{
|
|
||||||
oldValue = 0;
|
|
||||||
}
|
|
||||||
statMap.put(statName, Pair.create(oldValue, 0L));
|
|
||||||
}
|
|
||||||
while (newSet.next())
|
|
||||||
{
|
|
||||||
String statName = newSet.getString(1);
|
|
||||||
long newValue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
newValue = newSet.getLong(2);
|
|
||||||
}
|
|
||||||
catch (MySQLDataException ex)
|
|
||||||
{
|
|
||||||
newValue = 0;
|
|
||||||
}
|
|
||||||
if (statMap.containsKey(statName))
|
|
||||||
{
|
|
||||||
statMap.get(statName).setRight(newValue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
statMap.put(statName, Pair.create(0L, newValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UtilServer.runSync(() -> callback.accept(statMap));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
UtilServer.runSync(() -> callback.accept(new HashMap<>()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all the remote registered stats
|
* Retrieves all the remote registered stats
|
||||||
*
|
*
|
||||||
@ -129,7 +62,7 @@ public class StatsRepository extends RepositoryBase
|
|||||||
{
|
{
|
||||||
try (Connection c = getConnection())
|
try (Connection c = getConnection())
|
||||||
{
|
{
|
||||||
executeInsert(c, "INSERT INTO stats (name) VALUES (?);", rs -> onComplete.run(), () -> {}, new ColumnVarChar("name", 100, name));
|
executeInsert(c, INSERT_STAT, rs -> onComplete.run(), () -> {}, new ColumnVarChar("name", 100, name));
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
{
|
{
|
||||||
@ -137,111 +70,33 @@ public class StatsRepository extends RepositoryBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveOnlyExisting(Map<Integer, Map<Integer, Long>> uploadQueue)
|
public void loadStats(int accountId, Consumer<Map<String, Long>> callback)
|
||||||
{
|
{
|
||||||
try (Connection c = getConnection();
|
UtilServer.runAsync(() ->
|
||||||
PreparedStatement ps = c.prepareStatement("UPDATE accountStat SET value=value+? WHERE accountId=? AND statId=?;");
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
for (Entry<Integer, Map<Integer, Long>> accountEntry : uploadQueue.entrySet())
|
Map<String, Long> loaded = new HashMap<>();
|
||||||
|
executeQuery(SELECT_ACCOUNT_STATS, resultSet ->
|
||||||
{
|
{
|
||||||
int accountId = accountEntry.getKey();
|
while (resultSet.next())
|
||||||
for (Entry<Integer, Long> statEntry : accountEntry.getValue().entrySet())
|
|
||||||
{
|
{
|
||||||
int statId = statEntry.getKey();
|
String statName = resultSet.getString(1);
|
||||||
long delta = statEntry.getValue();
|
long value;
|
||||||
ps.setLong(1, delta);
|
try
|
||||||
ps.setInt(2, accountId);
|
|
||||||
ps.setInt(3, statId);
|
|
||||||
ps.addBatch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ps.executeBatch();
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<Integer, Map<Integer, Long>> uploadQueue, boolean overrideStat)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DSLContext context = DSL.using(getConnectionPool(), SQLDialect.MYSQL);
|
|
||||||
|
|
||||||
List<Update> updates = new ArrayList<>();
|
|
||||||
List<Insert> inserts = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int accountId : uploadQueue.keySet())
|
|
||||||
{
|
|
||||||
for (Integer statId : uploadQueue.get(accountId).keySet())
|
|
||||||
{
|
|
||||||
if (overrideStat)
|
|
||||||
{
|
{
|
||||||
Update update = context
|
value = resultSet.getLong(2);
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
else
|
catch (MySQLDataException ex)
|
||||||
{
|
{
|
||||||
Update update = context
|
value = 0;
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
|
loaded.put(statName, value);
|
||||||
Insert insert = context
|
|
||||||
.insertInto(Tables.accountStat)
|
|
||||||
.set(Tables.accountStat.accountId, accountId)
|
|
||||||
.set(Tables.accountStat.statId, statId)
|
|
||||||
.set(Tables.accountStat.value, ULong.valueOf(uploadQueue.get(accountId).get(statId)));
|
|
||||||
|
|
||||||
inserts.add(insert);
|
|
||||||
}
|
}
|
||||||
}
|
}, new ColumnInt("accountId", accountId));
|
||||||
|
|
||||||
int[] updateResult = context.batch(updates).execute();
|
UtilServer.runSync(() -> callback.accept(loaded));
|
||||||
|
});
|
||||||
for (int i = 0; i < updateResult.length; i++)
|
|
||||||
{
|
|
||||||
if (updateResult[i] > 0)
|
|
||||||
inserts.set(i, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
inserts.removeIf(Objects::isNull);
|
|
||||||
|
|
||||||
context.batch(inserts).execute();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
System.out.println("Failed to save stats: " + uploadQueue);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets offline stats for the specified player name. This performs SQL on the current thread
|
* Gets offline stats for the specified player name. This performs SQL on the current thread
|
||||||
*/
|
*/
|
||||||
@ -249,32 +104,113 @@ public class StatsRepository extends RepositoryBase
|
|||||||
{
|
{
|
||||||
PlayerStats playerStats = null;
|
PlayerStats playerStats = null;
|
||||||
|
|
||||||
DSLContext context;
|
Map<String, Long> loaded = new HashMap<>();
|
||||||
|
executeQuery(SELECT_USER_STATS, resultSet ->
|
||||||
synchronized (this)
|
|
||||||
{
|
{
|
||||||
context = DSL.using(getConnectionPool(), SQLDialect.MYSQL);
|
while (resultSet.next())
|
||||||
}
|
{
|
||||||
|
String statName = resultSet.getString(1);
|
||||||
|
long value;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
value = resultSet.getLong(2);
|
||||||
|
}
|
||||||
|
catch (MySQLDataException ex)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
loaded.put(statName, value);
|
||||||
|
}
|
||||||
|
}, new ColumnVarChar("name", playerName.length(), playerName));
|
||||||
|
|
||||||
Result<Record2<String, ULong>> result = context.select(Tables.stats.name, Tables.accountStat.value).from(Tables.accountStat)
|
if (!loaded.isEmpty())
|
||||||
.join(Tables.stats)
|
|
||||||
.on(Tables.stats.id.eq(Tables.accountStat.statId))
|
|
||||||
.where(Tables.accountStat.accountId.eq(DSL.select(Tables.accounts.id)
|
|
||||||
.from(Tables.accounts)
|
|
||||||
.where(Tables.accounts.name.eq(playerName)).limit(1))
|
|
||||||
)
|
|
||||||
.fetch();
|
|
||||||
|
|
||||||
|
|
||||||
if (result.isNotEmpty())
|
|
||||||
{
|
{
|
||||||
playerStats = new PlayerStats(false);
|
playerStats = new PlayerStats(false);
|
||||||
for (Record2<String, ULong> record : result)
|
loaded.forEach(playerStats::addStat);
|
||||||
{
|
|
||||||
playerStats.addStat(record.value1(), record.value2().longValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return playerStats;
|
return playerStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insertStats(Map<Integer, Map<Integer, Long>> stats)
|
||||||
|
{
|
||||||
|
UtilServer.runAsync(() ->
|
||||||
|
{
|
||||||
|
try (Connection c = getConnection();
|
||||||
|
PreparedStatement updateStat = c.prepareStatement(UPDATE_ACCOUNT_STAT);
|
||||||
|
PreparedStatement insertStat = c.prepareStatement(INSERT_ACCOUNT_STAT);
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (Integer accountId : stats.keySet())
|
||||||
|
{
|
||||||
|
for (Integer statId : stats.get(accountId).keySet())
|
||||||
|
{
|
||||||
|
updateStat.setLong(1, stats.get(accountId).get(statId));
|
||||||
|
updateStat.setInt(2, accountId);
|
||||||
|
updateStat.setInt(3, statId);
|
||||||
|
updateStat.addBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[] rowsAffected = updateStat.executeBatch();
|
||||||
|
int i = 0;
|
||||||
|
for (Integer accountId : stats.keySet())
|
||||||
|
{
|
||||||
|
for (Integer statId : stats.get(accountId).keySet())
|
||||||
|
{
|
||||||
|
if (rowsAffected[i] < 1)
|
||||||
|
{
|
||||||
|
insertStat.setInt(1, accountId);
|
||||||
|
insertStat.setInt(2, statId);
|
||||||
|
insertStat.setLong(3, stats.get(accountId).get(statId));
|
||||||
|
insertStat.addBatch();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertStat.executeBatch();
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertStats(int accountId, Map<Integer, Long> stats)
|
||||||
|
{
|
||||||
|
UtilServer.runAsync(() ->
|
||||||
|
{
|
||||||
|
try (Connection c = getConnection();
|
||||||
|
PreparedStatement updateStat = c.prepareStatement(UPDATE_ACCOUNT_STAT);
|
||||||
|
PreparedStatement insertStat = c.prepareStatement(INSERT_ACCOUNT_STAT);
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (Integer statId : stats.keySet())
|
||||||
|
{
|
||||||
|
updateStat.setLong(1, stats.get(statId));
|
||||||
|
updateStat.setInt(2, accountId);
|
||||||
|
updateStat.setInt(3, statId);
|
||||||
|
updateStat.addBatch();
|
||||||
|
}
|
||||||
|
int[] rowsAffected = updateStat.executeBatch();
|
||||||
|
int i = 0;
|
||||||
|
for (Integer statId : stats.keySet())
|
||||||
|
{
|
||||||
|
if (rowsAffected[i] < 1)
|
||||||
|
{
|
||||||
|
insertStat.setInt(1, accountId);
|
||||||
|
insertStat.setInt(2, statId);
|
||||||
|
insertStat.setLong(3, stats.get(statId));
|
||||||
|
insertStat.addBatch();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
insertStat.executeBatch();
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
@ -38,6 +38,12 @@ public class GiveStatCommand extends CommandBase<StatsManager>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (amount < 1)
|
||||||
|
{
|
||||||
|
UtilPlayer.message(caller, F.main("Stats", "That amount is invalid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String statName = StringUtils.join(args, " ", 2, args.length);
|
String statName = StringUtils.join(args, " ", 2, args.length);
|
||||||
|
|
||||||
if (player == null)
|
if (player == null)
|
||||||
|
Loading…
Reference in New Issue
Block a user