From 83aa504c308c0cd47c6bc9d47c88462de96ad30c Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Wed, 17 Dec 2025 14:47:09 +0100 Subject: [PATCH] Initial commit --- .gitignore | 113 ++++++++++++++++++ pom.xml | 95 +++++++++++++++ .../crateregistry/CrateKeyStorage.java | 106 ++++++++++++++++ .../crateregistry/CrateRegistry.java | 44 +++++++ .../crateregistry/command/ClaimCommand.java | 53 ++++++++ .../command/CrateRegistryCommand.java | 56 +++++++++ .../crateregistry/command/GiveCommand.java | 89 ++++++++++++++ .../crateregistry/command/PluginCommand.java | 48 ++++++++ src/main/resources/plugin.yml | 15 +++ 9 files changed, 619 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/net/knarcraft/crateregistry/CrateKeyStorage.java create mode 100644 src/main/java/net/knarcraft/crateregistry/CrateRegistry.java create mode 100644 src/main/java/net/knarcraft/crateregistry/command/ClaimCommand.java create mode 100644 src/main/java/net/knarcraft/crateregistry/command/CrateRegistryCommand.java create mode 100644 src/main/java/net/knarcraft/crateregistry/command/GiveCommand.java create mode 100644 src/main/java/net/knarcraft/crateregistry/command/PluginCommand.java create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87d4436 --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bbf244e --- /dev/null +++ b/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + net.knarcraft + crateregistry + 1.0-SNAPSHOT + jar + + CrateRegistry + + + 17 + UTF-8 + + + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + false + + + org.jetbrains.annotations + net.knarcraft.crateregistry.lib.annotations + + + + + org.jetbrains:annotations + + org/jetbrains/annotations/** + + + + + + + + + + + src/main/resources + true + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + + + + org.spigotmc + spigot-api + 1.20.2-R0.1-SNAPSHOT + provided + + + org.jetbrains + annotations + 24.0.0 + compile + + + diff --git a/src/main/java/net/knarcraft/crateregistry/CrateKeyStorage.java b/src/main/java/net/knarcraft/crateregistry/CrateKeyStorage.java new file mode 100644 index 0000000..e7957af --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/CrateKeyStorage.java @@ -0,0 +1,106 @@ +package net.knarcraft.crateregistry; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * A storage for players' unclaimed crates + */ +public class CrateKeyStorage { + + private final Map unclaimedCrateKeys; + private final FileConfiguration configuration; + + /** + * Initializes an empty crate key storage + * + * @param configuration

The file configuration to use for saving and loading

+ */ + public CrateKeyStorage(@NotNull FileConfiguration configuration) { + this.unclaimedCrateKeys = load(configuration); + this.configuration = configuration; + } + + /** + * Checks whether the given player has unclaimed crate keys + * + * @param player

The player to check

+ * @return

True if the player has unclaimed crate keys

+ */ + public boolean hasStoredKeys(@NotNull Player player) { + return this.unclaimedCrateKeys.containsKey(player.getUniqueId()); + } + + /** + * Adds unclaimed crate keys for a player + * + * @param player

The player to store the crate keys for

+ * @param amount

The amount to store

+ */ + public void addCrateKeys(@NotNull Player player, int amount) { + int existing = this.unclaimedCrateKeys.getOrDefault(player.getUniqueId(), 0); + this.unclaimedCrateKeys.put(player.getUniqueId(), existing + amount); + save(); + } + + /** + * Removes a player's stored crate keys + * + * @param player

The player to remove crate keys for

+ * @return

The amount of keys removed

+ */ + public int removeKeys(@NotNull Player player) { + Integer amount = this.unclaimedCrateKeys.remove(player.getUniqueId()); + int realAmount = Objects.requireNonNullElse(amount, 0); + if (realAmount > 64) { + this.unclaimedCrateKeys.put(player.getUniqueId(), realAmount - 64); + realAmount -= 64; + } + save(); + return realAmount; + } + + /** + * Saves all unclaimed crate keys to the configuration file + */ + private void save() { + this.configuration.set("playerKeys", null); + ConfigurationSection playerKeysSection = this.configuration.createSection("playerKeys"); + + for (Map.Entry entry : this.unclaimedCrateKeys.entrySet()) { + playerKeysSection.set(entry.getKey().toString(), entry.getValue()); + } + + CrateRegistry.getInstance().saveConfig(); + } + + /** + * Loads crate keys from disk + * + * @param configuration

The file configuration to load values from

+ * @return

The loaded values

+ */ + @NotNull + private Map load(@NotNull FileConfiguration configuration) { + ConfigurationSection playerKeysSection = configuration.getConfigurationSection("playerKeys"); + if (playerKeysSection == null) { + return new HashMap<>(); + } + + Map loaded = new HashMap<>(); + Set keys = playerKeysSection.getKeys(false); + for (String key : keys) { + loaded.put(UUID.fromString(key), playerKeysSection.getInt(key)); + } + return loaded; + } + +} diff --git a/src/main/java/net/knarcraft/crateregistry/CrateRegistry.java b/src/main/java/net/knarcraft/crateregistry/CrateRegistry.java new file mode 100644 index 0000000..8e78edb --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/CrateRegistry.java @@ -0,0 +1,44 @@ +package net.knarcraft.crateregistry; + +import net.knarcraft.crateregistry.command.CrateRegistryCommand; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * The crate registry's main class + */ +public final class CrateRegistry extends JavaPlugin { + + private static CrateRegistry instance; + private CrateKeyStorage crateKeyStorage; + + @Override + public void onEnable() { + instance = this; + crateKeyStorage = new CrateKeyStorage(this.getConfig()); + + PluginCommand command = this.getCommand("cr"); + if (command != null) { + command.setExecutor(new CrateRegistryCommand()); + } + } + + /** + * Gets an instance of this plugin + * + * @return

