let there be jank

This commit is contained in:
2023-06-17 11:14:01 +02:00
parent b21d6bc92b
commit 04e9f6a720
6 changed files with 403 additions and 67 deletions
+63 -63
View File
@@ -2,73 +2,73 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<groupId>me.youhavetrouble</groupId>
<artifactId>StatsTop</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<groupId>me.youhavetrouble</groupId>
<artifactId>StatsTop</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>StatsTop</name>
<name>StatsTop</name>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
+7
View File
@@ -0,0 +1,7 @@
# StatsTop
Simple plugin adding a command that shows the top players on the server for given statistic.
Some stats are probably broken or don't have correct translation strings set.
This project is completely unsupported, use at your own risk.
@@ -1,2 +1,86 @@
package me.youhavetrouble.statstop;public class StatsData {
package me.youhavetrouble.statstop;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
public class StatsData {
private final LinkedHashMap<String, Integer> data = new LinkedHashMap<>();
private final long timestamp;
private final Statistic stat;
private final Object arg;
protected StatsData(LinkedHashMap<String, Integer> data, Statistic stat, Object arg) {
this.data.putAll(data);
this.stat = stat;
this.arg = arg;
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
public Component getTop(int amount, CommandSender sender) {
Component component = Component.text("Top", NamedTextColor.GOLD)
.append(Component.space())
.append(Component.translatable("stat.minecraft." + stat.toString().toLowerCase(Locale.ENGLISH), NamedTextColor.GOLD));
if (arg != null) {
if (arg instanceof EntityType entityType) {
component = component
.append(Component.text(" - "))
.append(Component.translatable("entity.minecraft." + entityType.toString().toLowerCase(Locale.ENGLISH)));
} else if (arg instanceof Material material) {
component = component.append(Component.text(" - ", NamedTextColor.GOLD));
if (material.isBlock()) {
component = component.append(Component.translatable("block.minecraft." + material.toString().toLowerCase(Locale.ENGLISH), NamedTextColor.GOLD));
} else if (material.isItem()) {
component = component.append(Component.translatable("item.minecraft." + material.toString().toLowerCase(Locale.ENGLISH), NamedTextColor.GOLD));
}
}
}
String senderName = null;
if (sender instanceof Player player) {
senderName = player.getName();
}
HashSet<String> names = new HashSet<>(amount);
Component senderData = null;
int i = 0;
for (Map.Entry<String, Integer> key : data.entrySet()) {
if (key.getKey().equals(senderName)) {
senderData = getLine(i + 1, key.getKey(), key.getValue(), NamedTextColor.YELLOW);
}
if (i >= amount && senderData != null) continue;
names.add(key.getKey());
component = component.append(Component.newline());
component = component.append(key.getKey().equals(senderName) ? senderData : getLine(i + 1, key.getKey(), key.getValue(), NamedTextColor.WHITE));
i++;
}
if (sender instanceof Player player && !names.contains(player.getName()) && senderData != null) {
component = component.append(senderData);
}
return component;
}
private Component getLine(int place, String name, int value, TextColor textColor) {
return Component.text(place + ". " + name + " - " + value, textColor);
}
}
@@ -6,7 +6,7 @@ public final class StatsTop extends JavaPlugin {
@Override
public void onEnable() {
// Plugin startup logic
getServer().getCommandMap().register("top", new StatsTopCommand());
}
@@ -1,2 +1,245 @@
package me.youhavetrouble.statstop;public class StatsTopCommand {
package me.youhavetrouble.statstop;
import net.kyori.adventure.text.Component;
import org.bukkit.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.util.StringUtil;
import org.bukkit.util.permissions.DefaultPermissions;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class StatsTopCommand extends Command {
private final HashMap<String, StatsData> cachedData = new HashMap<>();
protected StatsTopCommand() {
super("top", "Display top for given stat", "/top <stat> [arg]", new ArrayList<>());
setPermission("statstop.top");
DefaultPermissions.registerPermission("statstop.top", "Allows you to use /top", PermissionDefault.TRUE);
}
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
List<String> completions = new ArrayList<>();
if (args.length == 1) {
for (Statistic stat : Statistic.values()) {
if (StringUtil.startsWithIgnoreCase(stat.toString(), args[0])) {
completions.add(stat.toString().toLowerCase(Locale.ENGLISH));
}
}
}
if (args.length == 2) {
Statistic statistic;
try {
statistic = Statistic.valueOf(args[0].toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
return completions;
}
switch (statistic.getType()) {
case ITEM -> {
for (Material material : Material.values()) {
if (!material.isItem()) continue;
if (StringUtil.startsWithIgnoreCase(material.toString(), args[1])) {
completions.add(material.toString().toLowerCase(Locale.ENGLISH));
}
}
}
case BLOCK -> {
for (Material material : Material.values()) {
if (!material.isBlock()) continue;
if (StringUtil.startsWithIgnoreCase(material.toString(), args[1])) {
completions.add(material.toString().toLowerCase(Locale.ENGLISH));
}
}
}
case ENTITY -> {
for (EntityType entityType : EntityType.values()) {
if (StringUtil.startsWithIgnoreCase(entityType.toString(), args[1])) {
completions.add(entityType.toString().toLowerCase(Locale.ENGLISH));
}
}
}
}
}
return completions;
}
@Override
public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMessage(Component.text("Only players can use this command"));
return true;
}
if (strings.length < 1) return false;
String statName = strings[0];
Statistic stat = null;
try {
stat = Statistic.valueOf(statName.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
commandSender.sendMessage(Component.text(getUsage()));
return false;
}
Object arg = null;
if (strings.length == 2) {
try {
arg = Material.valueOf(strings[1].toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
if (arg == null) {
try {
arg = EntityType.valueOf(strings[1].toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
}
if (arg == null) {
commandSender.sendMessage(Component.text(getUsage()));
return false;
}
}
StatsData statsData = null;
switch (stat.getType()) {
case UNTYPED -> {
statsData = cachedData.get(getStatId(stat, null));
if (statsData == null || statsData.getTimestamp() + 60000 < System.currentTimeMillis()) {
statsData = createData(stat);
cachedData.put(getStatId(stat, null), statsData);
}
}
case ITEM, BLOCK -> {
if (!(arg instanceof Material material)) return false;
statsData = cachedData.get(getStatId(stat, arg));
if (statsData == null || statsData.getTimestamp() + 60000 < System.currentTimeMillis()) {
statsData = createData(stat, material);
cachedData.put(getStatId(stat, arg), statsData);
}
}
case ENTITY -> {
if (!(arg instanceof EntityType entityType)) return false;
statsData = cachedData.get(getStatId(stat, arg));
if (statsData == null || statsData.getTimestamp() + 60000 < System.currentTimeMillis()) {
statsData = createData(stat, entityType);
cachedData.put(getStatId(stat, arg), statsData);
}
}
}
if (statsData == null) {
commandSender.sendMessage(Component.text("Error getting data"));
return false;
}
Component topComponent = statsData.getTop(10, commandSender);
commandSender.sendMessage(topComponent);
return false;
}
private String getStatId(Statistic stat, Object arg) {
String statKey = stat.getKey().getKey();
return switch (stat.getType()) {
case UNTYPED -> statKey;
case ITEM, BLOCK -> {
if (arg instanceof Material item) {
yield statKey + "." + item;
} else {
yield null;
}
}
case ENTITY -> {
if (arg instanceof EntityType entityType) {
yield statKey + "." + entityType;
} else {
yield null;
}
}
};
}
/**
* Creates a map of player names to their stat value. This will return null for stats that are not UNTYPED.
*
* @param stat statistic to get data for
* @return map of player names to their stat value
*/
private StatsData createData(Statistic stat) {
if (stat.getType() != Statistic.Type.UNTYPED) return null;
HashMap<String, Integer> data = new HashMap<>();
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
int statValue = offlinePlayer.getStatistic(stat);
String playerName = offlinePlayer.getName();
data.put(playerName, statValue);
}
LinkedHashMap<String, Integer> sortedData = new LinkedHashMap<>();
data.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEachOrdered(x -> sortedData.put(x.getKey(), x.getValue()));
return new StatsData(sortedData, stat, null);
}
/**
* Creates a map of player names to their stat value. This will return null for stats that are not ENTITY.
*
* @param stat statistic to get data for
* @return map of player names to their stat value
*/
private StatsData createData(Statistic stat, EntityType entityType) {
if (stat.getType() != Statistic.Type.ENTITY) return null;
HashMap<String, Integer> data = new HashMap<>();
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
int statValue = offlinePlayer.getStatistic(stat, entityType);
String playerName = offlinePlayer.getName();
data.put(playerName, statValue);
}
LinkedHashMap<String, Integer> sortedData = new LinkedHashMap<>();
data.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEachOrdered(x -> sortedData.put(x.getKey(), x.getValue()));
return new StatsData(sortedData, stat, entityType);
}
/**
* Creates a map of player names to their stat value. This will return null for stats that are not BLOCK or ITEM.
*
* @param stat statistic to get data for
* @return map of player names to their stat value
*/
private StatsData createData(Statistic stat, Material item) {
if (stat.getType() != Statistic.Type.ITEM && stat.getType() != Statistic.Type.BLOCK) return null;
HashMap<String, Integer> data = new HashMap<>();
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
int statValue = offlinePlayer.getStatistic(stat, item);
String playerName = offlinePlayer.getName();
data.put(playerName, statValue);
}
LinkedHashMap<String, Integer> sortedData = new LinkedHashMap<>();
data.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEachOrdered(x -> sortedData.put(x.getKey(), x.getValue()));
return new StatsData(sortedData, stat, item);
}
}
+3 -1
View File
@@ -1,4 +1,6 @@
name: StatsTop
version: '${project.version}'
main: me.youhavetrouble.statstop.StatsTop
api-version: 1.20
authors:
- YouHaveTrouble
api-version: "1.20"