diff --git a/pom.xml b/pom.xml index 2166e1c..80a4f23 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,12 @@ 2.0.0-SNAPSHOT provided + + de.iani.cubeside + CubesideStatistics + 1.0.0-SNAPSHOT + provided + diff --git a/src/main/java/de/fanta/challengesjoinentities/ChallengesJoinEntities.java b/src/main/java/de/fanta/challengesjoinentities/ChallengesJoinEntities.java index aedb9d8..f93019e 100644 --- a/src/main/java/de/fanta/challengesjoinentities/ChallengesJoinEntities.java +++ b/src/main/java/de/fanta/challengesjoinentities/ChallengesJoinEntities.java @@ -11,6 +11,7 @@ import de.fanta.challengesjoinentities.commands.AdventureCommand.AdventureMapsCommand; import de.fanta.challengesjoinentities.commands.AdventureCommand.AdventureTestMapCommand; import de.fanta.challengesjoinentities.commands.AdventureCommand.ChallengesRemovePlayerServer; +import de.fanta.challengesjoinentities.commands.ChallengesCommand.ChallengesStatsCommand; import de.fanta.challengesjoinentities.commands.ChallengesCommand.ChallengesloadCommand; import de.fanta.challengesjoinentities.commands.PiglinCommand.AddEntityCommand; import de.fanta.challengesjoinentities.commands.PiglinCommand.Entitytphere; @@ -23,6 +24,8 @@ import de.fanta.challengesjoinentities.listeners.PlayerListener; import de.fanta.challengesjoinentities.loadgui.AdventureLoadGUI; import de.fanta.challengesjoinentities.loadgui.ChallengeLoadGUI; +import de.fanta.challengesjoinentities.utils.Statistics; +import de.iani.cubesidestats.api.CubesideStatisticsAPI; import de.iani.cubesideutils.bukkit.commands.CommandRouter; import de.iani.playerUUIDCache.PlayerUUIDCache; import net.kyori.adventure.text.Component; @@ -67,6 +70,9 @@ private AdventureMapsConfig adventureMapsConfig; private PlayerUUIDCache playerUUIDCache; + private CubesideStatisticsAPI cubesideStatistics; + private Statistics statistics; + public ChallengesJoinEntities() { this.entityData = new HashMap<>(); @@ -83,6 +89,10 @@ plugin = this; playerUUIDCache = (PlayerUUIDCache) getServer().getPluginManager().getPlugin("PlayerUUIDCache"); nmsUtils = getServer().getServicesManager().load(NMSUtils.class); + + cubesideStatistics = getServer().getServicesManager().load(CubesideStatisticsAPI.class); + statistics = new Statistics(this); + this.globalDataHelper = new ChallengesGlobalDataHelper(this); this.config = new Config(this); loadCategoriesAndMaps(); @@ -101,6 +111,7 @@ CommandRouter challengesrouter = new CommandRouter(getCommand("challenges")); challengesrouter.addCommandMapping(new ChallengesloadCommand(this), "load"); + challengesrouter.addCommandMapping(new ChallengesStatsCommand(plugin.getStatistics()), "stats"); CommandRouter adventurerouter = new CommandRouter(getCommand("adventure")); adventurerouter.addCommandMapping(new AdventureLoadCommand(this), "load"); @@ -357,4 +368,12 @@ public Set getAvailableServers() { return availableServers; } + + public CubesideStatisticsAPI getCubesideStatistics() { + return cubesideStatistics; + } + + public Statistics getStatistics() { + return statistics; + } } diff --git a/src/main/java/de/fanta/challengesjoinentities/commands/ChallengesCommand/ChallengesStatsCommand.java b/src/main/java/de/fanta/challengesjoinentities/commands/ChallengesCommand/ChallengesStatsCommand.java new file mode 100644 index 0000000..c3a0a02 --- /dev/null +++ b/src/main/java/de/fanta/challengesjoinentities/commands/ChallengesCommand/ChallengesStatsCommand.java @@ -0,0 +1,107 @@ +package de.fanta.challengesjoinentities.commands.ChallengesCommand; + +import de.fanta.challengesjoinentities.ChatUtil; +import de.fanta.challengesjoinentities.utils.PlayerStatisticsData; +import de.fanta.challengesjoinentities.utils.Statistics; +import de.iani.cubesideutils.StringUtil; +import de.iani.cubesideutils.bukkit.commands.SubCommand; +import de.iani.cubesideutils.commands.ArgsParser; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.function.Consumer; + +public class ChallengesStatsCommand extends SubCommand { + + private final Statistics statistics; + + public ChallengesStatsCommand(Statistics statistics) { + this.statistics = statistics; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String alias, String commandString, ArgsParser args) { + Statistics.StatType statType = Statistics.StatType.valueOf(args.getNext("SOLO").toUpperCase()); + String playerName = args.getNext(null); + + Consumer callback = data -> { + if (data == null) { + ChatUtil.sendErrorMessage(sender, "Für Spieler '" + playerName + "' existieren keine Daten."); + return; + } + if (playerName == null) { + ChatUtil.sendNormalMessage(sender, "Deine Speedrun-Statistik " + "(" + statType.getPrefix() + ")"); + } else { + ChatUtil.sendNormalMessage(sender, "Speedrun-Statistik von " + data.getPlayerName() + " (" + statType.getPrefix() + ")"); + } + + + int bestTimeThisMonth = data.getBestTimeMonth(); + if (bestTimeThisMonth < 0) { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Beste Zeit: " + ChatUtil.GREEN + formatTime(data.getBestTime())); + } else { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Beste Zeit: " + ChatUtil.GREEN + (data.getBestTime() < 0 ? "-" : formatTime(data.getBestTime())) + " (Dieser Monat: " + formatTime(bestTimeThisMonth) + ")"); + } + + int runsPlayerThisMonth = data.getRunsPlayedMonth(); + if (bestTimeThisMonth < 0) { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Speedruns gespielt: " + ChatUtil.GREEN + data.getRunsPlayed()); + } else { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Speedruns gespielt: " + ChatUtil.GREEN + (data.getRunsPlayed() < 0 ? "-" : data.getRunsPlayed()) + " (Dieser Monat: " + runsPlayerThisMonth + ")"); + } + + int runsWonThisMonth = data.getRunsWonMonth(); + if (bestTimeThisMonth < 0) { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Speedruns gewonnen: " + ChatUtil.GREEN + data.getRunsWon()); + } else { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Speedruns gewonnen: " + ChatUtil.GREEN + (data.getRunsWon() < 0 ? "-" : data.getRunsWon()) + " (Dieser Monat: " + runsWonThisMonth + ")"); + } + + int positionThisMonth = data.getRunsWonMonth(); + if (bestTimeThisMonth < 0) { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Position: " + ChatUtil.GREEN + data.getPosition()); + } else { + ChatUtil.sendNormalMessage(sender, ChatUtil.ORANGE + " Position: " + ChatUtil.GREEN + (data.getPosition() < 0 ? "-" : data.getPosition()) + " (Dieser Monat: " + positionThisMonth + ")"); + } + }; + if (playerName == null) { + if (sender instanceof Player player) { + statistics.getDataForPlayer(player, statType, callback); + } else { + sender.sendMessage(ChatColor.GREEN + "Für die Konsole existieren keine Daten."); + } + } else { + try { + int pos = Integer.parseInt(playerName); + statistics.getDataForPositionIfExists(pos, statType, callback); + } catch (NumberFormatException e) { + statistics.getDataForPlayerIfExists(playerName, statType, callback); + } + } + return true; + } + + @Override + public ArrayList onTabComplete(CommandSender sender, Command command, String alias, ArgsParser args) { + int i = args.remaining(); + if (i == 1) { + ArrayList li = new ArrayList<>(); + for (Statistics.StatType statType : Statistics.StatType.values()) { + li.add(statType.getPrefix()); + } + return li; + } + return new ArrayList<>(); + } + + public String formatTime(long time) { + String formattime = StringUtil.formatTimespan((time / 1000) * 1000, "1 Tage, ", ":", "", "", "", ":", false, true); + if (formattime.startsWith("1 Tage")) { + return StringUtil.formatTimespan((time / 1000) * 1000, " Tag, ", ":", "", "", "", ":", false, true); + } + return formattime; + } +} diff --git a/src/main/java/de/fanta/challengesjoinentities/utils/PlayerStatisticsData.java b/src/main/java/de/fanta/challengesjoinentities/utils/PlayerStatisticsData.java new file mode 100644 index 0000000..3b39b99 --- /dev/null +++ b/src/main/java/de/fanta/challengesjoinentities/utils/PlayerStatisticsData.java @@ -0,0 +1,69 @@ +package de.fanta.challengesjoinentities.utils; + +import java.util.UUID; + +public class PlayerStatisticsData { + private final UUID playerUUID; + private final String playerName; + private final int runsPlayed; + private final int runsPlayedMonth; + private final int runsWon; + private final int runsWonMonth; + private final int bestTime; + private final int bestTimeMonth; + private final int position; + private final int positionMonth; + + public PlayerStatisticsData(UUID uniqueId, String name, int runsPlayed, int runsPlayedMonth, int runsWon, int runsWonMonth, int bestTime, int bestTimeMonth, int position, int positionMonth) { + this.playerUUID = uniqueId; + this.playerName = name; + this.runsPlayed = runsPlayed; + this.runsPlayedMonth = runsPlayedMonth; + this.runsWon = runsWon; + this.runsWonMonth = runsWonMonth; + this.bestTime = bestTime; + this.bestTimeMonth = bestTimeMonth; + this.position = position; + this.positionMonth = positionMonth; + } + + public UUID getPlayerId() { + return playerUUID; + } + + public String getPlayerName() { + return playerName; + } + + public int getRunsPlayed() { + return runsPlayed; + } + + public int getRunsPlayedMonth() { + return runsPlayedMonth; + } + + public int getRunsWon() { + return runsWon; + } + + public int getRunsWonMonth() { + return runsWonMonth; + } + + public int getBestTime() { + return bestTime; + } + + public int getBestTimeMonth() { + return bestTimeMonth; + } + + public int getPosition() { + return position; + } + + public int getPositionMonth() { + return positionMonth; + } +} \ No newline at end of file diff --git a/src/main/java/de/fanta/challengesjoinentities/utils/Statistics.java b/src/main/java/de/fanta/challengesjoinentities/utils/Statistics.java new file mode 100644 index 0000000..bf3763c --- /dev/null +++ b/src/main/java/de/fanta/challengesjoinentities/utils/Statistics.java @@ -0,0 +1,207 @@ +package de.fanta.challengesjoinentities.utils; + +import de.fanta.challengesjoinentities.ChallengesJoinEntities; +import de.iani.cubesidestats.api.CubesideStatisticsAPI; +import de.iani.cubesidestats.api.Ordering; +import de.iani.cubesidestats.api.PlayerStatistics; +import de.iani.cubesidestats.api.PlayerStatisticsQueryKey; +import de.iani.cubesidestats.api.StatisticKey; +import de.iani.cubesidestats.api.StatisticsQueryKey; +import de.iani.cubesidestats.api.TimeFrame; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class Statistics { + private final CubesideStatisticsAPI statistics; + + private final StatisticKey speedRunsPlayedSolo; + private final StatisticKey speedRunsWonSolo; + private final StatisticKey speedRunsTimeSolo; + + private final StatisticKey speedRunsPlayedDuo; + private final StatisticKey speedRunsWonDuo; + private final StatisticKey speedRunsTimeDuo; + + private final StatisticKey speedRunsPlayedTeam; + private final StatisticKey speedRunsWonTeam; + private final StatisticKey speedRunsTimeTeam; + + public Statistics(ChallengesJoinEntities plugin) { + statistics = plugin.getCubesideStatistics(); + + speedRunsPlayedSolo = statistics.getStatisticKey("challenge.speedruns.solo.played"); + speedRunsPlayedSolo.setDisplayName("Challenge - SpeedRun's gespielt (Solo)"); + speedRunsPlayedSolo.setIsMonthlyStats(true); + + speedRunsWonSolo = statistics.getStatisticKey("challenge.speedruns.solo.won"); + speedRunsWonSolo.setDisplayName("Challenge - SpeedRun's gewonnen (Solo)"); + speedRunsWonSolo.setIsMonthlyStats(true); + + speedRunsTimeSolo = statistics.getStatisticKey("challenge.speedruns.solo.time"); + speedRunsTimeSolo.setDisplayName("Beste Zeit (Solo)"); + speedRunsTimeSolo.setIsMonthlyStats(true); + + + speedRunsPlayedDuo = statistics.getStatisticKey("challenge.speedruns.duo.played"); + speedRunsPlayedDuo.setDisplayName("Challenge - SpeedRun's gespielt (Duo)"); + speedRunsPlayedDuo.setIsMonthlyStats(true); + + speedRunsWonDuo = statistics.getStatisticKey("challenge.speedruns.duo.won"); + speedRunsWonDuo.setDisplayName("Challenge - SpeedRun's gewonnen (Duo)"); + speedRunsWonDuo.setIsMonthlyStats(true); + + speedRunsTimeDuo = statistics.getStatisticKey("challenge.speedruns.duo.time"); + speedRunsTimeDuo.setDisplayName("Beste Zeit (Duo)"); + speedRunsTimeDuo.setIsMonthlyStats(true); + + + speedRunsPlayedTeam = statistics.getStatisticKey("challenge.speedruns.team.played"); + speedRunsPlayedTeam.setDisplayName("Challenge - SpeedRun's gespielt (Team)"); + speedRunsPlayedTeam.setIsMonthlyStats(true); + + speedRunsWonTeam = statistics.getStatisticKey("challenge.speedruns.team.won"); + speedRunsWonTeam.setDisplayName("Challenge - SpeedRun's gewonnen (Team)"); + speedRunsWonTeam.setIsMonthlyStats(true); + + speedRunsTimeTeam = statistics.getStatisticKey("challenge.speedruns.team.time"); + speedRunsTimeTeam.setDisplayName("Beste Zeit (Team)"); + speedRunsTimeTeam.setIsMonthlyStats(true); + } + + public void getDataForPlayer(OfflinePlayer player, StatType statType, Consumer callback) { + List keys = new ArrayList<>(); + PlayerStatistics ps = statistics.getStatistics(player.getUniqueId()); + + PlayerStatisticsQueryKey kRunsPlayed = null; + PlayerStatisticsQueryKey kRunsPlayedMonth = null; + + PlayerStatisticsQueryKey kRunsWon = null; + PlayerStatisticsQueryKey kRunsWonMonth = null; + + PlayerStatisticsQueryKey kBestTime = null; + PlayerStatisticsQueryKey kBestTimeMonth = null; + + PlayerStatisticsQueryKey kPosition = null; + PlayerStatisticsQueryKey kPositionMonth = null; + + if (statType == StatType.SOLO) { + keys.add(kRunsPlayed = new PlayerStatisticsQueryKey(ps, speedRunsPlayedSolo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsPlayedMonth = new PlayerStatisticsQueryKey(ps, speedRunsPlayedSolo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kRunsWon = new PlayerStatisticsQueryKey(ps, speedRunsWonSolo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsWonMonth = new PlayerStatisticsQueryKey(ps, speedRunsWonSolo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kBestTime = new PlayerStatisticsQueryKey(ps, speedRunsTimeSolo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kBestTimeMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeSolo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kPosition = new PlayerStatisticsQueryKey(ps, speedRunsTimeSolo, PlayerStatisticsQueryKey.QueryType.POSITION_MAX)); + keys.add(kPositionMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeSolo, PlayerStatisticsQueryKey.QueryType.POSITION_MAX, TimeFrame.MONTH)); + } else if (statType == StatType.DUO) { + keys.add(kRunsPlayed = new PlayerStatisticsQueryKey(ps, speedRunsPlayedDuo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsPlayedMonth = new PlayerStatisticsQueryKey(ps, speedRunsPlayedDuo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kRunsWon = new PlayerStatisticsQueryKey(ps, speedRunsWonDuo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsWonMonth = new PlayerStatisticsQueryKey(ps, speedRunsWonDuo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kBestTime = new PlayerStatisticsQueryKey(ps, speedRunsTimeDuo, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kBestTimeMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeDuo, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kPosition = new PlayerStatisticsQueryKey(ps, speedRunsTimeDuo, PlayerStatisticsQueryKey.QueryType.POSITION_MAX)); + keys.add(kPositionMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeDuo, PlayerStatisticsQueryKey.QueryType.POSITION_MAX, TimeFrame.MONTH)); + } else if (statType == StatType.TEAM) { + keys.add(kRunsPlayed = new PlayerStatisticsQueryKey(ps, speedRunsPlayedTeam, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsPlayedMonth = new PlayerStatisticsQueryKey(ps, speedRunsPlayedTeam, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kRunsWon = new PlayerStatisticsQueryKey(ps, speedRunsWonTeam, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kRunsWonMonth = new PlayerStatisticsQueryKey(ps, speedRunsWonTeam, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kBestTime = new PlayerStatisticsQueryKey(ps, speedRunsTimeTeam, PlayerStatisticsQueryKey.QueryType.SCORE)); + keys.add(kBestTimeMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeTeam, PlayerStatisticsQueryKey.QueryType.SCORE, TimeFrame.MONTH)); + + keys.add(kPosition = new PlayerStatisticsQueryKey(ps, speedRunsTimeTeam, PlayerStatisticsQueryKey.QueryType.POSITION_MAX)); + keys.add(kPositionMonth = new PlayerStatisticsQueryKey(ps, speedRunsTimeTeam, PlayerStatisticsQueryKey.QueryType.POSITION_MAX, TimeFrame.MONTH)); + } + + PlayerStatisticsQueryKey finalKRunsPlayed = kRunsPlayed; + PlayerStatisticsQueryKey finalKRunsPlayedMonth = kRunsPlayedMonth; + + PlayerStatisticsQueryKey finalKRunsWon = kRunsWon; + PlayerStatisticsQueryKey finalKRunsWonMonth = kRunsWonMonth; + + PlayerStatisticsQueryKey finalKBestTime = kBestTime; + PlayerStatisticsQueryKey finalKBestTimeMonth = kBestTimeMonth; + + PlayerStatisticsQueryKey finalKPosition = kPosition; + PlayerStatisticsQueryKey finalKPositionMonth = kPositionMonth; + + statistics.queryStats(keys, (c) -> { + int runsPlayed = c.getOrDefault(finalKRunsPlayed, 0); + int runsPlayedMonth = c.getOrDefault(finalKRunsPlayedMonth, 0); + + int runsWon = c.getOrDefault(finalKRunsWon, 0); + int runsWonMonth = c.getOrDefault(finalKRunsWonMonth, 0); + + int bestTime = c.getOrDefault(finalKBestTime, 0); + int bestTimeMonth = c.getOrDefault(finalKBestTimeMonth, 0); + + int position = c.getOrDefault(finalKPosition, -1); + int positionMonth = c.getOrDefault(finalKPositionMonth, -1); + + callback.accept(new PlayerStatisticsData(player.getUniqueId(), player.getName(), runsPlayed, runsPlayedMonth, runsWon, runsWonMonth, bestTime, bestTimeMonth, position, positionMonth)); + }); + } + + public void getDataForPositionIfExists(int pos, StatType statType, Consumer callback) { + if (pos < 1) { + callback.accept(null); + return; + } + + StatisticKey score = null; + + if (statType == StatType.SOLO) { + score = speedRunsTimeSolo; + } else if (statType == StatType.DUO) { + score = speedRunsTimeDuo; + } else if (statType == StatType.TEAM) { + score = speedRunsTimeTeam; + } + + if (score != null) { + score.getTop(pos - 1, 1, Ordering.DESCENDING, TimeFrame.ALL_TIME, (s) -> { + if (s.isEmpty()) { + callback.accept(null); + } else { + OfflinePlayer cplayer = Bukkit.getOfflinePlayer(s.get(0).getPlayer().getOwner()); + getDataForPlayer(cplayer, statType, callback); + } + }); + } + } + + public void getDataForPlayerIfExists(String player, StatType statType, Consumer callback) { + OfflinePlayer cplayer = Bukkit.getOfflinePlayer(player); + getDataForPlayer(cplayer, statType, callback); + } + + public enum StatType { + SOLO("Solo"), + DUO("Duo"), + TEAM("Team"); + + private final String prefix; + + StatType(String prefix) { + this.prefix = prefix; + } + + public String getPrefix() { + return prefix; + } + } +} + diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5c49cad..21595e8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,7 +4,7 @@ author: ${project.author} api-version: 1.13 -depend: [GlobalClient, CubesideUtils, GlobalPort, CubesideNMSUtils] +depend: [GlobalClient, CubesideUtils, GlobalPort, CubesideNMSUtils, CubesideStatistics] softdepend: [Challenges, CubesideNPCs] commands: