mirror of
https://github.com/itHotL/PlayerStats.git
synced 2024-11-22 11:55:17 +01:00
Caught the ConcurrentModificationException and added a bunch of logging-statements for testing
This commit is contained in:
parent
2fed00fc57
commit
5d0333b823
@ -1,6 +1,7 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.filehandlers.TestFileHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
|
||||
@ -11,9 +12,12 @@ import org.bukkit.command.CommandSender;
|
||||
|
||||
public class ThreadManager {
|
||||
|
||||
private static final int threshold = 10;
|
||||
|
||||
private final Main plugin;
|
||||
private final BukkitAudiences adventure;
|
||||
private static ConfigHandler config;
|
||||
private static TestFileHandler testFile;
|
||||
private final MessageFactory messageFactory;
|
||||
|
||||
private ReloadThread reloadThread;
|
||||
@ -26,16 +30,17 @@ public class ThreadManager {
|
||||
config = c;
|
||||
messageFactory = m;
|
||||
|
||||
testFile = new TestFileHandler(plugin);
|
||||
startReloadThread(null, true);
|
||||
}
|
||||
|
||||
public void startReloadThread(CommandSender sender, boolean firstTimeLoading) {
|
||||
reloadThread = new ReloadThread(config, plugin, statThread, sender, firstTimeLoading);
|
||||
reloadThread = new ReloadThread(threshold, config, testFile, plugin, statThread, sender, firstTimeLoading);
|
||||
reloadThread.start();
|
||||
}
|
||||
|
||||
public void startStatThread(StatRequest request) {
|
||||
statThread = new StatThread(request, reloadThread, adventure, config, messageFactory, plugin);
|
||||
statThread = new StatThread(threshold, request, reloadThread, adventure, config, testFile, messageFactory, plugin);
|
||||
statThread.start();
|
||||
}
|
||||
|
||||
|
@ -11,28 +11,43 @@ import java.io.IOException;
|
||||
|
||||
public class TestFileHandler {
|
||||
|
||||
private static File testFile;
|
||||
private static FileConfiguration testConf;
|
||||
private static ConfigurationSection playerCount;
|
||||
private File testFile;
|
||||
private FileConfiguration testConf;
|
||||
private ConfigurationSection number;
|
||||
private final Main plugin;
|
||||
|
||||
private String onEnable;
|
||||
private String reload;
|
||||
private String debugging;
|
||||
private String topStat;
|
||||
|
||||
public TestFileHandler(Main p) {
|
||||
plugin = p;
|
||||
loadFile();
|
||||
onEnable = "onEnable";
|
||||
reload = "reload";
|
||||
debugging = "exception-debugging";
|
||||
topStat = "top-stat";
|
||||
}
|
||||
|
||||
public static void savePlayerCount(int count) {
|
||||
/**
|
||||
* Creates a new config section for the given threshold. Only needs to be called once, unless threshold changes.
|
||||
* @param count amount of players to calculate statistics with
|
||||
* @param threshold how small the subTasks have to become
|
||||
*/
|
||||
public void saveThreshold(int count, int threshold) {
|
||||
loadFile(count);
|
||||
String path = threshold + " threshold";
|
||||
try {
|
||||
playerCount = testConf.getConfigurationSection(count + " players");
|
||||
if (playerCount == null) {
|
||||
playerCount = testConf.createSection(count + " players");
|
||||
playerCount.createSection("onEnable");
|
||||
playerCount.createSection("individual-stat");
|
||||
playerCount.createSection("top-stat");
|
||||
number = testConf.getConfigurationSection(path);
|
||||
if (number == null) {
|
||||
number = testConf.createSection(path);
|
||||
number.createSection(onEnable);
|
||||
number.createSection(reload);
|
||||
number.createSection(debugging);
|
||||
number.createSection(topStat);
|
||||
}
|
||||
else {
|
||||
playerCount = testConf.getConfigurationSection(count + " players");
|
||||
number = testConf.getConfigurationSection(path);
|
||||
}
|
||||
saveFile();
|
||||
}
|
||||
@ -41,18 +56,49 @@ public class TestFileHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveTimeTaken(long time, String timeDescription) {
|
||||
public void logRunCount(boolean errorEncountered) {
|
||||
try {
|
||||
if (timeDescription.equalsIgnoreCase("onEnable")) {
|
||||
saveToSection(time, playerCount.getConfigurationSection("onEnable"));
|
||||
ConfigurationSection section = number.getConfigurationSection(debugging);
|
||||
if (section != null) {
|
||||
int runs = section.getInt("runs");
|
||||
section.set("runs", runs +1);
|
||||
|
||||
if (errorEncountered) {
|
||||
int errors = section.getInt("errors");
|
||||
section.set("errors", errors + 1);
|
||||
|
||||
String path = "error-" + (errors + 1) + "-during-run";
|
||||
int lastError = section.getInt("error-" + errors + "-during-run");
|
||||
|
||||
int runsUntilError = runs - lastError;
|
||||
String path2 = "until-error-" + (errors + 1);
|
||||
|
||||
section.set(path2, runsUntilError);
|
||||
section.set(path, runs);
|
||||
}
|
||||
saveFile();
|
||||
}
|
||||
else if (timeDescription.equalsIgnoreCase("individual-stat")) {
|
||||
saveToSection(time, playerCount.getConfigurationSection("individual-stat"));
|
||||
saveFile();
|
||||
}
|
||||
else if (timeDescription.equalsIgnoreCase("top-stat")) {
|
||||
saveToSection(time, playerCount.getConfigurationSection("top-stat"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs how long a certain method took for the earlier set threshold. Always make sure saveThreshold has been
|
||||
* called once before this method is called.
|
||||
* @param time how long the given action took
|
||||
* @param scenario describes which section to get. 1 means onEnable, 2 means reload, and 3 means top-stat
|
||||
*/
|
||||
public void saveTimeTaken(long time, int scenario) {
|
||||
String path = "";
|
||||
if (scenario == 1) path = onEnable;
|
||||
else if (scenario == 2) path = reload;
|
||||
else if (scenario == 3) path = topStat;
|
||||
|
||||
try {
|
||||
ConfigurationSection section = number.getConfigurationSection(path);
|
||||
if (section != null) {
|
||||
saveTimeToSection(time, section);
|
||||
saveFile();
|
||||
}
|
||||
}
|
||||
@ -61,7 +107,7 @@ public class TestFileHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveToSection(long time, ConfigurationSection section) {
|
||||
private void saveTimeToSection(long time, ConfigurationSection section) {
|
||||
if (section.contains("average")) {
|
||||
long average = section.getLong("average");
|
||||
long newAverage = ((average * (section.getKeys(false).size() -1)) + time)/section.getKeys(false).size();
|
||||
@ -75,9 +121,11 @@ public class TestFileHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFile() {
|
||||
testFile = new File(plugin.getDataFolder(), "test.yml");
|
||||
private void loadFile(int players) {
|
||||
String fileName = "test_" + players + ".yml";
|
||||
testFile = new File(plugin.getDataFolder(), fileName);
|
||||
if (!testFile.exists()) {
|
||||
plugin.getLogger().info("Attempting to create testFile...");
|
||||
createFile();
|
||||
}
|
||||
|
||||
@ -91,24 +139,23 @@ public class TestFileHandler {
|
||||
saveFile();
|
||||
}
|
||||
|
||||
private static void createFile() {
|
||||
testFile.getParentFile().mkdirs();
|
||||
private void createFile() {
|
||||
testFile.getParentFile().mkdirs();
|
||||
try {
|
||||
testFile.createNewFile();
|
||||
plugin.getLogger().info("Even though this would return false, secretly a file has been created anyway");
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean saveFile() {
|
||||
private void saveFile() {
|
||||
try {
|
||||
testConf.save(testFile);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.reload;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.UnixTimeHandler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -11,18 +11,34 @@ import java.util.concurrent.RecursiveAction;
|
||||
|
||||
public class ReloadAction extends RecursiveAction {
|
||||
|
||||
private static final int threshold = 10;
|
||||
private final int threshold;
|
||||
|
||||
private final OfflinePlayer[] players;
|
||||
private final int start;
|
||||
private final int end;
|
||||
|
||||
private final boolean whitelistOnly;
|
||||
private final boolean excludeBanned;
|
||||
private final int lastPlayedLimit;
|
||||
private final ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
|
||||
public ReloadAction(OfflinePlayer[] players,
|
||||
public ReloadAction(int threshold, OfflinePlayer[] players,
|
||||
boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit,
|
||||
ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
|
||||
this(threshold, players, 0, players.length,
|
||||
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
|
||||
}
|
||||
|
||||
protected ReloadAction(int threshold, OfflinePlayer[] players, int start, int end,
|
||||
boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit,
|
||||
ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
|
||||
this.threshold = threshold;
|
||||
this.players = players;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
this.whitelistOnly = whitelistOnly;
|
||||
this.excludeBanned = excludeBanned;
|
||||
this.lastPlayedLimit = lastPlayedLimit;
|
||||
@ -31,13 +47,15 @@ public class ReloadAction extends RecursiveAction {
|
||||
|
||||
@Override
|
||||
protected void compute() {
|
||||
if (players.length < threshold) {
|
||||
final int length = end - start;
|
||||
if (length < threshold) {
|
||||
process();
|
||||
}
|
||||
else {
|
||||
ReloadAction subTask1 = new ReloadAction(Arrays.copyOfRange(players, 0, players.length/2),
|
||||
final int split = length / 2;
|
||||
final ReloadAction subTask1 = new ReloadAction(threshold, players, start, (start + split),
|
||||
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
|
||||
ReloadAction subTask2 = new ReloadAction(Arrays.copyOfRange(players, players.length/2, players.length),
|
||||
final ReloadAction subTask2 = new ReloadAction(threshold, players, (start + split), end,
|
||||
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
|
||||
|
||||
try {
|
||||
@ -51,13 +69,19 @@ public class ReloadAction extends RecursiveAction {
|
||||
}
|
||||
|
||||
private void process() {
|
||||
for (OfflinePlayer player : players) {
|
||||
if (player.getName() != null &&
|
||||
(!whitelistOnly || player.isWhitelisted()) &&
|
||||
(!excludeBanned || !player.isBanned()) &&
|
||||
(lastPlayedLimit == 0 || UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed()))) {
|
||||
offlinePlayerUUIDs.put(player.getName(), player.getUniqueId());
|
||||
try {
|
||||
for (int i = start; i < end; i++) {
|
||||
OfflinePlayer player = players[i];
|
||||
if (player.getName() != null &&
|
||||
(!whitelistOnly || player.isWhitelisted()) &&
|
||||
(!excludeBanned || !player.isBanned()) &&
|
||||
(lastPlayedLimit == 0 || UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed()))) {
|
||||
offlinePlayerUUIDs.put(player.getName(), player.getUniqueId());
|
||||
}
|
||||
}
|
||||
} catch (ConcurrentModificationException e) {
|
||||
Bukkit.getLogger().warning("ReloadAction has thrown a ConcurrentModificationException because of " + e.getCause());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,19 +15,25 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
public class ReloadThread extends Thread {
|
||||
|
||||
private final int threshold;
|
||||
|
||||
private static ConfigHandler config;
|
||||
private static TestFileHandler testFile;
|
||||
private final Main plugin;
|
||||
|
||||
private final StatThread statThread;
|
||||
private final CommandSender sender;
|
||||
private final boolean firstTimeLoading;
|
||||
|
||||
public ReloadThread(ConfigHandler c, Main p, @Nullable StatThread s, @Nullable CommandSender se, boolean firstTime) {
|
||||
public ReloadThread(int threshold, ConfigHandler c, TestFileHandler t, Main p, @Nullable StatThread s, @Nullable CommandSender se, boolean firstTime) {
|
||||
this.threshold = threshold;
|
||||
config = c;
|
||||
testFile = t;
|
||||
plugin = p;
|
||||
|
||||
statThread = s;
|
||||
@ -55,6 +61,7 @@ public class ReloadThread extends Thread {
|
||||
if (config.reloadConfig()) {
|
||||
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(false));
|
||||
|
||||
testFile.saveTimeTaken(System.currentTimeMillis() - time, 2);
|
||||
plugin.getLogger().info("Amount of relevant players: " + OfflinePlayerHandler.getOfflinePlayerCount());
|
||||
plugin.logTimeTaken("ReloadThread", "loading offline players", time);
|
||||
if (sender != null) {
|
||||
@ -66,8 +73,8 @@ public class ReloadThread extends Thread {
|
||||
plugin.getLogger().info("Loading offline players...");
|
||||
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(true));
|
||||
|
||||
TestFileHandler.savePlayerCount(OfflinePlayerHandler.getOfflinePlayerCount());
|
||||
TestFileHandler.saveTimeTaken(System.currentTimeMillis() - time, "onEnable");
|
||||
testFile.saveThreshold(OfflinePlayerHandler.getOfflinePlayerCount(), threshold);
|
||||
testFile.saveTimeTaken(System.currentTimeMillis() - time, 1);
|
||||
plugin.getLogger().info("Amount of relevant players: " + OfflinePlayerHandler.getOfflinePlayerCount());
|
||||
plugin.logTimeTaken("ReloadThread", "loading offline players", time);
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
@ -80,18 +87,21 @@ public class ReloadThread extends Thread {
|
||||
|
||||
ConcurrentHashMap<String, UUID> playerMap = new ConcurrentHashMap<>(size);
|
||||
|
||||
ReloadAction task = new ReloadAction(offlinePlayers, config.whitelistOnly(), config.excludeBanned(), config.lastPlayedLimit(), playerMap);
|
||||
ReloadAction task = new ReloadAction(threshold, offlinePlayers, config.whitelistOnly(), config.excludeBanned(), config.lastPlayedLimit(), playerMap);
|
||||
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
||||
commonPool.invoke(task);
|
||||
|
||||
ConcurrentHashMap<String, UUID> newPlayerMap = new ConcurrentHashMap<>(playerMap.size() * 11);
|
||||
ConcurrentHashMap<String, UUID> newPlayerMap = new ConcurrentHashMap<>(playerMap.size());
|
||||
|
||||
/*
|
||||
for (int i = 0; i < 11; i++) {
|
||||
for (String key : playerMap.keySet()) {
|
||||
newPlayerMap.put(key + i, playerMap.get(key));
|
||||
}
|
||||
}
|
||||
//newPlayerMap.putAll(playerMap);
|
||||
*/
|
||||
|
||||
newPlayerMap.putAll(playerMap);
|
||||
return newPlayerMap;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.MessageFactory;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@ -19,26 +20,31 @@ import java.util.ConcurrentModificationException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StatThread extends Thread {
|
||||
|
||||
private final int threshold;
|
||||
private final StatRequest request;
|
||||
private final ReloadThread reloadThread;
|
||||
|
||||
private final BukkitAudiences adventure;
|
||||
private final ConfigHandler config;
|
||||
private static ConfigHandler config;
|
||||
private static TestFileHandler testFile;
|
||||
private final MessageFactory messageFactory;
|
||||
private final Main plugin;
|
||||
|
||||
//constructor (called on thread creation)
|
||||
public StatThread(StatRequest s, @Nullable ReloadThread r, BukkitAudiences b, ConfigHandler c, MessageFactory o, Main p) {
|
||||
public StatThread(int threshold, StatRequest s, @Nullable ReloadThread r, BukkitAudiences b, ConfigHandler c, TestFileHandler t, MessageFactory o, Main p) {
|
||||
this.threshold = threshold;
|
||||
request = s;
|
||||
reloadThread = r;
|
||||
|
||||
adventure = b;
|
||||
config = c;
|
||||
testFile = t;
|
||||
messageFactory = o;
|
||||
plugin = p;
|
||||
plugin.getLogger().info("StatThread created!");
|
||||
@ -84,11 +90,13 @@ public class StatThread extends Thread {
|
||||
adventure.sender(sender).sendMessage(messageFactory.formatTopStats(
|
||||
getTopStatistics(), statName, subStatEntry));
|
||||
|
||||
TestFileHandler.saveTimeTaken(System.currentTimeMillis() - time, "top-stat");
|
||||
testFile.saveTimeTaken(System.currentTimeMillis() - time, 3);
|
||||
testFile.logRunCount(false);
|
||||
plugin.logTimeTaken("StatThread", "calculating top stat", time);
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
|
||||
} catch (ConcurrentModificationException e) {
|
||||
testFile.logRunCount(true);
|
||||
adventure.sender(sender).sendMessage(messageFactory.unknownError());
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage(messageFactory.formatExceptions(e.toString()));
|
||||
@ -101,7 +109,6 @@ public class StatThread extends Thread {
|
||||
adventure.sender(sender).sendMessage(
|
||||
messageFactory.formatPlayerStat(
|
||||
playerName, statName, subStatEntry, getStatistic()));
|
||||
TestFileHandler.saveTimeTaken(System.currentTimeMillis() - time, "individual-stat");
|
||||
plugin.logTimeTaken("StatThread", "calculating individual stat", time);
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -125,8 +132,10 @@ public class StatThread extends Thread {
|
||||
//invokes a bunch of worker pool threads to divide and conquer (get the statistics for all players in the list)
|
||||
private LinkedHashMap<String, Integer> getTopStatistics() throws ConcurrentModificationException {
|
||||
ConcurrentHashMap<String, Integer> playerStats = new ConcurrentHashMap<>((int) (getOfflinePlayerCount() * 1.05));
|
||||
String[] playerNames = OfflinePlayerHandler.getOfflinePlayerNames().toArray(new String[0]);
|
||||
TopStatAction task = new TopStatAction(playerNames,
|
||||
//ConcurrentLinkedDeque<String> playerNames = new ConcurrentLinkedDeque<>(OfflinePlayerHandler.getOfflinePlayerNames());
|
||||
//String[] playerNames = OfflinePlayerHandler.getOfflinePlayerNames().toArray(new String[0]);
|
||||
ImmutableList<String> playerNames = ImmutableList.copyOf(OfflinePlayerHandler.getOfflinePlayerNames());
|
||||
TopStatAction task = new TopStatAction(threshold, playerNames,
|
||||
request, playerStats);
|
||||
|
||||
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
||||
@ -134,7 +143,17 @@ public class StatThread extends Thread {
|
||||
commonPool.invoke(task);
|
||||
} catch (ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
try {
|
||||
if (!task.cancel(true)) {
|
||||
plugin.getLogger().severe("Tried to cancel task, but failed. You might need to shut down the server and reboot");
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
} else {
|
||||
plugin.getLogger().warning("Canceling task because of a ConcurrentModificationException...");
|
||||
}
|
||||
} catch (ConcurrentModificationException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new ConcurrentModificationException(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return playerStats.entrySet().stream()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
@ -11,9 +12,9 @@ import java.util.concurrent.RecursiveAction;
|
||||
|
||||
public class TopStatAction extends RecursiveAction {
|
||||
|
||||
private static final int threshold = 11;
|
||||
private final int threshold;
|
||||
|
||||
private final String[] playerNames;
|
||||
private final ImmutableList<String> playerNames;
|
||||
private final StatRequest request;
|
||||
private final ConcurrentHashMap<String, Integer> playerStats;
|
||||
|
||||
@ -25,23 +26,22 @@ public class TopStatAction extends RecursiveAction {
|
||||
* @param playerStats the ConcurrentHashMap to put the results on
|
||||
*/
|
||||
|
||||
public TopStatAction(String[] playerNames, StatRequest statRequest, ConcurrentHashMap<String, Integer> playerStats) {
|
||||
public TopStatAction(int threshold, ImmutableList<String> playerNames, StatRequest statRequest, ConcurrentHashMap<String, Integer> playerStats) {
|
||||
this.threshold = threshold;
|
||||
this.playerNames = playerNames;
|
||||
request = statRequest;
|
||||
|
||||
this.request = statRequest;
|
||||
this.playerStats = playerStats;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compute() {
|
||||
if (playerNames.length < threshold) {
|
||||
if (playerNames.size() < threshold) {
|
||||
getStatsDirectly();
|
||||
}
|
||||
else {
|
||||
Bukkit.getLogger().info("playerNames length: " + playerNames.length);
|
||||
TopStatAction subTask1 = new TopStatAction(Arrays.copyOfRange(playerNames, 0, playerNames.length/2),
|
||||
request, playerStats);
|
||||
TopStatAction subTask2 = new TopStatAction(Arrays.copyOfRange(playerNames, playerNames.length/2, playerNames.length),
|
||||
request, playerStats);
|
||||
final TopStatAction subTask1 = new TopStatAction(threshold, playerNames.subList(0, playerNames.size()/2), request, playerStats);
|
||||
final TopStatAction subTask2 = new TopStatAction(threshold, playerNames.subList(playerNames.size()/2, playerNames.size()), request, playerStats);
|
||||
|
||||
//queue and compute all subtasks in the right order
|
||||
invokeAll(subTask1, subTask2);
|
||||
@ -49,9 +49,10 @@ public class TopStatAction extends RecursiveAction {
|
||||
}
|
||||
|
||||
private void getStatsDirectly() throws IllegalArgumentException, ConcurrentModificationException {
|
||||
Bukkit.getLogger().info("ArrayCopy Length: " + playerNames.length);
|
||||
for (String playerName : playerNames) {
|
||||
try {
|
||||
try {
|
||||
Iterator<String> iterator = playerNames.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String playerName = iterator.next();
|
||||
OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName);
|
||||
int statistic = 0;
|
||||
switch (request.getStatType()) {
|
||||
@ -60,16 +61,17 @@ public class TopStatAction extends RecursiveAction {
|
||||
case BLOCK -> statistic = player.getStatistic(request.getStatEnum(), request.getBlock());
|
||||
case ITEM -> statistic = player.getStatistic(request.getStatEnum(), request.getItem());
|
||||
}
|
||||
|
||||
if (statistic > 0) {
|
||||
playerStats.put(playerName, statistic);
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
Bukkit.getLogger().warning("A ConcurrentModificationException has occurred");
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
} catch (ConcurrentModificationException e) {
|
||||
Bukkit.getLogger().warning("A ConcurrentModificationException has occurred" + e.getCause());
|
||||
e.printStackTrace();
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class OfflinePlayerHandler {
|
||||
|
||||
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
private static ArrayList<String> playerNames;
|
||||
|
||||
private OfflinePlayerHandler() {
|
||||
}
|
||||
@ -23,7 +24,7 @@ public class OfflinePlayerHandler {
|
||||
}
|
||||
|
||||
public static ArrayList<String> getOfflinePlayerNames() {
|
||||
return new ArrayList<>(offlinePlayerUUIDs.keySet());
|
||||
return playerNames;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,6 +33,7 @@ public class OfflinePlayerHandler {
|
||||
*/
|
||||
public static void updateOfflinePlayerList(ConcurrentHashMap<String, UUID> playerList) {
|
||||
offlinePlayerUUIDs = playerList;
|
||||
playerNames = Collections.list(offlinePlayerUUIDs.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user