diff --git a/src/main/java/cc/fascinated/bat/command/impl/server/MemberCountCommand.java b/src/main/java/cc/fascinated/bat/command/impl/server/MemberCountCommand.java index 96652bb..8d2e13f 100644 --- a/src/main/java/cc/fascinated/bat/command/impl/server/MemberCountCommand.java +++ b/src/main/java/cc/fascinated/bat/command/impl/server/MemberCountCommand.java @@ -4,7 +4,7 @@ import cc.fascinated.bat.Emojis; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.CommandInfo; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.common.NumberUtils; +import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import lombok.NonNull; @@ -52,17 +52,17 @@ public class MemberCountCommand extends BatCommand { %s Idle: `%s` %s Do Not Disturb: `%s` %s Offline: `%s`""".formatted( - NumberUtils.formatNumberCommas(totalMembers), - NumberUtils.formatNumberCommas(totalUsers), - NumberUtils.formatNumberCommas(totalBots), + NumberFormatter.format(totalMembers), + NumberFormatter.format(totalUsers), + NumberFormatter.format(totalBots), Emojis.ONLINE_EMOJI, - NumberUtils.formatNumberCommas(memberCounts.getOrDefault(OnlineStatus.ONLINE, 0)), + NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.ONLINE, 0)), Emojis.IDLE_EMOJI, - NumberUtils.formatNumberCommas(memberCounts.getOrDefault(OnlineStatus.IDLE, 0)), + NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.IDLE, 0)), Emojis.DND_EMOJI, - NumberUtils.formatNumberCommas(memberCounts.getOrDefault(OnlineStatus.DO_NOT_DISTURB, 0)), + NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.DO_NOT_DISTURB, 0)), Emojis.OFFLINE_EMOJI, - NumberUtils.formatNumberCommas(memberCounts.getOrDefault(OnlineStatus.OFFLINE, 0)))); + NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.OFFLINE, 0)))); interaction.replyEmbeds(embed.build()).queue(); } } \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/common/NumberFormatter.java b/src/main/java/cc/fascinated/bat/common/NumberFormatter.java new file mode 100644 index 0000000..fc8ecc3 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/common/NumberFormatter.java @@ -0,0 +1,83 @@ +package cc.fascinated.bat.common; + +import java.text.DecimalFormat; +import java.util.Locale; + +/** + * @author Fascinated (fascinated7) + */ +public class NumberFormatter { + /** + * The suffixes for the numbers + */ + private static final String[] SUFFIXES = new String[] { "K", "M", "B", "T", "Q", "QT", "S", "SP", "O", "N", "D", "UD", "DD", "TD" }; + private static final DecimalFormat FORMAT = new DecimalFormat("###.##"); + + /** + * Format the provided double + * + * @param input the value to format + * @return the formatted double, in the format of xx.xx[suffix] + */ + public static String format(double input) { + if (Double.isNaN(input)) { + return "ERROR"; + } + if (Double.isInfinite(input) || input == Double.MAX_VALUE) { + return "∞"; + } + if (1000 > input) { + return FORMAT.format(input); + } + double power = (int) Math.log10(input); + int index = (int) Math.floor(power / 3) - 1; + double factor = input / Math.pow(10, 3 + index * 3); + if (index >= SUFFIXES.length) { + return "ERROR"; + } + return FORMAT.format(factor) + SUFFIXES[index]; + } + + /** + * Format the provided double with commas + * + * @param input the value to format + * @return the formatted double, in the format of xx,xxx,xxx + */ + public static String formatCommas(double input) { + return String.format("%,.0f", input); + } + + /** + * Turns a provided string into a double, for example 1M -> 1000000.00 + * Accepts decimal and negative values and is not case-sensitive + * + * @param input the string to convert + * @return the value the string represents + */ + public static double fromString(String input) { + if ((input = input.trim()).isEmpty()) { + return -1D; + } + try { + double value = Double.parseDouble(input); // parse pure numbers + if (Double.isNaN(value) || Double.isInfinite(value)) { + return -1; + } + return value; + } catch (NumberFormatException ignored) { + input = input.toUpperCase(Locale.UK); + for (int i = SUFFIXES.length - 1; i > 0; i--) { + String suffix = SUFFIXES[i]; + if (!input.endsWith(suffix)) { + continue; + } + String amount = input.substring(0, input.length() - suffix.length()); + if (!amount.isEmpty()) { + return Double.parseDouble(amount) * Math.pow(10, 3 + i * 3); + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/common/NumberUtils.java b/src/main/java/cc/fascinated/bat/common/NumberUtils.java deleted file mode 100644 index 21770d1..0000000 --- a/src/main/java/cc/fascinated/bat/common/NumberUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -package cc.fascinated.bat.common; - -import lombok.experimental.UtilityClass; - -import java.text.NumberFormat; - -/** - * @author Fascinated (fascinated7) - */ -@UtilityClass -public class NumberUtils { - /** - * Formats a number with commas. - *

- * Example: 1000 -> 1,000 | Example: 1000.5 -> 1,000.5 - *

- * - * @param number the number to format - * @return the formatted number - */ - public static String formatNumberCommas(double number) { - NumberFormat format = NumberFormat.getNumberInstance(); - format.setGroupingUsed(true); - format.setMaximumFractionDigits(2); - return format.format(number); - } -} diff --git a/src/main/java/cc/fascinated/bat/features/command/ListSubCommand.java b/src/main/java/cc/fascinated/bat/features/command/ListSubCommand.java index 0a29881..5184281 100644 --- a/src/main/java/cc/fascinated/bat/features/command/ListSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/command/ListSubCommand.java @@ -8,14 +8,10 @@ import cc.fascinated.bat.features.FeatureProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.FeatureService; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import net.dv8tion.jda.api.interactions.commands.OptionMapping; -import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java index 7a01469..a19ff7f 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.features.scoresaber; -import cc.fascinated.bat.common.NumberUtils; +import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile; import cc.fascinated.bat.model.BatGuild; @@ -41,7 +41,7 @@ public class NumberOneScoreFeedListener implements EventListener { log.info("A new #1 score has been set by {} on {} ({})!", player.getName(), leaderboard.getSongName(), - "%s⭐".formatted(NumberUtils.formatNumberCommas(leaderboard.getStars())) + "%s⭐".formatted(NumberFormatter.formatCommas(leaderboard.getStars())) ); for (Guild guild : DiscordService.JDA.getGuilds()) { diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java b/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java index 43df435..382f608 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/ScoreSaberFeature.java @@ -3,7 +3,7 @@ package cc.fascinated.bat.features.scoresaber; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.common.DateUtils; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.common.NumberUtils; +import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.common.ScoreSaberUtils; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.scoresaber.command.numberone.NumberOneFeedCommand; @@ -55,10 +55,10 @@ public class ScoreSaberFeature extends Feature { ); String accuracy = leaderboardToken.getMaxScore() == 0 ? "N/A" : - String.format("%s%%", NumberUtils.formatNumberCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100)); + String.format("%s%%", NumberFormatter.formatCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100)); - String rawPp = scoreToken.getPp() == 0 ? "Unranked" : NumberUtils.formatNumberCommas(scoreToken.getPp()); - String rank = String.format("#%s", NumberUtils.formatNumberCommas(scoreToken.getRank())); + String rawPp = scoreToken.getPp() == 0 ? "Unranked" : NumberFormatter.formatCommas(scoreToken.getPp()); + String rank = String.format("#%s", NumberFormatter.formatCommas(scoreToken.getRank())); String misses = String.format("%s", scoreToken.getMissedNotes()); String badCuts = String.format("%s", scoreToken.getBadCuts()); String maxCombo = String.format("%s %s", diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java index d08172e..ae50353 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java @@ -5,7 +5,7 @@ import cc.fascinated.bat.command.CommandInfo; import cc.fascinated.bat.common.Colors; import cc.fascinated.bat.common.DateUtils; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.common.NumberUtils; +import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.exception.RateLimitException; import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile; import cc.fascinated.bat.model.BatGuild; @@ -84,9 +84,9 @@ public class ScoreSaberCommand extends BatCommand { "https://cdn.scoresaber.com/avatars/%s.jpg".formatted(account.getId())) .addField("Name", account.getName(), true) .addField("Country", account.getCountry(), true) - .addField("Rank", "#" + NumberUtils.formatNumberCommas(account.getRank()), true) - .addField("Country Rank", "#" + NumberUtils.formatNumberCommas(account.getCountryRank()), true) - .addField("PP", NumberUtils.formatNumberCommas(account.getPp()), true) + .addField("Rank", "#" + NumberFormatter.formatCommas(account.getRank()), true) + .addField("Country Rank", "#" + NumberFormatter.formatCommas(account.getCountryRank()), true) + .addField("PP", NumberFormatter.formatCommas(account.getPp()), true) .addField("Joined", "".formatted(DateUtils.getDateFromString(account.getFirstSeen()).toInstant().toEpochMilli() / 1000), true) .setTimestamp(LocalDateTime.now()) .setFooter(fetchTime > 3 ? "Fetched in %sms".formatted(fetchTime) : "Cached", "https://flagcdn.com/h120/%s.png".formatted(account.getCountry().toLowerCase())) diff --git a/src/main/java/cc/fascinated/bat/service/DiscordService.java b/src/main/java/cc/fascinated/bat/service/DiscordService.java index d3ded74..3110ce6 100644 --- a/src/main/java/cc/fascinated/bat/service/DiscordService.java +++ b/src/main/java/cc/fascinated/bat/service/DiscordService.java @@ -1,5 +1,6 @@ package cc.fascinated.bat.service; +import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.common.TimerUtils; import lombok.Getter; import net.dv8tion.jda.api.JDA; @@ -26,10 +27,9 @@ public class DiscordService { public static JDA JDA; private final List messages = List.of( - "over {guilds} guilds", - "over {users} users", - "over ScoreSaber scores", - "your messages", + "{guilds} guilds", + "{users} users", + "your ScoreSaber scores", "/help for help" ); @@ -60,8 +60,8 @@ public class DiscordService { public void updateActivity() { int guildCount = JDA.getGuilds().size(); JDA.getPresence().setActivity(Activity.watching(messages.get(guildCount % messages.size()) - .replace("{guilds}", String.valueOf(guildCount)) - .replace("{users}", String.valueOf(JDA.getUsers().size())) + .replace("{guilds}", NumberFormatter.format(guildCount)) + .replace("{users}", NumberFormatter.format(JDA.getUsers().size())) )); } } diff --git a/src/main/java/cc/fascinated/bat/service/FeatureService.java b/src/main/java/cc/fascinated/bat/service/FeatureService.java index 650c8ef..4f4ee0e 100644 --- a/src/main/java/cc/fascinated/bat/service/FeatureService.java +++ b/src/main/java/cc/fascinated/bat/service/FeatureService.java @@ -12,9 +12,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; /**