diff --git a/Changelog.txt b/Changelog.txt index 64781125a..101a74ab1 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,7 @@ +Version 2.1.153 + Fixed a bug where most sub-skills were not being displayed when using a skills command (for example /taming) + Fixed a bug where some URL links were not being colored + Version 2.1.152 Fixed a bug where Tree Feller would sometimes double drop blocks inappropriately Fixed a bug with bleed damage calculations and player armor diff --git a/pom.xml b/pom.xml index 7a662f7a0..0006c8fa2 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.152 + 2.1.153-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO @@ -202,17 +202,17 @@ net.kyori adventure-text-serializer-gson - 4.1.1 + 4.2.0-SNAPSHOT net.kyori adventure-api - 4.1.1 + 4.2.0-SNAPSHOT net.kyori adventure-nbt - 4.1.1 + 4.2.0-SNAPSHOT net.kyori diff --git a/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java b/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java index 276c997f6..302fe335c 100644 --- a/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java @@ -22,11 +22,15 @@ import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.concurrent.atomic.AtomicReference; /** * This class handles many of the JSON components that mcMMO makes and uses @@ -105,49 +109,138 @@ public class TextComponentFactory { ), MessageType.SYSTEM); } - public static void sendPlayerSubSkillList(Player player, List textComponents) - { - TextComponent emptySpace = Component.space(); - - AtomicReference messageToSend = new AtomicReference<>(); - int newLineCount = 0; //Hacky solution to wordwrap problems - + public static void sendPlayerSubSkillList(@NotNull Player player, @NotNull List subSkillComponents) { final Audience audience = mcMMO.getAudiences().player(player); - for (Component textComponent : textComponents) { - //Don't send more than 3 subskills per line to avoid MOST wordwrap problems - if(newLineCount > 2) - { - Component toSend = messageToSend.get(); - if (toSend != null) { - audience.sendMessage(Identity.nil(), toSend.append(emptySpace)); - } - messageToSend.set(null); - newLineCount = 0; - } - //Style the skills into @links - final String originalTxt = textComponent instanceof TextComponent ? ((TextComponent) textComponent).content() : ""; + //@ Signs, done for style + Component space = Component.space(); + TextComponent atSignComponent = Component.text(LocaleLoader.getString("JSON.Hover.AtSymbolSkills")); - TextComponent.Builder stylizedText = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolSkills")); - addChild(stylizedText, originalTxt); + //Only send 3 sub-skills per line + Component[][] splitSubSkills = splitComponentsIntoGroups(subSkillComponents, 3); + ArrayList individualLinesToSend = new ArrayList<>(); - if(textComponent.hoverEvent() != null) - stylizedText.hoverEvent(textComponent.hoverEvent()); - - if(textComponent.clickEvent() != null) - stylizedText.clickEvent(textComponent.clickEvent()); - - messageToSend.set(stylizedText.build().append(emptySpace)); - - newLineCount++; + //Create each line + for (Component[] componentArray : splitSubSkills) { + individualLinesToSend.add(fromArray(componentArray, atSignComponent, space)); } - Component toSend = messageToSend.get(); - if (toSend != null) { - audience.sendMessage(Identity.nil(), toSend.append(emptySpace)); + //Send each group + for(Component curLine : individualLinesToSend) { + audience.sendMessage(Identity.nil(), curLine); } } + /** + * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component + * @param componentsArray target array + * @return + */ + private static @NotNull Component fromArray(@NotNull Component[] componentsArray, @Nullable Component prefixComponent, @Nullable Component suffixComponent) { + TextComponent.Builder componentBuilder = Component.text(); + + for(Component component : componentsArray) { + if(component == null) //Individual elements can be null + continue; + + if(prefixComponent != null) + componentBuilder.append(prefixComponent); + + componentBuilder.append(component); + + if(suffixComponent != null) + componentBuilder.append(suffixComponent); + + } + + return componentBuilder.build(); + } + + + /** + * Takes a list of components and splits them into arrays each with a maximum element limit + * Individual elements in [][X] may be null + * + * @param components target component list + * @param groupsSize maximum size per array + * @return a 2D array with components split into groups + */ + private static @NotNull Component[][] splitComponentsIntoGroups(@NotNull List components, int groupsSize) { + int groupCount = (int) Math.ceil((double) components.size() / (double) groupsSize); + + Component[][] splitGroups = new Component[groupCount][groupsSize]; + + int groupsFinished = 0; + + while (groupsFinished < groupCount) { + //Fill group with members + for(int i = 0; i < groupsSize; i++) { + int indexOfPotentialMember = i + (groupsFinished * 3); //Groups don't always fill all members neatly + + //Some groups won't have entirely non-null elements + if(indexOfPotentialMember > components.size()-1) { + break; + } + + Component potentialMember = components.get(indexOfPotentialMember); + + //Make sure the potential member exists because of rounding + if(potentialMember != null) { + splitGroups[groupsFinished][i] = potentialMember; + } + } + + //Another group is finished + groupsFinished++; + } + + return splitGroups; + } + + +// public static void sendPlayerSubSkillList(Player player, List textComponents) +// { +// TextComponent emptySpace = Component.space(); +// +// AtomicReference messageToSend = new AtomicReference<>(); +// int newLineCount = 0; //Hacky solution to wordwrap problems +// +// final Audience audience = mcMMO.getAudiences().player(player); +// for (Component textComponent : textComponents) { +// //Don't send more than 3 subskills per line to avoid MOST wordwrap problems +// if(newLineCount > 2) +// { +// Component toSend = messageToSend.get(); +// if (toSend != null) { +// audience.sendMessage(Identity.nil(), toSend.append(emptySpace)); +// } +// +// messageToSend.set(null); +// newLineCount = 0; +// } +// //Style the skills into @links +// final String originalTxt = textComponent instanceof TextComponent ? ((TextComponent) textComponent).content() : ""; +// +// TextComponent.Builder stylizedText = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolSkills")); +// addChild(stylizedText, originalTxt); +// +// if(textComponent.hoverEvent() != null) +// stylizedText.hoverEvent(textComponent.hoverEvent()); +// +// if(textComponent.clickEvent() != null) +// stylizedText.clickEvent(textComponent.clickEvent()); +// +// messageToSend.set(stylizedText.build().append(emptySpace)); +// +// newLineCount++; +// } +// +// Component toSend = messageToSend.get(); +// if (toSend != null) { +// audience.sendMessage(Identity.nil(), toSend.append(emptySpace)); +// } +// } + private static Component getWebLinkTextComponent(McMMOWebLinks webLinks) { TextComponent.Builder webTextComponent; @@ -201,8 +294,7 @@ public class TextComponentFactory { } private static void addChild(ComponentBuilder webTextComponent, String childName) { - TextComponent childComponent = Component.text(childName); - childComponent.color(NamedTextColor.BLUE); + TextComponent childComponent = Component.text(childName).color(NamedTextColor.BLUE); webTextComponent.append(childComponent); }