This plugin's main class

+ */ + public static CrateRegistry getInstance() { + return instance; + } + + /** + * Gets the crate key storage + * + * @return

The crate key storage

+ */ + public CrateKeyStorage getCrateKeyStorage() { + return this.crateKeyStorage; + } + +} diff --git a/src/main/java/net/knarcraft/crateregistry/command/ClaimCommand.java b/src/main/java/net/knarcraft/crateregistry/command/ClaimCommand.java new file mode 100644 index 0000000..73deac0 --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/command/ClaimCommand.java @@ -0,0 +1,53 @@ +package net.knarcraft.crateregistry.command; + +import net.knarcraft.crateregistry.CrateKeyStorage; +import net.knarcraft.crateregistry.CrateRegistry; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * The command for claiming stored crate keys + */ +public class ClaimCommand extends PluginCommand { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] arguments) { + if (!(sender instanceof Player player)) { + sender.sendMessage("This command can only be used by players"); + return false; + } + + CrateKeyStorage crateKeyStorage = CrateRegistry.getInstance().getCrateKeyStorage(); + + if (!crateKeyStorage.hasStoredKeys(player)) { + player.sendMessage("You have no unclaimed crate keys."); + return true; + } + + if (player.getInventory().firstEmpty() == -1) { + player.sendMessage("You must have an empty slot in your inventory in order to claim crate keys."); + return true; + } + + int amount = crateKeyStorage.removeKeys(player); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "crates giveKey vote_crate " + player.getName() + " " + amount); + player.sendMessage("Crate keys claimed"); + if (crateKeyStorage.hasStoredKeys(player)) { + player.sendMessage("You still have more unclaimed crate keys remaining."); + } + return true; + } + + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + return List.of(); + } + +} diff --git a/src/main/java/net/knarcraft/crateregistry/command/CrateRegistryCommand.java b/src/main/java/net/knarcraft/crateregistry/command/CrateRegistryCommand.java new file mode 100644 index 0000000..b1ad6bc --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/command/CrateRegistryCommand.java @@ -0,0 +1,56 @@ +package net.knarcraft.crateregistry.command; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The main command for the CrateRegistry plugin + */ +public class CrateRegistryCommand extends PluginCommand { + + private final TabExecutor claimExecutor; + private final TabExecutor giveExecutor; + + /** + * Instantiates a new crate registry command + */ + public CrateRegistryCommand() { + claimExecutor = new ClaimCommand(); + giveExecutor = new GiveCommand(); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] arguments) { + return switch (arguments[0].toLowerCase()) { + case "givekey" -> giveExecutor.onCommand(sender, command, label, arguments); + case "claim" -> claimExecutor.onCommand(sender, command, label, arguments); + default -> false; + }; + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + if (args.length == 1) { + if (sender.hasPermission("crateregistry.give")) { + return filterMatchingStartsWith(List.of("giveKey", "claim"), args[0]); + } else { + return filterMatchingStartsWith(List.of("claim"), args[0]); + } + } else { + return switch (args[0].toLowerCase()) { + case "givekey" -> giveExecutor.onTabComplete(sender, command, label, args); + case "claim" -> claimExecutor.onTabComplete(sender, command, label, args); + default -> List.of(); + }; + } + } + +} diff --git a/src/main/java/net/knarcraft/crateregistry/command/GiveCommand.java b/src/main/java/net/knarcraft/crateregistry/command/GiveCommand.java new file mode 100644 index 0000000..223be1d --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/command/GiveCommand.java @@ -0,0 +1,89 @@ +package net.knarcraft.crateregistry.command; + +import net.knarcraft.crateregistry.CrateRegistry; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The command for giving or storing a crate key + */ +public class GiveCommand extends PluginCommand { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] arguments) { + if (arguments.length < 3) { + return false; + } + + if (!sender.hasPermission("crateregistry.give")) { + sender.sendMessage("You don't have permission to use this command"); + return false; + } + + try { + return giveOrStoreCrateKeys(sender, arguments); + } catch (NumberFormatException exception) { + return false; + } + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] arguments) { + if (arguments.length == 2) { + return filterMatchingContains(getPlayerNames(), arguments[1]); + } else if (arguments.length == 3) { + return filterMatchingStartsWith(List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"), arguments[2]); + } else { + return List.of(); + } + } + + /** + * Gives crate keys to a player, or stores them if the player has no available space + * + * @param sender

The sender of the command

+ * @param arguments

The arguments given

+ * @return

True if this command was used correctly

+ */ + private boolean giveOrStoreCrateKeys(@NotNull CommandSender sender, @NotNull String[] arguments) { + String userName = arguments[1]; + int amount = Integer.parseInt(arguments[2]); + Player player = Bukkit.getPlayer(userName); + if (player == null) { + sender.sendMessage("No player " + userName + " exists!"); + return false; + } + + if (player.getInventory().firstEmpty() == -1) { + CrateRegistry.getInstance().getCrateKeyStorage().addCrateKeys(player, amount); + player.sendMessage("Your crate key was stored, as your inventory is full. Claim it with \"/cr claim\""); + } else { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "crates giveKey vote_crate " + player.getName() + " " + amount); + } + return true; + } + + /** + * Gets all online player names + * + * @return

All online player names

+ */ + private List getPlayerNames() { + List output = new ArrayList<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + output.add(player.getName()); + } + return output; + } + +} diff --git a/src/main/java/net/knarcraft/crateregistry/command/PluginCommand.java b/src/main/java/net/knarcraft/crateregistry/command/PluginCommand.java new file mode 100644 index 0000000..7fcd1a5 --- /dev/null +++ b/src/main/java/net/knarcraft/crateregistry/command/PluginCommand.java @@ -0,0 +1,48 @@ +package net.knarcraft.crateregistry.command; + +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * A class containing useful command-related methods + */ +public abstract class PluginCommand implements TabExecutor { + + /** + * Finds tab complete values that contain the typed text + * + * @param values

The values to filter

+ * @param typedText

The text the player has started typing

+ * @return

The given string values that contain the player's typed text

+ */ + protected static @NotNull List filterMatchingContains(@NotNull List values, @NotNull String typedText) { + List configValues = new ArrayList<>(); + for (String value : values) { + if (value.toLowerCase().contains(typedText.toLowerCase())) { + configValues.add(value); + } + } + return configValues; + } + + /** + * Finds tab complete values that match the start of the typed text + * + * @param values

The values to filter

+ * @param typedText

The text the player has started typing

+ * @return

The given string values that start with the player's typed text

+ */ + protected static @NotNull List filterMatchingStartsWith(@NotNull List values, @NotNull String typedText) { + List configValues = new ArrayList<>(); + for (String value : values) { + if (value.toLowerCase().startsWith(typedText.toLowerCase())) { + configValues.add(value); + } + } + return configValues; + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..8137389 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,15 @@ +name: CrateRegistry +version: '1.0-SNAPSHOT' +main: net.knarcraft.crateregistry.CrateRegistry +api-version: '1.20' + +commands: + cr: + description: "The main command for the CrateRegistry plugin" + usage: | + / claim + / giveKey +permissions: + crateregistry.give: + description: Gives permission to the /cr give command + default: false \ No newline at end of file