From 858df7201fc3b6db05ba7b15b6b428da6f305fe5 Mon Sep 17 00:00:00 2001 From: rolyPolyVole Date: Tue, 13 Aug 2024 21:55:29 +0700 Subject: [PATCH] Added working custom item manager, which replaces the crossbow registry entry with a custom class by working in conjunction with the paper bootstrapper. --- build.gradle.kts | 8 +- .../FireworkWarsPlugin.java | 37 +++--- .../FireworkWarsPluginBootstrapper.java | 30 +++++ .../data/player/PlayerDataManager.java | 12 +- .../items/FireworkRifleItem.java | 82 ------------ .../items/guns/BaseGunItem.java | 109 ++++++++++++++++ .../items/guns/rifle/FireworkRifleItem.java | 50 ++++++++ .../items/{ => guns/rifle}/RifleAmmo.java | 13 +- .../guns/shotgun/FireworkShotgunItem.java | 57 +++++++++ .../items/guns/shotgun/ShotgunAmmo.java | 28 +++++ .../items/manager/AbstractItem.java | 12 +- .../items/manager/CustomItemManager.java | 77 +++++------- .../items/nms/CustomCrossbow.java | 71 +++++++++-- .../language/Message.java | 5 + .../slqmy/firework_wars_plugin/util/Keys.java | 15 +++ .../util/PersistentDataManager.java | 29 ++--- .../util/ReflectUtil.java | 117 ++++++++++++------ .../languages/English (United Kingdom).yaml | 9 +- .../languages/English (United States).yaml | 2 +- 19 files changed, 527 insertions(+), 236 deletions(-) create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPluginBootstrapper.java delete mode 100644 src/main/java/net/slqmy/firework_wars_plugin/items/FireworkRifleItem.java create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/items/guns/BaseGunItem.java create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/FireworkRifleItem.java rename src/main/java/net/slqmy/firework_wars_plugin/items/{ => guns/rifle}/RifleAmmo.java (62%) create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/FireworkShotgunItem.java create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/ShotgunAmmo.java create mode 100644 src/main/java/net/slqmy/firework_wars_plugin/util/Keys.java diff --git a/build.gradle.kts b/build.gradle.kts index ba0e8bb6..794dcb36 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ import org.gradle.api.JavaVersion -import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml plugins { java @@ -8,7 +7,7 @@ plugins { `maven-publish` id("io.papermc.paperweight.userdev") version "1.7.2" - id("xyz.jpenilla.resource-factory-bukkit-convention") version "1.1.1" + id("xyz.jpenilla.resource-factory-paper-convention") version "1.1.2" id("xyz.jpenilla.run-paper") version "2.3.0" id("io.github.goooler.shadow") version "8.1.7" @@ -46,6 +45,7 @@ val projectAuthors = listOfNotNull(mainProjectAuthor, mainestProjectAuthor) val topLevelDomain = "net" val projectNameString = rootProject.name +val bootstrapperNameString = rootProject.name + "Bootstrapper" group = topLevelDomain + groupStringSeparator + mainProjectAuthor.lowercase() + groupStringSeparator + snakeCase(projectNameString) version = "1.0.0" @@ -94,13 +94,13 @@ tasks { } } -bukkitPluginYaml { +paperPluginYaml { authors = projectAuthors main = projectGroupString + groupStringSeparator + pascalCase(projectNameString) apiVersion = paperApiVersion - load = BukkitPluginYaml.PluginLoadOrder.STARTUP + bootstrapper = projectGroupString + groupStringSeparator + pascalCase(bootstrapperNameString) } publishing { diff --git a/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPlugin.java b/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPlugin.java index 016c5527..fa1a7dbe 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPlugin.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPlugin.java @@ -1,14 +1,5 @@ package net.slqmy.firework_wars_plugin; -import net.slqmy.firework_wars_plugin.util.PersistentDataManager; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.java.JavaPlugin; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.framework.qual.DefaultQualifier; - import dev.jorel.commandapi.CommandAPI; import dev.jorel.commandapi.CommandAPIBukkitConfig; import net.slqmy.firework_wars_plugin.arena.manager.ArenaManager; @@ -18,19 +9,30 @@ import net.slqmy.firework_wars_plugin.game.GameManager; import net.slqmy.firework_wars_plugin.items.manager.CustomItemManager; import net.slqmy.firework_wars_plugin.language.LanguageManager; +import net.slqmy.firework_wars_plugin.util.PersistentDataManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; import java.util.logging.Logger; public final class FireworkWarsPlugin extends JavaPlugin implements Listener { + private static FireworkWarsPlugin instance; public static Logger LOGGER; + private final CustomItemManager customItemManager; private PlayerDataManager playerDataManager; private LanguageManager languageManager; private ArenaManager arenaManager; private GameManager gameManager; - private CustomItemManager customItemManager; private PersistentDataManager pdcManager; + public static FireworkWarsPlugin getInstance() { + return instance; + } + public PlayerDataManager getPlayerDataManager() { return this.playerDataManager; } @@ -55,8 +57,11 @@ public PersistentDataManager getPdcManager() { return this.pdcManager; } - public FireworkWarsPlugin() { + public FireworkWarsPlugin(CustomItemManager customItemManager) { + instance = this; LOGGER = getLogger(); + + this.customItemManager = customItemManager; } @Override @@ -73,8 +78,10 @@ public void onEnable() { this.languageManager = new LanguageManager(this); this.arenaManager = new ArenaManager(this); this.gameManager = new GameManager(this); - this.customItemManager = new CustomItemManager(this); - this.pdcManager = new PersistentDataManager(this); + this.pdcManager = new PersistentDataManager(); + + customItemManager.setPlugin(this); + customItemManager.registerCustomItems(); new SetLanguageCommand(this); new ArenaCommand(this); @@ -91,8 +98,8 @@ public void onDisable() { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - ItemStack item1 = customItemManager.getItem("firework_rifle_ammo").getItem(event.getPlayer()); - ItemStack item2 = customItemManager.getItem("firework_rifle").getItem(event.getPlayer()); + ItemStack item1 = customItemManager.getItem("firework_shotgun_ammo").getItem(event.getPlayer()); + ItemStack item2 = customItemManager.getItem("firework_shotgun").getItem(event.getPlayer()); event.getPlayer().getInventory().addItem(item1, item2); } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPluginBootstrapper.java b/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPluginBootstrapper.java new file mode 100644 index 00000000..c3c1d467 --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/FireworkWarsPluginBootstrapper.java @@ -0,0 +1,30 @@ +package net.slqmy.firework_wars_plugin; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.bootstrap.PluginBootstrap; +import io.papermc.paper.plugin.bootstrap.PluginProviderContext; +import io.papermc.paper.registry.event.RegistryEvents; +import net.slqmy.firework_wars_plugin.items.manager.CustomItemManager; +import net.slqmy.firework_wars_plugin.util.ReflectUtil; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings({"UnstableApiUsage", "unused"}) +public final class FireworkWarsPluginBootstrapper implements PluginBootstrap { + private final ReflectUtil reflectUtil = new ReflectUtil(); + private final CustomItemManager customItemManager = new CustomItemManager(reflectUtil); + + @Override + public void bootstrap(@NotNull BootstrapContext context) { + reflectUtil.useLogger(context.getLogger()); + + context.getLifecycleManager().registerEventHandler(RegistryEvents.GAME_EVENT.freeze(), event -> { + customItemManager.registerNMSItems(); + }); + } + + @Override + public @NotNull JavaPlugin createPlugin(@NotNull PluginProviderContext context) { + return new FireworkWarsPlugin(customItemManager); + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/data/player/PlayerDataManager.java b/src/main/java/net/slqmy/firework_wars_plugin/data/player/PlayerDataManager.java index 75eeab8f..b8b33750 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/data/player/PlayerDataManager.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/data/player/PlayerDataManager.java @@ -1,5 +1,9 @@ package net.slqmy.firework_wars_plugin.data.player; +import com.google.gson.Gson; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import org.bukkit.entity.Player; + import java.io.File; import java.io.FileReader; import java.io.FileWriter; @@ -9,12 +13,6 @@ import java.util.Map.Entry; import java.util.UUID; -import org.bukkit.entity.Player; - -import com.google.gson.Gson; - -import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; - public class PlayerDataManager { private final FireworkWarsPlugin plugin; @@ -88,8 +86,8 @@ public void save() { writer.write(json); - writer.close(); writer.flush(); + writer.close(); } catch (IOException exception) { exception.printStackTrace(); } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/FireworkRifleItem.java b/src/main/java/net/slqmy/firework_wars_plugin/items/FireworkRifleItem.java deleted file mode 100644 index 2e460225..00000000 --- a/src/main/java/net/slqmy/firework_wars_plugin/items/FireworkRifleItem.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.slqmy.firework_wars_plugin.items; - -import io.papermc.paper.event.entity.EntityLoadCrossbowEvent; -import net.slqmy.firework_wars_plugin.game.FireworkWarsGame; -import net.slqmy.firework_wars_plugin.game.FireworkWarsTeam; -import net.slqmy.firework_wars_plugin.items.nms.CustomCrossbow; -import net.slqmy.firework_wars_plugin.util.ItemBuilder; -import org.bukkit.Color; -import org.bukkit.FireworkEffect; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.entity.EntityShootBowEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.CrossbowMeta; -import org.bukkit.inventory.meta.FireworkMeta; - -import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; -import net.slqmy.firework_wars_plugin.items.manager.AbstractItem; -import net.slqmy.firework_wars_plugin.language.Message; - -import java.util.List; - -public class FireworkRifleItem extends AbstractItem { - - public FireworkRifleItem(FireworkWarsPlugin plugin) { - super(plugin, "firework_rifle", Material.CROSSBOW); - } - - @Override - public ItemStack getItem(Player player) { - return new ItemBuilder(plugin, itemMaterial) - .setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE, player)) - .setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_LORE, player)) - .setEnchanted(true) - .setUnbreakable(true) - .itemSupplier(() -> plugin.getCustomItemManager().getBukkitItemStackFromNMS("crossbow")) - .modifyMeta(meta -> meta.addEnchant(Enchantment.QUICK_CHARGE, 3, true)) - .build(); - } - - @EventHandler - public void onCrossbowLoad(EntityLoadCrossbowEvent event) { - if (!(event.getEntity() instanceof Player player)) { - return; - } - - FireworkWarsGame game = plugin.getGameManager().getFireworkWarsGame(player); - - if (game == null) { - return; - } - - FireworkWarsTeam team = game.getTeam(player); - - ItemStack firework = new ItemStack(Material.FIREWORK_ROCKET); - FireworkMeta fireworkMeta = (FireworkMeta) firework.getItemMeta(); - - addFireworkStars(fireworkMeta, team.getConfiguredTeam().getColor()); - firework.setItemMeta(fireworkMeta); - - CrossbowMeta crossbowMeta = (CrossbowMeta) event.getCrossbow().getItemMeta(); - crossbowMeta.setChargedProjectiles(List.of(firework)); - } - - @EventHandler - public void onCrossbowShoot(EntityShootBowEvent event) { - - } - - private void addFireworkStars(FireworkMeta meta, Color color) { - for (int i = 0; i < 4; i++) { - meta.addEffect(FireworkEffect - .builder() - .withColor(Color.WHITE) - .withFade(color) - .withFlicker() - .build()); - } - } -} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/guns/BaseGunItem.java b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/BaseGunItem.java new file mode 100644 index 00000000..9ac95aaa --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/BaseGunItem.java @@ -0,0 +1,109 @@ +package net.slqmy.firework_wars_plugin.items.guns; + +import io.papermc.paper.event.entity.EntityLoadCrossbowEvent; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.game.FireworkWarsGame; +import net.slqmy.firework_wars_plugin.items.manager.AbstractItem; +import net.slqmy.firework_wars_plugin.items.nms.CustomCrossbow; +import net.slqmy.firework_wars_plugin.util.ItemBuilder; +import net.slqmy.firework_wars_plugin.util.Keys; +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.CrossbowMeta; +import org.bukkit.inventory.meta.FireworkMeta; + +public abstract class BaseGunItem extends AbstractItem { + protected final String ammoId; + + public BaseGunItem(FireworkWarsPlugin plugin, String itemId, String ammoId) { + super(plugin, itemId, Material.CROSSBOW); + + this.ammoId = ammoId; + } + + protected ItemBuilder getItemBuilder() { + return new ItemBuilder(plugin, itemMaterial) + .setEnchanted(true) + .setUnbreakable(true); + } + + protected ItemStack getCustomCrossbow() { + CustomCrossbow crossbow = (CustomCrossbow) plugin.getCustomItemManager().getNMSItem("crossbow"); + ItemStack itemStack = crossbow.getDefaultInstance().asBukkitCopy(); + + itemStack.setItemMeta(new ItemStack(Material.CROSSBOW).getItemMeta()); + return itemStack; + } + + protected void modifyMeta(CrossbowMeta meta) { + pdcManager.setStringValue(meta, isItemKey, itemId); + pdcManager.setStringValue(meta, Keys.GUN_ACCEPTED_AMMO_ID, ammoId); + } + + protected ItemStack createFirework(Color color, int stars) { + ItemStack firework = new ItemStack(Material.FIREWORK_ROCKET); + FireworkMeta fireworkMeta = (FireworkMeta) firework.getItemMeta(); + + addFireworkStars(fireworkMeta, color, stars); + firework.setItemMeta(fireworkMeta); + + return firework; + } + + protected void addFireworkStars(FireworkMeta meta, Color color, int amount) { + for (int i = 0; i < amount; i++) { + meta.addEffect(FireworkEffect + .builder() + .withColor(Color.WHITE) + .withFade(color) + .withFlicker() + .build()); + } + } + + protected abstract void onCrossbowLoad(Player player, FireworkWarsGame game, EntityLoadCrossbowEvent event); + protected abstract void onCrossbowShoot(Player player, FireworkWarsGame game, EntityShootBowEvent event); + + @EventHandler + public void onCrossbowLoad(EntityLoadCrossbowEvent event) { + if (!isValidCustomItem(event.getCrossbow())) { + return; + } + + if (!(event.getEntity() instanceof Player player)) { + return; + } + + FireworkWarsGame game = plugin.getGameManager().getFireworkWarsGame(player); + + if (game == null) { + return; + } + + onCrossbowLoad(player, game, event); + } + + @EventHandler + public void onCrossbowShoot(EntityShootBowEvent event) { + if (!isValidCustomItem(event.getBow())) { + return; + } + + if (!(event.getEntity() instanceof Player player)) { + return; + } + + FireworkWarsGame game = plugin.getGameManager().getFireworkWarsGame(player); + + if (game == null) { + return; + } + + onCrossbowShoot(player, game, event); + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/FireworkRifleItem.java b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/FireworkRifleItem.java new file mode 100644 index 00000000..6f815649 --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/FireworkRifleItem.java @@ -0,0 +1,50 @@ +package net.slqmy.firework_wars_plugin.items.guns.rifle; + +import io.papermc.paper.event.entity.EntityLoadCrossbowEvent; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.game.FireworkWarsGame; +import net.slqmy.firework_wars_plugin.game.FireworkWarsTeam; +import net.slqmy.firework_wars_plugin.items.guns.BaseGunItem; +import net.slqmy.firework_wars_plugin.language.Message; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.CrossbowMeta; + +import java.util.List; +import java.util.function.Consumer; + +public class FireworkRifleItem extends BaseGunItem { + + public FireworkRifleItem(FireworkWarsPlugin plugin) { + super(plugin, "firework_rifle", "firework_rifle_ammo"); + } + + @Override + public ItemStack getItem(Player player) { + Consumer consumer = this::modifyMeta; + + return getItemBuilder() + .setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE, player)) + .setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_LORE, player)) + .itemSupplier(this::getCustomCrossbow) + .modifyMeta(consumer.andThen(meta -> meta.addEnchant(Enchantment.QUICK_CHARGE, 3, true))) + .build(); + } + + @Override + protected void onCrossbowLoad(Player player, FireworkWarsGame game, EntityLoadCrossbowEvent event) { + FireworkWarsTeam team = game.getTeam(player); + + ItemStack firework = createFirework(team.getConfiguredTeam().getColor(), 4); + + CrossbowMeta crossbowMeta = (CrossbowMeta) event.getCrossbow().getItemMeta(); + crossbowMeta.setChargedProjectiles(List.of(firework)); + } + + @Override + protected void onCrossbowShoot(Player player, FireworkWarsGame game, EntityShootBowEvent event) { + + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/RifleAmmo.java b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/RifleAmmo.java similarity index 62% rename from src/main/java/net/slqmy/firework_wars_plugin/items/RifleAmmo.java rename to src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/RifleAmmo.java index 73f1656c..edb1839b 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/items/RifleAmmo.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/rifle/RifleAmmo.java @@ -1,26 +1,29 @@ -package net.slqmy.firework_wars_plugin.items; +package net.slqmy.firework_wars_plugin.items.guns.rifle; import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; import net.slqmy.firework_wars_plugin.items.manager.AbstractItem; import net.slqmy.firework_wars_plugin.language.Message; import net.slqmy.firework_wars_plugin.util.ItemBuilder; -import org.bukkit.FireworkEffect; +import net.slqmy.firework_wars_plugin.util.Keys; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.FireworkMeta; public class RifleAmmo extends AbstractItem { public RifleAmmo(FireworkWarsPlugin plugin) { - super(plugin, "firework_rifle_ammo", Material.FIREWORK_ROCKET); + super(plugin, "firework_rifle_ammo", Material.GHAST_TEAR); } @Override public ItemStack getItem(Player player) { - return new ItemBuilder(plugin, itemMaterial) + return new ItemBuilder<>(plugin, itemMaterial) .setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_AMMO, player)) .setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_AMMO_LORE, player)) + .modifyMeta(meta -> { + pdcManager.setStringValue(meta, isItemKey, itemId); + pdcManager.setStringValue(meta, Keys.ITEM_OWNER_UUID, player.getUniqueId().toString()); + }) .build(); } } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/FireworkShotgunItem.java b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/FireworkShotgunItem.java new file mode 100644 index 00000000..6fa1f6b1 --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/FireworkShotgunItem.java @@ -0,0 +1,57 @@ +package net.slqmy.firework_wars_plugin.items.guns.shotgun; + +import io.papermc.paper.event.entity.EntityLoadCrossbowEvent; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.game.FireworkWarsGame; +import net.slqmy.firework_wars_plugin.game.FireworkWarsTeam; +import net.slqmy.firework_wars_plugin.items.guns.BaseGunItem; +import net.slqmy.firework_wars_plugin.language.Message; +import org.bukkit.entity.Firework; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.CrossbowMeta; +import org.bukkit.util.Vector; + +import java.util.List; + +public class FireworkShotgunItem extends BaseGunItem { + public FireworkShotgunItem(FireworkWarsPlugin plugin) { + super(plugin, "firework_shotgun", "firework_shotgun_ammo"); + } + + @Override + public ItemStack getItem(Player player) { + return getItemBuilder() + .setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_SHOTGUN, player)) + .setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_SHOTGUN_LORE, player)) + .itemSupplier(this::getCustomCrossbow) + .modifyMeta(this::modifyMeta) + .build(); + } + + @Override + protected void onCrossbowLoad(Player player, FireworkWarsGame game, EntityLoadCrossbowEvent event) { + FireworkWarsTeam team = game.getTeam(player); + + ItemStack firework = createFirework(team.getConfiguredTeam().getColor(), 2); + + CrossbowMeta crossbowMeta = (CrossbowMeta) event.getCrossbow().getItemMeta(); + crossbowMeta.setChargedProjectiles(List.of(firework)); + } + + @Override + protected void onCrossbowShoot(Player player, FireworkWarsGame game, EntityShootBowEvent event) { + ItemStack firework = ((Firework) event.getProjectile()).getItem(); + Vector velocity = event.getProjectile().getVelocity(); + + for (int i = 0; i < 3; i++) { + Vector deviated = velocity.clone().add( + new Vector(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5)); + + player.launchProjectile(Firework.class, deviated, (fw) -> { + fw.setItem(firework.clone()); + }); + } + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/ShotgunAmmo.java b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/ShotgunAmmo.java new file mode 100644 index 00000000..d8e9b347 --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/guns/shotgun/ShotgunAmmo.java @@ -0,0 +1,28 @@ +package net.slqmy.firework_wars_plugin.items.guns.shotgun; + +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.items.manager.AbstractItem; +import net.slqmy.firework_wars_plugin.language.Message; +import net.slqmy.firework_wars_plugin.util.ItemBuilder; +import net.slqmy.firework_wars_plugin.util.Keys; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class ShotgunAmmo extends AbstractItem { + public ShotgunAmmo(FireworkWarsPlugin plugin) { + super(plugin, "firework_rifle_ammo", Material.NETHER_WART); + } + + @Override + public ItemStack getItem(Player player) { + return new ItemBuilder<>(plugin, itemMaterial) + .setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_SHOTGUN_AMMO, player)) + .setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_SHOTGUN_AMMO_LORE, player)) + .modifyMeta(meta -> { + pdcManager.setStringValue(meta, isItemKey, itemId); + pdcManager.setStringValue(meta, Keys.ITEM_OWNER_UUID, player.getUniqueId().toString()); + }) + .build(); + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/manager/AbstractItem.java b/src/main/java/net/slqmy/firework_wars_plugin/items/manager/AbstractItem.java index c307f8d7..5a1b027c 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/items/manager/AbstractItem.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/manager/AbstractItem.java @@ -1,20 +1,19 @@ package net.slqmy.firework_wars_plugin.items.manager; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Bukkit; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.util.Keys; +import net.slqmy.firework_wars_plugin.util.PersistentDataManager; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; - -import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; public abstract class AbstractItem implements Listener { protected final FireworkWarsPlugin plugin; + protected final PersistentDataManager pdcManager; protected final MiniMessage MM; protected final String itemId; @@ -24,12 +23,13 @@ public abstract class AbstractItem implements Listener { public AbstractItem(FireworkWarsPlugin plugin, String itemId, Material itemMaterial) { this.plugin = plugin; + this.pdcManager = plugin.getPdcManager(); this.MM = MiniMessage.miniMessage(); this.itemId = itemId; this.itemMaterial = itemMaterial; - this.isItemKey = new NamespacedKey(plugin, "custom_item_id"); + this.isItemKey = Keys.CUSTOM_ITEM_ID; plugin.getServer().getPluginManager().registerEvents(this, plugin); } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/manager/CustomItemManager.java b/src/main/java/net/slqmy/firework_wars_plugin/items/manager/CustomItemManager.java index 6fec8fdb..a0b1d219 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/items/manager/CustomItemManager.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/manager/CustomItemManager.java @@ -3,8 +3,6 @@ import com.mojang.serialization.Lifecycle; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ReferenceList; -import net.minecraft.core.DefaultedMappedRegistry; import net.minecraft.core.Holder; import net.minecraft.core.MappedRegistry; import net.minecraft.core.RegistrationInfo; @@ -14,41 +12,45 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; -import net.slqmy.firework_wars_plugin.items.FireworkRifleItem; -import net.slqmy.firework_wars_plugin.items.RifleAmmo; +import net.slqmy.firework_wars_plugin.items.guns.rifle.FireworkRifleItem; +import net.slqmy.firework_wars_plugin.items.guns.rifle.RifleAmmo; +import net.slqmy.firework_wars_plugin.items.guns.shotgun.FireworkShotgunItem; +import net.slqmy.firework_wars_plugin.items.guns.shotgun.ShotgunAmmo; import net.slqmy.firework_wars_plugin.items.nms.CustomCrossbow; import net.slqmy.firework_wars_plugin.util.ReflectUtil; -import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.inventory.ItemStack; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.sql.Ref; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; public class CustomItemManager { - private final FireworkWarsPlugin plugin; + private FireworkWarsPlugin plugin; + private final ReflectUtil reflectUtil; private final Map itemRegistry = new HashMap<>(); private final Map nmsItemRegistry = new HashMap<>(); - public CustomItemManager(FireworkWarsPlugin plugin) { + public void setPlugin(FireworkWarsPlugin plugin) { this.plugin = plugin; + } + + public CustomItemManager(ReflectUtil reflectUtil) { + this.reflectUtil = reflectUtil; + } + public void registerCustomItems() { registerItem(new FireworkRifleItem(plugin)); registerItem(new RifleAmmo(plugin)); - reopenItemRegistry(); //Prevent error + registerItem(new FireworkShotgunItem(plugin)); + registerItem(new ShotgunAmmo(plugin)); + } + public void registerNMSItems() { registerNMSItem( "crossbow", - new CustomCrossbow(CustomCrossbow.PROPERTIES, getItem("firework_rifle_ammo")), + new CustomCrossbow(CustomCrossbow.PROPERTIES), Items.CROSSBOW); - - BuiltInRegistries.ITEM.freeze(); } public Map getItemRegistry() { @@ -67,14 +69,6 @@ public Item getNMSItem(String itemId) { return nmsItemRegistry.get(itemId); } - public ItemStack getBukkitItemStackFromNMS(String itemId) { - net.minecraft.world.item.ItemStack nmsItemStack = nmsItemRegistry.get(itemId).getDefaultInstance(); - ItemStack itemStack = nmsItemStack.asBukkitCopy(); - - itemStack.setItemMeta(CraftItemStack.getItemMeta(nmsItemStack)); - return itemStack; - } - private void registerItem(AbstractItem item) { itemRegistry.put(item.getItemId(), item); } @@ -85,52 +79,45 @@ private void registerNMSItem(String id, Item item, Item override) { nmsItemRegistry.put(id, item); } - private void reopenItemRegistry() { - ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> { - ReflectUtil.setFieldValue("frozen", false); - ReflectUtil.setFieldValue("unregisteredIntrusiveHolders", new IdentityHashMap<>()); - }); - } - private void overrideItemRegistryEntry(String id, Item item, Item override) { ResourceKey key = ResourceKey.create( BuiltInRegistries.ITEM.key(), ResourceLocation.withDefaultNamespace(id)); RegistrationInfo info = RegistrationInfo.BUILT_IN; - Holder.Reference holder = ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> { - Map> map = ReflectUtil.getFieldValue("unregisteredIntrusiveHolders"); + Holder.Reference holder = reflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> { + Map> map = reflectUtil.getFieldValue("unregisteredIntrusiveHolders"); return map.get(item); }); - ReflectUtil.reflect(Holder.Reference.class, holder, () -> { - ReflectUtil.invokeMethod("bindKey", new Class[] {ResourceKey.class}, key); + reflectUtil.reflect(Holder.Reference.class, holder, () -> { + reflectUtil.invokeMethod("bindKey", new Class[] {ResourceKey.class}, key); }); - ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> { - HashMap, Holder.Reference> byKey = ReflectUtil.getFieldValue("byKey"); + reflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> { + HashMap, Holder.Reference> byKey = reflectUtil.getFieldValue("byKey"); byKey.put(key, holder); - HashMap> byLocation = ReflectUtil.getFieldValue("byLocation"); + HashMap> byLocation = reflectUtil.getFieldValue("byLocation"); byLocation.put(key.location(), holder); - IdentityHashMap> byValue = ReflectUtil.getFieldValue("byValue"); + IdentityHashMap> byValue = reflectUtil.getFieldValue("byValue"); byValue.put(item, holder); - ObjectArrayList> byId = ReflectUtil.getFieldValue("byId"); + ObjectArrayList> byId = reflectUtil.getFieldValue("byId"); byId.set(byId.indexOf(byValue.remove(override)), holder); - Reference2IntOpenHashMap toId = ReflectUtil.getFieldValue("toId"); + Reference2IntOpenHashMap toId = reflectUtil.getFieldValue("toId"); toId.put(item, toId.getInt(override)); toId.removeInt(override); - IdentityHashMap, RegistrationInfo> registrationInfos = ReflectUtil.getFieldValue("registrationInfos"); + IdentityHashMap, RegistrationInfo> registrationInfos = reflectUtil.getFieldValue("registrationInfos"); registrationInfos.put(key, info); - Lifecycle lifecycle = ReflectUtil.getFieldValue("registryLifecycle"); - ReflectUtil.setFieldValue("registryLifecycle", lifecycle.add(info.lifecycle())); + Lifecycle lifecycle = reflectUtil.getFieldValue("registryLifecycle"); + reflectUtil.setFieldValue("registryLifecycle", lifecycle.add(info.lifecycle())); - Map> unregisteredHolders = ReflectUtil.getFieldValue("unregisteredIntrusiveHolders"); + Map> unregisteredHolders = reflectUtil.getFieldValue("unregisteredIntrusiveHolders"); unregisteredHolders.remove(item); }); } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/items/nms/CustomCrossbow.java b/src/main/java/net/slqmy/firework_wars_plugin/items/nms/CustomCrossbow.java index 58ceb09f..a88d5e09 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/items/nms/CustomCrossbow.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/items/nms/CustomCrossbow.java @@ -2,14 +2,19 @@ import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.component.DataComponents; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CrossbowItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.component.ChargedProjectiles; -import net.slqmy.firework_wars_plugin.items.manager.AbstractItem; +import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; +import net.slqmy.firework_wars_plugin.util.Keys; +import net.slqmy.firework_wars_plugin.util.PersistentDataManager; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.meta.ItemMeta; +import java.util.UUID; import java.util.function.Predicate; @MethodsReturnNonnullByDefault @@ -20,21 +25,67 @@ public class CustomCrossbow extends CrossbowItem { .durability(465) .component(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY); - private final AbstractItem ammoItem; - - public CustomCrossbow(Item.Properties settings, AbstractItem ammoItem) { + public CustomCrossbow(Item.Properties settings) { super(settings); - - this.ammoItem = ammoItem; } @Override public Predicate getAllSupportedProjectiles() { - return (item) -> ammoItem.isValidCustomItem(item.asBukkitCopy()); + return this::isValidAmmoItem; } @Override public Predicate getSupportedHeldProjectiles() { - return getAllSupportedProjectiles(); + return this.getAllSupportedProjectiles(); + } + + @SuppressWarnings("UnstableApiUsage") + private boolean isValidAmmoItem(ItemStack stack) { + FireworkWarsPlugin plugin = FireworkWarsPlugin.getInstance(); + + if (plugin == null) { + Bukkit.getLogger().severe("Failed to get FireworkWars plugin instance!"); + return super.getAllSupportedProjectiles().test(stack); + } + + PersistentDataManager pdcManager = plugin.getPdcManager(); + + org.bukkit.inventory.ItemStack bukkitStack = stack.asBukkitCopy(); + ItemMeta meta = bukkitStack.getItemMeta(); + + if (meta == null) { + return false; + } + + if (!pdcManager.hasKey(meta, Keys.ITEM_OWNER_UUID)) { + return false; + } + + if (!pdcManager.hasKey(meta, Keys.CUSTOM_ITEM_ID)) { + return false; + } + + UUID ownerUUID = UUID.fromString(pdcManager.getStringValue(meta, Keys.ITEM_OWNER_UUID)); + Player owner = plugin.getServer().getPlayer(ownerUUID); + assert owner != null; + + org.bukkit.inventory.ItemStack mainHandItem = owner.getInventory().getItemInMainHand(); + org.bukkit.inventory.ItemStack offHandItem = owner.getInventory().getItemInOffHand(); + + String ammoId = pdcManager.getStringValue(meta, Keys.CUSTOM_ITEM_ID); + + if (!mainHandItem.isEmpty() && toNMS(mainHandItem).is(this)) { + String acceptedAmmoId = pdcManager.getStringValue(mainHandItem.getItemMeta(), Keys.GUN_ACCEPTED_AMMO_ID); + return ammoId.equals(acceptedAmmoId); + } else if (!offHandItem.isEmpty() && toNMS(offHandItem).is(this)) { + String acceptedAmmoId = pdcManager.getStringValue(offHandItem.getItemMeta(), Keys.GUN_ACCEPTED_AMMO_ID); + return ammoId.equals(acceptedAmmoId); + } else { + return false; + } + } + + private ItemStack toNMS(org.bukkit.inventory.ItemStack stack) { + return CraftItemStack.asNMSCopy(stack); } } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/language/Message.java b/src/main/java/net/slqmy/firework_wars_plugin/language/Message.java index 41e65008..32c2c3e9 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/language/Message.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/language/Message.java @@ -9,6 +9,11 @@ public enum Message { FIREWORK_RIFLE_AMMO, FIREWORK_RIFLE_AMMO_LORE, + FIREWORK_SHOTGUN, + FIREWORK_SHOTGUN_LORE, + FIREWORK_SHOTGUN_AMMO, + FIREWORK_SHOTGUN_AMMO_LORE, + GAME_STARTING_IN_TIME_PLURAL, GAME_STARTING_IN_TIME_SINGULAR, diff --git a/src/main/java/net/slqmy/firework_wars_plugin/util/Keys.java b/src/main/java/net/slqmy/firework_wars_plugin/util/Keys.java new file mode 100644 index 00000000..a5c07bdd --- /dev/null +++ b/src/main/java/net/slqmy/firework_wars_plugin/util/Keys.java @@ -0,0 +1,15 @@ +package net.slqmy.firework_wars_plugin.util; + +import org.bukkit.NamespacedKey; + +public final class Keys { + public static final NamespacedKey CUSTOM_ITEM_ID = fromString("custom_item_id"); + public static final NamespacedKey ITEM_OWNER_UUID = fromString("item_owner_uuid"); + public static final NamespacedKey GUN_ACCEPTED_AMMO_ID = fromString("gun_accepted_ammo_id"); + + private Keys() {} + + public static NamespacedKey fromString(String key) { + return new NamespacedKey("firework_wars_plugin", key); + } +} diff --git a/src/main/java/net/slqmy/firework_wars_plugin/util/PersistentDataManager.java b/src/main/java/net/slqmy/firework_wars_plugin/util/PersistentDataManager.java index 5b940eea..b5eb9c08 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/util/PersistentDataManager.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/util/PersistentDataManager.java @@ -1,6 +1,5 @@ package net.slqmy.firework_wars_plugin.util; -import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; import org.bukkit.NamespacedKey; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataHolder; @@ -8,12 +7,6 @@ @SuppressWarnings("unused") public class PersistentDataManager { - private final FireworkWarsPlugin plugin; - - public PersistentDataManager(FireworkWarsPlugin plugin) { - this.plugin = plugin; - } - public boolean hasKey(PersistentDataHolder holder, NamespacedKey key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); return pdc.has(key); @@ -21,7 +14,7 @@ public boolean hasKey(PersistentDataHolder holder, NamespacedKey key) { public boolean hasKey(PersistentDataHolder holder, String key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - return pdc.has(this.fromString(key)); + return pdc.has(Keys.fromString(key)); } public String getStringValue(PersistentDataHolder holder, NamespacedKey key) { @@ -31,7 +24,7 @@ public String getStringValue(PersistentDataHolder holder, NamespacedKey key) { public String getStringValue(PersistentDataHolder holder, String key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - return pdc.get(this.fromString(key), PersistentDataType.STRING); + return pdc.get(Keys.fromString(key), PersistentDataType.STRING); } public Boolean getBooleanValue(PersistentDataHolder holder, NamespacedKey key) { @@ -41,7 +34,7 @@ public Boolean getBooleanValue(PersistentDataHolder holder, NamespacedKey key) { public Boolean getBooleanValue(PersistentDataHolder holder, String key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - return pdc.get(this.fromString(key), PersistentDataType.BOOLEAN); + return pdc.get(Keys.fromString(key), PersistentDataType.BOOLEAN); } public Integer getIntValue(PersistentDataHolder holder, NamespacedKey key) { @@ -51,7 +44,7 @@ public Integer getIntValue(PersistentDataHolder holder, NamespacedKey key) { public Integer getIntValue(PersistentDataHolder holder, String key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - return pdc.get(this.fromString(key), PersistentDataType.INTEGER); + return pdc.get(Keys.fromString(key), PersistentDataType.INTEGER); } public int[] getIntListValue(PersistentDataHolder holder, NamespacedKey key) { @@ -61,7 +54,7 @@ public int[] getIntListValue(PersistentDataHolder holder, NamespacedKey key) { public int[] getIntListValue(PersistentDataHolder holder, String key) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - return pdc.get(this.fromString(key), PersistentDataType.INTEGER_ARRAY); + return pdc.get(Keys.fromString(key), PersistentDataType.INTEGER_ARRAY); } public void setStringValue(PersistentDataHolder holder, NamespacedKey key, String value) { @@ -71,7 +64,7 @@ public void setStringValue(PersistentDataHolder holder, NamespacedKey key, Strin public void setStringValue(PersistentDataHolder holder, String key, String value) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - pdc.set(fromString(key), PersistentDataType.STRING, value); + pdc.set(Keys.fromString(key), PersistentDataType.STRING, value); } public void setBooleanValue(PersistentDataHolder holder, NamespacedKey key, Boolean value) { @@ -81,7 +74,7 @@ public void setBooleanValue(PersistentDataHolder holder, NamespacedKey key, Bool public void setBooleanValue(PersistentDataHolder holder, String key, Boolean value) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - pdc.set(fromString(key), PersistentDataType.BOOLEAN, value); + pdc.set(Keys.fromString(key), PersistentDataType.BOOLEAN, value); } public void setIntValue(PersistentDataHolder holder, NamespacedKey key, Integer value) { @@ -91,7 +84,7 @@ public void setIntValue(PersistentDataHolder holder, NamespacedKey key, Integer public void setIntValue(PersistentDataHolder holder, String key, Integer value) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - pdc.set(fromString(key), PersistentDataType.INTEGER, value); + pdc.set(Keys.fromString(key), PersistentDataType.INTEGER, value); } public void setIntListValue(PersistentDataHolder holder, NamespacedKey key, int[] value) { @@ -101,10 +94,6 @@ public void setIntListValue(PersistentDataHolder holder, NamespacedKey key, int[ public void setIntListValue(PersistentDataHolder holder, String key, int[] value) { PersistentDataContainer pdc = holder.getPersistentDataContainer(); - pdc.set(fromString(key), PersistentDataType.INTEGER_ARRAY, value); - } - - private NamespacedKey fromString(String key) { - return new NamespacedKey(plugin, key); + pdc.set(Keys.fromString(key), PersistentDataType.INTEGER_ARRAY, value); } } diff --git a/src/main/java/net/slqmy/firework_wars_plugin/util/ReflectUtil.java b/src/main/java/net/slqmy/firework_wars_plugin/util/ReflectUtil.java index 565367f7..e62c4b7d 100644 --- a/src/main/java/net/slqmy/firework_wars_plugin/util/ReflectUtil.java +++ b/src/main/java/net/slqmy/firework_wars_plugin/util/ReflectUtil.java @@ -1,7 +1,7 @@ package net.slqmy.firework_wars_plugin.util; +import net.kyori.adventure.text.logger.slf4j.ComponentLogger; import net.minecraft.MethodsReturnNonnullByDefault; -import net.slqmy.firework_wars_plugin.FireworkWarsPlugin; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -10,24 +10,29 @@ @MethodsReturnNonnullByDefault @SuppressWarnings("unused") public final class ReflectUtil { - private static boolean reflecting; + private boolean reflecting; + private ComponentLogger logger; - private static Class clazz; - private static Object instance; + private Class clazz; + private Object instance; - public static Field getField(Class clazz, String fieldName) { + public void useLogger(ComponentLogger logger) { + this.logger = logger; + } + + public Field getField(Class clazz, String fieldName) { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (NoSuchFieldException e) { - FireworkWarsPlugin.LOGGER.warning("Failed to get field:" + e.getMessage()); + logger.error("Failed to get field:" + e.getMessage()); } throw new RuntimeException("Failed to get field!"); } - public static Field getField(String fieldName) { + public Field getField(String fieldName) { if (!reflecting) { throw new IllegalStateException("Cannot get field without class context outside a reflection function!"); } @@ -36,17 +41,17 @@ public static Field getField(String fieldName) { } @SuppressWarnings("unchecked") - public static T getFieldValue(Field field, Object instance) { + public T getFieldValue(Field field, Object instance) { try { return (T) field.get(instance); } catch (IllegalAccessException e) { - FireworkWarsPlugin.LOGGER.warning("Failed to get field value:" + e.getMessage()); + logger.error("Failed to get field value:" + e.getMessage()); } throw new RuntimeException("Failed to get field value!"); } - public static T getFieldValue(Field field) { + public T getFieldValue(Field field) { if (!reflecting) { throw new IllegalStateException("Cannot get field value without class context outside a reflection function!"); } @@ -54,12 +59,12 @@ public static T getFieldValue(Field field) { return getFieldValue(field, instance); } - public static T getFieldValue(Class clazz, String fieldName, Object instance) { + public T getFieldValue(Class clazz, String fieldName, Object instance) { Field field = getField(clazz, fieldName); return getFieldValue(field, instance); } - public static T getFieldValue(String fieldName) { + public T getFieldValue(String fieldName) { if (!reflecting) { throw new IllegalStateException("Cannot get field value without class context outside a reflection function!"); } @@ -67,15 +72,15 @@ public static T getFieldValue(String fieldName) { return getFieldValue(clazz, fieldName, instance); } - public static void setFieldValue(Field field, Object instance, Object value) { + public void setFieldValue(Field field, Object instance, Object value) { try { field.set(instance, value); } catch (IllegalAccessException e) { - FireworkWarsPlugin.LOGGER.warning("Failed to set field value:" + e.getMessage()); + logger.error("Failed to set field value:" + e.getMessage()); } } - public static void setFieldValue(Field field, Object value) { + public void setFieldValue(Field field, Object value) { if (!reflecting) { throw new IllegalStateException("Cannot set field value without class context outside a reflection function!"); } @@ -83,12 +88,12 @@ public static void setFieldValue(Field field, Object value) { setFieldValue(field, instance, value); } - public static void setFieldValue(Class clazz, String fieldName, Object instance, Object value) { + public void setFieldValue(Class clazz, String fieldName, Object instance, Object value) { Field field = getField(clazz, fieldName); setFieldValue(field, instance, value); } - public static void setFieldValue(String fieldName, Object value) { + public void setFieldValue(String fieldName, Object value) { if (!reflecting) { throw new IllegalStateException("Cannot set field value without class context outside a reflection function!"); } @@ -96,19 +101,53 @@ public static void setFieldValue(String fieldName, Object value) { setFieldValue(clazz, fieldName, instance, value); } - public static Method getMethod(Class clazz, String methodName, Class... parameterTypes) { + public void setFinalFieldValue(Field field, Object instance, Object value) { + try { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~java.lang.reflect.Modifier.FINAL); + + field.set(instance, value); + modifiersField.setInt(field, field.getModifiers() | java.lang.reflect.Modifier.FINAL); + } catch (IllegalAccessException | NoSuchFieldException e) { + logger.error("Failed to set final field value:" + e.getMessage()); + } + } + + public void setFinalFieldValue(Field field, Object value) { + if (!reflecting) { + throw new IllegalStateException("Cannot set final field value without class context outside a reflection function!"); + } + + setFinalFieldValue(field, instance, value); + } + + public void setFinalFieldValue(Class clazz, String fieldName, Object instance, Object value) { + Field field = getField(clazz, fieldName); + setFinalFieldValue(field, instance, value); + } + + public void setFinalFieldValue(String fieldName, Object value) { + if (!reflecting) { + throw new IllegalStateException("Cannot set final field value without class context outside a reflection function!"); + } + + setFinalFieldValue(clazz, fieldName, instance, value); + } + + public Method getMethod(Class clazz, String methodName, Class... parameterTypes) { try { Method method = clazz.getDeclaredMethod(methodName, parameterTypes); method.setAccessible(true); return method; } catch (NoSuchMethodException e) { - FireworkWarsPlugin.LOGGER.warning("Failed to get method:" + e.getMessage()); + logger.error("Failed to get method:" + e.getMessage()); } throw new RuntimeException("Failed to get method!"); } - public static Method getMethod(String methodName, Class... parameterTypes) { + public Method getMethod(String methodName, Class... parameterTypes) { if (!reflecting) { throw new IllegalStateException("Cannot get method without class context outside a reflection function!"); } @@ -117,17 +156,17 @@ public static Method getMethod(String methodName, Class... parameterTypes) { } @SuppressWarnings("unchecked") - public static T invokeMethod(Method method, Object instance, Object... args) { + public T invokeMethod(Method method, Object instance, Object... args) { try { return (T) method.invoke(instance, args); } catch (Exception e) { - FireworkWarsPlugin.LOGGER.warning("Failed to invoke method:" + e.getMessage()); + logger.error("Failed to invoke method:" + e.getMessage()); } throw new RuntimeException("Failed to invoke method!"); } - public static T invokeMethod(Method method, Object... args) { + public T invokeMethod(Method method, Object... args) { if (!reflecting) { throw new IllegalStateException("Cannot invoke method without class context outside a reflection function!"); } @@ -135,12 +174,12 @@ public static T invokeMethod(Method method, Object... args) { return invokeMethod(method, instance, args); } - public static T invokeMethod(Class clazz, String methodName, Class[] parameterTypes, Object instance, Object... args) { + public T invokeMethod(Class clazz, String methodName, Class[] parameterTypes, Object instance, Object... args) { Method method = getMethod(clazz, methodName, parameterTypes); return invokeMethod(method, instance, args); } - public static T invokeMethod(String methodName, Class[] parameterTypes, Object... args) { + public T invokeMethod(String methodName, Class[] parameterTypes, Object... args) { if (!reflecting) { throw new IllegalStateException("Cannot invoke method without class context outside a reflection function!"); } @@ -148,28 +187,28 @@ public static T invokeMethod(String methodName, Class[] parameterTypes, O return invokeMethod(clazz, methodName, parameterTypes, instance, args); } - public static void reflect(Class clazz, Object instance, Runnable runnable) { - ReflectUtil.reflecting = true; - ReflectUtil.clazz = clazz; - ReflectUtil.instance = instance; + public void reflect(Class clazz, Object instance, Runnable runnable) { + reflecting = true; + this.clazz = clazz; + this.instance = instance; runnable.run(); - ReflectUtil.reflecting = false; - ReflectUtil.clazz = null; - ReflectUtil.instance = null; + reflecting = false; + this.clazz = null; + this.instance = null; } - public static T reflect(Class clazz, Object instance, Supplier supplier) { - ReflectUtil.reflecting = true; - ReflectUtil.clazz = clazz; - ReflectUtil.instance = instance; + public T reflect(Class clazz, Object instance, Supplier supplier) { + reflecting = true; + this.clazz = clazz; + this.instance = instance; T value = supplier.get(); - ReflectUtil.reflecting = false; - ReflectUtil.clazz = null; - ReflectUtil.instance = null; + reflecting = false; + this.clazz = null; + this.instance = null; return value; } diff --git a/src/main/resources/languages/English (United Kingdom).yaml b/src/main/resources/languages/English (United Kingdom).yaml index 5c5e9c14..57e843cd 100644 --- a/src/main/resources/languages/English (United Kingdom).yaml +++ b/src/main/resources/languages/English (United Kingdom).yaml @@ -2,12 +2,17 @@ SET_LANGUAGE_SUCCESSFULLY: "Successfully set your language to {0} UNKNOWN_LANGUAGE: "Unsupported or unknown language: '{0}'." FIREWORK_RIFLE: "Firework Rifle" -FIREWORK_RIFLE_LORE: "High range, fast and powerful. Shoots one firework at a time." +FIREWORK_RIFLE_LORE: "High range, fast and powerful.\nShoots one firework at a time." FIREWORK_RIFLE_AMMO: "Rifle Ammo" FIREWORK_RIFLE_AMMO_LORE: "1x rifle ammo" +FIREWORK_SHOTGUN: "Firework Shotgun" +FIREWORK_SHOTGUN_LORE: "Extremely powerful at short range.\nShoots 4 fireworks at a time." +FIREWORK_SHOTGUN_AMMO: "Shotgun Ammo" +FIREWORK_SHOTGUN_AMMO_LORE: "1x shotgun ammo" + GAME_STARTING_IN_TIME_PLURAL: "The game will start in {0} seconds." GAME_STARTING_IN_TIME_SINGULAR: "The game will start in {0} second." -TEAM_ELIMINATED: "{0} has been elimenated!" +TEAM_ELIMINATED: "{0} has been eliminated!" TEAM_WON: "{0} has won the game!" diff --git a/src/main/resources/languages/English (United States).yaml b/src/main/resources/languages/English (United States).yaml index 851229e3..d96d6e78 100644 --- a/src/main/resources/languages/English (United States).yaml +++ b/src/main/resources/languages/English (United States).yaml @@ -7,5 +7,5 @@ FIREWORK_RIFLE_LORE: "High range, fast and powerful. Shoots one firework a GAME_STARTING_IN_TIME_PLURAL: "The game will start in {0} seconds." GAME_STARTING_IN_TIME_SINGULAR: "The game will start in {0} second." -TEAM_ELIMENATED: "{0} has been elimenated!" +TEAM_ELIMINATED: "{0} has been eliminated!" TEAM_WON: "{0} has won the game!"