commit e86e6258a231af2d97a2bab5b3b54e040f31debd Author: Liam Date: Wed Mar 20 13:42:42 2024 +0000 bob diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..8f00030 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/copilot/chatSessions/00000000000.xd b/.idea/copilot/chatSessions/00000000000.xd new file mode 100644 index 0000000..7122368 Binary files /dev/null and b/.idea/copilot/chatSessions/00000000000.xd differ diff --git a/.idea/copilot/chatSessions/blobs/version b/.idea/copilot/chatSessions/blobs/version new file mode 100644 index 0000000..720d64f Binary files /dev/null and b/.idea/copilot/chatSessions/blobs/version differ diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6a35cd4 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3394e6a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..31c840a --- /dev/null +++ b/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + cc.fascinated + aetheria + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + + + io.papermc.paper + paper-api + 1.20.4-R0.1-SNAPSHOT + provided + + + org.projectlombok + lombok + 1.18.32 + provided + + + + \ No newline at end of file diff --git a/src/main/java/cc/fascinated/Aetheria.java b/src/main/java/cc/fascinated/Aetheria.java new file mode 100644 index 0000000..7176746 --- /dev/null +++ b/src/main/java/cc/fascinated/Aetheria.java @@ -0,0 +1,26 @@ +package cc.fascinated; + +import cc.fascinated.command.CommandManager; +import cc.fascinated.worldsize.WorldSizeManager; +import cc.fascinated.worldsize.impl.WorldSizeCommand; +import org.bukkit.plugin.java.JavaPlugin; + +public class Aetheria extends JavaPlugin { + + /** + * The instance of the plugin. + */ + public static Aetheria INSTANCE; + + public static final String PREFIX = "§6§lAetheria §7» §f"; + + public Aetheria() { + INSTANCE = this; + } + + @Override + public void onEnable() { + new CommandManager(); + new WorldSizeManager(); + } +} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/command/Command.java b/src/main/java/cc/fascinated/command/Command.java new file mode 100644 index 0000000..b41d121 --- /dev/null +++ b/src/main/java/cc/fascinated/command/Command.java @@ -0,0 +1,23 @@ +package cc.fascinated.command; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +@RequiredArgsConstructor @Getter +public abstract class Command implements CommandExecutor { + + private final String command; + + private final String[] permissions; + + @Override + public boolean onCommand(@NotNull CommandSender commandSender, org.bukkit.command.@NotNull Command command, @NotNull String s, @NotNull String[] strings) { + execute(commandSender, strings); + return true; + } + + public abstract void execute(CommandSender commandSender, String[] args); +} diff --git a/src/main/java/cc/fascinated/command/CommandManager.java b/src/main/java/cc/fascinated/command/CommandManager.java new file mode 100644 index 0000000..269863c --- /dev/null +++ b/src/main/java/cc/fascinated/command/CommandManager.java @@ -0,0 +1,21 @@ +package cc.fascinated.command; + +import cc.fascinated.Aetheria; +import cc.fascinated.command.impl.TotalJoinsCommand; +import org.bukkit.Bukkit; + +import java.util.Objects; + +public class CommandManager { + + public CommandManager() { + registerCommand(new TotalJoinsCommand()); + } + + public static void registerCommand(Command command) { + if (command == null) { + throw new IllegalArgumentException("Command cannot be null."); + } + Objects.requireNonNull(Aetheria.INSTANCE.getCommand(command.getCommand())).setExecutor(command); + } +} diff --git a/src/main/java/cc/fascinated/command/impl/TotalJoinsCommand.java b/src/main/java/cc/fascinated/command/impl/TotalJoinsCommand.java new file mode 100644 index 0000000..89453cc --- /dev/null +++ b/src/main/java/cc/fascinated/command/impl/TotalJoinsCommand.java @@ -0,0 +1,18 @@ +package cc.fascinated.command.impl; + +import cc.fascinated.Aetheria; +import cc.fascinated.command.Command; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +public class TotalJoinsCommand extends Command { + + public TotalJoinsCommand() { + super("totaljoins", new String[]{ "aetheria.command.totaljoins" }); + } + + @Override + public void execute(CommandSender commandSender, String[] args) { + commandSender.sendPlainMessage(Aetheria.PREFIX + "§fTotal joins: §e" + Bukkit.getOfflinePlayers().length + "§f."); + } +} diff --git a/src/main/java/cc/fascinated/utils/FormatterUtils.java b/src/main/java/cc/fascinated/utils/FormatterUtils.java new file mode 100644 index 0000000..4538642 --- /dev/null +++ b/src/main/java/cc/fascinated/utils/FormatterUtils.java @@ -0,0 +1,13 @@ +package cc.fascinated.utils; + +public class FormatterUtils { + + public static String formatBytes(long bytes) { + if (bytes < 1024) { + return bytes + " B"; + } + int exp = (int) (Math.log(bytes) / Math.log(1024)); + char pre = "KMGTPE".charAt(exp - 1); + return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre); + } +} diff --git a/src/main/java/cc/fascinated/utils/MathUtils.java b/src/main/java/cc/fascinated/utils/MathUtils.java new file mode 100644 index 0000000..965e789 --- /dev/null +++ b/src/main/java/cc/fascinated/utils/MathUtils.java @@ -0,0 +1,22 @@ +package cc.fascinated.utils; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +public class MathUtils { + + /** + * Format a number to a specific amount of decimal places. + * + * @param number the number to format + * @param additional the additional decimal places to format + * @return the formatted number + */ + public static double format(double number, int additional) { + return Double.parseDouble( + new DecimalFormat("#.#" + "#".repeat(Math.max(0, additional - 1)), + new DecimalFormatSymbols() + ).format(number) + ); + } +} diff --git a/src/main/java/cc/fascinated/utils/TimeUtils.java b/src/main/java/cc/fascinated/utils/TimeUtils.java new file mode 100644 index 0000000..0608fca --- /dev/null +++ b/src/main/java/cc/fascinated/utils/TimeUtils.java @@ -0,0 +1,162 @@ +package cc.fascinated.utils; + +import lombok.*; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import java.text.SimpleDateFormat; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@UtilityClass +public final class TimeUtils { + /** + * Format a time in millis to a readable time format. + * + * @param millis the millis to format + * @return the formatted time + */ + public static String format(long millis) { + return format(millis, WildTimeUnit.FIT); + } + + /** + * Format a time in millis to a readable time format. + * + * @param millis the millis to format + * @param timeUnit the time unit to format the millis to + * @return the formatted time + */ + public static String format(long millis, WildTimeUnit timeUnit) { + return format(millis, timeUnit, false); + } + + /** + * Format a time in millis to a readable time format. + * + * @param millis the millis to format + * @param timeUnit the time unit to format the millis to + * @param compact whether to use a compact display + * @return the formatted time + */ + public static String format(long millis, WildTimeUnit timeUnit, boolean compact) { + return format(millis, timeUnit, true, compact); + } + + /** + * Format a time in millis to a readable time format. + * + * @param millis the millis to format + * @param timeUnit the time unit to format the millis to + * @param decimals whether to include decimals + * @param compact whether to use a compact display + * @return the formatted time + */ + public static String format(long millis, WildTimeUnit timeUnit, boolean decimals, boolean compact) { + if (millis == -1L) { // Format permanent + return "Perm" + (compact ? "" : "anent"); + } + // Format the time to the best fitting time unit + if (timeUnit == WildTimeUnit.FIT) { + for (WildTimeUnit otherTimeUnit : WildTimeUnit.VALUES) { + if (otherTimeUnit != WildTimeUnit.FIT && millis >= otherTimeUnit.getMillis()) { + timeUnit = otherTimeUnit; + break; + } + } + } + double time = MathUtils.format((double) millis / timeUnit.getMillis(), 1); // Format the time + if (!decimals) { // Remove decimals + time = (int) time; + } + String formatted = time + (compact ? timeUnit.getSuffix() : " " + timeUnit.getDisplay()); // Append the time unit + if (time != 1.0 && !compact) { // Pluralize the time unit + formatted+= "s"; + } + return formatted; + } + + /** + * Convert the given input into a time in millis. + *

+ * E.g: 1d, 1h, 1d1h, etc + *

+ * + * @param input the input to parse + * @return the time in millis + */ + public static long fromString(String input) { + Matcher matcher = WildTimeUnit.SUFFIX_PATTERN.matcher(input); // Match the given input + long millis = 0; // The total millis + + // Match corresponding suffixes and add up the total millis + while (matcher.find()) { + int amount = Integer.parseInt(matcher.group(1)); // The amount of time to add + String suffix = matcher.group(2); // The unit suffix + WildTimeUnit timeUnit = WildTimeUnit.fromSuffix(suffix); // The time unit to add + if (timeUnit != null) { // Increment the total millis + millis+= amount * timeUnit.getMillis(); + } + } + return millis; + } + + /** + * Represents a unit of time. + */ + @NoArgsConstructor @AllArgsConstructor + @Getter(AccessLevel.PRIVATE) @ToString + public enum WildTimeUnit { + FIT, + YEARS("Year", "y", TimeUnit.DAYS.toMillis(365L)), + MONTHS("Month", "mo", TimeUnit.DAYS.toMillis(30L)), + WEEKS("Week", "w", TimeUnit.DAYS.toMillis(7L)), + DAYS("Day", "d", TimeUnit.DAYS.toMillis(1L)), + HOURS("Hour", "h", TimeUnit.HOURS.toMillis(1L)), + MINUTES("Minute", "m", TimeUnit.MINUTES.toMillis(1L)), + SECONDS("Second", "s", TimeUnit.SECONDS.toMillis(1L)), + MILLISECONDS("Millisecond", "ms", 1L); + + /** + * Our cached unit values. + */ + public static final WildTimeUnit[] VALUES = values(); + + /** + * Our cached suffix pattern. + */ + public static final Pattern SUFFIX_PATTERN = Pattern.compile("(\\d+)(mo|ms|[ywdhms])"); + + /** + * The display of this time unit. + */ + private String display; + + /** + * The suffix of this time unit. + */ + private String suffix; + + /** + * The amount of millis in this time unit. + */ + private long millis; + + /** + * Get the time unit with the given suffix. + * + * @param suffix the time unit suffix + * @return the time unit, null if not found + */ + @Nullable + public static WildTimeUnit fromSuffix(String suffix) { + for (WildTimeUnit unit : VALUES) { + if (unit != FIT && unit.getSuffix().equals(suffix)) { + return unit; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/worldsize/WorldSizeManager.java b/src/main/java/cc/fascinated/worldsize/WorldSizeManager.java new file mode 100644 index 0000000..4b30627 --- /dev/null +++ b/src/main/java/cc/fascinated/worldsize/WorldSizeManager.java @@ -0,0 +1,64 @@ +package cc.fascinated.worldsize; + +import cc.fascinated.Aetheria; +import cc.fascinated.command.CommandManager; +import cc.fascinated.utils.FormatterUtils; +import cc.fascinated.worldsize.impl.WorldSizeCommand; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +public class WorldSizeManager { + + private static final int INTERVAL = 30; // 30 mins + + /** + * The total size of all worlds. + */ + @Getter + private static long totalWorldSize; + + /** + * The last time the total world size was updated. + */ + @Getter + private static long lastUpdated; + + public WorldSizeManager() { + CommandManager.registerCommand(new WorldSizeCommand()); + + totalWorldSize = calculateTotalWorldSize(); + Aetheria.INSTANCE.getServer().getAsyncScheduler().runAtFixedRate(Aetheria.INSTANCE, (task) -> { + totalWorldSize = calculateTotalWorldSize(); + }, INTERVAL, INTERVAL, TimeUnit.MINUTES); + } + + /** + * Get the total size of all worlds formatted. + * + * @return The total size of all worlds formatted. + */ + public static String getWorldSizeFormatted() { + return FormatterUtils.formatBytes(totalWorldSize); + } + + /** + * Calculate the total size of all worlds. + * + * @return The total size of all worlds. + */ + public long calculateTotalWorldSize() { + long size = 0; + for (World world : Bukkit.getWorlds()) { + File worldFolder = world.getWorldFolder(); + + size += FileUtils.sizeOfDirectory(worldFolder); + } + lastUpdated = System.currentTimeMillis(); + return size; + } +} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/worldsize/impl/WorldSizeCommand.java b/src/main/java/cc/fascinated/worldsize/impl/WorldSizeCommand.java new file mode 100644 index 0000000..5ea8a93 --- /dev/null +++ b/src/main/java/cc/fascinated/worldsize/impl/WorldSizeCommand.java @@ -0,0 +1,20 @@ +package cc.fascinated.worldsize.impl; + +import cc.fascinated.Aetheria; +import cc.fascinated.command.Command; +import cc.fascinated.utils.TimeUtils; +import cc.fascinated.worldsize.WorldSizeManager; +import org.bukkit.command.CommandSender; + +public class WorldSizeCommand extends Command { + + public WorldSizeCommand() { + super("worldsize", new String[]{ "aetheria.command.worldsize" }); + } + + @Override + public void execute(CommandSender commandSender, String[] args) { + commandSender.sendPlainMessage(Aetheria.PREFIX + "§fTotal size of all worlds: §e" + WorldSizeManager.getWorldSizeFormatted() + "§f."); + commandSender.sendPlainMessage(Aetheria.PREFIX + "§fLast updated: §e" + TimeUtils.format(System.currentTimeMillis() - WorldSizeManager.getLastUpdated()) + " ago§f."); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..c3c94db --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,10 @@ +name: Aetheria +main: cc.fascinated.Aetheria +version: 1.0 +commands: + totaljoins: + description: "Shows the total amount of joins" + usage: "/totaljoins" + worldsize: + description: "Shows the size of all worlds" + usage: "/worldsize" \ No newline at end of file