From 1995e740e8cd7bbd534cd0d6d9a9b963cd3edcf3 Mon Sep 17 00:00:00 2001 From: Jsinco Date: Tue, 10 Dec 2024 22:01:02 -0500 Subject: [PATCH] some api changes --- build.gradle.kts | 2 +- src/main/java/com/dre/brewery/BCauldron.java | 2 +- .../java/com/dre/brewery/BIngredients.java | 7 +- src/main/java/com/dre/brewery/BSealer.java | 2 +- src/main/java/com/dre/brewery/Brew.java | 23 ++- .../java/com/dre/brewery/api/BreweryApi.java | 7 +- .../api/addons/AddonConfigManager.java | 7 + .../dre/brewery/api/addons/AddonManager.java | 163 +++++++++--------- .../api/events/brew/BrewModifyEvent.java | 23 +-- .../commands/subcommands/CreateCommand.java | 2 +- .../sector/AbstractOkaeriConfigSector.java | 3 +- .../java/com/dre/brewery/recipe/BRecipe.java | 4 + 12 files changed, 138 insertions(+), 107 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b089be52..54c34a5f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,7 +32,7 @@ val langVersion = 17 val encoding = "UTF-8" group = "com.dre.brewery" -version = "3.4.4-SNAPSHOT" +version = "3.4.4" repositories { mavenCentral() diff --git a/src/main/java/com/dre/brewery/BCauldron.java b/src/main/java/com/dre/brewery/BCauldron.java index 4308aa67..94ef9c3d 100644 --- a/src/main/java/com/dre/brewery/BCauldron.java +++ b/src/main/java/com/dre/brewery/BCauldron.java @@ -201,7 +201,7 @@ public boolean fill(Player player, Block block) { lang.sendEntry(player, "Perms_NoCauldronFill"); return true; } - ItemStack potion = ingredients.cook(state, player.getName()); + ItemStack potion = ingredients.cook(state, player); if (potion == null) return false; if (VERSION.isOrLater(MinecraftVersion.V1_13)) { diff --git a/src/main/java/com/dre/brewery/BIngredients.java b/src/main/java/com/dre/brewery/BIngredients.java index 4a781e6e..9cc99923 100644 --- a/src/main/java/com/dre/brewery/BIngredients.java +++ b/src/main/java/com/dre/brewery/BIngredients.java @@ -38,6 +38,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; @@ -134,7 +135,7 @@ public void add(ItemStack ingredient, RecipeItem rItem) { /** * returns an Potion item with cooked ingredients */ - public ItemStack cook(int state, String brewer) { + public ItemStack cook(int state, Player brewer) { ItemStack potion = new ItemStack(Material.POTION); PotionMeta potionMeta = (PotionMeta) potion.getItemMeta(); @@ -158,7 +159,7 @@ public ItemStack cook(int state, String brewer) { lore.updateQualityStars(false); lore.updateCustomLore(); lore.updateAlc(false); - lore.updateBrewer(brewer); + lore.updateBrewer(brewer.getDisplayName()); lore.addOrReplaceEffects(brew.getEffects(), brew.getQuality()); lore.write(); @@ -210,7 +211,7 @@ public ItemStack cook(int state, String brewer) { //potionMeta.addCustomEffect((PotionEffectType.REGENERATION).createEffect((uid * 4), 0), true); brew.touch(); - BrewModifyEvent modifyEvent = new BrewModifyEvent(brew, potionMeta, BrewModifyEvent.Type.FILL); + BrewModifyEvent modifyEvent = new BrewModifyEvent(brew, potionMeta, BrewModifyEvent.Type.FILL, brewer); plugin.getServer().getPluginManager().callEvent(modifyEvent); if (modifyEvent.isCancelled()) { return null; diff --git a/src/main/java/com/dre/brewery/BSealer.java b/src/main/java/com/dre/brewery/BSealer.java index d5b367e2..588beb38 100644 --- a/src/main/java/com/dre/brewery/BSealer.java +++ b/src/main/java/com/dre/brewery/BSealer.java @@ -119,7 +119,7 @@ private void itemChecking() { slotTime[i] = -1; Brew brew = Brew.get(contents[i]); if (brew != null && !brew.isStripped()) { - brew.seal(contents[i]); + brew.seal(contents[i], player); if (playerValid && BreweryPlugin.getMCVersion().isOrLater(MinecraftVersion.V1_9)) { player.playSound(player.getLocation(), Sound.ITEM_BOTTLE_FILL_DRAGONBREATH, 1, 1.5f + (float) (Math.random() * 0.2)); } diff --git a/src/main/java/com/dre/brewery/Brew.java b/src/main/java/com/dre/brewery/Brew.java index 3d3ae87e..cd8e42e1 100644 --- a/src/main/java/com/dre/brewery/Brew.java +++ b/src/main/java/com/dre/brewery/Brew.java @@ -44,6 +44,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.BrewerInventory; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; @@ -510,7 +511,7 @@ public void unLabel(ItemStack item) { * * @param potion The Item this Brew is on */ - public void seal(ItemStack potion) { + public void seal(ItemStack potion, @Nullable Player player) { if (stripped) return; ItemMeta origMeta = potion.getItemMeta(); if (!(origMeta instanceof PotionMeta)) return; @@ -535,7 +536,7 @@ public void seal(ItemStack potion) { wood = BarrelWoodType.NONE; touch(); - BrewModifyEvent modifyEvent = new BrewModifyEvent(this, meta, BrewModifyEvent.Type.SEAL); + BrewModifyEvent modifyEvent = new BrewModifyEvent(this, meta, BrewModifyEvent.Type.SEAL, player); BreweryPlugin.getInstance().getServer().getPluginManager().callEvent(modifyEvent); if (modifyEvent.isCancelled()) { @@ -776,6 +777,10 @@ public void woodShift(float time, BarrelWoodType to) { } } + public ItemStack createItem() { + return createItem(null, true, null); + } + /** * Create a new Item of this Brew. A BrewModifyEvent type CREATE will be called. * @@ -783,7 +788,15 @@ public void woodShift(float time, BarrelWoodType to) { * @return The created Item, null if the Event is cancelled */ public ItemStack createItem(@Nullable BRecipe recipe) { - return createItem(recipe, true); + return createItem(recipe, true, null); + } + + public ItemStack createItem(@Nullable BRecipe recipe, @Nullable Player player) { + return createItem(recipe, true, player); + } + + public ItemStack createItem(@Nullable BRecipe recipe, boolean event) { + return createItem(recipe, true, null); } /** @@ -794,7 +807,7 @@ public ItemStack createItem(@Nullable BRecipe recipe) { * @return The created Item, null if the Event is cancelled */ @Contract("_, false -> !null") - public ItemStack createItem(@Nullable BRecipe recipe, boolean event) { + public ItemStack createItem(@Nullable BRecipe recipe, boolean event, @Nullable Player player) { if (recipe == null) { recipe = getCurrentRecipe(); } @@ -828,7 +841,7 @@ public ItemStack createItem(@Nullable BRecipe recipe, boolean event) { lore.write(); touch(); if (event) { - BrewModifyEvent modifyEvent = new BrewModifyEvent(this, potionMeta, BrewModifyEvent.Type.CREATE); + BrewModifyEvent modifyEvent = new BrewModifyEvent(this, potionMeta, BrewModifyEvent.Type.CREATE, player); BreweryPlugin.getInstance().getServer().getPluginManager().callEvent(modifyEvent); if (modifyEvent.isCancelled()) { return null; diff --git a/src/main/java/com/dre/brewery/api/BreweryApi.java b/src/main/java/com/dre/brewery/api/BreweryApi.java index 611c4ec3..b3a9a86d 100644 --- a/src/main/java/com/dre/brewery/api/BreweryApi.java +++ b/src/main/java/com/dre/brewery/api/BreweryApi.java @@ -203,9 +203,14 @@ public static Brew createBrew(BRecipe recipe, int quality) { */ @Nullable public static ItemStack createBrewItem(String recipeName, int quality) { + return createBrewItem(recipeName, quality, null); + } + + @Nullable + public static ItemStack createBrewItem(String recipeName, int quality, Player player) { BRecipe matching = BRecipe.getMatching(recipeName); if (matching != null) { - return matching.create(quality); + return matching.create(quality, player); } return null; } diff --git a/src/main/java/com/dre/brewery/api/addons/AddonConfigManager.java b/src/main/java/com/dre/brewery/api/addons/AddonConfigManager.java index 7b69fc23..dcb45b69 100644 --- a/src/main/java/com/dre/brewery/api/addons/AddonConfigManager.java +++ b/src/main/java/com/dre/brewery/api/addons/AddonConfigManager.java @@ -28,6 +28,8 @@ import org.jetbrains.annotations.Nullable; import java.nio.file.Path; +import java.util.Collection; +import java.util.List; /** * Management of addon configuration files. @@ -39,6 +41,7 @@ public class AddonConfigManager { private final ConfigHead INSTANCE; + public AddonConfigManager(BreweryAddon addon) { this.INSTANCE = new ConfigHead(BreweryPlugin.getInstance().getDataFolder().toPath().resolve("addons").resolve(addon.getAddonInfo().name())); } @@ -78,6 +81,10 @@ public Path getFilePath(Class configClass) { } + public Collection getLoadedConfigs() { + return INSTANCE.LOADED_CONFIGS.values().stream().map(AddonConfigFile.class::cast).toList(); + } + /** diff --git a/src/main/java/com/dre/brewery/api/addons/AddonManager.java b/src/main/java/com/dre/brewery/api/addons/AddonManager.java index f790ade9..e501acb2 100644 --- a/src/main/java/com/dre/brewery/api/addons/AddonManager.java +++ b/src/main/java/com/dre/brewery/api/addons/AddonManager.java @@ -22,6 +22,7 @@ import com.dre.brewery.BreweryPlugin; import com.dre.brewery.utility.Logging; +import com.dre.brewery.utility.Tuple; import java.io.File; import java.io.FileInputStream; @@ -137,55 +138,63 @@ public void loadAddons() { * @param file The jar file to load the addon from */ public void loadAddon(File file) { - try { - List> classes = loadAllClassesFromJar(file); // Get all our loaded classes. + try (URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, getClass().getClassLoader())) { + var pair = getClassesFromJar(file, classLoader); // Get all our loaded classes. + Class mainClass = pair.first(); + List> classes = pair.second(); - // I actually don't like that I used a loop here, should replace with like findFirst or something. - for (Class clazz : classes) { - if (!BreweryAddon.class.isAssignableFrom(clazz)) { - continue; - } - Class addonClass = clazz.asSubclass(BreweryAddon.class); - BreweryAddon addon; - try { - addon = addonClass.getConstructor().newInstance(); // Instantiate our main class, the class shouldn't have constructor args. - } catch (Exception e) { - Logging.errorLog("Failed to load addon: " + file.getName(), e); - continue; - } - try { + BreweryAddon addon; + try { + addon = mainClass.getConstructor().newInstance(); // Instantiate our main class, the class shouldn't have constructor args. + } catch (Exception e) { + Logging.errorLog("Failed to load addon: " + file.getName(), e); + return; + } + try { - Class breweryAddonClass = BreweryAddon.class; - // Set the logger and file manager - Field infoField = breweryAddonClass.getDeclaredField("addonInfo"); infoField.setAccessible(true); - infoField.set(addon, addonClass.getAnnotation(AddonInfo.class)); + // Set the logger and file manager - if (addon.getAddonInfo() == null) { // This CAN be null for us. It's only annotated NotNull for addons. - Logging.errorLog("Addon " + addonClass.getSimpleName() + " is missing the AddonInfo annotation. It will not be loaded."); - continue; - } + Field infoField = BreweryAddon.class.getDeclaredField("addonInfo"); infoField.setAccessible(true); + infoField.set(addon, mainClass.getAnnotation(AddonInfo.class)); - // Set all the fields for our addon reflectively. + if (addon.getAddonInfo() == null) { // This CAN be null for us. It's only annotated NotNull for addons. + Logging.errorLog("Addon " + mainClass.getSimpleName() + " is missing the AddonInfo annotation. It will not be loaded."); + return; + } + + // Set all the fields for our addon reflectively. - Field loggerField = breweryAddonClass.getDeclaredField("logger"); loggerField.setAccessible(true); - Field fileManagerField = breweryAddonClass.getDeclaredField("addonFileManager"); fileManagerField.setAccessible(true); - Field addonConfigManagerField = breweryAddonClass.getDeclaredField("addonConfigManager"); addonConfigManagerField.setAccessible(true); + Field loggerField = BreweryAddon.class.getDeclaredField("logger"); loggerField.setAccessible(true); + Field fileManagerField = BreweryAddon.class.getDeclaredField("addonFileManager"); fileManagerField.setAccessible(true); + Field addonConfigManagerField = BreweryAddon.class.getDeclaredField("addonConfigManager"); addonConfigManagerField.setAccessible(true); - loggerField.set(addon, new AddonLogger(addon.getAddonInfo())); - fileManagerField.set(addon, new AddonFileManager(addon, file)); - addonConfigManagerField.set(addon, new AddonConfigManager(addon)); + loggerField.set(addon, new AddonLogger(addon.getAddonInfo())); + fileManagerField.set(addon, new AddonFileManager(addon, file)); + addonConfigManagerField.set(addon, new AddonConfigManager(addon)); - addon.getAddonLogger().info("Loading &a" + addon.getAddonInfo().name() + " &f-&a v" + addon.getAddonInfo().version() + " &fby &a" + addon.getAddonInfo().author()); - LOADED_ADDONS.add(addon); // Add to our list of addons + addon.getAddonLogger().info("Loading &a" + addon.getAddonInfo().name() + " &f-&a v" + addon.getAddonInfo().version() + " &fby &a" + addon.getAddonInfo().author()); + LOADED_ADDONS.add(addon); // Add to our list of addons + + // let the addon know it has been loaded, it can do some pre-enable stuff here. + addon.onAddonPreEnable(); + } catch (Exception e) { + Logging.errorLog("Failed to load addon: " + file.getName(), e); + unloadAddon(addon); + } - // let the addon know it has been loaded, it can do some pre-enable stuff here. - addon.onAddonPreEnable(); - } catch (Exception e) { - Logging.errorLog("Failed to load addon: " + file.getName(), e); - unloadAddon(addon); + // Now that we're done loading our main class, we can go ahead and load the rest of our classes. We don't care about the order of these classes. + for (Class clazz : classes) { + if (BreweryAddon.class.isAssignableFrom(clazz)) { // Just make sure it's not our main class we're trying to load again. + continue; + } + try { + classLoader.loadClass(clazz.getName()); + } catch (ClassNotFoundException e) { + plugin.getLogger().log(Level.SEVERE, "Failed to load class " + clazz.getName(), e); } } + } catch (Throwable ex) { Logging.errorLog("Failed to load addon classes from jar " + file.getName(), ex); } @@ -195,7 +204,7 @@ public void loadAddon(File file) { * It's about time I document this... *

* What we're doing here is trying to recreate what Bukkit does to load plugins. Obviously the code could be cleaned up and spread out to - * multiple functions but I honestly can't be bothered and this is fine I guess. + * multiple functions, but I honestly can't be bothered and this is fine I guess. *

* We have to load each class file, but first, we must load the class which extends BreweryAddon (our main class) before all else. If we * don't load this class first we can get some nasty race conditions. Also, plugin developers expect their main class to be loaded first @@ -204,62 +213,52 @@ public void loadAddon(File file) { * @param jarFile The jar file to load classes from * @return A list of classes loaded from the jar */ - private List> loadAllClassesFromJar(File jarFile) { + private Tuple, List>> getClassesFromJar(File jarFile, ClassLoader classLoader) { List> classes = new ArrayList<>(); + Class mainClass = null; // We have to use the same class loader used to load this class AKA, the 'PluginLoader' class provided by Bukkit. // ClassLoaders in Java are pretty interesting, and only classes loaded by the same ClassLoader can access each other. // So to prevent any issues, we're using the same ClassLoader that loaded this class to load the classes from the jar. - try (URLClassLoader classLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}, getClass().getClassLoader())) { - - try (JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile))) { - JarEntry jarEntry; - String mainDir = ""; - while ((jarEntry = jarInputStream.getNextJarEntry()) != null) { // Just iterate through every file in the jar file and check if it's a compiled java class. - if (jarEntry.getName().endsWith(".class")) { - - // We have to replace the '/' with '.' and remove the '.class' extension to get the canonical name of the class. (org.example.Whatever) - String className = jarEntry.getName().replaceAll("/", ".").replace(".class", ""); + try (JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile))) { + JarEntry jarEntry; + String mainDir = ""; + while ((jarEntry = jarInputStream.getNextJarEntry()) != null) { // Just iterate through every file in the jar file and check if it's a compiled java class. + if (jarEntry.getName().endsWith(".class")) { + + // We have to replace the '/' with '.' and remove the '.class' extension to get the canonical name of the class. (org.example.Whatever) + String className = jarEntry.getName().replaceAll("/", ".").replace(".class", ""); + try { + Class clazz; try { - Class clazz; - try { - // It's important that we don't initialize any other classes before our main class. - clazz = Class.forName(className, false, classLoader); - } catch (ClassNotFoundException | NoClassDefFoundError e) { - continue; - } - if (BreweryAddon.class.isAssignableFrom(clazz)) { - // Found our main class, we're going to load it now. - classLoader.loadClass(className); - mainDir = className.substring(0, className.lastIndexOf('.')); - } - // Prevents loading classes that aren't in the same package. Addons that have dependencies better shade em in I guess. (TODO: remove this?) - if (!clazz.getName().contains(mainDir)) { - continue; - } - classes.add(clazz); // And finally... add the class to our list of classes. - - } catch (ClassNotFoundException e) { - plugin.getLogger().log(Level.SEVERE, "Failed to load class " + className, e); + // It's important that we don't initialize any other classes before our main class. + clazz = Class.forName(className, false, classLoader); + } catch (ClassNotFoundException | NoClassDefFoundError e) { + continue; } - } - } - - // Now that we're done loading our main class, we can go ahead and load the rest of our classes. We don't care about the order of these classes. - for (Class clazz : classes) { - if (!BreweryAddon.class.isAssignableFrom(clazz)) { // Just make sure it's not our main class we're trying to load again. - try { - classLoader.loadClass(clazz.getName()); - } catch (ClassNotFoundException e) { - plugin.getLogger().log(Level.SEVERE, "Failed to load class " + clazz.getName(), e); + if (BreweryAddon.class.isAssignableFrom(clazz)) { + // Found our main class, we're going to load it now. + classLoader.loadClass(className); + mainDir = className.substring(0, className.lastIndexOf('.')); + mainClass = clazz.asSubclass(BreweryAddon.class); } + // Prevents loading classes that aren't in the same package. Addons that have dependencies better shade em in I guess. (TODO: remove this?) + if (!clazz.getName().contains(mainDir)) { + continue; + } + classes.add(clazz); // And finally... add the class to our list of classes. + + } catch (ClassNotFoundException e) { + plugin.getLogger().log(Level.SEVERE, "Failed to load class " + className, e); } } } + + } catch (IOException e) { - plugin.getLogger().log(Level.SEVERE, "Error loading classes from JAR", e); + plugin.getLogger().log(Level.SEVERE, "Failed to load classes from jar " + jarFile.getName(), e); } - return classes; + return new Tuple<>(mainClass, classes); } } \ No newline at end of file diff --git a/src/main/java/com/dre/brewery/api/events/brew/BrewModifyEvent.java b/src/main/java/com/dre/brewery/api/events/brew/BrewModifyEvent.java index 971ead14..0fbeb3aa 100644 --- a/src/main/java/com/dre/brewery/api/events/brew/BrewModifyEvent.java +++ b/src/main/java/com/dre/brewery/api/events/brew/BrewModifyEvent.java @@ -22,11 +22,15 @@ import com.dre.brewery.Brew; import com.dre.brewery.lore.BrewLore; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * A Brew has been created or modified. @@ -34,23 +38,24 @@ *

Modifications to the Brew or the PotionMeta can be done now *

Cancelling reverts the Brew to the state it was before the modification */ +@Getter +@Setter public class BrewModifyEvent extends BrewEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final Type type; private boolean cancelled; + @Nullable + private Player player; + public BrewModifyEvent(@NotNull Brew brew, @NotNull ItemMeta meta, @NotNull Type type) { super(brew, meta); this.type = type; } - - /** - * Get the Type of modification being applied to the Brew. - */ - @NotNull - public Type getType() { - return type; + public BrewModifyEvent(@NotNull Brew brew, @NotNull ItemMeta meta, @NotNull Type type, @Nullable Player player) { + this(brew, meta, type); + this.player = player; } /** @@ -66,10 +71,6 @@ public boolean isCancelled() { return cancelled; } - /** - * Setting the Event cancelled cancels all modificatons to the brew. - *

Modifications to the Brew or ItemMeta will not be applied - */ @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; diff --git a/src/main/java/com/dre/brewery/commands/subcommands/CreateCommand.java b/src/main/java/com/dre/brewery/commands/subcommands/CreateCommand.java index f9705401..a3358ca8 100644 --- a/src/main/java/com/dre/brewery/commands/subcommands/CreateCommand.java +++ b/src/main/java/com/dre/brewery/commands/subcommands/CreateCommand.java @@ -50,7 +50,7 @@ public void execute(BreweryPlugin breweryPlugin, Lang lang, CommandSender sender return; } - ItemStack item = brewForPlayer.a().createItem(null); + ItemStack item = brewForPlayer.a().createItem(null, brewForPlayer.b()); if (item != null) { brewForPlayer.b().getInventory().addItem(item); lang.sendEntry(sender, "CMD_Created"); diff --git a/src/main/java/com/dre/brewery/configuration/sector/AbstractOkaeriConfigSector.java b/src/main/java/com/dre/brewery/configuration/sector/AbstractOkaeriConfigSector.java index 921cb5bf..94188a57 100644 --- a/src/main/java/com/dre/brewery/configuration/sector/AbstractOkaeriConfigSector.java +++ b/src/main/java/com/dre/brewery/configuration/sector/AbstractOkaeriConfigSector.java @@ -35,7 +35,7 @@ * Abstract class to aid in the creation of OkaeriConfig sectors * @param The type of the capsule */ -public abstract class AbstractOkaeriConfigSector { +public abstract class AbstractOkaeriConfigSector extends OkaeriConfig { public Map getCapsules() { Map map = new LinkedHashMap<>(); @@ -44,6 +44,7 @@ public Map getCapsules() { Class typeOfT = getTypeOfT(); for (Field field : this.getClass().getDeclaredFields()) { + field.setAccessible(true); // Check if the field's type matches T if (Objects.equals(field.getType(), typeOfT)) { try { diff --git a/src/main/java/com/dre/brewery/recipe/BRecipe.java b/src/main/java/com/dre/brewery/recipe/BRecipe.java index aa2c013c..f0578a3c 100644 --- a/src/main/java/com/dre/brewery/recipe/BRecipe.java +++ b/src/main/java/com/dre/brewery/recipe/BRecipe.java @@ -528,6 +528,10 @@ private void executeCommand(Player player, String cmd, String playerName, int qu * @param quality The Quality of the Brew * @return The Created Item */ + public ItemStack create(int quality, Player player) { + return createBrew(quality).createItem(this, player); + } + public ItemStack create(int quality) { return createBrew(quality).createItem(this); }