Merge branch 'main' into share-button

# Conflicts:
#	src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java
#	src/main/java/com/gmail/artemis/the/gr8/playerstats/msg/MessageWriter.java
This commit is contained in:
Artemis-the-gr8 2022-07-11 20:34:12 +02:00
commit 3fe8afe216
10 changed files with 210 additions and 160 deletions

View File

@ -4,9 +4,12 @@ import com.gmail.artemis.the.gr8.playerstats.commands.ReloadCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.ShareCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.StatCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.TabCompleter;
import com.gmail.artemis.the.gr8.playerstats.commands.cmdutils.TabCompleteHelper;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel;
import com.gmail.artemis.the.gr8.playerstats.listeners.JoinListener;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageWriter;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.statistic.ShareManager;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit;
@ -37,6 +40,9 @@ public class Main extends JavaPlugin {
//initialize the threadManager
ThreadManager threadManager = new ThreadManager(adventure(), config, messageWriter, shareManager);
ThreadManager threadManager = new ThreadManager(adventure(), config, messageWriter, this);
TabCompleteHelper tab = new TabCompleteHelper();
Bukkit.getLogger().info(tab.getEntityKilledSuggestions().toString());
//register all commands and the tabCompleter
PluginCommand statcmd = this.getCommand("statistic");

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.commands.cmdutils.TabCompleteHelper;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import org.bukkit.Statistic;
@ -14,6 +15,7 @@ import java.util.stream.Collectors;
public class TabCompleter implements org.bukkit.command.TabCompleter {
private final List<String> commandOptions;
private final TabCompleteHelper tabCompleteHelper;
//TODO add "example" to the list
public TabCompleter() {
@ -22,6 +24,8 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
commandOptions.add("player");
commandOptions.add("server");
commandOptions.add("me");
tabCompleteHelper = new TabCompleteHelper();
}
//args[0] = statistic (length = 1)
@ -49,18 +53,14 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
Statistic stat = EnumHandler.getStatEnum(previousArg);
if (stat != null) {
tabSuggestions = switch (stat.getType()) {
case UNTYPED -> commandOptions;
case BLOCK -> getTabSuggestions(EnumHandler.getBlockNames(), currentArg);
case ITEM -> getTabSuggestions(EnumHandler.getItemNames(), currentArg);
case ENTITY -> getTabSuggestions(EnumHandler.getEntityNames(), currentArg);
};
tabSuggestions = getTabSuggestions(getRelevantList(stat), currentArg);
}
}
//if previous arg = "player", suggest playerNames
else if (previousArg.equalsIgnoreCase("player")) {
if (args.length >= 3 && EnumHandler.getEntitySubStatNames().contains(args[args.length-3].toLowerCase())) {
//if args.length-3 is kill_entity or entity_killed_by
if (args.length >= 3 && EnumHandler.isEntityStatistic(args[args.length-3])) {
tabSuggestions = commandOptions;
}
else {
@ -82,4 +82,27 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
.filter(item -> item.toLowerCase().contains(currentArg.toLowerCase()))
.collect(Collectors.toList());
}
private List<String> getRelevantList(Statistic stat) {
switch (stat.getType()) {
case BLOCK -> {
return tabCompleteHelper.getAllBlockNames();
}
case ITEM -> {
if (stat == Statistic.BREAK_ITEM) {
return tabCompleteHelper.getItemBrokenSuggestions();
} else if (stat == Statistic.CRAFT_ITEM) {
return tabCompleteHelper.getAllItemNames(); //TODO fix
} else {
return tabCompleteHelper.getAllItemNames();
}
}
case ENTITY -> {
return tabCompleteHelper.getEntityKilledSuggestions();
}
default -> {
return commandOptions;
}
}
}
}

View File

@ -0,0 +1,53 @@
package com.gmail.artemis.the.gr8.playerstats.commands.cmdutils;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TabCompleteHelper {
private static List<String> itemBrokenSuggestions;
private static List<String> entityKilledSuggestions;
public TabCompleteHelper() {
prepareLists();
}
public List<String> getAllItemNames() {
return EnumHandler.getItemNames();
}
public List<String> getItemBrokenSuggestions() {
return itemBrokenSuggestions;
}
public List<String> getAllBlockNames() {
return EnumHandler.getBlockNames();
}
public List<String> getEntityKilledSuggestions() {
return entityKilledSuggestions;
}
private static void prepareLists() {
itemBrokenSuggestions = Arrays.stream(Material.values())
.parallel()
.filter(Material::isItem)
.filter(item -> item.getMaxDurability() != 0)
.map(Material::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
entityKilledSuggestions = Arrays.stream(EntityType.values())
.parallel()
.filter(EntityType::isAlive)
.map(EntityType::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
}
}

View File

@ -94,48 +94,34 @@ public enum Unit {
}
public double getSeconds() {
switch (this) {
case DAY -> {
return 86400;
}
case HOUR -> {
return 3600;
}
case MINUTE -> {
return 60;
}
case SECOND -> {
return 1;
}
case TICK -> {
return 1 / 20.0;
}
default -> {
return -1;
}
}
return switch (this) {
case DAY -> 86400;
case HOUR -> 3600;
case MINUTE -> 60;
case SECOND -> 1;
case TICK -> 1 / 20.0;
default -> -1;
};
}
/** Returns the Unit corresponding to the given String. This String does NOT need to
match exactly (it can be "day" or "days", for example), and is case-insensitive.
@param unitName an approximation of the name belonging to the desired Unit, case-insensitive */
public static @NotNull Unit fromString(@NotNull String unitName) {
Unit unit;
switch (unitName.toLowerCase()) {
case "cm" -> unit = Unit.CM;
case "m", "block", "blocks" -> unit = Unit.BLOCK;
case "mile", "miles" -> unit = Unit.MILE;
case "km" -> unit = Unit.KM;
case "hp" -> unit = Unit.HP;
case "heart", "hearts" -> unit = Unit.HEART;
case "day", "days" -> unit = Unit.DAY;
case "hour", "hours" -> unit = Unit.HOUR;
case "minute", "minutes", "min" -> unit = Unit.MINUTE;
case "second", "seconds", "sec" -> unit = Unit.SECOND;
case "tick", "ticks" -> unit = Unit.TICK;
default -> unit = Unit.NUMBER;
}
return unit;
return switch (unitName.toLowerCase()) {
case "cm" -> Unit.CM;
case "m", "block", "blocks" -> Unit.BLOCK;
case "mile", "miles" -> Unit.MILE;
case "km" -> Unit.KM;
case "hp" -> Unit.HP;
case "heart", "hearts" -> Unit.HEART;
case "day", "days" -> Unit.DAY;
case "hour", "hours" -> Unit.HOUR;
case "minute", "minutes", "min" -> Unit.MINUTE;
case "second", "seconds", "sec" -> Unit.SECOND;
case "tick", "ticks" -> Unit.TICK;
default -> Unit.NUMBER;
};
}
/** Returns the Unit.Type of this Statistic, which can be Untyped, Distance, Damage, or Time.

View File

@ -1,10 +1,10 @@
package com.gmail.artemis.the.gr8.playerstats.msg;
import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel;
import com.gmail.artemis.the.gr8.playerstats.enums.PluginColor;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
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;
@ -12,12 +12,8 @@ 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;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import org.bukkit.Bukkit;
import org.bukkit.Statistic;
import org.bukkit.map.MinecraftFont;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@ -86,7 +82,7 @@ public class MessageWriter {
return componentFactory.pluginPrefixComponent(isBukkitConsole)
.append(space())
.append(componentFactory.messageComponent().content(
"Please add a valid " + getSubStatTypeName(statType) + " to look up this statistic!"));
"Please add a valid " + EnumHandler.getSubStatTypeName(statType) + " to look up this statistic!"));
}
public TextComponent missingPlayerName(boolean isBukkitConsole) {
@ -100,7 +96,7 @@ public class MessageWriter {
return componentFactory.pluginPrefixComponent(isBukkitConsole)
.append(space())
.append(componentFactory.messageComponent().content(
"\"" + subStatEntry + "\" is not a valid " + getSubStatTypeName(statType) + "!"));
"\"" + subStatEntry + "\" is not a valid " + EnumHandler.getSubStatTypeName(statType) + "!"));
}
public TextComponent requestAlreadyRunning(boolean isBukkitConsole) {
@ -139,46 +135,28 @@ public class MessageWriter {
.append(getStatNameComponent(request)) //space is provided by statUnitComponent
.append(getStatUnitComponent(request.getStatistic(), request.getSelection(), request.isConsoleSender()));
ArrayList<Unit> timeUnits = null;
if (Unit.getTypeFromStatistic(request.getStatistic()) == Unit.Type.TIME) {
timeUnits = getTimeUnitRange(topStats.values().iterator().next());
}
boolean useDots = config.useDots();
boolean boldNames = config.playerNameIsBold();
MinecraftFont font = new MinecraftFont();
Set<String> playerNames = topStats.keySet();
int count = 0;
for (String playerName : playerNames) {
TextComponent.Builder playerNameBuilder = componentFactory.playerNameBuilder(playerName, Target.TOP);
count++;
topList.append(newline())
.append(componentFactory.rankingNumberComponent(count + "."))
.append(componentFactory.rankingNumberComponent(++count + "."))
.append(space());
if (useDots) {
topList.append(playerNameBuilder)
.append(space());
TextComponent.Builder dotsBuilder = componentFactory.dotsBuilder();
int dots;
if (request.isConsoleSender()) {
dots = (int) Math.round((130.0 - font.getWidth(count + ". " + playerName))/6) + 7;
} else if (!boldNames) {
dots = (int) Math.round((130.0 - font.getWidth(count + ". " + playerName))/2);
} else {
dots = (int) Math.round((130.0 - font.getWidth(count + ". ") - (font.getWidth(playerName) * 1.19))/2);
}
int dots = FontUtils.getNumberOfDotsToAlign(count + ". " + playerName, request.isConsoleSender(), boldNames);
if (dots >= 1) {
topList.append(dotsBuilder.append(text((".".repeat(dots)))));
topList.append(componentFactory.dotsBuilder().append(text((".".repeat(dots)))));
}
} else {
}
else {
topList.append(playerNameBuilder.append(text(":")));
}
if (timeUnits != null) {
topList.append(space()).append(getTimeNumberComponent(topStats.get(playerName), request.getSelection(), timeUnits));
} else {
topList.append(space()).append(getStatNumberComponent(request.getStatistic(), topStats.get(playerName), Target.TOP, request.isConsoleSender()));
}
topList.append(space()).append(getStatNumberComponent(request.getStatistic(), topStats.get(playerName), Target.TOP, request.isConsoleSender()));
}
return topList.build();
}
@ -203,6 +181,17 @@ public class MessageWriter {
.hoverEvent(HoverEvent.showText(text("CLICK ME").color(PluginColor.LIGHT_GOLD.getColor()))));
}
public TextComponent usageExamples(boolean isBukkitConsole) {
return new ExampleMessage(componentFactory, isBukkitConsole);
}
public TextComponent helpMsg(boolean isConsoleSender) {
return new HelpMessage(componentFactory,
config.useHoverText() && !isConsoleSender,
isConsoleSender && Bukkit.getName().equalsIgnoreCase("CraftBukkit"),
config.getTopListMaxSize());
}
/** Depending on the config settings, return either a TranslatableComponent representing
the statName (and potential subStatName), or a TextComponent with capitalized English names.*/
private TextComponent getStatNameComponent(StatRequest request) {
@ -222,8 +211,8 @@ public class MessageWriter {
}
else {
return componentFactory.statNameTextComponent(
getPrettyName(request.getStatistic().toString()),
getPrettyName(request.getSubStatEntry()),
StringUtils.prettify(request.getStatistic().toString()),
StringUtils.prettify(request.getSubStatEntry()),
request.getSelection());
}
}
@ -337,43 +326,4 @@ public class MessageWriter {
return Component.space()
.append(componentFactory.statUnitComponent(statName, null, selection));
}
/** Returns "block", "entity", "item", or "sub-statistic" if the provided Type is null. */
private String getSubStatTypeName(Statistic.Type statType) {
String subStat = "sub-statistic";
if (statType == null) return subStat;
switch (statType) {
case BLOCK -> subStat = "block";
case ENTITY -> subStat = "entity";
case ITEM -> subStat = "item";
}
return subStat;
}
/** Replace "_" with " " and capitalize each first letter of the input.
@param input String to prettify, case-insensitive*/
private String getPrettyName(String input) {
if (input == null) return null;
StringBuilder capitals = new StringBuilder(input.toLowerCase());
capitals.setCharAt(0, Character.toUpperCase(capitals.charAt(0)));
while (capitals.indexOf("_") != -1) {
MyLogger.replacingUnderscores();
int index = capitals.indexOf("_");
capitals.setCharAt(index + 1, Character.toUpperCase(capitals.charAt(index + 1)));
capitals.setCharAt(index, ' ');
}
return capitals.toString();
}
public TextComponent usageExamples(boolean isBukkitConsole) {
return new ExampleMessage(componentFactory, isBukkitConsole);
}
public TextComponent helpMsg(boolean isConsoleSender) {
return new HelpMessage(componentFactory,
config.useHoverText() && !isConsoleSender,
isConsoleSender && Bukkit.getName().equalsIgnoreCase("CraftBukkit"),
config.getTopListMaxSize());
}
}

View File

@ -0,0 +1,19 @@
package com.gmail.artemis.the.gr8.playerstats.msg.msgutils;
import org.bukkit.map.MinecraftFont;
public final class FontUtils {
private FontUtils() {
}
public static int getNumberOfDotsToAlign(String displayText, boolean isConsoleSender, boolean fontIsBold) {
if (isConsoleSender) {
return (int) Math.round((130.0 - MinecraftFont.Font.getWidth(displayText))/6) + 7;
} else if (!fontIsBold) {
return (int) Math.round((130.0 - MinecraftFont.Font.getWidth(displayText))/2);
} else {
return (int) Math.round((130.0 - (MinecraftFont.Font.getWidth(displayText) * 1.5))/2);
}
}
}

View File

@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashMap;
public class LanguageKeyHandler {
public final class LanguageKeyHandler {
private final HashMap<Statistic, String> statNameKeys;

View File

@ -1,10 +1,10 @@
package com.gmail.artemis.the.gr8.playerstats.msg;
package com.gmail.artemis.the.gr8.playerstats.msg.msgutils;
import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import java.text.DecimalFormat;
public class NumberFormatter {
public final class NumberFormatter {
private final DecimalFormat format;
@ -23,17 +23,11 @@ public class NumberFormatter {
public String format(long number, Unit statUnit, Unit smallTimeUnit) {
if (smallTimeUnit == null) {
switch (statUnit.getType()) {
case DISTANCE -> {
return formatDistance(number, statUnit);
}
case DAMAGE -> {
return formatDamage(number, statUnit);
}
default -> {
return format.format(number);
}
}
return switch (statUnit.getType()) {
case DISTANCE -> formatDistance(number, statUnit);
case DAMAGE -> formatDamage(number, statUnit);
default -> format.format(number);
};
} else {
return formatTime(number, statUnit, smallTimeUnit);
}

View File

@ -0,0 +1,25 @@
package com.gmail.artemis.the.gr8.playerstats.msg.msgutils;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
public final class StringUtils {
private StringUtils() {
}
/** Replace "_" with " " and capitalize each first letter of the input.
@param input String to prettify, case-insensitive*/
public static String prettify(String input) {
if (input == null) return null;
StringBuilder capitals = new StringBuilder(input.toLowerCase());
capitals.setCharAt(0, Character.toUpperCase(capitals.charAt(0)));
while (capitals.indexOf("_") != -1) {
MyLogger.replacingUnderscores();
int index = capitals.indexOf("_");
capitals.setCharAt(index + 1, Character.toUpperCase(capitals.charAt(index + 1)));
capitals.setCharAt(index, ' ');
}
return capitals.toString();
}
}

View File

@ -18,7 +18,6 @@ public class EnumHandler {
private final static List<String> entityNames;
private final static List<String> itemNames;
private final static List<String> statNames;
private final static List<String> entitySubStatNames;
private final static List<String> subStatNames;
static {
@ -26,40 +25,34 @@ public class EnumHandler {
.filter(Material::isBlock)
.map(Material::toString)
.map(String::toLowerCase)
.toList();
.collect(Collectors.toList());
entityNames = Arrays.stream(EntityType.values())
.map(EntityType::toString)
.map(String::toLowerCase)
.filter(entityName -> !entityName.equalsIgnoreCase("unknown"))
.toList();
.collect(Collectors.toList());
itemNames = Arrays.stream(Material.values())
.filter(Material::isItem)
.map(Material::toString)
.map(String::toLowerCase)
.toList();
statNames = Arrays.stream(Statistic.values())
.map(Statistic::toString)
.map(String::toLowerCase)
.toList();
entitySubStatNames = Arrays.stream(Statistic.values())
.filter(statistic -> statistic.getType().equals(Statistic.Type.ENTITY))
.map(Statistic::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
subStatNames = Stream.of(blockNames, entityNames, itemNames)
.flatMap(Collection::stream)
.toList();
.distinct()
.collect(Collectors.toList());
statNames = Arrays.stream(Statistic.values())
.map(Statistic::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
}
private EnumHandler() {
}
/** Returns all item names in lowercase */
public static List<String> getItemNames() {
return itemNames;
}
@ -112,16 +105,10 @@ public class EnumHandler {
return statNames.contains(statName.toLowerCase());
}
public static boolean isDistanceStatistic(@NotNull String statName) {
return statName.toLowerCase().contains("one_cm");
}
public static boolean isDamageStatistic(@NotNull String statName) {
return statName.toLowerCase().contains("damage");
}
public static boolean isTimeStatistic(@NotNull String statName) {
return statName.toLowerCase().contains("time") || statName.toLowerCase().contains("one_minute");
/** Checks whether the given String equals the name of an entity-type statistic. */
public static boolean isEntityStatistic(String statName) {
return statName.equalsIgnoreCase(Statistic.ENTITY_KILLED_BY.toString()) ||
statName.equalsIgnoreCase(Statistic.KILL_ENTITY.toString());
}
/** Returns the names of all general statistics in lowercase */
@ -140,14 +127,21 @@ public class EnumHandler {
}
}
/** Returns "block", "entity", "item", or "sub-statistic" if the provided Type is null. */
public static String getSubStatTypeName(Statistic.Type statType) {
String subStat = "sub-statistic";
if (statType == null) return subStat;
switch (statType) {
case BLOCK -> subStat = "block";
case ENTITY -> subStat = "entity";
case ITEM -> subStat = "item";
}
return subStat;
}
/** Checks if this statistic is a subStatEntry, meaning it is a block, item or entity
@param statName String, case-insensitive*/
public static boolean isSubStatEntry(@NotNull String statName) {
return subStatNames.contains(statName.toLowerCase());
}
/** Returns all statistics that have type entities, in lowercase */
public static List<String> getEntitySubStatNames() {
return entitySubStatNames;
}
}