mirror of
https://github.com/hyperdefined/ToolStats.git
synced 2025-12-06 06:41:44 +00:00
feat: add format lore that replaces several placeholders with a map
This commit is contained in:
@@ -27,6 +27,7 @@ import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ItemLore {
|
||||
|
||||
@@ -767,8 +768,8 @@ public class ItemLore {
|
||||
}
|
||||
container.remove(toolStats.flightTime);
|
||||
if (meta.hasLore()) {
|
||||
String oldFlightTimeFormatted = toolStats.numberFormat.formatDouble(flightTime);
|
||||
Component lineToRemove = toolStats.configTools.formatLore("flight-time", "{time}", oldFlightTimeFormatted);
|
||||
Map<String, String> oldFlightTimeFormatted = toolStats.numberFormat.formatTime(flightTime);
|
||||
Component lineToRemove = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", oldFlightTimeFormatted);
|
||||
List<Component> newLore = removeLore(meta.lore(), lineToRemove);
|
||||
meta.lore(newLore);
|
||||
}
|
||||
@@ -815,10 +816,10 @@ public class ItemLore {
|
||||
}
|
||||
|
||||
container.set(toolStats.flightTime, PersistentDataType.LONG, flightTime + duration);
|
||||
String oldFlightFormatted = toolStats.numberFormat.formatTime(flightTime);
|
||||
String newFlightFormatted = toolStats.numberFormat.formatTime(flightTime + duration);
|
||||
Component oldLine = toolStats.configTools.formatLore("flight-time", "{time}", oldFlightFormatted);
|
||||
Component newLine = toolStats.configTools.formatLore("flight-time", "{time}", newFlightFormatted);
|
||||
Map<String, String> oldFlightFormatted = toolStats.numberFormat.formatTime(flightTime);
|
||||
Map<String, String> newFlightFormatted = toolStats.numberFormat.formatTime(flightTime + duration);
|
||||
Component oldLine = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", oldFlightFormatted);
|
||||
Component newLine = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", newFlightFormatted);
|
||||
if (oldLine == null || newLine == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class NumberFormat {
|
||||
|
||||
@@ -138,39 +140,57 @@ public class NumberFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats time in milliseconds in a human readable format.
|
||||
* @param time The time in milliseconds to format.
|
||||
* @return The time in a human readable format.
|
||||
* Returns a human readable form of time in milliseconds.
|
||||
* E.g. given 3752348000L outputs 1 years, 5 months, 2 weeks, 3 days, 14 hours, 12 minutes, 28 seconds.
|
||||
* @param time The time in ms.
|
||||
* @return Map with units as keys and time value, e.g. "years" (key) -> 1 (value)
|
||||
*/
|
||||
public String formatTime(Long time) {
|
||||
public Map<String, String> formatTime(Long time) {
|
||||
final int SECONDS_PER_MINUTE = 60;
|
||||
final int MINUTES_PER_HOUR = 60;
|
||||
final int HOURS_PER_DAY = 24;
|
||||
final int DAYS_PER_WEEK = 7;
|
||||
final int DAYS_PER_MONTH = 30; // Approximation
|
||||
final int DAYS_PER_YEAR = 365; // Approximation
|
||||
|
||||
long totalSeconds = time / 1000;
|
||||
|
||||
Map<String, String> timeUnits = new HashMap<>();
|
||||
|
||||
long years = totalSeconds / (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
if (years > 0) {
|
||||
timeUnits.put("years", Long.toString(years));
|
||||
}
|
||||
totalSeconds %= (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
long months = totalSeconds / (DAYS_PER_MONTH * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
if (months > 0) {
|
||||
timeUnits.put("months", Long.toString(months));
|
||||
}
|
||||
totalSeconds %= (DAYS_PER_MONTH * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
long weeks = totalSeconds / (DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
totalSeconds %= (DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
long days = totalSeconds / (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
if (days > 0) {
|
||||
timeUnits.put("days", Long.toString(days));
|
||||
}
|
||||
totalSeconds %= (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
long hours = totalSeconds / (MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
if (hours > 0) {
|
||||
timeUnits.put("hours", Long.toString(hours));
|
||||
}
|
||||
totalSeconds %= (MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
long minutes = totalSeconds / SECONDS_PER_MINUTE;
|
||||
if (minutes > 0) {
|
||||
timeUnits.put("minutes", Long.toString(minutes));
|
||||
}
|
||||
totalSeconds %= SECONDS_PER_MINUTE;
|
||||
|
||||
long seconds = totalSeconds;
|
||||
return "";
|
||||
if (seconds > 0 || timeUnits.isEmpty()) { // Always include seconds if everything else is zero
|
||||
timeUnits.put("seconds", Long.toString(seconds));
|
||||
}
|
||||
|
||||
return timeUnits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.bukkit.Material;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -133,6 +134,75 @@ public class ConfigTools {
|
||||
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string with several placeholders to be ready for lore usage.
|
||||
* @param configName The message to use.
|
||||
* @param placeHoldersValues Map containing placeholders names as keys and values.
|
||||
* @return Formatted string, null if the configName doesn't exist.
|
||||
*/
|
||||
public Component formatLoreMultiplePlaceholders(String configName, Map<String, String> placeHoldersValues) {
|
||||
String lore = toolStats.config.getString("messages." + configName);
|
||||
if (lore == null) {
|
||||
toolStats.logger.warning("Unable to find config message for: messages." + configName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the config message is empty, don't send it
|
||||
if (lore.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile("\\{([^}]+)\\}");
|
||||
Matcher matcher = pattern.matcher(lore);
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
while (matcher.find()) {
|
||||
String placeholder = matcher.group(1);
|
||||
if (placeHoldersValues.containsKey(placeholder)) {
|
||||
matcher.appendReplacement(result, placeHoldersValues.get(placeholder));
|
||||
} else {
|
||||
// Placeholder not found in our time values, so remove it and any unit suffix
|
||||
// Find the next non-alphanumeric character after this placeholder to remove the unit
|
||||
int end = matcher.end();
|
||||
while (end < lore.length() &&
|
||||
!Character.isWhitespace(lore.charAt(end)) &&
|
||||
!lore.substring(end, end + 1).matches("[^a-zA-Z]")) {
|
||||
end++;
|
||||
}
|
||||
|
||||
matcher.appendReplacement(result, "");
|
||||
|
||||
// Remove trailing space if there is one
|
||||
if (end < lore.length() && Character.isWhitespace(lore.charAt(end))) {
|
||||
// Skip this space in the next append
|
||||
end++;
|
||||
}
|
||||
|
||||
// Adjust region to char after skipped placeholder
|
||||
matcher.region(end, lore.length());
|
||||
}
|
||||
}
|
||||
|
||||
matcher.appendTail(result);
|
||||
|
||||
Component component;
|
||||
// Clean output text
|
||||
String outputText = result.toString().replaceAll("\\s+", " ").trim();
|
||||
|
||||
// if we match the old color codes, then format them as so
|
||||
Matcher hexMatcher = CONFIG_HEX_PATTERN.matcher(outputText);
|
||||
Matcher colorMatcher = COLOR_CODES.matcher(outputText);
|
||||
if (hexMatcher.find() || colorMatcher.find()) {
|
||||
component = LegacyComponentSerializer.legacyAmpersand().deserialize(outputText);
|
||||
} else {
|
||||
// otherwise format them normally
|
||||
component = MiniMessage.miniMessage().deserialize(outputText);
|
||||
}
|
||||
|
||||
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string from the config.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user