diff --git a/.github/ISSUE_TEMPLATE/01-bug_report.yml b/.github/ISSUE_TEMPLATE/01-bug_report.yml new file mode 100644 index 00000000..f96ede58 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-bug_report.yml @@ -0,0 +1,61 @@ +name: Bug Report +description: Report an issue with HMCCosmetics +labels: [bug] +assignees: ["LoJoSho"] +body: + - type: markdown + attributes: + value: | + Thank you for filing an bug report! If you are here to ask a question, use our [Discord server](https://discord.gg/pcm8kWrdNt) instead! + - type: input + id: release_version + attributes: + label: Plugin Version + placeholder: vx.x.x + description: | + Insert the version of HMCCosmetics you are using (e.g. `v2.2.8`). Before continuing make sure you have the latest version of HMCCosmetics as + your issue may have already been resolved. + - type: input + id: server_version + attributes: + label: Server Version + placeholder: fork-x-x.x.x + description: | + Insert the version of your minecraft server in the format `fork-build-version` (e.g. `PAPER-521-1.19.4`, `PURPUR-1838-1.19.2`) + - type: textarea + id: description + attributes: + label: Issue description + description: Describe the issue in as much detail as possible (Include any error logs in a code block below) + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Explain how to reproduce this issue step-by-step, in as much detail as possible. + placeholder: | + Steps to reproduce: + 1. Do thing + 2. Observe behavior + 3. Post any error logs below + validations: + required: true + - type: dropdown + id: priority + attributes: + label: Issue priority + description: Please be realistic. If you need to elaborate on your reasoning, please use the issue description field above. + options: + - Low (slightly annoying) + - Medium (should be fixed somewhat soon) + - High (immediate attention needed) + validations: + required: true + - type: textarea + id: versions + attributes: + label: Other Versions + placeholder: | + - ModelEngine R3.0.1 (`/version ModelEngine`) + - Any other relevant version information such as depenedencies + description: | + List any necessary or relevant versions here. diff --git a/.github/ISSUE_TEMPLATE/02-feature_request.yml b/.github/ISSUE_TEMPLATE/02-feature_request.yml new file mode 100644 index 00000000..d5c7958e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02-feature_request.yml @@ -0,0 +1,28 @@ +name: Feature Request +description: Request a new feature for HMCCosmetics +labels: [enhancement] +assignees: ["LoJoSho"] +body: + - type: markdown + attributes: + value: | + If you are here to ask a question, use our [Discord server](https://discord.gg/pcm8kWrdNt) instead! + - type: markdown + attributes: + value: | + Please check that the feature you are requesting does not already exist *and/or* hasn't already been requested by someone else. + - type: textarea + id: description + attributes: + label: Feature Description + description: A clear and concise description of what the problem is, or what feature you want to be implemented. + placeholder: A good addition would be... + validations: + required: true + - type: textarea + id: solution + attributes: + label: Implementation Description + description: A clear and concise description of what you want to happen, and any optional **configuration changes** that need to be made. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index 2e57ae16..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Bug Report -description: Create a bug report to help us keep track of all bugs that have to be fixed -title: "[BUG] " -labels: [bug] - -body: - - type: checkboxes - id: i-have-checked - attributes: - label: I have checked... - options: - - label: "I am using the latest version of HMCCosmetics" - required: true - - label: "I am using the latest version of any dependencies" - required: true - - label: "I have checked if any similar bug reports exist" - required: true - - type: textarea - id: description - attributes: - label: Description - description: A full description of the bug - validations: - required: true - - type: textarea - id: reproduce - attributes: - label: Steps to reproduce - description: Explain how to reproduce this issue step-by-step, in as much detail as possible. - validations: - required: true - - type: textarea - id: hmcc-version - attributes: - label: Plugin Version - description: Run `version HMCCosmetics` in your console and paste the output - validations: - required: true - - type: textarea - id: meg-version - attributes: - label: ModelEngine Version - description: "Run `version ModelEngine` in your console and paste the output. Optional if not using balloons." - validations: - required: false - - type: textarea - id: server-version - attributes: - label: Server Version - description: "Run `version` in your console and paste the output." - validations: - required: true - - type: "dropdown" - id: "type" - attributes: - label: "How breaking is the bug?" - options: - - "Breaking Bug - Plugin unusable" - - "Non-breaking Bug - Plugin still usable, but certain features unavailable" - - "Minor Bug - Plugin completely functional, but features have non-working aspects" - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index ec4bb386..59c2b51d 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,5 @@ -blank_issues_enabled: false \ No newline at end of file +blank_issues_enabled: false +contact_links: + - name: General Questions and Help + url: https://discord.gg/pcm8kWrdNt + about: This issue tracker is not for support questions. Please refer to the Hibiscus community's help and discussion discord server. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index f0498ff1..00000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Feature Request -description: Create a feature request to help us keep track of all features you want to be added -title: "[FEATURE] " -labels: [enhancement] - -body: - - type: "checkboxes" - id: "i-have-checked" - attributes: - label: "I have checked that..." - options: - - label: "...such a feature does not exist already" - required: true - - label: "...such a feature request has not been submitted already" - required: true - - type: "textarea" - id: "description" - attributes: - label: "Description" - description: "A full description of the feature" - validations: - required: true - - type: "textarea" - id: "config-changes" - attributes: - label: "Config Changes" - description: "The configuration changes your feature should have" - validations: - required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d25e4678..611eb543 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,14 @@ #### Select the option(s) that best describes this PR: - [ ] Major breaking change - [ ] Minor change -- [ ] Bug fix - [ ] Feature implementation -- [ ] Documentation -- [ ] Cleaning -- [ ] Refactoring +- [ ] Bug fix +- [ ] Chore (Changes that don't fix or add new features *and don't* modify source files) +- [ ] Refactoring (Changes that dont't fix or add new features *but do* modify source files) +- [ ] Documentation (Changes to README files and/or JavaDocs) +- [ ] Style (Changes that don't affect the meaning of the code) +- [ ] Performance +- [ ] Other (Please specify below) #### Please describe the changes this PR makes and why it should be merged: diff --git a/build.gradle.kts b/build.gradle.kts index 1f87d73b..9d76d442 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.hibiscusmc" -version = "2.2.8" +version = "2.3.0" allprojects { apply(plugin = "java") @@ -34,8 +34,8 @@ allprojects { //Hikari maven("https://mvnrepository.com/artifact/com.zaxxer/HikariCP") - // Citizens - maven("https://repo.citizensnpcs.co") + // Citizens & Denizen + maven("https://maven.citizensnpcs.co/repo") // Worldguard maven("https://maven.enginehub.org/repo/") @@ -100,7 +100,8 @@ dependencies { implementation("org.bstats:bstats-bukkit:3.0.0") implementation("com.jeff_media:SpigotUpdateChecker:3.0.0") implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT") - implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5") + implementation("com.ticxo:PlayerAnimator:R1.2.6") + //implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5") } tasks { @@ -168,7 +169,7 @@ bukkit { apiVersion = "1.17" authors = listOf("LoJoSho") depend = listOf("ProtocolLib") - softDepend = listOf("ModelEngine", "Oraxen", "ItemsAdder", "Looty", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish") + softDepend = listOf("ModelEngine", "Oraxen", "ItemsAdder", "Looty", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen") version = "${project.version}" commands { diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 060ffef5..6cbdfa2d 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -18,7 +18,11 @@ dependencies { compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT") compileOnly("it.unimi.dsi:fastutil:8.5.11") compileOnly("io.lumine:Mythic-Dist:5.2.1") + compileOnly("com.denizenscript:denizen:1.2.7-SNAPSHOT") compileOnly("com.github.LeonMangler:SuperVanish:6.2.6-4") + compileOnlyApi("LibsDisguises:LibsDisguises:10.0.21") { + exclude("org.spigotmc", "spigot") + } //compileOnly("com.github.Fisher2911:FisherLib:master-SNAPSHOT") implementation("net.kyori:adventure-api:4.12.0") @@ -29,7 +33,8 @@ dependencies { implementation("org.bstats:bstats-bukkit:3.0.0") implementation("com.jeff_media:SpigotUpdateChecker:3.0.0") implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT") - implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5") + implementation("com.ticxo:PlayerAnimator:R1.2.6") + //implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5") } java { diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java index d0ce232b..d80a5ad0 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/HMCCosmeticsPlugin.java @@ -11,6 +11,7 @@ import com.hibiscusmc.hmccosmetics.config.serializer.LocationSerializer; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics; import com.hibiscusmc.hmccosmetics.database.Database; +import com.hibiscusmc.hmccosmetics.emotes.EmoteManager; import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.hooks.Hooks; import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGHook; @@ -20,15 +21,11 @@ import com.hibiscusmc.hmccosmetics.listener.PlayerGameListener; import com.hibiscusmc.hmccosmetics.nms.NMSHandlers; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; -import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager; import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.TranslationUtil; import com.jeff_media.updatechecker.UpdateCheckSource; import com.jeff_media.updatechecker.UpdateChecker; import com.ticxo.playeranimator.PlayerAnimatorImpl; -import com.ticxo.playeranimator.api.PlayerAnimator; -import com.ticxo.playeranimator.api.animation.pack.AnimationPack; -import org.apache.commons.io.FilenameUtils; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -44,7 +41,6 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader; import java.io.File; import java.nio.file.Path; -import java.util.Map; public final class HMCCosmeticsPlugin extends JavaPlugin { @@ -241,23 +237,7 @@ public final class HMCCosmeticsPlugin extends JavaPlugin { } } - File emoteFolder = new File(getInstance().getDataFolder().getPath() + "/emotes/"); - if (emoteFolder.exists()) { - PlayerAnimator.api.getAnimationManager().clearRegistry(); - File[] emotesFiles = emoteFolder.listFiles(); - for (File emoteFile : emotesFiles) { - if (!emoteFile.getName().contains("bbmodel")) continue; - String animationName = FilenameUtils.removeExtension(emoteFile.getName()); - PlayerAnimator.api.getAnimationManager().importAnimations(animationName, emoteFile); - MessagesUtil.sendDebugMessages("Added '" + animationName + "' to Player Animator "); - } - - /* - for (Map.Entry<String, AnimationPack> packEntry : PlayerAnimator.api.getAnimationManager().getRegistry().entrySet()) { - Set<String> animationNames = packEntry.getValue().getAnimations().keySet().stream().map(animation -> packEntry.getKey().replace(":", ".") + "." + animation).collect(Collectors.toSet()); - } - */ - } + EmoteManager.loadEmotes(); getInstance().getLogger().info("Successfully Enabled HMCCosmetics"); getInstance().getLogger().info(Cosmetics.values().size() + " Cosmetics Successfully Setup"); diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommand.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommand.java index 46f65cd7..60fb4aaa 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommand.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommand.java @@ -8,6 +8,7 @@ import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticEmoteType; import com.hibiscusmc.hmccosmetics.database.Database; +import com.hibiscusmc.hmccosmetics.emotes.EmoteManager; import com.hibiscusmc.hmccosmetics.gui.Menu; import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu; @@ -15,7 +16,6 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.ServerUtils; -import com.ticxo.playeranimator.api.PlayerAnimator; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import org.apache.commons.lang3.EnumUtils; @@ -428,12 +428,10 @@ public class CosmeticCommand implements CommandExecutor { return true; } - if (args.length >= 2) { - if (!PlayerAnimator.api.getAnimationManager().getRegistry().keySet().contains(args[1])) { - MessagesUtil.sendDebugMessages("Did not contain " + args[1]); - if (!silent) MessagesUtil.sendMessage(sender, "emote-invalid"); - return true; - } + if (!EmoteManager.has(args[1])) { + MessagesUtil.sendDebugMessages("Did not contain " + args[1]); + if (!silent) MessagesUtil.sendMessage(sender, "emote-invalid"); + return true; } if (sender.hasPermission("hmccosmetics.cmd.playemote.other")) { @@ -444,7 +442,7 @@ public class CosmeticCommand implements CommandExecutor { return true; } CosmeticUser user = CosmeticUsers.getUser(player); - user.getUserEmoteManager().playEmote(args[1]); + user.getUserEmoteManager().playEmote(EmoteManager.get(args[1])); return true; } } diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommandTabComplete.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommandTabComplete.java index 563e79ed..03445bdd 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommandTabComplete.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/command/CosmeticCommandTabComplete.java @@ -3,11 +3,11 @@ package com.hibiscusmc.hmccosmetics.command; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics; +import com.hibiscusmc.hmccosmetics.emotes.EmoteManager; import com.hibiscusmc.hmccosmetics.gui.Menu; import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; -import com.ticxo.playeranimator.api.PlayerAnimator; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -81,9 +81,7 @@ public class CosmeticCommandTabComplete implements TabCompleter { completions.add("viewerlocation"); completions.add("leavelocation"); } - case "playemote" -> { - completions.addAll(PlayerAnimator.api.getAnimationManager().getRegistry().keySet()); - } + case "playemote" -> completions.addAll(EmoteManager.getAllNames()); } StringUtil.copyPartialMatches(args[1], completions, finalCompletions); } diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/cosmetic/Cosmetic.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/cosmetic/Cosmetic.java index 44e74a92..fb2b13b5 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/cosmetic/Cosmetic.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/cosmetic/Cosmetic.java @@ -17,6 +17,7 @@ public abstract class Cosmetic { private String id; private String permission; private ItemStack item; + private String material; private CosmeticSlot slot; private boolean dyable; @@ -29,7 +30,10 @@ public abstract class Cosmetic { this.permission = null; } - if (!config.node("item").virtual()) this.item = generateItemStack(config.node("item")); + if (!config.node("item").virtual()) { + this.material = config.node("item", "material").getString(); + this.item = generateItemStack(config.node("item")); + } MessagesUtil.sendDebugMessages("Slot: " + config.node("slot").getString()); @@ -76,6 +80,10 @@ public abstract class Cosmetic { return this.dyable; } + public String getMaterial() { + return material; + } + public abstract void update(CosmeticUser user); @Nullable diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/emotes/EmoteManager.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/emotes/EmoteManager.java new file mode 100644 index 00000000..ea0d8a39 --- /dev/null +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/emotes/EmoteManager.java @@ -0,0 +1,85 @@ +package com.hibiscusmc.hmccosmetics.emotes; + +import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; +import com.ticxo.playeranimator.api.PlayerAnimator; +import com.ticxo.playeranimator.api.animation.pack.AnimationPack; +import org.apache.commons.io.FilenameUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Manages Emotes + */ +@SuppressWarnings("SpellCheckingInspection") +public class EmoteManager { + private static final @NotNull Map<@NotNull String, @NotNull String> emotes = new HashMap<>(); + + /** + * Loads all BlockBench animations from the emotes folder and puts it into the animation manager registry and local registry + */ + public static void loadEmotes() { + // Clear the PlayerAnimator and local registries + PlayerAnimator.api.getAnimationManager().clearRegistry(); + emotes.clear(); + + // Get the emote directory and check if it exists + File emoteDir = new File(HMCCosmeticsPlugin.getInstance().getDataFolder().getPath() + "/emotes/"); + if (!emoteDir.exists()) return; + + // Get all the files inside the directory and check if it isn't 0 + File[] emoteFiles = emoteDir.listFiles(); + if (emoteFiles == null || emoteFiles.length == 0) return; + + // Remove any files that don't have the file extension ".bbmodel" and check if there are still resulting files + emoteFiles = Arrays.stream(emoteFiles).filter(file -> file.getPath().endsWith(".bbmodel")).distinct().toArray(File[]::new); + if (emoteFiles.length == 0) return; + + // Loop through all files, importing all block bench animations into the registry + for (File animationFile : emoteFiles) { + String animationKey = FilenameUtils.removeExtension(animationFile.getName()); + PlayerAnimator.api.getAnimationManager().importAnimations(animationKey, animationFile); + } + + // Loops through all the entries in the registries and unpacks any animation packs to ensure if there were multiple animations + // inside a singular file, that they are added to the local registry individually for tab completion + for (Map.Entry<String, AnimationPack> packEntry : PlayerAnimator.api.getAnimationManager().getRegistry().entrySet()) { + packEntry.getValue().getAnimations().keySet().forEach(animationName -> { + // API key is the format "animationKey.animationFileName.animationName" + String apiKey = packEntry.getKey().replace(":", ".") + "." + animationName; + emotes.put(animationName, apiKey); + }); + } + } + + /** + * Returns true if there is an animation with the specified name + * @param animationName Name whose presence is to be tested + * @return True if this registry contains a mapping for the specified name + */ + public static boolean has(@NotNull String animationName) { + return emotes.containsKey(animationName); + } + + /** + * Returns the {@code API key} to which the specified name is mapped, or {@code null} if this map contains no mapping for the name. + * @param animationName Name whose {@code API key} is to be fetched + * @return The {@code API key} of the specified name or {@code null} if there was no animation name found + */ + public static @Nullable String get(@NotNull String animationName) { + return emotes.get(animationName); + } + + /** + * Gets a set of all the laoded animation names + * @return A set of all loaded animation names + */ + public static @NotNull Set<String> getAllNames() { + return emotes.keySet(); + } +} diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/Menu.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/Menu.java index 7107c0d9..8d57d6a2 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/Menu.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/Menu.java @@ -118,14 +118,12 @@ public class Menu { List<Integer> slots = getSlots(slotString); - if (slots == null) { MessagesUtil.sendDebugMessages("Slot is null for " + config.key().toString()); continue; } ItemStack item; - try { item = ItemSerializer.INSTANCE.deserialize(ItemStack.class, config.node("item")); //item = config.node("item").get(ItemStack.class); @@ -145,24 +143,25 @@ public class Menu { if (Types.isType(typeId)) type = Types.getType(typeId); } - ItemStack originalItem = item.clone(); - item = updateLore(user, item, type, config); + for (int slot : slots) { + ItemStack originalItem = updateItem(user, item, type, config, slot).clone(); + GuiItem guiItem = ItemBuilder.from(originalItem).asGuiItem(); - GuiItem guiItem = ItemBuilder.from(item).asGuiItem(); + Type finalType = type; + guiItem.setAction(event -> { + MessagesUtil.sendDebugMessages("Selected slot " + slot); + final ClickType clickType = event.getClick(); + if (finalType != null) finalType.run(user, config, clickType); - Type finalType = type; - guiItem.setAction(event -> { - final ClickType clickType = event.getClick(); - if (finalType != null) finalType.run(user, config, clickType); + for (int guiSlot : slots) { + gui.updateItem(guiSlot, updateItem(user, originalItem.clone(), finalType, config, guiSlot)); + } + MessagesUtil.sendDebugMessages("Updated slot " + slot); + }); - for (int i : slots) { - gui.updateItem(i, updateLore(user, originalItem.clone(), finalType, config)); - MessagesUtil.sendDebugMessages("Updated slot " + i); - } - }); - - MessagesUtil.sendDebugMessages("Added " + slots + " as " + guiItem + " in the menu"); - gui.setItem(slots, guiItem); + MessagesUtil.sendDebugMessages("Added " + slots + " as " + guiItem + " in the menu"); + gui.setItem(slot, guiItem); + } } return gui; } @@ -195,9 +194,9 @@ public class Menu { @Contract("_, _, _, _ -> param2") @NotNull - private ItemStack updateLore(CosmeticUser user, @NotNull ItemStack itemStack, Type type, ConfigurationNode config) { + private ItemStack updateItem(CosmeticUser user, @NotNull ItemStack itemStack, Type type, ConfigurationNode config, int slot) { if (itemStack.hasItemMeta()) { - itemStack.setItemMeta(type.setLore(user, config, itemStack.getItemMeta())); + itemStack = type.setItem(user, config, itemStack, slot); } return itemStack; } diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/Type.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/Type.java index ef8d7b74..4c5cbddf 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/Type.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/Type.java @@ -2,6 +2,7 @@ package com.hibiscusmc.hmccosmetics.gui.type; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.spongepowered.configurate.ConfigurationNode; @@ -24,5 +25,5 @@ public abstract class Type { public abstract void run(CosmeticUser user, ConfigurationNode config, ClickType clickType); - public abstract ItemMeta setLore(CosmeticUser user, ConfigurationNode config, ItemMeta itemMeta); + public abstract ItemStack setItem(CosmeticUser user, ConfigurationNode config, ItemStack itemStack, int slot); } diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeCosmetic.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeCosmetic.java index 6068fc3e..8ebdbe4d 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeCosmetic.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeCosmetic.java @@ -1,6 +1,7 @@ package com.hibiscusmc.hmccosmetics.gui.type.types; import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; +import com.hibiscusmc.hmccosmetics.config.serializer.ItemSerializer; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType; @@ -17,12 +18,14 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.serialize.SerializationException; +import java.lang.invoke.TypeDescriptor; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -96,55 +99,51 @@ public class TypeCosmetic extends Type { } @Override - public ItemMeta setLore(CosmeticUser user, @NotNull ConfigurationNode config, ItemMeta itemMeta) { - List<String> processedLore = new ArrayList<>(); + public ItemStack setItem(CosmeticUser user, @NotNull ConfigurationNode config, ItemStack itemStack, int slot) { + ItemMeta itemMeta = itemStack.getItemMeta(); - if (config.node("cosmetic").virtual()) return processLoreLines(user, itemMeta);; + if (config.node("cosmetic").virtual()) { + itemStack.setItemMeta(processLoreLines(user, itemMeta)); + return itemStack; + }; String cosmeticName = config.node("cosmetic").getString(); Cosmetic cosmetic = Cosmetics.getCosmetic(cosmeticName); if (cosmetic == null) { - return processLoreLines(user, itemMeta); + itemStack.setItemMeta(processLoreLines(user, itemMeta)); + return itemStack; } - if (user.canEquipCosmetic(cosmetic)) { - return processLoreLines(user, itemMeta); - } else { - ConfigurationNode itemConfig = config.node("item"); - if (itemConfig.virtual()) return itemMeta; - if (itemConfig.node("locked-name").virtual() && itemConfig.node("locked-lore").virtual()) { - return processLoreLines(user, itemMeta); + if (user.hasCosmeticInSlot(cosmetic) && !config.node("equipped-item").virtual()) { + ConfigurationNode equippedItem = config.node("equipped-item"); + try { + if (equippedItem.node("material").virtual()) equippedItem.node("material").set(config.node("item", "material").getString()); + } catch (SerializationException e) { + // Nothing >:) } try { - List<String> lockedLore = itemMeta.getLore(); - String lockedName = itemMeta.getDisplayName(); - - if (!itemConfig.node("locked-lore").virtual()) { - lockedLore = Utils.replaceIfNull(itemConfig.node("locked-lore").getList(String.class), - new ArrayList<String>()). - stream().map(StringUtils::parseStringToString).collect(Collectors.toList()); - } - if (!itemConfig.node("locked-name").virtual()) { - lockedName = StringUtils.parseStringToString(Utils.replaceIfNull(itemConfig.node("locked-name").getString(), "")); - } - - if (Hooks.isActiveHook("PlaceHolderAPI")) { - lockedName = PlaceholderAPI.setPlaceholders(user.getPlayer(), lockedName); - } - itemMeta.setDisplayName(lockedName); - if (itemMeta.hasLore()) { - itemMeta.getLore().clear(); - for (String loreLine : lockedLore) { - if (Hooks.isActiveHook("PlaceHolderAPI")) loreLine = PlaceholderAPI.setPlaceholders(user.getPlayer(), loreLine); - processedLore.add(loreLine); - } - } - } catch (Exception e) { - e.printStackTrace(); + itemStack = ItemSerializer.INSTANCE.deserialize(ItemStack.class, equippedItem); + } catch (SerializationException e) { + throw new RuntimeException(e); } + return itemStack; } - itemMeta.setLore(processedLore); - return itemMeta; + if (!user.canEquipCosmetic(cosmetic) && !config.node("locked-item").virtual()) { + ConfigurationNode lockedItem = config.node("locked-item"); + try { + if (lockedItem.node("material").virtual()) lockedItem.node("material").set(config.node("item", "material").getString()); + } catch (SerializationException e) { + // Nothing >:) + } + try { + itemStack = ItemSerializer.INSTANCE.deserialize(ItemStack.class, lockedItem); + //item = config.node("item").get(ItemStack.class); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return itemStack; + } + return itemStack; } @Contract("_, _ -> param2") diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeEmpty.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeEmpty.java index 5c33b16f..94f08ad7 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeEmpty.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/gui/type/types/TypeEmpty.java @@ -6,6 +6,7 @@ import com.hibiscusmc.hmccosmetics.hooks.Hooks; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import me.clip.placeholderapi.PlaceholderAPI; import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.spongepowered.configurate.ConfigurationNode; @@ -53,8 +54,9 @@ public class TypeEmpty extends Type { @Override @SuppressWarnings("Duplicates") - public ItemMeta setLore(CosmeticUser user, ConfigurationNode config, @NotNull ItemMeta itemMeta) { + public ItemStack setItem(CosmeticUser user, ConfigurationNode config, @NotNull ItemStack itemStack, int slot) { List<String> processedLore = new ArrayList<>(); + ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta.hasLore()) { for (String loreLine : itemMeta.getLore()) { @@ -63,8 +65,8 @@ public class TypeEmpty extends Type { processedLore.add(loreLine); } } - - return itemMeta; + itemStack.setItemMeta(itemMeta); + return itemStack; } // That's it! Now, add it as a static in another one of your classes (such as your main class) and you are good to go. diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/Hooks.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/Hooks.java index 7c6ed5e9..ecf0b325 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/Hooks.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/Hooks.java @@ -2,10 +2,7 @@ package com.hibiscusmc.hmccosmetics.hooks; import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; import com.hibiscusmc.hmccosmetics.hooks.items.*; -import com.hibiscusmc.hmccosmetics.hooks.misc.HookCMI; -import com.hibiscusmc.hmccosmetics.hooks.misc.HookHMCColor; -import com.hibiscusmc.hmccosmetics.hooks.misc.HookPremiumVanish; -import com.hibiscusmc.hmccosmetics.hooks.misc.HookSuperVanish; +import com.hibiscusmc.hmccosmetics.hooks.misc.*; import com.hibiscusmc.hmccosmetics.hooks.placeholders.HookPlaceholderAPI; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -22,12 +19,14 @@ public class Hooks { private static HookItemAdder ITEMADDER_HOOK = new HookItemAdder(); private static HookLooty LOOTY_HOOK = new HookLooty(); private static HookMythic MYTHIC_HOOK = new HookMythic(); + private static HookDenizen DENIZEN_HOOK = new HookDenizen(); private static HookHMCCosmetics HMCCOSMETIC_HOOK = new HookHMCCosmetics(); private static HookPlaceholderAPI PAPI_HOOK = new HookPlaceholderAPI(); private static HookPremiumVanish PREMIUM_VANISH_HOOK = new HookPremiumVanish(); private static HookSuperVanish SUPER_VANISH_HOOK = new HookSuperVanish(); private static HookHMCColor HMC_COLOR_HOOK = new HookHMCColor(); private static HookCMI CMI_HOOK = new HookCMI(); + private static HookLibsDisguises LIBS_DISGUISES_HOOK = new HookLibsDisguises(); public static Hook getHook(@NotNull String id) { return hooks.get(id.toLowerCase()); diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/items/HookDenizen.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/items/HookDenizen.java new file mode 100644 index 00000000..f9b935eb --- /dev/null +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/items/HookDenizen.java @@ -0,0 +1,27 @@ +package com.hibiscusmc.hmccosmetics.hooks.items; + +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.hibiscusmc.hmccosmetics.hooks.Hook; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * A hook that integrates the plugin {@link com.denizenscript.denizen.Denizen Denizen} to provide custom items + */ +@SuppressWarnings("SpellCheckingInspection") +public class HookDenizen extends Hook { + public HookDenizen() { + super("denizen"); + setEnabledItemHook(true); + } + + /** + * Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link com.denizenscript.denizen.Denizen Denizen} + */ + @Override + public ItemStack getItem(@NotNull String itemId) { + ItemTag item = ItemTag.valueOf(itemId, CoreUtilities.noDebugContext); + return item == null ? null : item.getItemStack(); + } +} diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/misc/HookLibsDisguises.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/misc/HookLibsDisguises.java new file mode 100644 index 00000000..4f540674 --- /dev/null +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/hooks/misc/HookLibsDisguises.java @@ -0,0 +1,32 @@ +package com.hibiscusmc.hmccosmetics.hooks.misc; + +import com.hibiscusmc.hmccosmetics.hooks.Hook; +import com.hibiscusmc.hmccosmetics.user.CosmeticUser; +import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; +import me.libraryaddict.disguise.events.DisguiseEvent; +import me.libraryaddict.disguise.events.UndisguiseEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.jetbrains.annotations.NotNull; + +public class HookLibsDisguises extends Hook { + public HookLibsDisguises() { + super("LibsDisguises"); + } + + @EventHandler + public void onPlayerVanish(@NotNull DisguiseEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + CosmeticUser user = CosmeticUsers.getUser(player); + if (user == null) return; + user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN); + } + + @EventHandler + public void onPlayerShow(@NotNull UndisguiseEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + CosmeticUser user = CosmeticUsers.getUser(player); + if (user == null) return; + user.showCosmetics(); + } +} diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUser.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUser.java index b05a2b75..d96d91d7 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUser.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUser.java @@ -52,7 +52,7 @@ public class CosmeticUser { private void tick() { // Occasionally updates the entity cosmetics Runnable run = () -> { - MessagesUtil.sendDebugMessages("Tick[" + uniqueId + "]", Level.INFO); + MessagesUtil.sendDebugMessages("Tick[uuid=" + uniqueId + "]", Level.INFO); updateCosmetic(); }; @@ -156,6 +156,14 @@ public class CosmeticUser { return playerCosmetics.containsKey(slot); } + public boolean hasCosmeticInSlot(Cosmetic cosmetic) { + if (getCosmetic(cosmetic.getSlot()) == null) return false; + if (cosmetic.getId() == getCosmetic(cosmetic.getSlot()).getId()) { + return true; + } + return false; + } + public Set<CosmeticSlot> getSlotsWithCosmetics() { return Set.copyOf(playerCosmetics.keySet()); } diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/manager/UserEmoteModel.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/manager/UserEmoteModel.java index 79258f47..403d5055 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/manager/UserEmoteModel.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/manager/UserEmoteModel.java @@ -57,6 +57,11 @@ public class UserEmoteModel extends PlayerModel { double DISTANCE = Settings.getEmoteDistance(); Location thirdPersonLocation = newLocation.add(newLocation.getDirection().normalize().multiply(DISTANCE)); + if (DISTANCE > 0) { + MessagesUtil.sendDebugMessages("Yaw " + (int) thirdPersonLocation.getYaw()); + MessagesUtil.sendDebugMessages("New Yaw " + ServerUtils.getNextYaw((int) thirdPersonLocation.getYaw(), 180)); + thirdPersonLocation.setYaw(ServerUtils.getNextYaw((int) thirdPersonLocation.getYaw(), 180)); + } if (Settings.getCosmeticEmoteBlockCheck() && thirdPersonLocation.getBlock().getType().isOccluding()) { stopAnimation(); MessagesUtil.sendMessage(player, "emote-blocked"); @@ -70,7 +75,7 @@ public class UserEmoteModel extends PlayerModel { PacketManager.sendEntitySpawnPacket(thirdPersonLocation, armorStandId, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer); PacketManager.sendInvisibilityPacket(armorStandId, viewer); - PacketManager.sendLookPacket(armorStandId, player.getLocation(), viewer); + PacketManager.sendLookPacket(armorStandId, thirdPersonLocation, viewer); PacketManager.gamemodeChangePacket(player, 3); PacketManager.sendCameraPacket(armorStandId, viewer); diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index ab147156..6739cedf 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -73,7 +73,7 @@ wardrobe: gamemode-options: exit-gamemode-enabled: false # Setting this to false will set the gamemode the player came in as. True sets to exit-gamemode gamemode - exit-gamemode: "SURVIVAL" # Only activates if force-exit-gamemode is true, find gamemodes here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/GameMode.html + exit-gamemode: "SURVIVAL" # Only activates if exit-gamemode-enabled is true, find gamemodes here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/GameMode.html # Bossbar that shows when a player is in a wardrobe. bossbar: diff --git a/common/src/main/resources/cosmetics/defaultcosmetics.yml b/common/src/main/resources/cosmetics/defaultcosmetics.yml index 0ed49145..912c517d 100644 --- a/common/src/main/resources/cosmetics/defaultcosmetics.yml +++ b/common/src/main/resources/cosmetics/defaultcosmetics.yml @@ -124,7 +124,6 @@ earth_day_grabber: slot: OFFHAND dyeable: true permission: "hmccosmetics.earth_day_grabber" - model: earth_day_grabber item: material: LEATHER_HORSE_ARMOR model-data: 4