diff --git a/.gitignore b/.gitignore index 794e70d7..ce170e50 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .vscode/ .gradle/ build/ -bin/ \ No newline at end of file +bin/ +.DS_Store diff --git a/README.md b/README.md index fde0b0b3..d4ddfdd8 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,14 @@ Featuring things from Projectile Trails, Particle Rings, Custom Structures, Pets ## 📓 Changelog +🔧 v1.2.2 - September 24, 2023 +- Gradle & CI Updates +- Heavy Optimization & GUI Creation Changes +- Added Custom Structures Loader in config.yml +- Fix StructureReader Bugs +- Improve Unit Testing +- Other Minor Additions & Bug Fixes + 📰 v1.2.1 - August 26, 2023 - Gradle Updates - **Armor Stand Holograms** diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/BaseShape.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/BaseShape.java index cecc2fff..6263169f 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/BaseShape.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/BaseShape.java @@ -9,6 +9,8 @@ import org.bukkit.Material; import org.bukkit.Particle; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import java.util.function.BiConsumer; @@ -126,6 +128,34 @@ public static void polygon(Location l, Object o, int points, double radius) { } } + public static void line(Location l, Object o, int length, long stepDelay) { + Vector dir = l.getDirection(); + double width = 0.1; + + int count = 0; + for (double i = 0; i < length * (1 / width); i += width) { + final double fi = i; + + BukkitRunnable r = new BukkitRunnable() { + @Override + public void run() { + dir.multiply(fi); + l.add(dir); + spawn(l, o); + l.subtract(dir); + dir.normalize(); + } + }; + + if (stepDelay == 0 || i == 0) + r.run(); + else + r.runTaskLater(StarConfig.getPlugin(), stepDelay * count); + + count++; + } + } + private final BiConsumer particle; private final ParticleSize size; diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/Generator.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/Generator.java index 032797d1..655f8e5e 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/Generator.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/Generator.java @@ -27,15 +27,16 @@ import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.util.ChatPaginator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; import static me.gamercoder215.starcosmetics.util.Constants.w; +import static me.gamercoder215.starcosmetics.util.inventory.StarInventoryUtil.itemBuilder; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.get; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.getWithArgs; +import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.builder; import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.of; @SuppressWarnings("unchecked") @@ -49,10 +50,10 @@ public static StarInventory genGUI(int size, String name) { return genGUI("", size, name); } - @Nullable + @NotNull public static StarInventory genGUI(String key, int size, String name) { - if (size < 9 || size > 54) return null; - if (size % 9 > 0) return null; + if (size < 9 || size > 54) throw new IllegalStateException("Invalid inventory size: " + size); + if (size % 9 > 0) throw new IllegalStateException("Invalid inventory size: " + size); StarInventory inv = w.createInventory(key, size, name); ItemStack bg = ItemBuilder.GUI_BACKGROUND; @@ -103,7 +104,7 @@ public static Map> generateRows(@NotNull Collection w.isItem(m.getType())) .collect(Collectors.toList()); - if (list.size() == 0) return map; + if (list.isEmpty()) return map; int size = list.size(); @@ -181,16 +182,10 @@ public static StarInventory createSelectionInventory(@NotNull Player p) { for (SoundEventSelection s : sp.getSoundSelections()) inv.addItem(StarInventoryUtil.toItemStack(s)); - ItemStack add = StarInventoryUtil.getHead("plus"); - ItemMeta aMeta = add.getItemMeta(); - aMeta.setDisplayName(ChatColor.GREEN + get("constants.cosmetics.add_selection")); - add.setItemMeta(aMeta); - - NBTWrapper nbt = of(add); - nbt.setID("add:soundevent"); - add = nbt.getItem(); - - if (size < selLimit) inv.addItem(add); + if (size < selLimit) inv.addItem(builder(StarInventoryUtil.getHead("plus"), + meta -> meta.setDisplayName(ChatColor.GREEN + get("constants.cosmetics.add_selection")), + nbt -> nbt.setID("add:soundevent") + )); for (int j = 0; j < BOTTOM_HALF_SLOTS.length; j++) { if (selLimit > j) continue; @@ -198,17 +193,17 @@ public static StarInventory createSelectionInventory(@NotNull Player p) { } if (selLimit < 35) { - ItemStack limit = new ItemStack(Material.NETHER_STAR); - ItemMeta lMeta = limit.getItemMeta(); - lMeta.setDisplayName(ChatColor.GOLD + get("constants.cosmetics.selection_limit")); - CompletionCriteria nextCriteria = CompletionCriteria.fromSelectionLimit(selLimit + 1); + ItemStack limit = itemBuilder(Material.NETHER_STAR, + meta -> { + meta.setDisplayName(ChatColor.GOLD + get("constants.cosmetics.selection_limit")); + meta.setLore(Arrays.asList( + ChatColor.YELLOW + nextCriteria.getDisplayMessage(), + ChatColor.GOLD + getWithArgs("constants.completed", String.format("%,.2f", nextCriteria.getProgressPercentage(p)) + "%") + )); + } + ); - lMeta.setLore(Arrays.asList( - ChatColor.YELLOW + nextCriteria.getDisplayMessage(), - ChatColor.GOLD + getWithArgs("constants.completed", String.format("%,.2f", nextCriteria.getProgressPercentage(p)) + "%") - )); - limit.setItemMeta(lMeta); inv.setItem(18, limit); } @@ -286,50 +281,42 @@ public static ItemStack generateSetting(@NotNull Player p, @NotNull PlayerSettin if (Boolean.class.isAssignableFrom(setting.getType())) { boolean on = sp.getSetting((PlayerSetting) setting); - - item = on ? StarMaterial.LIME_TERRACOTTA.findStack() : StarMaterial.RED_TERRACOTTA.findStack(); - ItemMeta meta = item.getItemMeta(); - - meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + (on ? ChatColor.GREEN + get("constants.on") : ChatColor.RED + get("constants.off"))); - if (on) { - meta.addEnchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1, true); - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - } - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("toggle:setting:boolean"); - nbt.set("setting", setting.getId()); - item = nbt.getItem(); + item = builder(on ? StarMaterial.LIME_TERRACOTTA.findStack() : StarMaterial.RED_TERRACOTTA.findStack(), + meta -> { + meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + (on ? ChatColor.GREEN + get("constants.on") : ChatColor.RED + get("constants.off"))); + if (on) { + meta.addEnchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1, true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + }, + nbt -> { + nbt.setID("toggle:setting:boolean"); + nbt.set("setting", setting.getId()); + } + ); } else if (Enum.class.isAssignableFrom(setting.getType())) { Enum value = sp.getSetting((PlayerSetting>) setting); - - item = StarMaterial.LIGHT_BLUE_TERRACOTTA.findStack(); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + ChatColor.AQUA + value.name()); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("toggle:setting:enum"); - nbt.set("setting", setting.getId()); - item = nbt.getItem(); + item = builder(StarMaterial.LIGHT_BLUE_TERRACOTTA.findStack(), + meta -> meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + ChatColor.AQUA + value.name()), + nbt -> { + nbt.setID("toggle:setting:enum"); + nbt.set("setting", setting.getId()); + } + ); } else { Object value = sp.getSetting(setting); - - item = StarMaterial.LIGHT_BLUE_TERRACOTTA.findStack(); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + ChatColor.YELLOW + value); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("toggle:setting"); - nbt.set("setting", setting.getId()); - item = nbt.getItem(); + item = builder(StarMaterial.LIGHT_BLUE_TERRACOTTA.findStack(), + meta -> meta.setDisplayName(ChatColor.YELLOW + setting.getDisplayName() + ": " + ChatColor.YELLOW + value), + nbt -> { + nbt.setID("toggle:setting"); + nbt.set("setting", setting.getId()); + } + ); } - ItemMeta meta = item.getItemMeta(); String desc = setting.getDescription() == null ? null : StarConfig.getConfig().get(setting.getDescription()); if (desc != null && !desc.equalsIgnoreCase("Unknown Value")) { + ItemMeta meta = item.getItemMeta(); List lore = new ArrayList<>(); lore.add(" "); @@ -338,10 +325,9 @@ public static ItemStack generateSetting(@NotNull Player p, @NotNull PlayerSettin ).map(s -> ChatColor.GRAY + s).collect(Collectors.toList())); meta.setLore(lore); + item.setItemMeta(meta); } - item.setItemMeta(meta); - return item; } diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarMaterial.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarMaterial.java index 1e63f20b..4841ad66 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarMaterial.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarMaterial.java @@ -3,6 +3,7 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; @@ -117,10 +118,12 @@ public enum StarMaterial { SNOWBALL("snow_ball"), ; - private final Material defaultV; + @VisibleForTesting + final Material defaultV; private final short data; private final boolean dataOnlyLegacy; - private final List names = new ArrayList<>(); + @VisibleForTesting + final List names = new ArrayList<>(); StarMaterial(Material defaultV, int data, boolean dataOnlyLegacy, String... allnames) { this.names.add(name()); diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarSound.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarSound.java index d0e5b436..6c92d43a 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarSound.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarSound.java @@ -7,6 +7,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; @@ -26,7 +27,8 @@ public enum StarSound { ITEM_TRIDENT_RIPTIDE_1, ; - private final List sounds = new ArrayList<>(); + @VisibleForTesting + final List sounds = new ArrayList<>(); StarSound(String... sounds) { // Ensure names are uppercase diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/InventorySelector.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/InventorySelector.java index c71bb38f..7838dbe4 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/InventorySelector.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/InventorySelector.java @@ -6,7 +6,6 @@ import me.gamercoder215.starcosmetics.util.Generator; import me.gamercoder215.starcosmetics.util.StarMaterial; import me.gamercoder215.starcosmetics.util.StarSound; -import me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; @@ -14,7 +13,6 @@ import org.bukkit.event.Event; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.ChatPaginator; import org.jetbrains.annotations.NotNull; @@ -26,7 +24,7 @@ import static me.gamercoder215.starcosmetics.util.inventory.ItemBuilder.SAVE; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.get; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.getWithArgs; -import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.of; +import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.builder; public final class InventorySelector { @@ -56,36 +54,30 @@ public static void loadInventories() { } List items = categoryItems.get(category); - - Material m = StarInventoryUtil.toMaterial(s); - ItemStack item = new ItemStack(m); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.GOLD + StarInventoryUtil.getFriendlyName(s)); - - List lore = new ArrayList<>(); - String desc = get("menu.cosmetics.choose.sound_desc." + s.name().toLowerCase(), ""); - - if (!desc.isEmpty()) { - lore.add(" "); - lore.addAll(Arrays.stream(ChatPaginator.wordWrap(desc, 30)) - .map(str -> ChatColor.GRAY + str) - .collect(Collectors.toList())); - lore.add(" "); - } - - lore.add(" "); - lore.add(ChatColor.YELLOW + get("constants.menu.right_click_hear")); - lore.add(ChatColor.YELLOW + get("constants.menu.left_click_select")); - - meta.setLore(lore); - - meta.addItemFlags(ItemFlag.values()); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.set("sound", s.name()); - item = nbt.getItem(); - + ItemStack item = builder(StarInventoryUtil.toMaterial(s), + meta -> { + meta.setDisplayName(ChatColor.GOLD + StarInventoryUtil.getFriendlyName(s)); + + List lore = new ArrayList<>(); + String desc = get("menu.cosmetics.choose.sound_desc." + s.name().toLowerCase(), ""); + + if (!desc.isEmpty()) { + lore.add(" "); + lore.addAll(Arrays.stream(ChatPaginator.wordWrap(desc, 30)) + .map(str -> ChatColor.GRAY + str) + .collect(Collectors.toList())); + lore.add(" "); + } + + lore.add(" "); + lore.add(ChatColor.YELLOW + get("constants.menu.right_click_hear")); + lore.add(ChatColor.YELLOW + get("constants.menu.left_click_select")); + + meta.setLore(lore); + meta.addItemFlags(ItemFlag.values()); + }, + nbt -> nbt.set("sound", s.name()) + ); items.add(item); } @@ -138,31 +130,26 @@ public static void chooseEvent(@NotNull Player p, Consumer items = new ArrayList<>(); for (Class clazz : SoundEventSelection.AVAILABLE_EVENTS) { - Material m = StarInventoryUtil.toMaterial(clazz); - ItemStack item = new ItemStack(m); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + clazz.getSimpleName()); - - List lore = new ArrayList<>(); - String desc = get("menu.cosmetics.choose.event_desc." + clazz.getSimpleName().toLowerCase(), ""); - - if (!desc.isEmpty()) { - lore.add(" "); - lore.addAll(Arrays.stream(ChatPaginator.wordWrap(desc, 30)) - .map(str -> ChatColor.GRAY + str) - .collect(Collectors.toList())); - lore.add(" "); - - meta.setLore(lore); - } - - meta.addItemFlags(ItemFlag.values()); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.set("event", clazz); - item = nbt.getItem(); - + ItemStack item = builder(StarInventoryUtil.toMaterial(clazz), + meta -> { + meta.setDisplayName(ChatColor.YELLOW + clazz.getSimpleName()); + + List lore = new ArrayList<>(); + String desc = get("menu.cosmetics.choose.event_desc." + clazz.getSimpleName().toLowerCase(), ""); + + if (!desc.isEmpty()) { + lore.add(" "); + lore.addAll(Arrays.stream(ChatPaginator.wordWrap(desc, 30)) + .map(str -> ChatColor.GRAY + str) + .collect(Collectors.toList())); + lore.add(" "); + + meta.setLore(lore); + } + + meta.addItemFlags(ItemFlag.values()); + }, nbt -> nbt.set("event", clazz) + ); items.add(item); } @@ -181,24 +168,16 @@ public static StarInventory confirm(@NotNull Player p, @NotNull Runnable confirm inv.setAttribute("confirm_action", confirmR); inv.setAttribute("cancel_action", cancelR); - ItemStack confirm = StarMaterial.LIME_WOOL.findStack(); - ItemMeta cMeta = confirm.getItemMeta(); - cMeta.setDisplayName(ChatColor.GREEN + get("menu.confirm")); - confirm.setItemMeta(cMeta); - - NBTWrapper confirmNBT = of(confirm); - confirmNBT.set("item", "confirm"); - confirm = confirmNBT.getItem(); + ItemStack confirm = builder(StarMaterial.LIME_WOOL.findStack(), + meta -> meta.setDisplayName(ChatColor.GREEN + get("menu.confirm")), + nbt -> nbt.set("item", "confirm") + ); inv.setItem(11, confirm); - ItemStack cancel = StarMaterial.RED_WOOL.findStack(); - ItemMeta caMeta = cancel.getItemMeta(); - caMeta.setDisplayName(ChatColor.RED + get("menu.cancel")); - cancel.setItemMeta(caMeta); - - NBTWrapper cancelNBT = of(cancel); - cancelNBT.set("item", "cancel"); - cancel = cancelNBT.getItem(); + ItemStack cancel = builder(StarMaterial.RED_WOOL.findStack(), + meta -> meta.setDisplayName(ChatColor.RED + get("menu.cancel")), + nbt -> nbt.set("item", "cancel") + ); inv.setItem(15, cancel); p.openInventory(inv); @@ -218,54 +197,49 @@ public static void choosePitchVolume(@NotNull Player p, @NotNull Sound sound, @N inv.setAttribute("sound", sound); inv.setCancelled(); - ItemStack pitch = new ItemStack(Material.NOTE_BLOCK); - ItemMeta pMeta = pitch.getItemMeta(); - pMeta.setDisplayName(ChatColor.YELLOW + get("constants.pitch")); - pMeta.setLore(Arrays.asList( - ChatColor.GREEN + "1.0", - " ", - ChatColor.YELLOW + get("constants.menu.right_click_up"), - ChatColor.YELLOW + get("constants.menu.left_click_down") - )); - pitch.setItemMeta(pMeta); - - NBTWrapper pitchNBT = of(pitch); - pitchNBT.set("item", "pitch"); - pitchNBT.set("value", 1.0f); - pitchNBT.set("min", 0.0f); - pitchNBT.set("max", 2.0f); - pitch = pitchNBT.getItem(); + ItemStack pitch = builder(Material.NOTE_BLOCK, + meta -> { + meta.setDisplayName(ChatColor.YELLOW + get("constants.pitch")); + meta.setLore(Arrays.asList( + ChatColor.GREEN + "1.0", + " ", + ChatColor.YELLOW + get("constants.menu.right_click_up"), + ChatColor.YELLOW + get("constants.menu.left_click_down") + )); + }, + nbt -> { + nbt.set("item", "pitch"); + nbt.set("value", 1.0f); + nbt.set("min", 0.0f); + nbt.set("max", 2.0f); + } + ); inv.setItem(11, pitch); - ItemStack volume = new ItemStack(Material.JUKEBOX); - ItemMeta vMeta = volume.getItemMeta(); - vMeta.setDisplayName(ChatColor.YELLOW + get("constants.volume")); - vMeta.setLore(Arrays.asList( - ChatColor.GREEN + "2.0", - " ", - ChatColor.YELLOW + get("constants.menu.right_click_up"), - ChatColor.YELLOW + get("constants.menu.left_click_down") - )); - volume.setItemMeta(vMeta); - - NBTWrapper volumeNBT = of(volume); - volumeNBT.set("item", "volume"); - volumeNBT.set("value", 2.0f); - volumeNBT.set("max", 10.0f); - volumeNBT.set("min", 0.1f); - volume = volumeNBT.getItem(); + ItemStack volume = builder(Material.JUKEBOX, + meta -> { + meta.setDisplayName(ChatColor.YELLOW + get("constants.volume")); + meta.setLore(Arrays.asList( + ChatColor.GREEN + "2.0", + " ", + ChatColor.YELLOW + get("constants.menu.right_click_up"), + ChatColor.YELLOW + get("constants.menu.left_click_down") + )); + }, + nbt -> { + nbt.set("item", "volume"); + nbt.set("value", 2.0f); + nbt.set("max", 10.0f); + nbt.set("min", 0.1f); + } + ); inv.setItem(15, volume); - ItemStack test = new ItemStack(StarInventoryUtil.toMaterial(sound)); - ItemMeta tMeta = test.getItemMeta(); - tMeta.setDisplayName(ChatColor.YELLOW + get("constants.test_sound")); - test.setItemMeta(tMeta); - - NBTWrapper testNBT = of(test); - testNBT.set("item", "test"); - test = testNBT.getItem(); + ItemStack test = builder(StarInventoryUtil.toMaterial(sound), + meta -> meta.setDisplayName(ChatColor.YELLOW + get("constants.test_sound")), + nbt -> nbt.set("item", "test") + ); inv.setItem(22, test); - inv.setItem(23, ItemBuilder.STOP_SOUND); if (back != null) { @@ -281,39 +255,28 @@ public static void editSelection(@NotNull Player p, @NotNull SoundEventSelection inv.setAttribute("current_event", initial); inv.setAttribute("chosen_action", edited); - ItemStack sound = new ItemStack(Material.NOTE_BLOCK); - ItemMeta sMeta = sound.getItemMeta(); - sMeta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.sound")); - sound.setItemMeta(sMeta); - - NBTWrapper soundNBT = of(sound); - soundNBT.set("item", "sound"); - sound = soundNBT.getItem(); + ItemStack sound = builder(Material.NOTE_BLOCK, + meta -> meta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.sound")), + nbt -> nbt.set("item", "sound") + ); inv.setItem(11, sound); - ItemStack pitchVolume = new ItemStack(Material.NOTE_BLOCK); - ItemMeta pMeta = pitchVolume.getItemMeta(); - pMeta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.pitch_volume")); - pMeta.setLore(Arrays.asList( - ChatColor.GREEN + getWithArgs("constants.menu.pitch", initial.getPitch()), - ChatColor.GREEN + getWithArgs("constants.menu.volume", initial.getVolume()) - )); - pitchVolume.setItemMeta(pMeta); - - NBTWrapper pitchNBT = of(pitchVolume); - pitchNBT.set("item", "pitch_volume"); - pitchVolume = pitchNBT.getItem(); - + ItemStack pitchVolume = builder(Material.NOTE_BLOCK, + meta -> { + meta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.pitch_volume")); + meta.setLore(Arrays.asList( + ChatColor.GREEN + getWithArgs("constants.menu.pitch", initial.getPitch()), + ChatColor.GREEN + getWithArgs("constants.menu.volume", initial.getVolume()) + )); + }, + nbt -> nbt.set("item", "pitch_volume") + ); inv.setItem(13, pitchVolume); - ItemStack event = new ItemStack(Material.BOOK); - ItemMeta eMeta = event.getItemMeta(); - eMeta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.event")); - event.setItemMeta(eMeta); - - NBTWrapper eNBT = of(event); - eNBT.set("item", "event"); - event = eNBT.getItem(); + ItemStack event = builder(Material.BOOK, + meta -> meta.setDisplayName(ChatColor.YELLOW + get("constants.menu.edit.event")), + nbt -> nbt.set("item", "event") + ); inv.setItem(15, event); inv.setItem(22, SAVE); diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/StarInventoryUtil.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/StarInventoryUtil.java index faa800cb..92115204 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/StarInventoryUtil.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/inventory/StarInventoryUtil.java @@ -50,6 +50,7 @@ import static me.gamercoder215.starcosmetics.util.StarMaterial.*; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.get; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.getWithArgs; +import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.builder; import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.of; import static org.bukkit.Material.*; @@ -110,60 +111,48 @@ public static Material toMaterial(@NotNull Class eventClass) { @NotNull public static ItemStack toItemStack(@NotNull SoundEventSelection s) { - ItemStack item = new ItemStack(toMaterial(s.getEvent())); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + s.getEvent().getSimpleName()); - - List lore = new ArrayList<>(); - lore.add(ChatColor.AQUA + get("constants.menu.sound") + " " + ChatColor.GOLD + getFriendlyName(s.getSound())); - lore.add(ChatColor.AQUA + getWithArgs("constants.menu.pitch", ChatColor.GOLD + String.format("%,.1f", s.getPitch()))); - lore.add(ChatColor.AQUA + getWithArgs("constants.menu.volume", ChatColor.GOLD + String.format("%,.1f", s.getVolume()))); - lore.add(" "); - DateTimeFormatter f = DateTimeFormatter.ofPattern("EEEE, LLL d, yyyy 'at' h:mm:ss a") .withLocale(StarConfig.getConfig().getLocale()) .withZone(ZoneId.systemDefault()); - lore.add(ChatColor.GREEN + getWithArgs("constants.menu.created_at", ChatColor.AQUA + f.format(s.getTimestamp().toInstant()))); - - lore.add(" "); - lore.add(ChatColor.YELLOW + get("constants.menu.left_click_edit")); - lore.add(ChatColor.YELLOW + get("constants.menu.right_click_delete")); - - meta.setLore(lore); - - meta.addItemFlags(ItemFlag.values()); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("manage:soundevent"); - nbt.set("selection", s); - item = nbt.getItem(); - - return item; + return builder(toMaterial(s.getEvent()), + meta -> { + meta.setDisplayName(ChatColor.YELLOW + s.getEvent().getSimpleName()); + meta.setLore(Arrays.asList( + ChatColor.AQUA + get("constants.menu.sound") + " " + ChatColor.GOLD + getFriendlyName(s.getSound()), + ChatColor.AQUA + getWithArgs("constants.menu.pitch", ChatColor.GOLD + String.format("%,.1f", s.getPitch())), + ChatColor.AQUA + getWithArgs("constants.menu.volume", ChatColor.GOLD + String.format("%,.1f", s.getVolume())), + " ", + ChatColor.GREEN + getWithArgs("constants.menu.created_at", ChatColor.AQUA + f.format(s.getTimestamp().toInstant())), + " ", + ChatColor.YELLOW + get("constants.menu.left_click_edit"), + ChatColor.YELLOW + get("constants.menu.right_click_delete") + )); + }, + nbt -> { + nbt.setID("manage:soundevent"); + nbt.set("selection", s); + } + ); } @NotNull public static ItemStack toItemStack(@NotNull StructureInfo info) { - ItemStack item = new ItemStack(info.getPrimaryMaterial()); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.GOLD + info.getLocalizedName()); - - List lore = new ArrayList<>(); - lore.add(info.getRarity().toString()); - lore.add(" "); - lore.add(ChatColor.YELLOW + info.getCriteria().getDisplayMessage()); - - meta.setLore(lore); - meta.addItemFlags(ItemFlag.values()); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("spawn:structure"); - nbt.set("info", info); - item = nbt.getItem(); - - return item; + return builder(info.getPrimaryMaterial(), + meta -> { + meta.setDisplayName(ChatColor.GOLD + info.getLocalizedName()); + meta.setLore(Arrays.asList( + info.getRarity().toString(), + " ", + ChatColor.YELLOW + info.getCriteria().getDisplayMessage() + )); + meta.addItemFlags(ItemFlag.values()); + }, + nbt -> { + nbt.setID("spawn:structure"); + nbt.set("info", info); + } + ); } private static final List ITEMS = Arrays.stream(Material.values()).filter(w::isItem).collect(Collectors.toList()); @@ -286,31 +275,15 @@ public static void setScrolls(StarInventory inv) { inv.setAttribute("row_count", 0); int size = inv.getSize(); - int upM; - int downM; + inv.setItem(size == 54 ? 26 : 17, builder(getHead("arrow_up"), + meta -> meta.setDisplayName(ChatColor.GREEN + get("constants.up")), + nbt -> nbt.setID("scroll_up") + )); - switch (size) { - case 54: upM = 26; downM = 35; break; - default: upM = 17; downM = 26; break; - } - - ItemStack up = getHead("arrow_up"); - ItemMeta uMeta = up.getItemMeta(); - uMeta.setDisplayName(ChatColor.GREEN + get("constants.up")); - up.setItemMeta(uMeta); - NBTWrapper uNBT = NBTWrapper.of(up); - uNBT.setID("scroll_up"); - up = uNBT.getItem(); - inv.setItem(upM, up); - - ItemStack down = getHead("arrow_down"); - ItemMeta dMeta = down.getItemMeta(); - dMeta.setDisplayName(ChatColor.GREEN + get("constants.down")); - down.setItemMeta(dMeta); - NBTWrapper dNBT = NBTWrapper.of(down); - dNBT.setID("scroll_down"); - down = dNBT.getItem(); - inv.setItem(downM, down); + inv.setItem(size == 54 ? 35 : 26, builder(getHead("arrow_down"), + meta -> meta.setDisplayName(ChatColor.GREEN + get("constants.down")), + nbt -> nbt.setID("scroll_down") + )); } public static ItemStack getHead(String key) { @@ -359,19 +332,19 @@ public static void setRows(Inventory inv, Map> rows, in @NotNull public static ItemStack toItemStack(@NotNull Cosmetic c) { - ItemStack item = new ItemStack(c.getIcon()); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.GOLD + c.getDisplayName()); - meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); - item.setItemMeta(meta); - NBTWrapper nbt = of(item); - nbt.setID("cosmetic:selection"); - nbt.set("cosmetic", c.getNamespace()); - nbt.set("display", c.getDisplayName()); - - if (c instanceof Trail) nbt.set("trail_type", ((Trail) c).getType().name()); - - return nbt.getItem(); + return builder(c.getIcon(), + meta -> { + meta.setDisplayName(ChatColor.GOLD + c.getDisplayName()); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + }, + nbt -> { + nbt.setID("cosmetic:selection"); + nbt.set("cosmetic", c.getNamespace()); + nbt.set("display", c.getDisplayName()); + + if (c instanceof Trail) nbt.set("trail_type", ((Trail) c).getType().name()); + } + ); } @NotNull @@ -462,35 +435,33 @@ else if (input instanceof AnimatedHatData) else item = new ItemStack(toInputMaterial(input, loc)); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + loc.getParent().getDisplayName() + " | " + loc.getDisplayName()); - meta.addItemFlags(ItemFlag.values()); + return builder(item, + meta -> { + meta.setDisplayName(ChatColor.YELLOW + loc.getParent().getDisplayName() + " | " + loc.getDisplayName()); + meta.addItemFlags(ItemFlag.values()); - List lore = new ArrayList<>(); - lore.add(loc.getRarity().toString()); + List lore = new ArrayList<>(); + lore.add(loc.getRarity().toString()); - ChatColor c = loc.isUnlocked(p) ? ChatColor.GREEN : ChatColor.RED; + ChatColor c = loc.isUnlocked(p) ? ChatColor.GREEN : ChatColor.RED; - if (!loc.getRarity().hasInvisibleRequirements() || loc.isUnlocked(p)) { - lore.add(" "); - CompletionCriteria criteria = loc.getCompletionCriteria(); + if (!loc.getRarity().hasInvisibleRequirements() || loc.isUnlocked(p)) { + lore.add(" "); + CompletionCriteria criteria = loc.getCompletionCriteria(); - lore.addAll(Arrays.stream( - ChatPaginator.wordWrap(criteria.getDisplayMessage(), 30) - ).map(s -> c + s).collect(Collectors.toList())); - lore.add(ChatColor.DARK_GREEN + getWithArgs("constants.completed", String.format("%,.2f", criteria.getProgressPercentage(p)) + "%")); - } + lore.addAll(Arrays.stream( + ChatPaginator.wordWrap(criteria.getDisplayMessage(), 30) + ).map(s -> c + s).collect(Collectors.toList())); + lore.add(ChatColor.DARK_GREEN + getWithArgs("constants.completed", String.format("%,.2f", criteria.getProgressPercentage(p)) + "%")); + } - meta.setLore(lore); - item.setItemMeta(meta); - - NBTWrapper nbt = NBTWrapper.of(item); - nbt.setID("choose:cosmetic"); - nbt.set("location", loc); - - item = nbt.getItem(); - - return item; + meta.setLore(lore); + }, + nbt -> { + nbt.setID("choose:cosmetic"); + nbt.set("location", loc); + } + ); } @NotNull @@ -516,16 +487,10 @@ public static Material toMaterial(@NotNull EntityType type) { } public static void setBack(@NotNull StarInventory inv, int slot, @NotNull Consumer action) { - ItemStack back = getHead("arrow_left"); - ItemMeta meta = back.getItemMeta(); - meta.setDisplayName(ChatColor.RED + get("constants.back")); - back.setItemMeta(meta); - - NBTWrapper nbt = of(back); - nbt.setID("back"); - back = nbt.getItem(); - - inv.setItem(slot, back); + inv.setItem(slot, builder(getHead("arrow_left"), + meta -> meta.setDisplayName(ChatColor.RED + get("constants.back")), + nbt -> nbt.setID("back") + )); inv.setAttribute("back_inventory_action", action); } @@ -540,17 +505,15 @@ public static void setPages(@NotNull List pages) { inv.setAttribute("current_page", index.getAndIncrement()); }); - ItemStack prev = getHead("arrow_left_gray"); - ItemMeta pMeta = prev.getItemMeta(); - pMeta.setDisplayName(ChatColor.YELLOW + get("constants.previous_page")); - prev.setItemMeta(pMeta); - prev = NBTWrapper.setID(prev, "previous_page"); + ItemStack prev = builder(getHead("arrow_left_gray"), + meta -> meta.setDisplayName(ChatColor.YELLOW + get("constants.previous_page")), + nbt -> nbt.setID("previous_page") + ); - ItemStack next = getHead("arrow_right_gray"); - ItemMeta nMeta = next.getItemMeta(); - nMeta.setDisplayName(ChatColor.YELLOW + get("constants.next_page")); - next.setItemMeta(nMeta); - next = NBTWrapper.setID(next, "next_page"); + ItemStack next = builder(getHead("arrow_right_gray"), + meta -> meta.setDisplayName(ChatColor.YELLOW + get("constants.next_page")), + nbt -> nbt.setID("next_page") + ); for (int i = 0; i < pages.size(); i++) { StarInventory page = pages.get(i); @@ -718,24 +681,21 @@ public static List getGUIPlacements(int size, int itemCount) { @NotNull public static ItemStack toItemStack(@NotNull Player p, @NotNull PetInfo info) { CompletionCriteria criteria = info.getCriteria(); - - ItemStack item = info.getIcon().clone(); - ItemMeta meta = item.getItemMeta(); - - meta.setDisplayName(ChatColor.GOLD + info.getName()); - List lore = new ArrayList<>(); - ChatColor c = criteria.isUnlocked(p) ? ChatColor.GREEN : ChatColor.RED; - - lore.add(info.getRarity().toString()); - lore.add(" "); - lore.addAll(Arrays.stream( - ChatPaginator.wordWrap(criteria.getDisplayMessage(), 30) - ).map(s -> c + s).collect(Collectors.toList())); - lore.add(ChatColor.DARK_GREEN + getWithArgs("constants.completed", String.format("%,.2f", criteria.getProgressPercentage(p)) + "%")); - meta.setLore(lore); - - item.setItemMeta(meta); - return item; + return itemBuilder(info.getIcon(), + meta -> { + meta.setDisplayName(ChatColor.GOLD + info.getName()); + List lore = new ArrayList<>(); + ChatColor c = criteria.isUnlocked(p) ? ChatColor.GREEN : ChatColor.RED; + + lore.add(info.getRarity().toString()); + lore.add(" "); + lore.addAll(Arrays.stream( + ChatPaginator.wordWrap(criteria.getDisplayMessage(), 30) + ).map(s -> c + s).collect(Collectors.toList())); + lore.add(ChatColor.DARK_GREEN + getWithArgs("constants.completed", String.format("%,.2f", criteria.getProgressPercentage(p)) + "%")); + meta.setLore(lore); + } + ); } public static void setReset(@NotNull StarInventory inv) { diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/TestDataWrapper.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/TestDataWrapper.java new file mode 100644 index 00000000..f3b52f3b --- /dev/null +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/TestDataWrapper.java @@ -0,0 +1,10 @@ +package me.gamercoder215.starcosmetics.wrapper; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; + +public final class TestDataWrapper implements DataWrapper { + @Override + public void blockDataParticle(Particle p, Location loc, int count, Material m) {} +} diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/Wrapper.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/Wrapper.java index 3b447b74..fcefdf30 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/Wrapper.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/Wrapper.java @@ -57,11 +57,12 @@ static boolean isOutdatedSubversion() { default void registerEvents() {} static String getServerVersion() { - if (Bukkit.getServer() == null) return ""; // Using Test Server + if (Bukkit.getServer() == null) return "1_20_R2"; // Using Test Server return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1); } static DataWrapper getDataWrapper() { + if (Bukkit.getServer() == null) return new TestDataWrapper(); // Using Test Server try { Constructor constr; @@ -81,6 +82,7 @@ static DataWrapper getDataWrapper() { } static Wrapper getWrapper() { + if (Bukkit.getServer() == null) return new TestWrapper(); // Using Test Server try { Constructor constr = Class.forName("me.gamercoder215.starcosmetics.wrapper.v" + getServerVersion() + ".Wrapper" + getServerVersion()) .asSubclass(Wrapper.class) diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/commands/CommandWrapper.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/commands/CommandWrapper.java index 129d0360..97ab2275 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/commands/CommandWrapper.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/commands/CommandWrapper.java @@ -20,7 +20,6 @@ import me.gamercoder215.starcosmetics.util.inventory.StarInventory; import me.gamercoder215.starcosmetics.util.inventory.StarInventoryUtil; import me.gamercoder215.starcosmetics.wrapper.Wrapper; -import me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper; import org.bukkit.*; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; @@ -37,8 +36,9 @@ import static me.gamercoder215.starcosmetics.util.Generator.cw; import static me.gamercoder215.starcosmetics.util.Generator.genGUI; +import static me.gamercoder215.starcosmetics.util.inventory.StarInventoryUtil.itemBuilder; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.*; -import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.of; +import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.builder; public interface CommandWrapper { @@ -117,35 +117,29 @@ default void about(Player p) { StarInventory inv = Generator.genGUI("about", 27, get("menu.about")); inv.setCancelled(); - ItemStack head = Generator.generateHead(p); - ItemMeta hMeta = head.getItemMeta(); - hMeta.setDisplayName(ChatColor.AQUA + get("menu.about.head")); - head.setItemMeta(hMeta); + ItemStack head = itemBuilder(Generator.generateHead(p), meta -> meta.setDisplayName(ChatColor.AQUA + get("menu.about.head"))); inv.setItem(4, head); - ItemStack cosmetics = StarMaterial.RED_CONCRETE.findStack(); - ItemMeta cMeta = cosmetics.getItemMeta(); - cMeta.setDisplayName(ChatColor.GOLD + get("menu.about.cosmetics")); - - List lore = new ArrayList<>(); - lore.add(ChatColor.YELLOW + getWithArgs("menu.about.projectile_trail_count", comma(getCosmeticCount(TrailType.PROJECTILE)) )); - lore.add(ChatColor.DARK_GREEN + getWithArgs("menu.about.ground_trail_count", comma(getCosmeticCount(TrailType.GROUND)) )); - lore.add(ChatColor.AQUA + getWithArgs("menu.about.sound_trail_count", comma(getCosmeticCount(TrailType.PROJECTILE_SOUND)) )); - - lore.add(" "); - - lore.add(ChatColor.DARK_PURPLE + getWithArgs("menu.about.particle_shape_count", comma(getCosmeticCount(ParticleShape.class)) )); - lore.add(ChatColor.DARK_AQUA + getWithArgs("menu.about.structure_count", comma(StarConfig.getRegistry().getAvailableStructures().size()) )); - lore.add(ChatColor.LIGHT_PURPLE + getWithArgs("menu.about.pet_count", comma(PetType.values().length))); - lore.add(ChatColor.GREEN + getWithArgs("menu.about.hat_count", comma(getCosmeticCount(Hat.class)))); - lore.add(ChatColor.BLUE + getWithArgs("menu.about.gadget_count", comma(getCosmeticCount(Gadget.class)))); - - lore.add(" "); - - lore.add(ChatColor.RED + getWithArgs("menu.about.total_cosmetic_count", comma(getCosmeticCount()) )); - cMeta.setLore(lore); - - cosmetics.setItemMeta(cMeta); + ItemStack cosmetics = itemBuilder(StarMaterial.RED_CONCRETE.findStack(), + meta -> { + meta.setDisplayName(ChatColor.GOLD + get("menu.about.cosmetics")); + meta.setLore( + Arrays.asList( + ChatColor.YELLOW + getWithArgs("menu.about.projectile_trail_count", comma(getCosmeticCount(TrailType.PROJECTILE))), + ChatColor.DARK_GREEN + getWithArgs("menu.about.ground_trail_count", comma(getCosmeticCount(TrailType.GROUND))), + ChatColor.AQUA + getWithArgs("menu.about.sound_trail_count", comma(getCosmeticCount(TrailType.PROJECTILE_SOUND))), + " ", + ChatColor.DARK_PURPLE + getWithArgs("menu.about.particle_shape_count", comma(getCosmeticCount(ParticleShape.class))), + ChatColor.DARK_AQUA + getWithArgs("menu.about.structure_count", comma(StarConfig.getRegistry().getAvailableStructures().size())), + ChatColor.LIGHT_PURPLE + getWithArgs("menu.about.pet_count", comma(PetType.values().length)), + ChatColor.GREEN + getWithArgs("menu.about.hat_count", comma(getCosmeticCount(Hat.class))), + ChatColor.BLUE + getWithArgs("menu.about.gadget_count", comma(getCosmeticCount(Gadget.class))), + " ", + ChatColor.RED + getWithArgs("menu.about.total_cosmetic_count", comma(getCosmeticCount())) + ) + ); + } + ); inv.setItem(10, cosmetics); inv.setItem(12, @@ -212,20 +206,17 @@ default void cosmetics(Player p) { // Parents - for (CosmeticParent parent : CosmeticParent.values()) { - ItemStack item = new ItemStack(parent.getIcon()); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.YELLOW + get(parent.getDisplayKey())); - meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); - item.setItemMeta(meta); - - NBTWrapper nbt = of(item); - nbt.setID("cosmetic:selection:parent"); - nbt.set("parent", parent.name()); - item = nbt.getItem(); - - inv.setItem(parent.getPlace(), item); - } + for (CosmeticParent parent : CosmeticParent.values()) + inv.setItem(parent.getPlace(), builder(parent.getIcon(), + meta -> { + meta.setDisplayName(ChatColor.YELLOW + get(parent.getDisplayKey())); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); + }, + nbt -> { + nbt.setID("cosmetic:selection:parent"); + nbt.set("parent", parent.name()); + }) + ); // Particle Shapes @@ -233,85 +224,70 @@ default void cosmetics(Player p) { inv.setAttribute("collections:custom:particle", sel); inv.setAttribute("items_display:particle", "menu.cosmetics.shape"); - ItemStack particles = StarMaterial.FIREWORK_STAR.findStack(); - FireworkEffectMeta pMeta = (FireworkEffectMeta) particles.getItemMeta(); - pMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.shape")); - pMeta.setEffect(FireworkEffect.builder() - .withColor(Color.fromRGB(r.nextInt(16777216))) - .build()); - - pMeta.addItemFlags(ItemFlag.values()); - - particles.setItemMeta(pMeta); - NBTWrapper pnbt = of(particles); - pnbt.setID("cosmetic:selection:custom"); - pnbt.set("type", "particle"); - pnbt.set("custom_id", "particle"); - particles = pnbt.getItem(); - inv.setItem(24, particles); + inv.setItem(24, builder(StarMaterial.FIREWORK_STAR.findStack(), + meta -> { + FireworkEffectMeta pMeta = (FireworkEffectMeta) meta; + pMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.shape")); + pMeta.setEffect(FireworkEffect.builder() + .withColor(Color.fromRGB(r.nextInt(16777216))) + .build()); + + pMeta.addItemFlags(ItemFlag.values()); + }, + nbt -> { + nbt.setID("cosmetic:selection:custom"); + nbt.set("type", "particle"); + nbt.set("custom_id", "particle"); + } + )); // Structures try { StarInventory structureInv = Generator.createStructureInventory(p); - - ItemStack structures = new ItemStack(Material.STRUCTURE_BLOCK); - ItemMeta stMeta = structures.getItemMeta(); - stMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.structure")); - - structures.setItemMeta(stMeta); - NBTWrapper stnbt = of(structures); - stnbt.setID("cosmetic:selection:custom_inventory"); - stnbt.set("inventory_key", "structures"); - stnbt.set("cooldown", "structures"); - structures = stnbt.getItem(); - inv.setItem(29, structures); + inv.setItem(29, builder(Material.STRUCTURE_BLOCK, + meta -> meta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.structure")), + nbt -> { + nbt.setID("cosmetic:selection:custom_inventory"); + nbt.set("inventory_key", "structures"); + nbt.set("cooldown", "structures"); + } + )); inv.setAttribute("structures", structureInv); } catch (IllegalArgumentException ignored) { inv.setItem(29, ItemBuilder.LOCKED); } // Sound Events - - ItemStack soundEvents = new ItemStack(Material.NOTE_BLOCK); - ItemMeta sMeta = soundEvents.getItemMeta(); - sMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.sound")); - - soundEvents.setItemMeta(sMeta); - NBTWrapper snbt = of(soundEvents); - snbt.setID("cosmetic:selection:custom_inventory"); - snbt.set("inventory_key", "sound_events"); - soundEvents = snbt.getItem(); - inv.setItem(30, soundEvents); + inv.setItem(30, builder(Material.NOTE_BLOCK, + meta -> meta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.sound")), + nbt -> { + nbt.setID("cosmetic:selection:custom_inventory"); + nbt.set("inventory_key", "sound_events"); + }) + ); inv.setAttribute("sound_events", Generator.createSelectionInventory(p)); // Gadgets - ItemStack gadgets = StarMaterial.FIREWORK_ROCKET.findStack(); - ItemMeta gMeta = gadgets.getItemMeta(); - gMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.gadget")); - - gadgets.setItemMeta(gMeta); - - NBTWrapper gnbt = of(gadgets); - gnbt.setID("cosmetic:selection"); - gnbt.set("cosmetic", BaseGadget.INSTANCE.getNamespace()); - gnbt.set("display", BaseGadget.INSTANCE.getDisplayName()); - gadgets = gnbt.getItem(); - inv.setItem(32, gadgets); + inv.setItem(32, builder(StarMaterial.FIREWORK_ROCKET.findStack(), + meta -> meta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.gadget")), + nbt -> { + nbt.setID("cosmetic:selection"); + nbt.set("cosmetic", BaseGadget.INSTANCE.getNamespace()); + nbt.set("display", BaseGadget.INSTANCE.getDisplayName()); + }) + ); // Pets - ItemStack pets = StarInventoryUtil.getHead("rabbit_pet"); - ItemMeta petMeta = pets.getItemMeta(); - petMeta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.pet")); - pets.setItemMeta(petMeta); - - NBTWrapper petNBT = of(pets); - petNBT.setID("cosmetic:selection:custom_inventory"); - petNBT.set("inventory_key", "pets"); - pets = petNBT.getItem(); - inv.setItem(33, pets); + inv.setItem(33, builder(StarInventoryUtil.getHead("rabbit_pet"), + meta -> meta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.choose.pet")), + nbt -> { + nbt.setID("cosmetic:selection:custom_inventory"); + nbt.set("inventory_key", "pets"); + } + )); inv.setAttribute("pets", Generator.createPetInventory(p)); ItemStack settings = ItemBuilder.of(Material.NETHER_STAR) @@ -421,17 +397,11 @@ default void shapes(Player p) { List invs = Generator.createSelectionInventory(p, sel, get("menu.cosmetics.shape")); invs.forEach(inv -> StarInventoryUtil.setBack(inv, cw::cosmetics)); - ItemStack cancel = new ItemStack(Material.BARRIER); - ItemMeta meta = cancel.getItemMeta(); - meta.setDisplayName(ChatColor.RED + get("menu.cosmetics.particle.reset")); - cancel.setItemMeta(meta); - - NBTWrapper n = of(cancel); - n.setID("cancel:particle"); - cancel = n.getItem(); - - ItemStack cancelF = cancel; - invs.forEach(i -> i.setItem(18, cancelF)); + ItemStack cancel = builder(Material.BARRIER, + meta -> meta.setDisplayName(ChatColor.RED + get("menu.cosmetics.particle.reset")), + nbt -> nbt.setID("cancel:particle") + ); + invs.forEach(i -> i.setItem(18, cancel)); p.openInventory(invs.get(0)); StarSound.ENTITY_ARROW_HIT_PLAYER.playSuccess(p); @@ -528,13 +498,13 @@ default void hologramInfo(Player p) { message.setItemMeta(mMeta); inv.setItem(12, message); - ItemStack setMessage = NBTWrapper.builder(Material.PAPER, + ItemStack setMessage = builder(Material.PAPER, meta -> meta.setDisplayName(ChatColor.YELLOW + get("menu.cosmetics.hologram.set")), nbt -> nbt.setID("cosmetic:hologram:set") ); inv.setItem(14, setMessage); - ItemStack resetMessage = NBTWrapper.builder(StarMaterial.RED_WOOL.findStack(), + ItemStack resetMessage = builder(StarMaterial.RED_WOOL.findStack(), meta -> meta.setDisplayName(ChatColor.RED + get("menu.cosmetics.hologram.reset")), nbt -> nbt.setID("cosmetic:hologram:reset") ); diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/nbt/NBTWrapper.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/nbt/NBTWrapper.java index 739b7cc7..d7a38dc2 100644 --- a/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/nbt/NBTWrapper.java +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/wrapper/nbt/NBTWrapper.java @@ -52,12 +52,6 @@ public static float getFloat(ItemStack item, String key) { return of(item).getFloat(key); } - public static ItemStack setID(ItemStack item, String id) { - NBTWrapper nbt = of(item); - nbt.setID(id); - return nbt.getItem(); - } - public final void setID(String value) { set("id", value); } diff --git a/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarChat.java b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarChat.java new file mode 100644 index 00000000..00d2a76a --- /dev/null +++ b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarChat.java @@ -0,0 +1,16 @@ +package me.gamercoder215.starcosmetics.util; + +import org.bukkit.ChatColor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TestStarChat { + + @Test + @DisplayName("Text Hex Message") + public void testHexMessage() { + Assertions.assertEquals(StarChat.hexMessage("ff0000", ""), ChatColor.translateAlternateColorCodes('&', "&x&f&f&0&0&0&0")); + } + +} diff --git a/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarMaterial.java b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarMaterial.java new file mode 100644 index 00000000..ca70e014 --- /dev/null +++ b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarMaterial.java @@ -0,0 +1,16 @@ +package me.gamercoder215.starcosmetics.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TestStarMaterial { + + @Test + @DisplayName("Test StarMaterial") + public void testStarMaterial() { + for (StarMaterial material : StarMaterial.values()) + Assertions.assertTrue(material.names.size() > 1 || material.defaultV != null); + } + +} diff --git a/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarSound.java b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarSound.java new file mode 100644 index 00000000..1ae9b3d1 --- /dev/null +++ b/abstraction/src/test/java/me/gamercoder215/starcosmetics/util/TestStarSound.java @@ -0,0 +1,16 @@ +package me.gamercoder215.starcosmetics.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TestStarSound { + + @Test + @DisplayName("Test StarSound") + public void testStarSound() { + for (StarSound sound : StarSound.values()) + Assertions.assertTrue(sound.sounds.size() > 0); + } + +} diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/CompletionCriteria.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/CompletionCriteria.java index fd67c449..99f2cb50 100644 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/CompletionCriteria.java +++ b/api/src/main/java/me/gamercoder215/starcosmetics/api/CompletionCriteria.java @@ -9,6 +9,7 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; import java.util.Arrays; import java.util.Collection; @@ -94,7 +95,8 @@ public String getDisplayMessage() { return String.format(StarConfig.getConfig().get(displayKey), displayArgs); } - private static String toPlural(String base) { + @VisibleForTesting + static String toPlural(String base) { String lower = base.toLowerCase(); String trimmed = base.substring(0, base.length() - 1); diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/StarConfig.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/StarConfig.java index 29628bf4..4277a047 100644 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/StarConfig.java +++ b/api/src/main/java/me/gamercoder215/starcosmetics/api/StarConfig.java @@ -3,6 +3,7 @@ import com.google.common.collect.Iterables; import me.gamercoder215.starcosmetics.api.cosmetics.CosmeticLocation; import me.gamercoder215.starcosmetics.api.cosmetics.CosmeticRegistry; +import me.gamercoder215.starcosmetics.api.cosmetics.structure.Structure; import me.gamercoder215.starcosmetics.api.cosmetics.structure.StructureReader; import me.gamercoder215.starcosmetics.api.player.SoundEventSelection; import org.bukkit.Bukkit; @@ -53,8 +54,6 @@ static void updateCache() { */ @NotNull static StarConfig getConfig() { - if (Bukkit.getServer() == null) return new TestStarConfig(); // Using Test Implementation - return (StarConfig) getPlugin(); } @@ -151,6 +150,8 @@ static FileConfiguration loadConfig() { if (hologramLimit < 5 || hologramLimit > getConfig().getInternalMaxHologramLimit()) config.set("cosmetics.max-hologram-size", getConfig().getInternalMaxHologramLimit()); + if (!config.isList("cosmetics.structures")) config.set("cosmetics.structures", new ArrayList<>()); + try { config.save(getConfigurationFile()); } catch (IOException e) { @@ -216,6 +217,13 @@ static CosmeticRegistry getRegistry() { @NotNull String getLanguage(); + /** + * Sets the current Language. + * @param language Language ID to set + */ + @NotNull + void setLanguage(@NotNull String language); + /** * Fetches the locale based on {@link #getLanguage()}. * @return Language Locale @@ -496,4 +504,11 @@ default boolean isBlacklisted(@Nullable Sound sound) { */ void setMaxHologramLimit(int limit); + /** + * Fetches all of the custom structures found in config.yml. + * @return Set of Custom Structures + */ + @NotNull + Set getCustomStructures(); + } diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/TestStarConfig.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/TestStarConfig.java deleted file mode 100644 index e346acb0..00000000 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/TestStarConfig.java +++ /dev/null @@ -1,120 +0,0 @@ -package me.gamercoder215.starcosmetics.api; - -import me.gamercoder215.starcosmetics.api.cosmetics.CosmeticLocation; -import me.gamercoder215.starcosmetics.api.cosmetics.structure.StructureReader; -import org.bukkit.OfflinePlayer; -import org.bukkit.Sound; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.InputStream; -import java.io.Reader; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -final class TestStarConfig implements StarConfig { - - @Override - public @NotNull String getLanguage() { - return "en"; - } - - @Override - public @NotNull String get(String key) { - return ""; - } - - @Override - public void updatePluginCache() { - } - - @Override - public long getEntityDisappearTime() { - return 4; - } - - @Override - public void setEntityDisappearTime(long time) throws IllegalArgumentException { - } - - @Override - public long getItemDisappearTime() { - return 10; - } - - @Override - public void setItemDisappearTime(long time) throws IllegalArgumentException { - } - - @Override - public long getBlockDisappearTime() { - return 15; - } - - @Override - public void setBlockDisappearTime(long time) throws IllegalArgumentException {} - - @Override - public StructureReader getStructureReader(@NotNull File file) { - return null; - } - - @Override - public StructureReader getStructureReader(@NotNull InputStream stream) { - return null; - } - - @Override - public StructureReader getStructureReader(@NotNull Reader reader) { - return null; - } - - @Override - public @NotNull Set> getDisabledCosmetics() { return null; } - - @Override - public boolean isAmbientPetSoundEnabled() { return true; } - - @Override - public void setAmbientPetSoundEnabled(boolean enabled) {} - - @Override - public double getRequirementMultiplier() { return 0; } - - @Override - public double getRequirementMultiplier(@Nullable CosmeticLocation loc) { return 0;} - - @Override - public void setRequirementMultiplier(double multiplier) {} - - @Override - public void setRequirementMultiplier(@Nullable CosmeticLocation loc, double multiplier) {} - - @Override - public @NotNull List getBlacklistedPlayers() { return new ArrayList<>(); } - - @Override - public void setBlacklistedPlayers(@NotNull Iterable players) {} - - @Override - public @NotNull Set getBlacklistedSounds() { return new HashSet<>(); } - - @Override - public void setBlacklistedSounds(@NotNull Iterable sounds) {} - - @Override - public @NotNull Set> getCustomCosmetics() { return new HashSet<>(); } - - @Override - public int getInternalMaxHologramLimit() { return 48; } - - @Override - public int getMaxHologramLimit() { return 0; } - - @Override - public void setMaxHologramLimit(int limit) {} - -} diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/Structure.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/Structure.java index ed311c06..acd12c30 100644 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/Structure.java +++ b/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/Structure.java @@ -119,6 +119,7 @@ public String toString() { return "Structure{" + "minVersion='" + minVersion + '\'' + ", key='" + key + '\'' + + ", name='" + getLocalizedName() + '\'' + '}'; } } diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/StructureReader.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/StructureReader.java index b51218f6..0f11dd7e 100644 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/StructureReader.java +++ b/api/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/StructureReader.java @@ -24,6 +24,7 @@ public interface StructureReader extends Closeable { */ static boolean isCompatible(String minVersion) { if (minVersion.equalsIgnoreCase("ALL")) return true; + if (Bukkit.getServer() == null) return false; String currentV = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1); diff --git a/api/src/main/java/me/gamercoder215/starcosmetics/api/player/SoundEventSelection.java b/api/src/main/java/me/gamercoder215/starcosmetics/api/player/SoundEventSelection.java index 4bcc0d28..0592b3a9 100644 --- a/api/src/main/java/me/gamercoder215/starcosmetics/api/player/SoundEventSelection.java +++ b/api/src/main/java/me/gamercoder215/starcosmetics/api/player/SoundEventSelection.java @@ -1,5 +1,6 @@ package me.gamercoder215.starcosmetics.api.player; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import me.gamercoder215.starcosmetics.api.StarConfig; import org.bukkit.Location; @@ -19,7 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -86,30 +90,31 @@ public static boolean isValid(@NotNull Class event) { } static { - AVAILABLE_EVENTS = new ArrayList>(){{ - add(BlockBreakEvent.class); - add(BlockPlaceEvent.class); - add(FurnaceExtractEvent.class); - add(InventoryOpenEvent.class); - add(optional("player.PlayerAdvancementDoneEvent")); - add(PlayerBedEnterEvent.class); - add(PlayerChangedWorldEvent.class); - add(PlayerDeathEvent.class); - add(PlayerEditBookEvent.class); - add(PlayerEggThrowEvent.class); - add(PlayerExpChangeEvent.class); - add(PlayerFishEvent.class); - add(PlayerJoinEvent.class); - add(PlayerItemBreakEvent.class); - add(PlayerItemConsumeEvent.class); - add(PlayerRespawnEvent.class); - add(optional("player.PlayerRiptideEvent")); - add(optional("player.PlayerItemMendEvent")); - add(PlayerGameModeChangeEvent.class); - add(SheepDyeWoolEvent.class); - add(SignChangeEvent.class); - add(PlayerInteractEntityEvent.class); - }}.stream().filter(Objects::nonNull).collect(Collectors.toList()); + AVAILABLE_EVENTS = ImmutableList.copyOf(ImmutableList.>builder() + .add(BlockBreakEvent.class) + .add(BlockPlaceEvent.class) + .add(FurnaceExtractEvent.class) + .add(InventoryOpenEvent.class) + .add(optional("player.PlayerAdvancementDoneEvent")) + .add(PlayerBedEnterEvent.class) + .add(PlayerChangedWorldEvent.class) + .add(PlayerDeathEvent.class) + .add(PlayerEditBookEvent.class) + .add(PlayerEggThrowEvent.class) + .add(PlayerExpChangeEvent.class) + .add(PlayerFishEvent.class) + .add(PlayerJoinEvent.class) + .add(PlayerItemBreakEvent.class) + .add(PlayerItemConsumeEvent.class) + .add(PlayerRespawnEvent.class) + .add(optional("player.PlayerRiptideEvent")) + .add(optional("player.PlayerItemMendEvent")) + .add(PlayerGameModeChangeEvent.class) + .add(SheepDyeWoolEvent.class) + .add(SignChangeEvent.class) + .add(PlayerInteractEntityEvent.class) + .build() + .stream().filter(Objects::nonNull).collect(Collectors.toList())); } private static Class optional(String name) { diff --git a/api/src/main/resources/lang/starcosmetics.properties b/api/src/main/resources/lang/starcosmetics.properties index 99733293..4ec063ab 100644 --- a/api/src/main/resources/lang/starcosmetics.properties +++ b/api/src/main/resources/lang/starcosmetics.properties @@ -177,6 +177,8 @@ menu.cosmetics.hologram.none=No Hologram Set... menu.cosmetics.hologram.set=Set Hologram Message menu.cosmetics.hologram.reset=Reset Hologram Message settings.hologram_format=Hologram Format +cosmetics.hat.miner_pot_animated=Animated Miner Pot +criteria.amount.player_kills=Kill %s Players diff --git a/api/src/main/resources/lang/starcosmetics_de.properties b/api/src/main/resources/lang/starcosmetics_de.properties index 6fd4d00a..445a12e7 100644 --- a/api/src/main/resources/lang/starcosmetics_de.properties +++ b/api/src/main/resources/lang/starcosmetics_de.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=Kein Hologramm-Set... menu.cosmetics.hologram.set=Hologramm-Nachricht Festlegen menu.cosmetics.hologram.reset=Hologramm-Nachricht Zur\u00FCcksetzen settings.hologram_format=Hologrammformat +cosmetics.hat.miner_pot_animated=Animierter Miner Pot +criteria.amount.player_kills=T\u00F6te %s Spieler diff --git a/api/src/main/resources/lang/starcosmetics_es.properties b/api/src/main/resources/lang/starcosmetics_es.properties index b0ca0a60..0a77b5b8 100644 --- a/api/src/main/resources/lang/starcosmetics_es.properties +++ b/api/src/main/resources/lang/starcosmetics_es.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=Sin conjunto de hologramas... menu.cosmetics.hologram.set=Establecer mensaje de Holograma menu.cosmetics.hologram.reset=Restablecer mensaje de Holograma settings.hologram_format=Formato de Holograma +cosmetics.hat.miner_pot_animated=Olla Minera Animada +criteria.amount.player_kills=Mata a %s jugadores diff --git a/api/src/main/resources/lang/starcosmetics_fr.properties b/api/src/main/resources/lang/starcosmetics_fr.properties index fa841bb7..87715068 100644 --- a/api/src/main/resources/lang/starcosmetics_fr.properties +++ b/api/src/main/resources/lang/starcosmetics_fr.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=Pas d'ensemble d'hologrammes... menu.cosmetics.hologram.set=D\u00E9finir le message de L'hologramme menu.cosmetics.hologram.reset=R\u00E9initialiser le message de L'hologramme settings.hologram_format=Format D'Hologramme +cosmetics.hat.miner_pot_animated=Pot de Mineur Anim\u00E9 +criteria.amount.player_kills=Tuer %s Joueurs diff --git a/api/src/main/resources/lang/starcosmetics_it.properties b/api/src/main/resources/lang/starcosmetics_it.properties index 09bb14a6..9ee599e8 100644 --- a/api/src/main/resources/lang/starcosmetics_it.properties +++ b/api/src/main/resources/lang/starcosmetics_it.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=Nessun set di ologrammi... menu.cosmetics.hologram.set=Imposta il Messaggio Dell'Ologramma menu.cosmetics.hologram.reset=Reimposta il Messaggio Dell'ologramma settings.hologram_format=Formato Ologramma +cosmetics.hat.miner_pot_animated=La Pentola del Minatore Animata +criteria.amount.player_kills=Uccidi %s Giocatori diff --git a/api/src/main/resources/lang/starcosmetics_ja.properties b/api/src/main/resources/lang/starcosmetics_ja.properties index 0e43f565..54d5178c 100644 --- a/api/src/main/resources/lang/starcosmetics_ja.properties +++ b/api/src/main/resources/lang/starcosmetics_ja.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=\u30DB\u30ED\u30B0\u30E9\u30E0\u304C\u8A2D\u5B9A\u3 menu.cosmetics.hologram.set=\u30DB\u30ED\u30B0\u30E9\u30E0\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u8A2D\u5B9A\u3059\u308B menu.cosmetics.hologram.reset=\u30DB\u30ED\u30B0\u30E9\u30E0\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30EA\u30BB\u30C3\u30C8 settings.hologram_format=\u30DB\u30ED\u30B0\u30E9\u30E0\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8 +cosmetics.hat.miner_pot_animated=\u30A2\u30CB\u30E1\u30FC\u30B7\u30E7\u30F3\u306E\u30DE\u30A4\u30CA\u30FC\u30BA\u30DD\u30C3\u30C8 +criteria.amount.player_kills=%s \u30D7\u30EC\u30A4\u30E4\u30FC\u3092\u30AD\u30EB\u3059\u308B diff --git a/api/src/main/resources/lang/starcosmetics_pt.properties b/api/src/main/resources/lang/starcosmetics_pt.properties index 1a96d8ca..00974933 100644 --- a/api/src/main/resources/lang/starcosmetics_pt.properties +++ b/api/src/main/resources/lang/starcosmetics_pt.properties @@ -176,6 +176,8 @@ menu.cosmetics.hologram.none=Sem conjunto de Holograma... menu.cosmetics.hologram.set=Definir mensagem de Holograma menu.cosmetics.hologram.reset=Redefinir Mensagem de Holograma settings.hologram_format=Formato Holograma +cosmetics.hat.miner_pot_animated=Pote do Mineiro Animado +criteria.amount.player_kills=Mate %s Jogadores diff --git a/api/src/main/resources/lang/starcosmetics_zh.properties b/api/src/main/resources/lang/starcosmetics_zh.properties index 8dcae78a..39c0726c 100644 --- a/api/src/main/resources/lang/starcosmetics_zh.properties +++ b/api/src/main/resources/lang/starcosmetics_zh.properties @@ -176,5 +176,7 @@ menu.cosmetics.hologram.none=\u6CA1\u6709\u5168\u606F\u56FE\u96C6... menu.cosmetics.hologram.set=\u8BBE\u7F6E\u5168\u606F\u56FE\u6D88\u606F menu.cosmetics.hologram.reset=\u91CD\u7F6E\u5168\u606F\u56FE\u6D88\u606F settings.hologram_format=\u5168\u606F\u56FE\u683C\u5F0F +cosmetics.hat.miner_pot_animated=\u52A8\u753B\u77FF\u5DE5\u7684\u9505 +criteria.amount.player_kills=\u6740\u6B7B %s \u540D\u73A9\u5BB6 diff --git a/api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/TestCompletionCriteria.java b/api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/TestCompletionCriteria.java deleted file mode 100644 index 279fa368..00000000 --- a/api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/TestCompletionCriteria.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.gamercoder215.starcosmetics.api.cosmetics; - -import me.gamercoder215.starcosmetics.api.CompletionCriteria; -import me.gamercoder215.starcosmetics.api.player.PlayerCompletion; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -public class TestCompletionCriteria { - - @Test - @DisplayName("Test Basic Criteria") - public void testBasicCriteria() { - CompletionCriteria criteria = CompletionCriteria.fromCompletion(PlayerCompletion.NETHER_ROOF); - Assertions.assertNotNull(criteria); - Assertions.assertNotNull(criteria.getDisplayMessage()); - } - -} diff --git a/build.gradle.kts b/build.gradle.kts index 473d8d64..1d01adf3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ plugins { } val pGroup = "me.gamercoder215.starcosmetics" -val pVersion = "1.2.1" +val pVersion = "1.2.2" val pAuthor = "GamerCoder215" sonarqube { @@ -125,9 +125,11 @@ subprojects { dependsOn(test) reports { - xml.required.set(false) csv.required.set(false) + xml.required.set(true) // SonarCloud + xml.outputLocation.set(layout.buildDirectory.file("jacoco/jacoco.xml")); + html.required.set(true) html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) } diff --git a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructure.java b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructure.java index b69de400..eeb92ee5 100644 --- a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructure.java +++ b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructure.java @@ -1,5 +1,6 @@ package me.gamercoder215.starcosmetics.api.cosmetics.structure; +import com.google.common.collect.ImmutableMap; import me.gamercoder215.starcosmetics.api.Rarity; import me.gamercoder215.starcosmetics.util.StarRunnable; import org.bukkit.Bukkit; @@ -28,12 +29,16 @@ final class ModernStructure extends Structure { this.rarity = rarity == null ? Rarity.COMMON : rarity; this.points = points; - this.pointData = pointData.entrySet() - .stream() - .filter(Objects::nonNull) - .filter(e -> e.getValue() != null && !e.getValue().isEmpty()) - .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), Bukkit.createBlockData(e.getValue()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + if (Bukkit.getServer() != null) + this.pointData = pointData.entrySet() + .stream() + .filter(Objects::nonNull) + .filter(e -> e.getValue() != null && !e.getValue().isEmpty()) + .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), Bukkit.createBlockData(e.getValue()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + else + this.pointData = ImmutableMap.of(); } diff --git a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructureReader.java b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructureReader.java index 09c3a2fd..33b01d9f 100644 --- a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructureReader.java +++ b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/ModernStructureReader.java @@ -45,17 +45,21 @@ public Structure read() { int i = index.get(); switch (i) { - case 0: minVersion = line; index.incrementAndGet(); continue; + case 0: { + minVersion = line; + if (!StructureReader.isCompatible(minVersion)) { + close(); + return null; + } + + index.incrementAndGet(); + continue; + } case 1: key = line.substring(line.indexOf(":") + 1, line.lastIndexOf(":")); index.incrementAndGet(); continue; case 2: displayKey = line; index.incrementAndGet(); continue; case 3: rarity = Rarity.valueOf(line.toUpperCase()); index.incrementAndGet(); continue; } - if (!StructureReader.isCompatible(minVersion)) { - close(); - return null; - } - if (i == 4 && !line.equalsIgnoreCase("---")) throw new MalformedStructureException("Malformed Strucutre File: Expected '---' but got '" + line + "'"); if (i > 4) { @@ -68,14 +72,15 @@ public Structure read() { String[] entries = material.split(","); for (String entry : entries) { - String[] split = entry.split("="); + String[] split = entry.split("=", 2); + String value = split[1].replaceAll("[{}]", ""); int chance = Integer.parseInt(split[0].replaceAll("[%{}]", "")); amount += chance; - if (split[1].contains("[") && split[1].endsWith("]")) { - String mat = split[1].split("\\[")[0]; - String data = "[" + split[1].split("\\[")[1]; + if (value.contains("[") && value.endsWith("]")) { + String mat = value.split("\\[")[0]; + String data = "[" + value.split("\\[")[1].toLowerCase(); Material m; @@ -92,7 +97,7 @@ public Structure read() { chances.put(m, chance); blockDataChances.put(m, data); } else { - String mat = split[1].replace("}", "").toUpperCase(); + String mat = value.toUpperCase(); Material m; @@ -131,7 +136,7 @@ public Structure read() { String data = null; if (material.contains("[") && material.endsWith("]")) { mat = material.split("\\[")[0].toUpperCase(); - data = "[" + material.split("\\[")[1]; + data = "[" + material.split("\\[")[1].toLowerCase(); } Material m; diff --git a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_13.java b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_13.java index 364090bb..2d802c07 100644 --- a/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_13.java +++ b/nms/1_13_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_13.java @@ -11,6 +11,7 @@ import me.gamercoder215.starcosmetics.util.StarMaterial; import me.gamercoder215.starcosmetics.util.StarSound; import me.gamercoder215.starcosmetics.util.selection.CosmeticSelection; +import me.gamercoder215.starcosmetics.util.selection.GadgetSelection; import me.gamercoder215.starcosmetics.util.selection.HatSelection; import me.gamercoder215.starcosmetics.util.selection.ParticleSelection; import me.gamercoder215.starcosmetics.util.selection.TrailSelection; @@ -231,6 +232,12 @@ final class CosmeticSelections1_13 implements CosmeticSelections { ), fromMined(100000, Material.SAND), LEGENDARY)) .build(); + // Gadgets + + private static final List> GADGETS = ImmutableList.>builder() + .add(new GadgetSelection("raygun", Material.LAPIS_LAZULI, loc -> line(loc, Particle.WATER_BUBBLE, 3, 5), fromStatistic(Statistic.PLAYER_KILLS, 200), UNCOMMON)) + .build(); + // Selections private static final Map>> SELECTIONS = ImmutableMap.>>builder() @@ -243,7 +250,7 @@ final class CosmeticSelections1_13 implements CosmeticSelections { .put(NORMAL, join(NORMAL_HATS, NORMAL, "1_12")) .put(ANIMATED, join(ANIMATED_HATS, ANIMATED, "1_12")) - .put(BaseGadget.INSTANCE, getForVersion(BaseGadget.INSTANCE, "1_12")) + .put(BaseGadget.INSTANCE, join(GADGETS, BaseGadget.INSTANCE, "1_12")) .build(); @Override diff --git a/nms/1_20_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_20.java b/nms/1_20_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_20.java index 97ecf218..ad718147 100644 --- a/nms/1_20_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_20.java +++ b/nms/1_20_R1/src/main/java/me/gamercoder215/starcosmetics/wrapper/cosmetics/CosmeticSelections1_20.java @@ -26,6 +26,9 @@ final class CosmeticSelections1_20 implements CosmeticSelections { // Projectile Trails private static final List> PROJECTILE_TRAIL = ImmutableList.>builder() + .add(new TrailSelection("bamboo_planks", BaseTrail.PROJECTILE_TRAIL, Material.BAMBOO_PLANKS, + fromMined(200, Material.BAMBOO), OCCASIONAL)) + .add(new TrailSelection("relic", BaseTrail.PROJECTILE_TRAIL, Material.MUSIC_DISC_RELIC, fromStatistic(Statistic.ANIMALS_BRED, 5500), EPIC)) .build(); @@ -35,6 +38,9 @@ final class CosmeticSelections1_20 implements CosmeticSelections { private static final List> GROUND_TRAIL = ImmutableList.>builder() .add(new TrailSelection("pink_petals", BaseTrail.GROUND_TRAIL, Material.PINK_PETALS, fromMined(100, Material.CHERRY_SAPLING), OCCASIONAL)) + + .add(new TrailSelection("cherry_pressure_plate", BaseTrail.GROUND_TRAIL, Material.CHERRY_PRESSURE_PLATE, + fromMined(120, Material.CHERRY_LOG), UNCOMMON)) .build(); // Hats @@ -62,6 +68,8 @@ private static ItemStack decoratedPot(Material... materials) { fromCrafted(50, Material.DECORATED_POT), UNCOMMON)) .add(new HatSelection("heart_pot", decoratedPot(Material.HEART_POTTERY_SHERD), fromStatistic(Statistic.ANIMALS_BRED, 200), UNCOMMON)) + .add(new HatSelection("tree_pot", decoratedPot(Material.SHELTER_POTTERY_SHERD), + fromMined(80, Material.OAK_LOG), UNCOMMON)) .add(new HatSelection("mourner_pot", decoratedPot(Material.MOURNER_POTTERY_SHERD), fromKilled(1, EntityType.WARDEN), RARE)) @@ -79,6 +87,14 @@ private static ItemStack decoratedPot(Material... materials) { fromKilled(100, EntityType.PIGLIN_BRUTE), LEGENDARY)) .build(); + // Animated Hats + + private static final List> ANIMATED_HATS = ImmutableList.>builder() + .add(new HatSelection("miner_pot_animated", HatSelection.of(20, + decoratedPot(Material.MINER_POTTERY_SHERD), decoratedPot(Material.PRIZE_POTTERY_SHERD) + ), fromMined(15, Material.EMERALD_ORE), LEGENDARY)) + .build(); + // Selections private static final Map>> SELECTIONS = ImmutableMap.>>builder() @@ -89,7 +105,7 @@ private static ItemStack decoratedPot(Material... materials) { .put(BaseShape.ALL, getForVersion(BaseShape.ALL, "1_19_R3")) .put(BaseHat.NORMAL, join(NORMAL_HATS, BaseHat.NORMAL, "1_19_R3")) - .put(BaseHat.ANIMATED, getForVersion(BaseHat.ANIMATED, "1_19_R3")) + .put(BaseHat.ANIMATED, join(ANIMATED_HATS, BaseHat.ANIMATED, "1_19_R3")) .put(BaseGadget.INSTANCE, getForVersion(BaseGadget.INSTANCE, "1_19_R3")) .build(); diff --git a/nms/1_20_R2/build.gradle.kts b/nms/1_20_R2/build.gradle.kts new file mode 100644 index 00000000..2020d85a --- /dev/null +++ b/nms/1_20_R2/build.gradle.kts @@ -0,0 +1,39 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import io.github.patrick.gradle.remapper.RemapTask + +plugins { + id("io.github.patrick.remapper") version "1.4.0" +} + +val mcVersion = "1.20.2" + +dependencies { + api(project(":starcosmetics-abstraction")) + api(project(":starcosmetics-api")) + + compileOnly("org.spigotmc:spigot:$mcVersion-R0.1-SNAPSHOT:remapped-mojang") +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +tasks { + assemble { + dependsOn("remap") + } + + jar.configure { + enabled = false + } + + remap { + dependsOn("shadowJar") + + inputTask.set(getByName("shadowJar")) + version.set(mcVersion) + action.set(RemapTask.Action.MOJANG_TO_SPIGOT) + archiveName.set("${project.name}-${project.version}.jar") + } +} \ No newline at end of file diff --git a/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/NBTWrapper1_20_R2.java b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/NBTWrapper1_20_R2.java new file mode 100644 index 00000000..9cd65452 --- /dev/null +++ b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/NBTWrapper1_20_R2.java @@ -0,0 +1,217 @@ +package me.gamercoder215.starcosmetics.wrapper.v1_20_R2; + +import me.gamercoder215.starcosmetics.api.StarConfig; +import me.gamercoder215.starcosmetics.api.player.SoundEventSelection; +import me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.event.Event; + +import java.util.Date; +import java.util.UUID; + +final class NBTWrapper1_20_R2 extends NBTWrapper { + + NBTWrapper1_20_R2(org.bukkit.inventory.ItemStack item) { + super(item); + } + + @Override + public String getString(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getString(key); + } + + @Override + public void set(String key, String value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putString(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public boolean getBoolean(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getBoolean(key); + } + + @Override + public void set(String key, boolean value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putBoolean(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public int getInt(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getInt(key); + } + + @Override + public void set(String key, int value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putInt(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public double getDouble(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getDouble(key); + } + + @Override + public void set(String key, double value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putDouble(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public UUID getUUID(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getUUID(key); + } + + @Override + public void set(String key, UUID value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putUUID(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public Class getClass(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + try { + return Class.forName(new String(starcosmetics.getByteArray(key))); + } catch (ClassNotFoundException e) { + StarConfig.print(e); + return null; + } + } + + @Override + public void set(String key, Class clazz) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putByteArray(key, clazz.getName().getBytes()); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public void set(String key, SoundEventSelection value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + CompoundTag selection = new CompoundTag(); + selection.putString("sound", value.getSound().name()); + selection.putString("event", value.getEvent().getName()); + selection.putLong("timestamp", value.getTimestamp().getTime()); + selection.putUUID("player", value.getPlayer().getUniqueId()); + selection.putFloat("volume", value.getVolume()); + selection.putFloat("pitch", value.getPitch()); + + starcosmetics.put(key, selection); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public SoundEventSelection getSoundEventSelection(String key) { + try { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + CompoundTag selection = starcosmetics.getCompound(key); + + return SoundEventSelection.of( + Class.forName(selection.getString("event")).asSubclass(Event.class), + Sound.valueOf(selection.getString("sound")), + selection.getFloat("volume"), + selection.getFloat("pitch"), + Bukkit.getOfflinePlayer(selection.getUUID("player")), + new Date(selection.getLong("timestamp")) + ); + } catch (ClassNotFoundException | ClassCastException e) { + StarConfig.print(e); + return null; + } + } + + @Override + public void set(String key, float value) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + starcosmetics.putFloat(key, value); + tag.put(ROOT, starcosmetics); + nmsitem.setTag(tag); + this.item = CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public float getFloat(String key) { + ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag starcosmetics = tag.getCompound(ROOT); + + return starcosmetics.getFloat(key); + } + +} diff --git a/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/PacketHandler1_20_R2.java b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/PacketHandler1_20_R2.java new file mode 100644 index 00000000..e1358e67 --- /dev/null +++ b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/PacketHandler1_20_R2.java @@ -0,0 +1,40 @@ +package me.gamercoder215.starcosmetics.wrapper.v1_20_R2; + +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import me.gamercoder215.starcosmetics.util.StarRunnable; +import net.minecraft.network.protocol.Packet; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; + +final class PacketHandler1_20_R2 extends ChannelDuplexHandler { + + public static final Map>> PACKET_HANDLERS = new HashMap<>(); + + private final Player p; + + public PacketHandler1_20_R2(Player p) { + this.p = p; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object packetO) throws Exception { + if (!(packetO instanceof Packet packet)) { + super.channelRead(ctx, packetO); + return; + } + + Predicate> handler = PACKET_HANDLERS.get(p.getUniqueId()); + if (handler != null) StarRunnable.sync(() -> { + boolean success = handler.test(packet); + if (success) PACKET_HANDLERS.remove(p.getUniqueId()); + }); + + super.channelRead(ctx, packetO); + } + +} \ No newline at end of file diff --git a/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/StarInventory1_20_R2.java b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/StarInventory1_20_R2.java new file mode 100644 index 00000000..591f048a --- /dev/null +++ b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/StarInventory1_20_R2.java @@ -0,0 +1,42 @@ +package me.gamercoder215.starcosmetics.wrapper.v1_20_R2; + +import com.google.common.collect.ImmutableMap; +import me.gamercoder215.starcosmetics.util.inventory.StarInventory; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventoryCustom; + +import java.util.HashMap; +import java.util.Map; + +final class StarInventory1_20_R2 extends CraftInventoryCustom implements StarInventory { + + private final String key; + private final Map attributes = new HashMap<>(); + + StarInventory1_20_R2(String key, int size, String title) { + super(null, size, title); + this.key = key; + + setAttribute("_name", title); + } + + @Override + public String getKey() { + return this.key; + } + + @Override + public Map getAllAttributes() { + return ImmutableMap.copyOf(attributes); + } + + @Override + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + + @Override + public void removeAttribute(String key) { + attributes.remove(key); + } + +} diff --git a/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/Wrapper1_20_R2.java b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/Wrapper1_20_R2.java new file mode 100644 index 00000000..2bdb37ab --- /dev/null +++ b/nms/1_20_R2/src/main/java/me/gamercoder215/starcosmetics/wrapper/v1_20_R2/Wrapper1_20_R2.java @@ -0,0 +1,357 @@ +package me.gamercoder215.starcosmetics.wrapper.v1_20_R2; + +import com.mojang.authlib.GameProfile; +import io.netty.channel.Channel; +import me.gamercoder215.starcosmetics.api.StarConfig; +import me.gamercoder215.starcosmetics.util.StarRunnable; +import me.gamercoder215.starcosmetics.util.entity.StarSelector; +import me.gamercoder215.starcosmetics.util.inventory.StarInventory; +import me.gamercoder215.starcosmetics.wrapper.Wrapper; +import me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.flag.FeatureFlag; +import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.advancement.CraftAdvancement; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockEntityState; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftDecoratedPot; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collections; +import java.util.UUID; +import java.util.function.Consumer; + +final class Wrapper1_20_R2 implements Wrapper { + + @Override + public int getCommandVersion() { + return 2; + } + + @Override + public NBTWrapper getNBTWrapper(ItemStack item) { + return new NBTWrapper1_20_R2(item); + } + + @Override + public void sendActionbar(Player p, String message) { + p.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + } + + @Override + public void spawnFakeEntity(Player p, EntityType type, Location loc, long deathTicks) { + CraftWorld cw = (CraftWorld) loc.getWorld(); + ServerPlayer sp = ((CraftPlayer) p).getHandle(); + Entity nmsEntity = cw.createEntity(loc, type.getEntityClass()); + + ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(nmsEntity); + sp.connection.send(add); + + new BukkitRunnable() { + @Override + public void run() { + ClientboundRemoveEntitiesPacket remove = new ClientboundRemoveEntitiesPacket(nmsEntity.getId()); + sp.connection.send(remove); + } + }.runTaskLater(StarConfig.getPlugin(), deathTicks); + } + + @Override + public void spawnFakeItem(ItemStack item, Location loc, long deathTicks) { + ServerLevel sw = ((CraftWorld) loc.getWorld()).getHandle(); + ItemEntity nmsEntity = new ItemEntity(sw, loc.getX(), loc.getY(), loc.getZ(), CraftItemStack.asNMSCopy(item)); + nmsEntity.setNeverPickUp(); + sw.addFreshEntity(nmsEntity); + + StarRunnable.syncLater(nmsEntity::kill, deathTicks); + } + + private static ServerPlayer createPlayer(Location loc) { + try { + DedicatedServer srv = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel sw = ((CraftWorld) loc.getWorld()).getHandle(); + UUID uid = UUID.randomUUID(); + GameProfile profile = new GameProfile(uid, uid.toString().substring(0, 16)); + ClientInformation info = new ClientInformation("en", 0, ChatVisiblity.HIDDEN, false, 0, HumanoidArm.RIGHT, false, false); + + ServerPlayer sp = new ServerPlayer(srv, sw, profile, info); + sp.connection = new ServerGamePacketListenerImpl(srv, new Connection(PacketFlow.CLIENTBOUND), sp, new CommonListenerCookie(profile, 0, info)); + sp.setPos(loc.getX(), loc.getY(), loc.getZ()); + + for (Player p : loc.getWorld().getPlayers()) { + ServerPlayer sph = ((CraftPlayer) p).getHandle(); + sph.connection.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, sp)); + sph.connection.send(new ClientboundAddEntityPacket(sp)); + StarRunnable.asyncLater(() -> sph.connection.send(new ClientboundPlayerInfoRemovePacket(Collections.singletonList(uid))), + 1); + } + + return sp; + } catch (Exception e) { + StarConfig.print(e); + return null; + } + } + + @Override + public void attachRiptide(org.bukkit.entity.Entity en) { + ServerPlayer sp = createPlayer(en.getLocation()); + sp.setSilent(true); + sp.setInvulnerable(true); + sp.setNoGravity(true); + sp.setInvisible(true); + + SynchedEntityData dw = sp.getEntityData(); + dw.set(EntityDataSerializers.BYTE.createAccessor(8), (byte) 0x04); + + for (Player p : en.getWorld().getPlayers()) { + ServerPlayer sph = ((CraftPlayer) p).getHandle(); + sph.connection.send(new ClientboundSetEntityDataPacket(sp.getId(), dw.packDirty())); + } + + new BukkitRunnable() { + @Override + public void run() { + if (StarSelector.isStopped(en)) { + cancel(); + sp.remove(Entity.RemovalReason.DISCARDED); + + for (Player p : en.getWorld().getPlayers()) { + ServerPlayer sph = ((CraftPlayer) p).getHandle(); + sph.connection.send(new ClientboundRemoveEntitiesPacket(sp.getId())); + } + + return; + } + + Location l = en.getLocation().clone(); + + Vec3 pos = sp.position(); + Vector dir = l.toVector().subtract(new Location(en.getWorld(), pos.x, pos.y, pos.z).toVector()).normalize().multiply(-1); + + if (Double.isNaN(dir.getX())) dir.setX(0); + if (Double.isNaN(dir.getY())) dir.setY(0); + if (Double.isNaN(dir.getZ())) dir.setZ(0); + + l.setDirection(dir); + + sp.absMoveTo(l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch()); + sp.setYHeadRot(l.getYaw()); + + for (Player p : en.getWorld().getPlayers()) { + ServerPlayer sph = ((CraftPlayer) p).getHandle(); + sph.connection.send(new ClientboundTeleportEntityPacket(sp)); + } + } + }.runTaskTimer(StarConfig.getPlugin(), 0, 2); + } + + @Override + public void setRotation(org.bukkit.entity.Entity en, float yaw, float pitch) { + en.setRotation(yaw, pitch); + } + + @Override + public String getKey(Sound s) { + return s.getKey().getKey(); + } + + @Override + public void stopSound(Player p) { + p.stopAllSounds(); + } + + @Override + public void sendBlockChange(Player p, Location loc, Material m, BlockState data) { + ServerPlayer sp = ((CraftPlayer) p).getHandle(); + BlockPos pos = new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + + if (data == null) { + p.sendBlockChange(loc, m.createBlockData()); + return; + } + + net.minecraft.world.level.block.state.BlockState nmsState = ((CraftBlockState) data).getHandle(); + ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(pos, nmsState); + sp.connection.send(packet); + } + + @Override + public boolean isItem(Material m) { + if (m == Material.AIR) return false; + return m.isItem(); + } + + @Override + public StarInventory createInventory(String key, int size, String title) { + return new StarInventory1_20_R2(key, size, title); + } + + @Override + public String getAdvancementDescription(String s) { + CraftAdvancement ca = (CraftAdvancement) Bukkit.getAdvancement(NamespacedKey.minecraft(s)); + return ca.getDisplay().getDescription(); + } + + @Override + public boolean hasFeatureFlag(String flag) { + try { + Field flagF = FeatureFlags.class.getDeclaredField(flag); + if (!Modifier.isStatic(flagF.getModifiers())) return false; + flagF.setAccessible(true); + + return FeatureFlags.REGISTRY.allFlags().contains((FeatureFlag) flagF.get(null)); + } catch (ReflectiveOperationException e) { + StarConfig.print(e); + return false; + } + } + + @Override + public ItemStack cleanSkull(ItemStack item) { + net.minecraft.world.item.ItemStack nmsitem = CraftItemStack.asNMSCopy(item); + CompoundTag tag = nmsitem.getOrCreateTag(); + CompoundTag skullOwner = tag.getCompound("SkullOwner"); + + skullOwner.remove("Id"); + skullOwner.remove("Properties"); + tag.put("SkullOwner", skullOwner); + nmsitem.setTag(tag); + return CraftItemStack.asBukkitCopy(nmsitem); + } + + @Override + public ItemStack createDecoratedPot(Material[] sherds) { + try { + ItemStack pot = new ItemStack(Material.DECORATED_POT); + if (Arrays.stream(sherds).allMatch(m -> m == Material.BRICK)) return pot; + + BlockStateMeta meta = (BlockStateMeta) pot.getItemMeta(); + + CraftDecoratedPot dp = (CraftDecoratedPot) meta.getBlockState(); + Item[] nms = Arrays.stream(sherds).map(CraftMagicNumbers::getItem).toArray(Item[]::new); + + Method snapshot = CraftBlockEntityState.class.getDeclaredMethod("getSnapshot"); + snapshot.setAccessible(true); + DecoratedPotBlockEntity b = (DecoratedPotBlockEntity) snapshot.invoke(dp); + b.decorations = new DecoratedPotBlockEntity.Decorations(nms[0], nms[1], nms[2], nms[3]); + + meta.setBlockState(dp); + pot.setItemMeta(meta); + return pot; + } catch (ReflectiveOperationException e) { + StarConfig.print(e); + } + + return null; + } + + @Override + public void addPacketInjector(Player p) { + ServerPlayer sp = ((CraftPlayer) p).getHandle(); + + try { + Field connection = ServerGamePacketListenerImpl.class.getDeclaredField("h"); + connection.setAccessible(true); + Channel ch = ((Connection) connection.get(sp.connection)).channel; + + if (ch.pipeline().get(PACKET_INJECTOR_ID) != null) return; + ch.pipeline().addAfter("decoder", PACKET_INJECTOR_ID, new PacketHandler1_20_R2(p)); + } catch (ReflectiveOperationException e) { + StarConfig.print(e); + } + } + + @Override + public void removePacketInjector(Player p) { + ServerPlayer sp = ((CraftPlayer) p).getHandle(); + + try { + Field connection = ServerGamePacketListenerImpl.class.getDeclaredField("h"); + connection.setAccessible(true); + Channel ch = ((Connection) connection.get(sp.connection)).channel; + + if (ch.pipeline().get(PACKET_INJECTOR_ID) == null) return; + ch.pipeline().remove(PACKET_INJECTOR_ID); + } catch (ReflectiveOperationException e) { + StarConfig.print(e); + } + } + + @Override + public void sendSign(Player p, Consumer lines) { + addPacketInjector(p); + + Location l = p.getLocation(); + BlockPos pos = new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + net.minecraft.world.level.block.state.BlockState old = ((CraftWorld) l.getWorld()).getHandle().getBlockState(pos); + + ClientboundBlockUpdatePacket sent1 = new ClientboundBlockUpdatePacket(pos, Blocks.OAK_SIGN.defaultBlockState()); + ((CraftPlayer) p).getHandle().connection.send(sent1); + + ClientboundOpenSignEditorPacket sent2 = new ClientboundOpenSignEditorPacket(pos, true); + ((CraftPlayer) p).getHandle().connection.send(sent2); + + PacketHandler1_20_R2.PACKET_HANDLERS.put(p.getUniqueId(), packetO -> { + if (!(packetO instanceof ServerboundSignUpdatePacket packet)) return false; + + ClientboundBlockUpdatePacket sent3 = new ClientboundBlockUpdatePacket(pos, old); + ((CraftPlayer) p).getHandle().connection.send(sent3); + + lines.accept(packet.getLines()); + return true; + }); + } + +} + diff --git a/nms/1_9_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/LegacyStructureReader.java b/nms/1_9_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/LegacyStructureReader.java index 5e57169b..837f6763 100644 --- a/nms/1_9_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/LegacyStructureReader.java +++ b/nms/1_9_R1/src/main/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/LegacyStructureReader.java @@ -39,17 +39,21 @@ public Structure read() { int i = index.get(); switch (i) { - case 0: minVersion = line; index.incrementAndGet(); continue; + case 0: { + minVersion = line; + if (!StructureReader.isCompatible(minVersion)) { + close(); + return null; + } + + index.incrementAndGet(); + continue; + } case 1: key = line.substring(line.indexOf(":") + 1, line.lastIndexOf(":")); index.incrementAndGet(); continue; case 2: displayKey = line; index.incrementAndGet(); continue; case 3: rarity = Rarity.valueOf(line.toUpperCase()); index.incrementAndGet(); continue; } - if (!StructureReader.isCompatible(minVersion)) { - close(); - return null; - } - if (i == 4 && !line.equalsIgnoreCase("---")) throw new MalformedStructureException("Malformed Strucutre File: Expected '---' but got '" + line + "'"); if (i > 4) { @@ -61,7 +65,7 @@ public Structure read() { String[] entries = material.split(","); for (String entry : entries) { - String[] split = entry.split("="); + String[] split = entry.split("=", 2); int chance = Integer.parseInt(split[0].replaceAll("[%{}]", "")); amount += chance; @@ -120,10 +124,10 @@ public Structure read() { close(); return new LegacyStructure(key, minVersion, displayKey, points, rarity); } catch (IOException e) { - StarConfig.print(e); + throw new RuntimeException(e); } - return null; +// return null; } @Override diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 11b30eba..ae5ef49d 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -5,6 +5,11 @@ dependencies { strictly("1.9-R0.1-SNAPSHOT") } } + testImplementation("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") { + version { + strictly("1.20.2-R0.1-SNAPSHOT") + } + } // Implementation Dependencies implementation("org.bstats:bstats-bukkit:3.0.2") @@ -35,7 +40,8 @@ dependencies { "1_19_R1", "1_19_R2", "1_19_R3", - "1_20_R1" + "1_20_R1", + "1_20_R2" ).forEach { api(project(":starcosmetics-$it")) } } @@ -49,6 +55,7 @@ tasks { "1_19_R2", "1_19_R3", "1_20_R1", + "1_20_R2" ).forEach { dependsOn(project(":starcosmetics-$it").tasks["remap"]) } } diff --git a/plugin/src/main/java/me/gamercoder215/starcosmetics/StarCosmetics.java b/plugin/src/main/java/me/gamercoder215/starcosmetics/StarCosmetics.java index b0a11bf7..86dce26e 100644 --- a/plugin/src/main/java/me/gamercoder215/starcosmetics/StarCosmetics.java +++ b/plugin/src/main/java/me/gamercoder215/starcosmetics/StarCosmetics.java @@ -51,10 +51,13 @@ import org.bukkit.event.player.PlayerStatisticIncrementEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; import java.io.*; import java.lang.reflect.Constructor; @@ -82,6 +85,15 @@ public final class StarCosmetics extends JavaPlugin implements StarConfig, Cosme private static final Gson GSON = new Gson(); + public StarCosmetics() { + super(); + } + + @VisibleForTesting + StarCosmetics(@NotNull final JavaPluginLoader loader, @NotNull final PluginDescriptionFile description, @NotNull final File dataFolder, @NotNull final File file) { + super(loader, description, dataFolder, file); + } + private boolean checkCompatible() { if (!Wrapper.isCompatible()) { getLogger().severe("StarCosmetics is not compatible with: " + Bukkit.getBukkitVersion() + " (Expected Wrapper" + Wrapper.getServerVersion() + ")"); @@ -107,7 +119,8 @@ private void registerEvents() { w.registerEvents(); } - private static FileConfiguration config; + @VisibleForTesting + static FileConfiguration config; private static FileConfiguration cosmeticsFile; private static final List> SERIALIZABLE = ImmutableList.>builder() @@ -215,6 +228,12 @@ public String getLanguage() { return config.getString("language", "en"); } + @Override + public void setLanguage(String lang) { + config.set("language", lang); + saveConfig(); + } + @Override public String get(String key) { Properties p = new Properties(); @@ -241,6 +260,7 @@ private void loadPlaceholders() { @Override public void updatePluginCache() { STAR_PLAYER_CACHE.clear(); + STRUCTURE_CACHE.clear(); } @Override @@ -425,6 +445,24 @@ public void setMaxHologramLimit(int limit) { saveConfig(); } + @Override + public @NotNull Set getCustomStructures() { + List files = config.getStringList("cosmetics.structures"); + if (files.isEmpty()) return ImmutableSet.of(); + + Set structures = new HashSet<>(); + + for (String file : files) { + File f = new File(getDataFolder(), file); + StructureReader r = getStructureReader(f); + if (r == null) continue; + + structures.add(r.read()); + } + + return ImmutableSet.copyOf(structures); + } + // Other Utilities private static OfflinePlayer getPlayer(String name) { @@ -712,6 +750,8 @@ public Cosmetic getByNamespace(@NotNull String key) { } } catch (IOException e) { StarConfig.print(e); } + set.addAll(getCustomStructures()); + STRUCTURE_CACHE.addAll(set.stream() .map(Structure::getInfo) .collect(Collectors.toSet())); diff --git a/plugin/src/main/java/me/gamercoder215/starcosmetics/events/ClickEvents.java b/plugin/src/main/java/me/gamercoder215/starcosmetics/events/ClickEvents.java index f38f7eef..6a129a75 100644 --- a/plugin/src/main/java/me/gamercoder215/starcosmetics/events/ClickEvents.java +++ b/plugin/src/main/java/me/gamercoder215/starcosmetics/events/ClickEvents.java @@ -58,6 +58,7 @@ import static me.gamercoder215.starcosmetics.util.Constants.w; import static me.gamercoder215.starcosmetics.util.Generator.cw; import static me.gamercoder215.starcosmetics.wrapper.Wrapper.*; +import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.builder; import static me.gamercoder215.starcosmetics.wrapper.nbt.NBTWrapper.of; @SuppressWarnings("unchecked") @@ -794,22 +795,20 @@ private static void updateCache(Player p) { return; } - ItemStack newItem = item.clone(); - ItemMeta meta = newItem.getItemMeta(); - meta.setLore(Arrays.asList( - ChatColor.GREEN + String.format("%,.1f", newV), - " ", - ChatColor.YELLOW + get("constants.menu.right_click_up"), - ChatColor.YELLOW + get("constants.menu.left_click_down") - )); - newItem.setItemMeta(meta); - - NBTWrapper newNBT = of(newItem); - newNBT.set("value", newV); - newNBT.set("min", min); - newNBT.set("max", max); - newNBT.set("item", type); - newItem = newNBT.getItem(); + ItemStack newItem = builder(item.clone(), + meta -> meta.setLore(Arrays.asList( + ChatColor.GREEN + String.format("%,.1f", newV), + " ", + ChatColor.YELLOW + get("constants.menu.right_click_up"), + ChatColor.YELLOW + get("constants.menu.left_click_down") + )), + newNBT -> { + newNBT.set("value", newV); + newNBT.set("min", min); + newNBT.set("max", max); + newNBT.set("item", type); + } + ); inv.setItem(e.getSlot(), newItem); if (click.isRightClick()) StarSound.ENTITY_ARROW_HIT_PLAYER.playSuccess(p); diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index cf6eafbc..997c7fa0 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -81,4 +81,11 @@ cosmetics: # In 1.9 until 1.13, this is hard-coded tobe 16. # In 1.13+ this is hard-coded to be 48. # The integer must be at or below the hard-coded limit, and must be above 5. - max-hologram-size: 16 \ No newline at end of file + max-hologram-size: 16 + + # A List of StarCosmetics Structure Files relative to this config.yml file. + # For how to format a Custom Structure File, see: https://github.com/GamerCoder215/StarCosmetics/wiki/StarCosmetics-Structure-Files + # + # Examples: + # - 'castle.scs' + structures: [] \ No newline at end of file diff --git a/plugin/src/test/java/me/gamercoder215/starcosmetics/MockServer.java b/plugin/src/test/java/me/gamercoder215/starcosmetics/MockServer.java new file mode 100644 index 00000000..fbe19760 --- /dev/null +++ b/plugin/src/test/java/me/gamercoder215/starcosmetics/MockServer.java @@ -0,0 +1,790 @@ +package me.gamercoder215.starcosmetics; + +import org.bukkit.*; +import org.bukkit.advancement.Advancement; +import org.bukkit.block.data.BlockData; +import org.bukkit.boss.*; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.SpawnCategory; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.help.HelpMap; +import org.bukkit.inventory.*; +import org.bukkit.loot.LootTable; +import org.bukkit.map.MapView; +import org.bukkit.packs.DataPackManager; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.ServicesManager; +import org.bukkit.plugin.messaging.Messenger; +import org.bukkit.profile.PlayerProfile; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scoreboard.Criteria; +import org.bukkit.scoreboard.ScoreboardManager; +import org.bukkit.structure.StructureManager; +import org.bukkit.util.CachedServerIcon; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.net.InetAddress; +import java.util.*; +import java.util.function.Consumer; +import java.util.logging.Logger; + +@SuppressWarnings({"unchecked", "UnstableApiUsage"}) +public class MockServer implements Server { + @Override + public String getName() { + return "TestServer"; + } + + @Override + public String getVersion() { + return "1.20.2"; + } + + @Override + public String getBukkitVersion() { + return "1.20.2-R0.1-SNAPSHOT"; + } + + @Override + public Collection getOnlinePlayers() { + return null; + } + + @Override + public int getMaxPlayers() { + return 0; + } + + @Override + public void setMaxPlayers(int maxPlayers) {} + + @Override + public int getPort() { + return 0; + } + + @Override + public int getViewDistance() { + return 0; + } + + @Override + public int getSimulationDistance() { + return 0; + } + + @Override + public String getIp() { + return null; + } + + @Override + public String getWorldType() { + return null; + } + + @Override + public boolean getGenerateStructures() { + return false; + } + + @Override + public int getMaxWorldSize() { + return 0; + } + + @Override + public boolean getAllowEnd() { + return false; + } + + @Override + public boolean getAllowNether() { + return false; + } + + @Override + public List getInitialEnabledPacks() { + return null; + } + + @Override + public List getInitialDisabledPacks() { + return null; + } + + @Override + public DataPackManager getDataPackManager() {return null;} + + @Override + public String getResourcePack() { + return null; + } + + @Override + public String getResourcePackHash() { + return null; + } + + @Override + public String getResourcePackPrompt() { + return null; + } + + @Override + public boolean isResourcePackRequired() { + return false; + } + + @Override + public boolean hasWhitelist() { + return false; + } + + @Override + public void setWhitelist(boolean value) { + + } + + @Override + public boolean isWhitelistEnforced() { + return false; + } + + @Override + public void setWhitelistEnforced(boolean value) { + + } + + @Override + public Set getWhitelistedPlayers() { + return null; + } + + @Override + public void reloadWhitelist() { + + } + + @Override + public int broadcastMessage(String message) { + return 0; + } + + @Override + public String getUpdateFolder() { + return null; + } + + @Override + public File getUpdateFolderFile() { + return null; + } + + @Override + public long getConnectionThrottle() { + return 0; + } + + @Override + public int getTicksPerAnimalSpawns() { + return 0; + } + + @Override + public int getTicksPerMonsterSpawns() { + return 0; + } + + @Override + public int getTicksPerWaterSpawns() { + return 0; + } + + @Override + public int getTicksPerWaterAmbientSpawns() { + return 0; + } + + @Override + public int getTicksPerWaterUndergroundCreatureSpawns() { + return 0; + } + + @Override + public int getTicksPerAmbientSpawns() { + return 0; + } + + @Override + public int getTicksPerSpawns(SpawnCategory spawnCategory) { + return 0; + } + + @Override + public Player getPlayer(String name) { + return null; + } + + @Override + public Player getPlayerExact(String name) { + return null; + } + + @Override + public List matchPlayer(String name) { + return null; + } + + @Override + public Player getPlayer(UUID id) { + return null; + } + + @Override + public PluginManager getPluginManager() { + return null; + } + + @Override + public BukkitScheduler getScheduler() { + return null; + } + + @Override + public ServicesManager getServicesManager() { + return null; + } + + @Override + public List getWorlds() { + return null; + } + + @Override + public World createWorld(WorldCreator creator) { + return null; + } + + @Override + public boolean unloadWorld(String name, boolean save) { + return false; + } + + @Override + public boolean unloadWorld(World world, boolean save) { + return false; + } + + @Override + public World getWorld(String name) { + return null; + } + + @Override + public World getWorld(UUID uid) { + return null; + } + + @Override + public WorldBorder createWorldBorder() { + return null; + } + + @Override + public MapView getMap(int id) { + return null; + } + + @Override + public MapView createMap(World world) { + return null; + } + + @Override + public ItemStack createExplorerMap(World world, Location location, StructureType structureType) { + return null; + } + + @Override + public ItemStack createExplorerMap(World world, Location location, StructureType structureType, int radius, boolean findUnexplored) { + return null; + } + + @Override + public void reload() { + + } + + @Override + public void reloadData() { + + } + + @Override + public Logger getLogger() { + return Logger.getLogger("Test Server"); + } + + @Override + public PluginCommand getPluginCommand(String name) { + return null; + } + + @Override + public void savePlayers() {} + + @Override + public boolean dispatchCommand(CommandSender sender, String commandLine) throws CommandException { + return false; + } + + @Override + public boolean addRecipe(Recipe recipe) { + return false; + } + + @Override + public List getRecipesFor(ItemStack result) { + return null; + } + + @Override + public Recipe getRecipe(NamespacedKey recipeKey) { + return null; + } + + @Override + public Recipe getCraftingRecipe(ItemStack[] craftingMatrix, World world) { + return null; + } + + @Override + public ItemStack craftItem(ItemStack[] craftingMatrix, World world, Player player) { + return null; + } + + @Override + public Iterator recipeIterator() { + return null; + } + + @Override + public void clearRecipes() { + + } + + @Override + public void resetRecipes() { + + } + + @Override + public boolean removeRecipe(NamespacedKey key) { + return false; + } + + @Override + public Map getCommandAliases() { + return null; + } + + @Override + public int getSpawnRadius() { + return 0; + } + + @Override + public void setSpawnRadius(int value) { + + } + + @Override + public boolean shouldSendChatPreviews() { + return false; + } + + @Override + public boolean isEnforcingSecureProfiles() { + return false; + } + + @Override + public boolean getHideOnlinePlayers() { + return false; + } + + @Override + public boolean getOnlineMode() { + return false; + } + + @Override + public boolean getAllowFlight() { + return false; + } + + @Override + public boolean isHardcore() { + return false; + } + + @Override + public void shutdown() { + + } + + @Override + public int broadcast(String message, String permission) { + return 0; + } + + @Override + public OfflinePlayer getOfflinePlayer(String name) { + return null; + } + + @Override + public OfflinePlayer getOfflinePlayer(UUID id) { + return null; + } + + @Override + public PlayerProfile createPlayerProfile(UUID uniqueId, String name) { + return null; + } + + @Override + public PlayerProfile createPlayerProfile(UUID uniqueId) { + return null; + } + + @Override + public PlayerProfile createPlayerProfile(String name) { + return null; + } + + @Override + public Set getIPBans() { + return null; + } + + @Override + public void banIP(String address) { + + } + + @Override + public void unbanIP(String address) { + + } + + @Override + public void banIP(InetAddress address) { + + } + + @Override + public void unbanIP(InetAddress address) { + + } + + @Override + public Set getBannedPlayers() { + return null; + } + + @Override + public BanList getBanList(BanList.Type type) { + return null; + } + + @Override + public Set getOperators() { + return null; + } + + @Override + public GameMode getDefaultGameMode() { + return null; + } + + @Override + public void setDefaultGameMode(GameMode mode) { + + } + + @Override + public ConsoleCommandSender getConsoleSender() { + return null; + } + + @Override + public File getWorldContainer() { + return null; + } + + @Override + public OfflinePlayer[] getOfflinePlayers() { + return new OfflinePlayer[0]; + } + + @Override + public Messenger getMessenger() { + return null; + } + + @Override + public HelpMap getHelpMap() { + return null; + } + + @Override + public Inventory createInventory(InventoryHolder owner, InventoryType type) { + return null; + } + + @Override + public Inventory createInventory(InventoryHolder owner, InventoryType type, String title) { + return null; + } + + @Override + public Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException { + return null; + } + + @Override + public Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException { + return null; + } + + @Override + public Merchant createMerchant(String title) { + return null; + } + + @Override + public int getMaxChainedNeighborUpdates() { + return 0; + } + + @Override + public int getMonsterSpawnLimit() { + return 0; + } + + @Override + public int getAnimalSpawnLimit() { + return 0; + } + + @Override + public int getWaterAnimalSpawnLimit() { + return 0; + } + + @Override + public int getWaterAmbientSpawnLimit() { + return 0; + } + + @Override + public int getWaterUndergroundCreatureSpawnLimit() { + return 0; + } + + @Override + public int getAmbientSpawnLimit() { + return 0; + } + + @Override + public int getSpawnLimit(SpawnCategory spawnCategory) { + return 0; + } + + @Override + public boolean isPrimaryThread() { + return false; + } + + @Override + public String getMotd() { + return null; + } + + @Override + public void setMotd(String motd) { + + } + + @Override + public String getShutdownMessage() { + return null; + } + + @Override + public Warning.WarningState getWarningState() { + return null; + } + + @Override + public ItemFactory getItemFactory() { + return null; + } + + @Override + public ScoreboardManager getScoreboardManager() { + return null; + } + + @Override + public Criteria getScoreboardCriteria(String name) { + return null; + } + + @Override + public CachedServerIcon getServerIcon() { + return null; + } + + @Override + public CachedServerIcon loadServerIcon(File file) { + return null; + } + + @Override + public CachedServerIcon loadServerIcon(BufferedImage image) { + return null; + } + + @Override + public void setIdleTimeout(int threshold) {} + + @Override + public int getIdleTimeout() { + return 0; + } + + @Override + public ChunkGenerator.ChunkData createChunkData(World world) { + return null; + } + + @Override + public BossBar createBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) { + return null; + } + + @Override + public KeyedBossBar createBossBar(NamespacedKey key, String title, BarColor color, BarStyle style, BarFlag... flags) { + return null; + } + + @Override + public Iterator getBossBars() { + return null; + } + + @Override + public KeyedBossBar getBossBar(NamespacedKey key) { + return null; + } + + @Override + public boolean removeBossBar(NamespacedKey key) { + return false; + } + + @Override + public Entity getEntity(UUID uuid) { + return null; + } + + @Override + public Advancement getAdvancement(NamespacedKey key) { + return null; + } + + @Override + public Iterator advancementIterator() { + return null; + } + + @Override + public BlockData createBlockData(Material material) { + return null; + } + + @Override + public BlockData createBlockData(Material material, Consumer consumer) { + return null; + } + + @Override + public BlockData createBlockData(String data) throws IllegalArgumentException { + return null; + } + + @Override + public BlockData createBlockData(Material material, String data) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + @Override + public Tag getTag(String registry, NamespacedKey tag, Class clazz) { + return null; + } + + @Override + public Iterable> getTags(String registry, Class clazz) { + return null; + } + + @Override + public LootTable getLootTable(NamespacedKey key) { + return null; + } + + @Override + public List selectEntities(CommandSender sender, String selector) throws IllegalArgumentException { + return null; + } + + @Override + public StructureManager getStructureManager() { + return null; + } + + @Override + public Registry getRegistry(Class tClass) { + return null; + } + + @Override + public UnsafeValues getUnsafe() { + return null; + } + + @Override + public Spigot spigot() { + return null; + } + + @Override + public void sendPluginMessage(Plugin source, String channel, byte[] message) {} + + @Override + public Set getListeningPluginChannels() { + return null; + } +} diff --git a/plugin/src/test/java/me/gamercoder215/starcosmetics/TestStarCosmetics.java b/plugin/src/test/java/me/gamercoder215/starcosmetics/TestStarCosmetics.java new file mode 100644 index 00000000..48aae85e --- /dev/null +++ b/plugin/src/test/java/me/gamercoder215/starcosmetics/TestStarCosmetics.java @@ -0,0 +1,75 @@ +package me.gamercoder215.starcosmetics; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.java.JavaPluginLoader; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.Locale; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class TestStarCosmetics { + + private static StarCosmetics plugin; + @TempDir + private static File dataFolder; + + @BeforeAll + public static void setup() { + MockServer server = new MockServer(); + Bukkit.setServer(server); + plugin = new StarCosmetics( + new JavaPluginLoader(server), + new PluginDescriptionFile("StarCosmetics", "1.0", "me.gamercoder215.starcosmetics.StarCosmetics"), + dataFolder, + null + ); + + File config = new File(dataFolder, "config.yml"); + StarCosmetics.config = YamlConfiguration.loadConfiguration(config); + } + + @AfterAll + public static void shutdown() throws Exception{ + Field server = Bukkit.class.getDeclaredField("server"); + server.setAccessible(true); + server.set(null, null); + } + + @Test + @DisplayName("Test StarConfig#get") + public void testGet() { + Assertions.assertEquals("Commands", plugin.get("constants.commands")); + Assertions.assertEquals("Hologram Format", plugin.get("settings.hologram_format")); + } + + private static void configTest(T newValue, Supplier getter, Consumer setter) { + setter.accept(newValue); + Assertions.assertEquals(newValue, getter.get()); + } + + @Test + @DisplayName("Test Configuration") + public void testConfiguration() { + plugin.setLanguage("es"); + Assertions.assertEquals("es", plugin.getLanguage()); + Assertions.assertEquals("Comandos", plugin.get("constants.commands")); + + plugin.setLanguage("it"); + Assertions.assertEquals("it", plugin.getLanguage()); + Assertions.assertEquals(Locale.ITALIAN, plugin.getLocale()); + + configTest(10, plugin::getMaxHologramLimit, plugin::setMaxHologramLimit); + configTest(5L, plugin::getBlockDisappearTime, plugin::setBlockDisappearTime); + configTest(6L, plugin::getEntityDisappearTime, plugin::setEntityDisappearTime); + configTest(11L, plugin::getItemDisappearTime, plugin::setItemDisappearTime); + configTest(2.5, plugin::getRequirementMultiplier, plugin::setRequirementMultiplier); + configTest(false, plugin::isAmbientPetSoundEnabled, plugin::setAmbientPetSoundEnabled); + } + +} diff --git a/plugin/src/test/java/me/gamercoder215/starcosmetics/api/TestCompletionCriteria.java b/plugin/src/test/java/me/gamercoder215/starcosmetics/api/TestCompletionCriteria.java new file mode 100644 index 00000000..9192a9b0 --- /dev/null +++ b/plugin/src/test/java/me/gamercoder215/starcosmetics/api/TestCompletionCriteria.java @@ -0,0 +1,30 @@ +package me.gamercoder215.starcosmetics.api; + +import me.gamercoder215.starcosmetics.api.player.PlayerCompletion; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TestCompletionCriteria { + + @Test + @DisplayName("Test Basic Criteria") + public void testBasicCriteria() { + CompletionCriteria criteria = CompletionCriteria.fromCompletion(PlayerCompletion.NETHER_ROOF); + Assertions.assertNotNull(criteria); + } + + @Test + @DisplayName("Test CompletionCriteria#toPlural") + public void testToPlural() { + Assertions.assertEquals(CompletionCriteria.toPlural("test"), "tests"); + Assertions.assertEquals(CompletionCriteria.toPlural("coral"), "coral"); + Assertions.assertEquals(CompletionCriteria.toPlural("tree"), "trees"); + Assertions.assertEquals(CompletionCriteria.toPlural("enderman"), "endermen"); + Assertions.assertEquals(CompletionCriteria.toPlural("blaze"), "blazes"); + Assertions.assertEquals(CompletionCriteria.toPlural("zombie"), "zombies"); + Assertions.assertEquals(CompletionCriteria.toPlural("droh"), "drohes"); + Assertions.assertEquals(CompletionCriteria.toPlural("cry"), "cries"); + } + +} diff --git a/api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java b/plugin/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java similarity index 66% rename from api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java rename to plugin/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java index cd1be8c2..95dbed97 100644 --- a/api/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java +++ b/plugin/src/test/java/me/gamercoder215/starcosmetics/api/cosmetics/structure/TestStructureReader.java @@ -5,10 +5,43 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.io.FileReader; import java.util.Arrays; public class TestStructureReader { + @Test + @DisplayName("Test LegacyStructureReader") + public void testLegacyStructureReader() throws Exception{ + Structure s = new LegacyStructureReader(new FileReader( + Thread.currentThread().getContextClassLoader().getResource("test.scs").getFile() + )).read(); + Assertions.assertNotNull(s); + Assertions.assertNotNull(s.getRarity()); + Assertions.assertFalse(s.getMaterials().isEmpty()); + Assertions.assertTrue(s.getPointsPlaced().isEmpty()); + } + + @Test + @DisplayName("Test ModernStructureReader") + public void testModernStructureReader() throws Exception { + Structure s = new ModernStructureReader(new FileReader( + Thread.currentThread().getContextClassLoader().getResource("test.scs").getFile() + )).read(); + Assertions.assertNotNull(s); + Assertions.assertNotNull(s.getRarity()); + Assertions.assertFalse(s.getMaterials().isEmpty()); + Assertions.assertTrue(s.getPointsPlaced().isEmpty()); + + Structure s2 = new ModernStructureReader(new FileReader( + Thread.currentThread().getContextClassLoader().getResource("test-modern.scs").getFile() + )).read(); + Assertions.assertNotNull(s2); + Assertions.assertNotNull(s2.getRarity()); + Assertions.assertFalse(s2.getMaterials().isEmpty()); + Assertions.assertTrue(s2.getPointsPlaced().isEmpty()); + } + @Test @DisplayName("Test Raw Points") public void testRawPoints() { diff --git a/plugin/src/test/resources/test-modern.scs b/plugin/src/test/resources/test-modern.scs new file mode 100644 index 00000000..ab68a588 --- /dev/null +++ b/plugin/src/test/resources/test-modern.scs @@ -0,0 +1,10 @@ +ALL +:test2: +"test2" +uncommon +--- +cobblestone:[-7,0,5]*[6,0,6]*[1,1,4]; +chest[waterlogged=true]:[0,0,0]; +beacon:(-1,1,1,4,-1,1)^[2,3,2]; +{50%=ladder[waterlogged=true],50%=stone_button[waterlogged=true]}:[15,0,0]; +{70%=stone,30%=water}:[0,10,0]*[0,11,0]; \ No newline at end of file diff --git a/plugin/src/test/resources/test.scs b/plugin/src/test/resources/test.scs new file mode 100644 index 00000000..d1be678d --- /dev/null +++ b/plugin/src/test/resources/test.scs @@ -0,0 +1,10 @@ +ALL +:test: +"test" +common +--- +oak_log:[0,0,0]*[0,1,0]*[0,2,0]*[0,3,0]; +oak_leaves:(-1,0,-1,1,-1,0)^[0,4,0]; +cobblestone:[5,0,5]*[6,0,6]; +{50%=stone,50%=dirt}:[10,0,0]*[11,0,0]; +beacon:(1,1,1,1,1,1)^[2,2,2]; \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index a39ace0c..123eef9b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,7 +34,8 @@ listOf( "1_19_R1", "1_19_R2", "1_19_R3", - "1_20_R1" + "1_20_R1", + "1_20_R2" ).forEach { include(":starcosmetics-$it") project(":starcosmetics-$it").projectDir = rootDir.resolve("nms/$it")