mirror of
https://github.com/itHotL/PlayerStats.git
synced 2024-11-22 11:55:17 +01:00
Made a ShareManager and designed methods to save/retrieve a statResult, save timestamp of sharing, and check waiting-time for players
This commit is contained in:
parent
e44e0e7b0e
commit
347e59220c
@ -3,13 +3,12 @@ package com.gmail.artemis.the.gr8.playerstats;
|
||||
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.MessageWriter;
|
||||
import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.ShareQueue;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.ShareManager;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -22,23 +21,24 @@ public class ThreadManager {
|
||||
private final BukkitAudiences adventure;
|
||||
private static ConfigHandler config;
|
||||
private static MessageWriter messageWriter;
|
||||
private final ShareQueue shareQueue;
|
||||
private final ShareManager shareManager;
|
||||
|
||||
private ReloadThread lastActiveReloadThread;
|
||||
private StatThread lastActiveStatThread;
|
||||
private final HashMap<String, Thread> statThreads;
|
||||
private static long lastRecordedCalcTime;
|
||||
|
||||
public ThreadManager(BukkitAudiences a, ConfigHandler c, MessageWriter m, @Nullable ShareQueue s) {
|
||||
public ThreadManager(BukkitAudiences a, ConfigHandler c, MessageWriter m) {
|
||||
adventure = a;
|
||||
config = c;
|
||||
messageWriter = m;
|
||||
shareQueue = s;
|
||||
shareManager = new ShareManager(config);
|
||||
|
||||
statThreads = new HashMap<>();
|
||||
statThreadID = 0;
|
||||
reloadThreadID = 0;
|
||||
lastRecordedCalcTime = 0;
|
||||
|
||||
startReloadThread(null);
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ public class ThreadManager {
|
||||
}
|
||||
|
||||
private void startNewStatThread(StatRequest request) {
|
||||
lastActiveStatThread = new StatThread(adventure, config, messageWriter, statThreadID, threshold, request, lastActiveReloadThread);
|
||||
lastActiveStatThread = new StatThread(adventure, config, messageWriter, statThreadID, threshold, request, lastActiveReloadThread, shareManager);
|
||||
statThreads.put(request.getCommandSender().getName(), lastActiveStatThread);
|
||||
lastActiveStatThread.start();
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ public class ShareCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, String label, String[] args) {
|
||||
//TODO use UUID code as arg to share the appropriate statResult
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package com.gmail.artemis.the.gr8.playerstats.commands;
|
||||
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.MessageWriter;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
|
@ -85,11 +85,11 @@ public class ConfigHandler {
|
||||
return config.getBoolean("enable-stat-sharing", true);
|
||||
}
|
||||
|
||||
/** Returns the number of minutes a command-sender has to wait before being able to
|
||||
/** Returns the number of minutes a player has to wait before being able to
|
||||
share another stat-result.
|
||||
<p>Default: 0</p>*/
|
||||
public int getStatShareLimit() {
|
||||
return config.getInt("sharing-time-limit", 0);
|
||||
public int getStatShareWaitingTime() {
|
||||
return config.getInt("waiting-time-before-sharing-again", 0);
|
||||
}
|
||||
|
||||
/** Returns the config setting for include-whitelist-only.
|
||||
@ -176,13 +176,13 @@ public class ConfigHandler {
|
||||
|
||||
/** Whether to use festive formatting, such as pride colors.
|
||||
<p>Default: true</p> */
|
||||
public boolean useFestiveFormatting() {
|
||||
public boolean enableFestiveFormatting() {
|
||||
return config.getBoolean("enable-festive-formatting", true);
|
||||
}
|
||||
|
||||
/** Whether to use rainbow colors for the [PlayerStats] prefix rather than the default gold/purple.
|
||||
<p>Default: false</p> */
|
||||
public boolean useRainbowMode() {
|
||||
public boolean enableRainbowMode() {
|
||||
return config.getBoolean("rainbow-mode", false);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
package com.gmail.artemis.the.gr8.playerstats.models;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import org.bukkit.Bukkit;
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.models;
|
||||
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public record StatResult(String playerName, TextComponent statResult, int ID, UUID uuid) {
|
||||
}
|
@ -7,7 +7,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.ExampleMessage;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.HelpMessage;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.LanguageKeyHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
@ -42,7 +42,7 @@ public class MessageWriter {
|
||||
}
|
||||
|
||||
private static void getComponentFactory() {
|
||||
if (config.useFestiveFormatting() || config.useRainbowMode()) {
|
||||
if (config.enableFestiveFormatting() || config.enableRainbowMode()) {
|
||||
componentFactory = new PrideComponentFactory(config);
|
||||
}
|
||||
else {
|
||||
|
@ -61,7 +61,7 @@ public class PrideComponentFactory extends ComponentFactory {
|
||||
if festive formatting is disabled or it is not pride month,
|
||||
or the commandsender is a Bukkit or Spigot console.*/
|
||||
private boolean cancelRainbow(boolean isBukkitConsole) {
|
||||
return !(config.useRainbowMode() || (config.useFestiveFormatting() && LocalDate.now().getMonth().equals(Month.JUNE))) ||
|
||||
return !(config.enableRainbowMode() || (config.enableFestiveFormatting() && LocalDate.now().getMonth().equals(Month.JUNE))) ||
|
||||
(isBukkitConsole);
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ public class ReloadThread extends Thread {
|
||||
MyLogger.waitingForOtherThread(this.getName(), statThread.getName());
|
||||
statThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
MyLogger.logException(e, "ReloadThread", "run(), trying to join" + statThread.getName());
|
||||
MyLogger.logException(e, "ReloadThread", "run(), trying to join " + statThread.getName());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,95 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatResult;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ShareManager {
|
||||
|
||||
private boolean isEnabled;
|
||||
private int waitingTime;
|
||||
|
||||
private volatile AtomicInteger resultID; //always starts with value 0
|
||||
private ConcurrentHashMap<UUID, StatResult> statResults = null;
|
||||
private ConcurrentHashMap<String, Instant> shareTimeStamp = null;
|
||||
|
||||
public ShareManager(ConfigHandler config) {
|
||||
isEnabled = config.enableStatSharing();
|
||||
waitingTime = config.getStatShareWaitingTime();
|
||||
if (isEnabled) {
|
||||
statResults = new ConcurrentHashMap<>();
|
||||
shareTimeStamp = new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.isEnabled;
|
||||
}
|
||||
|
||||
public void updateSettings(ConfigHandler config) {
|
||||
isEnabled = config.enableStatSharing();
|
||||
waitingTime = config.getStatShareWaitingTime();
|
||||
if (isEnabled && statResults == null) {
|
||||
statResults = new ConcurrentHashMap<>();
|
||||
shareTimeStamp = new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public UUID saveStatResult(String playerName, TextComponent statResult) {
|
||||
removeExcessResults(playerName);
|
||||
|
||||
int ID = getNextIDNumber();
|
||||
UUID identifier = UUID.randomUUID();
|
||||
|
||||
statResults.put(identifier, new StatResult(playerName, statResult, ID, identifier));
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public @Nullable TextComponent getStatResult(String playerName, UUID identifier) {
|
||||
if (statResults.containsKey(identifier) && playerCanShare(playerName)) {
|
||||
shareTimeStamp.put(playerName, Instant.now());
|
||||
return statResults.remove(identifier).statResult();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean playerCanShare(String playerName) {
|
||||
if (waitingTime == 0 || !shareTimeStamp.containsKey(playerName)) {
|
||||
return true;
|
||||
} else {
|
||||
long seconds = shareTimeStamp.get(playerName).until(Instant.now(), ChronoUnit.SECONDS);
|
||||
return seconds >= waitingTime;
|
||||
}
|
||||
}
|
||||
|
||||
/** If the given player already has more than x (in this case 25) StatResults saved,
|
||||
remove the oldest one.*/
|
||||
private void removeExcessResults(String playerName) {
|
||||
List<StatResult> alreadySavedResults = statResults.values()
|
||||
.parallelStream()
|
||||
.filter(result -> result.playerName().equalsIgnoreCase(playerName))
|
||||
.toList();
|
||||
|
||||
if (alreadySavedResults.size() > 25) {
|
||||
UUID uuid = alreadySavedResults
|
||||
.parallelStream()
|
||||
.min(Comparator.comparing(StatResult::ID))
|
||||
.orElseThrow().uuid();
|
||||
statResults.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
private int getNextIDNumber() {
|
||||
return resultID.incrementAndGet();
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ShareQueue {
|
||||
|
||||
private volatile long timeThreshold;
|
||||
private final ConcurrentHashMap<String, TextComponent> statResults;
|
||||
private final ConcurrentHashMap<String, Instant> shareTimestamp;
|
||||
|
||||
public ShareQueue(long timeThreshold) {
|
||||
this.timeThreshold = timeThreshold;
|
||||
statResults = new ConcurrentHashMap<>();
|
||||
shareTimestamp = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void saveStatResults(String senderName, TextComponent statResult) {
|
||||
statResults.put(senderName, statResult);
|
||||
}
|
||||
|
||||
public boolean senderCanShare(String senderName) {
|
||||
return senderCanShare(senderName, 0);
|
||||
}
|
||||
|
||||
/** Returns true if the given sender has a statResult that can be shared,
|
||||
if they have not shared a statResult yet, or if they have passed the timeLimit.
|
||||
@param senderName name of the commandSender to evaluate
|
||||
@param timeLimit the waiting time in seconds during which sharing is not allowed*/
|
||||
public boolean senderCanShare(String senderName, long timeLimit) {
|
||||
if (timeLimit == 0 || !shareTimestamp.containsKey(senderName)) {
|
||||
return statResults.containsKey(senderName);
|
||||
} else {
|
||||
long seconds = shareTimestamp.get(senderName).until(Instant.now(), ChronoUnit.SECONDS);
|
||||
return seconds >= timeLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes and returns the last statResults for this sender,
|
||||
and stores the timestamp the results were retrieved on.*/
|
||||
public @Nullable TextComponent getLastStatResult(String senderName) {
|
||||
if (statResults.containsKey(senderName)) {
|
||||
shareTimestamp.put(senderName, Instant.now());
|
||||
return statResults.remove(senderName);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.msg.MessageWriter;
|
||||
import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
|
||||
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
||||
@ -23,21 +24,18 @@ public class StatThread extends Thread {
|
||||
|
||||
private final int threshold;
|
||||
private final ReloadThread reloadThread;
|
||||
private final ShareQueue shareQueue;
|
||||
private final ShareManager shareManager;
|
||||
|
||||
private final BukkitAudiences adventure;
|
||||
private static ConfigHandler config;
|
||||
private static MessageWriter messageWriter;
|
||||
private final StatRequest request;
|
||||
|
||||
public StatThread(BukkitAudiences a, ConfigHandler c, MessageWriter m, int ID, int threshold, StatRequest s, @Nullable ReloadThread r) {
|
||||
this(a, c, m, ID, threshold, s, r, null);
|
||||
}
|
||||
|
||||
public StatThread(BukkitAudiences a, ConfigHandler c, MessageWriter m, int ID, int threshold, StatRequest s, @Nullable ReloadThread r, @Nullable ShareQueue q) {
|
||||
public StatThread(BukkitAudiences a, ConfigHandler c, MessageWriter m, int ID, int threshold, StatRequest s, @Nullable ReloadThread r, @Nullable ShareManager sm) {
|
||||
this.threshold = threshold;
|
||||
reloadThread = r;
|
||||
shareQueue = q;
|
||||
shareManager = sm;
|
||||
|
||||
adventure = a;
|
||||
config = c;
|
||||
@ -65,7 +63,7 @@ public class StatThread extends Thread {
|
||||
reloadThread.join();
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
MyLogger.logException(e, "StatThread", "Trying to join" + reloadThread.getName());
|
||||
MyLogger.logException(e, "StatThread", "Trying to join " + reloadThread.getName());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@ -85,7 +83,9 @@ public class StatThread extends Thread {
|
||||
} else {
|
||||
statResult = messageWriter.formatServerStat(getServerTotal(), request);
|
||||
}
|
||||
|
||||
if (shareManager.isEnabled()) {
|
||||
UUID shareCode = shareManager.saveStatResult(request.getCommandSender().getName(), statResult);
|
||||
}
|
||||
adventure.sender(request.getCommandSender()).sendMessage(statResult);
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
@ -103,7 +103,7 @@ public class StatThread extends Thread {
|
||||
}
|
||||
|
||||
private long getServerTotal() {
|
||||
List<Integer> numbers = getAllStats().values().stream().toList();
|
||||
List<Integer> numbers = getAllStats().values().parallelStream().toList();
|
||||
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ public class StatThread extends Thread {
|
||||
private @NotNull ConcurrentHashMap<String, Integer> getAllStats() throws ConcurrentModificationException {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
int size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? (int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05) : 16;
|
||||
int size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? OfflinePlayerHandler.getOfflinePlayerCount() : 16;
|
||||
ConcurrentHashMap<String, Integer> playerStats = new ConcurrentHashMap<>(size);
|
||||
ImmutableList<String> playerNames = ImmutableList.copyOf(OfflinePlayerHandler.getOfflinePlayerNames());
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -21,9 +21,9 @@ only-allow-one-lookup-at-a-time-per-player: true
|
||||
# Whether statistics can be shared with everyone in chat
|
||||
enable-stat-sharing: true
|
||||
|
||||
# How often players can share statistics in chat. You can specify a waiting time (in minutes) below,
|
||||
# or leave this setting on 0 to not use any time-limit
|
||||
sharing-time-limit: 0
|
||||
# How often players can share statistics in chat (use this if you want to limit chat spam)
|
||||
# Leave this on 0 to disable the cool-down, or specify the number of minutes you want players to wait
|
||||
waiting-time-before-sharing-again: 0
|
||||
|
||||
# Filtering options to control which players should be included in statistic calculations
|
||||
include-whitelist-only: false
|
||||
|
Loading…
Reference in New Issue
Block a user