From 1e4178755f6b4b6a31be5b34617d1e46119a636b Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Tue, 18 Apr 2023 13:45:45 -0400 Subject: [PATCH 1/5] Cool skill --- src/main/java/com/volmit/adapt/Adapt.java | 5 + .../adapt/content/adaptation/axe/AxeChop.java | 1 - .../excavation/ExcavationSpelunker.java | 469 +++++++++ .../adapt/content/item/ItemListings.java | 72 ++ .../adapt/content/skill/SkillExcavation.java | 2 + .../com/volmit/adapt/nms/GlowingEntities.java | 941 ++++++++++++++++++ .../java/com/volmit/adapt/nms/NMS_1_19_4.java | 2 + src/main/resources/en_US.json | 8 + 8 files changed, 1499 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java create mode 100644 src/main/java/com/volmit/adapt/nms/GlowingEntities.java diff --git a/src/main/java/com/volmit/adapt/Adapt.java b/src/main/java/com/volmit/adapt/Adapt.java index 88b94b55..af46875b 100644 --- a/src/main/java/com/volmit/adapt/Adapt.java +++ b/src/main/java/com/volmit/adapt/Adapt.java @@ -29,6 +29,7 @@ import com.volmit.adapt.content.gui.SkillsGui; import com.volmit.adapt.content.protector.FactionsClaimProtector; import com.volmit.adapt.content.protector.WorldGuardProtector; +import com.volmit.adapt.nms.GlowingEntities; import com.volmit.adapt.nms.NMS; import com.volmit.adapt.util.*; import com.volmit.adapt.util.secret.SecretSplash; @@ -62,6 +63,8 @@ public class Adapt extends VolmitPlugin { private final CommandAdapt commandAdapt = new CommandAdapt(); public boolean usingMagicCosmetics = Bukkit.getServer().getPluginManager().getPlugin("MagicCosmetics") != null; @Getter + private GlowingEntities glowingEntities; + @Getter private Ticker ticker; @Getter private AdaptServer adaptServer; @@ -73,6 +76,7 @@ public class Adapt extends VolmitPlugin { @Getter private Map guiLeftovers = new HashMap<>(); + public Adapt() { super(); @@ -253,6 +257,7 @@ public void start() { if (getServer().getPluginManager().getPlugin("Factions") != null) { protectorRegistry.registerProtector(new FactionsClaimProtector()); } + glowingEntities = new GlowingEntities(this); } @Override diff --git a/src/main/java/com/volmit/adapt/content/adaptation/axe/AxeChop.java b/src/main/java/com/volmit/adapt/content/adaptation/axe/AxeChop.java index 534874dd..e73e560f 100644 --- a/src/main/java/com/volmit/adapt/content/adaptation/axe/AxeChop.java +++ b/src/main/java/com/volmit/adapt/content/adaptation/axe/AxeChop.java @@ -110,7 +110,6 @@ private boolean breakStuff(Block b, int power, Player player) { b.getWorld().playSound(ll.getLocation(), Sound.ITEM_AXE_STRIP, 0.75f, 1.3f); player.breakBlock(ll); -// ll.breakNaturally(); return true; } diff --git a/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java b/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java new file mode 100644 index 00000000..6a4922e1 --- /dev/null +++ b/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java @@ -0,0 +1,469 @@ +/*------------------------------------------------------------------------------ + - Adapt is a Skill/Integration plugin for Minecraft Bukkit Servers + - Copyright (c) 2022 Arcane Arts (Volmit Software) + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation, either version 3 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see . + -----------------------------------------------------------------------------*/ + +package com.volmit.adapt.content.adaptation.excavation; + +import com.volmit.adapt.Adapt; +import com.volmit.adapt.api.adaptation.SimpleAdaptation; +import com.volmit.adapt.api.recipe.AdaptRecipe; +import com.volmit.adapt.content.item.ItemListings; +import com.volmit.adapt.nms.GlowingEntities; +import com.volmit.adapt.util.C; +import com.volmit.adapt.util.Element; +import com.volmit.adapt.util.J; +import com.volmit.adapt.util.Localizer; +import lombok.NoArgsConstructor; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.Map; + +public class ExcavationSpelunker extends SimpleAdaptation { + private final Map cooldowns; + + public ExcavationSpelunker() { + super("excavation-spelunker"); + registerConfiguration(ExcavationSpelunker.Config.class); + setDisplayName(Localizer.dLocalize("excavation", "spelunker", "name")); + setDescription(Localizer.dLocalize("excavation", "spelunker", "description")); + setIcon(Material.GOLDEN_HELMET); + setInterval(20388); + setBaseCost(getConfig().baseCost); + setMaxLevel(getConfig().maxLevel); + setInitialCost(getConfig().initialCost); + setCostFactor(getConfig().costFactor); + // Use Stone as base + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-iron-ore") + .ingredient(Material.STONE) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .result(new ItemStack(Material.IRON_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-gold-ore") + .ingredient(Material.STONE) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-copper-ore") + .ingredient(Material.STONE) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .result(new ItemStack(Material.COPPER_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-lapis-ore") + .ingredient(Material.STONE) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .result(new ItemStack(Material.LAPIS_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-redstone-ore") + .ingredient(Material.STONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .result(new ItemStack(Material.REDSTONE_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-emerald-ore") + .ingredient(Material.STONE) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .result(new ItemStack(Material.EMERALD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-diamond-ore") + .ingredient(Material.STONE) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .result(new ItemStack(Material.DIAMOND_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-coal-ore") + .ingredient(Material.STONE) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .result(new ItemStack(Material.COAL_ORE)) + .build()); + + // Use Deepslate + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-iron-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .result(new ItemStack(Material.DEEPSLATE_IRON_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-gold-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.DEEPSLATE_GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-copper-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .result(new ItemStack(Material.DEEPSLATE_COPPER_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-lapis-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .result(new ItemStack(Material.DEEPSLATE_LAPIS_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-redstone-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .result(new ItemStack(Material.DEEPSLATE_REDSTONE_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-emerald-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .result(new ItemStack(Material.DEEPSLATE_EMERALD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-diamond-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .result(new ItemStack(Material.DEEPSLATE_DIAMOND_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-deepslate-coal-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .result(new ItemStack(Material.DEEPSLATE_COAL_ORE)) + .build()); + +// Use Nether Bricks + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-nether-gold-ore") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.NETHER_GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-nether-quartz-ore") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .result(new ItemStack(Material.NETHER_QUARTZ_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("spelunker-ancient-debris") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .result(new ItemStack(Material.ANCIENT_DEBRIS)) + .build()); + cooldowns = new HashMap<>(); + + } + + @Override + public void addStats(int level, Element v) { + v.addLore(C.GREEN + Localizer.dLocalize("excavation", "spelunker", "lore1")); + v.addLore(C.YELLOW + Localizer.dLocalize("excavation", "spelunker", "lore2") + getConfig().rangeMultiplier * level); + v.addLore(C.YELLOW + Localizer.dLocalize("excavation", "spelunker", "lore3")); + v.addLore(C.BOLD + Localizer.dLocalize("excavation", "spelunker", "lore4")); + } + + @EventHandler(priority = EventPriority.HIGH) + public void on(PlayerToggleSneakEvent e) { + Player p = e.getPlayer(); + // Check if player is sneaking, has Glowberries in main hand, and an ore in offhand + if (p.isSneaking() && hasGlowberries(p) && hasOreInOffhand(p) && hasAdaptation(p)) { + // Check if player is on cooldown + if (cooldowns.containsKey(p)) { + if (cooldowns.get(p) > System.currentTimeMillis()) { + p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1); + return; + } + } + int radius = getConfig().rangeMultiplier * getLevel(p); + consumeGlowberry(p); + searchForOres(p, radius); + cooldowns.put(p, (long) (System.currentTimeMillis() + (1000 * getConfig().cooldown))); + } + } + + private boolean hasGlowberries(Player player) { + return player.getInventory().getItemInMainHand().getType() == Material.GLOW_BERRIES; + } + + private void consumeGlowberry(Player player) { + ItemStack berries = player.getInventory().getItemInMainHand(); + berries.setAmount(berries.getAmount() - 1); + player.getInventory().setItemInMainHand(berries); + } + + private boolean hasOreInOffhand(Player player) { + Material offhandType = player.getInventory().getItemInOffHand().getType(); + return ItemListings.ores.contains(offhandType); + } + + private void searchForOres(Player p, int radius) { + Location playerLocation = p.getLocation(); + World world = p.getWorld(); + Material targetOre = p.getInventory().getItemInOffHand().getType(); + ChatColor c = ItemListings.oreColorsChatColor.get(targetOre); + Particle.DustOptions dustOptions = new Particle.DustOptions(Color.WHITE, 1); + J.a(() -> { + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + for (int z = -radius; z <= radius; z++) { + if (x * x + y * y + z * z <= radius * radius) { + Location blockLocation = playerLocation.clone().add(x, y, z); + Block block = world.getBlockAt(blockLocation); + GlowingEntities glowingEntities = Adapt.instance.getGlowingEntities(); + + + if (block.getType() == targetOre) { + // Raytrace particles from player to the found ore + Vector vector = blockLocation.clone().subtract(playerLocation).toVector().normalize().multiply(0.5); + Location particleLocation = playerLocation.clone(); + + while (particleLocation.distance(blockLocation) > 0.5) { + particleLocation.add(vector); + J.s(() -> { + p.spawnParticle(Particle.REDSTONE, particleLocation, 1, dustOptions); + }); + } + + J.s(() -> { + + world.playSound(block.getLocation().add(0.5, 0, 0.5), Sound.BLOCK_BEACON_ACTIVATE, 1, 1); + Slime slime = block.getWorld().spawn(block.getLocation().add(0.5, 0, 0.5), Slime.class, (s) -> { + s.setRotation(0, 0); + s.setInvulnerable(true); + s.setCollidable(false); + s.setGravity(false); + s.setSilent(true); + s.setAI(false); + s.setSize(2); + s.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + s.setMetadata("preventSuffocation", new FixedMetadataValue(Adapt.instance, true)); + }); + + try { + glowingEntities.setGlowing(slime, p, c); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + + J.s(() -> { + try { + glowingEntities.unsetGlowing(slime, p); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + + slime.remove(); + }, 5 * 20); + }); + + } + } + } + } + } + }); + } + + + @EventHandler + public void onEntityDamage(EntityDamageEvent e) { + if (e.getEntity() instanceof Slime && e.getCause() == EntityDamageEvent.DamageCause.SUFFOCATION) { + Slime slime = (Slime) e.getEntity(); + if (slime.hasMetadata("preventSuffocation")) { + e.setCancelled(true); + } else { + e.setCancelled(true); + slime.remove(); + } + } + } + + + @Override + public boolean isEnabled() { + return getConfig().enabled; + } + + + @Override + public void onTick() { + } + + @Override + public boolean isPermanent() { + return getConfig().permanent; + } + + @NoArgsConstructor + protected static class Config { + boolean permanent = false; + boolean enabled = true; + double cooldown =6.0; + int baseCost = 3; + int initialCost = 3; + double costFactor = 0.3; + int maxLevel = 5; + int rangeMultiplier = 5; + } +} diff --git a/src/main/java/com/volmit/adapt/content/item/ItemListings.java b/src/main/java/com/volmit/adapt/content/item/ItemListings.java index 8f05177a..45785a58 100644 --- a/src/main/java/com/volmit/adapt/content/item/ItemListings.java +++ b/src/main/java/com/volmit/adapt/content/item/ItemListings.java @@ -18,10 +18,13 @@ package com.volmit.adapt.content.item; +import com.volmit.adapt.util.C; import lombok.Getter; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.EntityType; +import java.util.HashMap; import java.util.List; public class ItemListings { @@ -68,6 +71,75 @@ public class ItemListings { Material.DEEPSLATE_COPPER_ORE ); + @Getter + public static List ores = List.of( + Material.IRON_ORE, + Material.GOLD_ORE, + Material.COPPER_ORE, + Material.LAPIS_ORE, + Material.REDSTONE_ORE, + Material.EMERALD_ORE, + Material.DIAMOND_ORE, + Material.COAL_ORE, + Material.DEEPSLATE_IRON_ORE, + Material.DEEPSLATE_GOLD_ORE, + Material.DEEPSLATE_COPPER_ORE, + Material.DEEPSLATE_LAPIS_ORE, + Material.DEEPSLATE_REDSTONE_ORE, + Material.DEEPSLATE_EMERALD_ORE, + Material.DEEPSLATE_DIAMOND_ORE, + Material.DEEPSLATE_COAL_ORE, + Material.NETHER_GOLD_ORE, + Material.NETHER_QUARTZ_ORE, + Material.ANCIENT_DEBRIS + ); + + @Getter + public static HashMap oreColorsChatColor = new HashMap<>() {{ + put(Material.IRON_ORE, ChatColor.GRAY); + put(Material.GOLD_ORE, ChatColor.YELLOW); + put(Material.COPPER_ORE, ChatColor.GOLD); + put(Material.LAPIS_ORE, ChatColor.BLUE); + put(Material.REDSTONE_ORE, ChatColor.RED); + put(Material.EMERALD_ORE, ChatColor.GREEN); + put(Material.DIAMOND_ORE, ChatColor.AQUA); + put(Material.COAL_ORE, ChatColor.DARK_GRAY); + put(Material.DEEPSLATE_IRON_ORE, ChatColor.GRAY); + put(Material.DEEPSLATE_GOLD_ORE, ChatColor.YELLOW); + put(Material.DEEPSLATE_COPPER_ORE, ChatColor.GOLD); + put(Material.DEEPSLATE_LAPIS_ORE, ChatColor.BLUE); + put(Material.DEEPSLATE_REDSTONE_ORE, ChatColor.RED); + put(Material.DEEPSLATE_EMERALD_ORE, ChatColor.GREEN); + put(Material.DEEPSLATE_DIAMOND_ORE, ChatColor.AQUA); + put(Material.DEEPSLATE_COAL_ORE, ChatColor.DARK_GRAY); + put(Material.NETHER_GOLD_ORE, ChatColor.YELLOW); + put(Material.NETHER_QUARTZ_ORE, ChatColor.WHITE); + put(Material.ANCIENT_DEBRIS, ChatColor.DARK_PURPLE); + }}; + + @Getter + public static HashMap oreColorColor = new HashMap<>() {{ + put(Material.IRON_ORE, C.GRAY); + put(Material.GOLD_ORE, C.YELLOW); + put(Material.COPPER_ORE, C.GOLD); + put(Material.LAPIS_ORE, C.BLUE); + put(Material.REDSTONE_ORE, C.RED); + put(Material.EMERALD_ORE, C.GREEN); + put(Material.DIAMOND_ORE, C.AQUA); + put(Material.COAL_ORE, C.DARK_GRAY); + put(Material.DEEPSLATE_IRON_ORE, C.GRAY); + put(Material.DEEPSLATE_GOLD_ORE, C.YELLOW); + put(Material.DEEPSLATE_COPPER_ORE, C.GOLD); + put(Material.DEEPSLATE_LAPIS_ORE, C.BLUE); + put(Material.DEEPSLATE_REDSTONE_ORE, C.RED); + put(Material.DEEPSLATE_EMERALD_ORE, C.GREEN); + put(Material.DEEPSLATE_DIAMOND_ORE, C.AQUA); + put(Material.DEEPSLATE_COAL_ORE, C.DARK_GRAY); + put(Material.NETHER_GOLD_ORE, C.YELLOW); + put(Material.NETHER_QUARTZ_ORE, C.WHITE); + put(Material.ANCIENT_DEBRIS, C.DARK_PURPLE); + }}; + @Getter public static List herbalLuckSeeds = List.of( Material.MELON_SEEDS, diff --git a/src/main/java/com/volmit/adapt/content/skill/SkillExcavation.java b/src/main/java/com/volmit/adapt/content/skill/SkillExcavation.java index 9b51bd25..caed354d 100644 --- a/src/main/java/com/volmit/adapt/content/skill/SkillExcavation.java +++ b/src/main/java/com/volmit/adapt/content/skill/SkillExcavation.java @@ -26,6 +26,7 @@ import com.volmit.adapt.content.adaptation.excavation.ExcavationDropToInventory; import com.volmit.adapt.content.adaptation.excavation.ExcavationHaste; import com.volmit.adapt.content.adaptation.excavation.ExcavationOmniTool; +import com.volmit.adapt.content.adaptation.excavation.ExcavationSpelunker; import com.volmit.adapt.util.C; import com.volmit.adapt.util.Localizer; import com.volmit.adapt.util.advancements.advancement.AdvancementDisplay; @@ -56,6 +57,7 @@ public SkillExcavation() { setIcon(Material.DIAMOND_SHOVEL); cooldowns = new HashMap<>(); registerAdaptation(new ExcavationHaste()); + registerAdaptation(new ExcavationSpelunker()); registerAdaptation(new ExcavationOmniTool()); registerAdaptation(new ExcavationDropToInventory()); registerAdvancement(AdaptAdvancement.builder() diff --git a/src/main/java/com/volmit/adapt/nms/GlowingEntities.java b/src/main/java/com/volmit/adapt/nms/GlowingEntities.java new file mode 100644 index 00000000..28d8c063 --- /dev/null +++ b/src/main/java/com/volmit/adapt/nms/GlowingEntities.java @@ -0,0 +1,941 @@ +/*------------------------------------------------------------------------------ + - Adapt is a Skill/Integration plugin for Minecraft Bukkit Servers + - Copyright (c) 2022 Arcane Arts (Volmit Software) + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation, either version 3 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see . + -----------------------------------------------------------------------------*/ + +package com.volmit.adapt.nms; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import io.netty.channel.*; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +/** + * A Spigot util to easily make entities glow. + *

+ * 1.17 -> 1.19.4 + * + * @version 1.2.1 + * @author SkytAsul + */ +public class GlowingEntities implements Listener { + + private final Plugin plugin; + private Map glowing; + private boolean enabled = false; + + private int uuid; + + /** + * Initializes the Glowing API. + * + * @param plugin plugin that will be used to register the events. + */ + public GlowingEntities(Plugin plugin) { + if (!Packets.enabled) + throw new IllegalStateException( + "The Glowing Entities API is disabled. An error has occured during initialization."); + + this.plugin = plugin; + + enable(); + } + + /** + * Enables the Glowing API. + * + * @see #disable() + */ + public void enable() { + if (enabled) + throw new IllegalStateException("The Glowing Entities API has already been enabled."); + + plugin.getServer().getPluginManager().registerEvents(this, plugin); + glowing = new HashMap<>(); + uuid = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE); + enabled = true; + } + + /** + * Disables the API. + *

+ * Methods such as {@link #setGlowing(int, String, Player, ChatColor, byte)} and + * {@link #unsetGlowing(int, Player)} will no longer be usable. + * + * @see #enable() + */ + public void disable() { + if (!enabled) + return; + HandlerList.unregisterAll(this); + glowing.values().forEach(playerData -> { + try { + Packets.removePacketsHandler(playerData); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + }); + glowing = null; + uuid = 0; + enabled = false; + } + + private void ensureEnabled() { + if (!enabled) + throw new IllegalStateException("The Glowing Entities API is not enabled."); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + glowing.remove(event.getPlayer()); + } + + /** + * Make the {@link Entity} passed as a parameter glow with its default team color. + * + * @param entity entity to make glow + * @param receiver player which will see the entity glowing + * @throws ReflectiveOperationException + */ + public void setGlowing(Entity entity, Player receiver) throws ReflectiveOperationException { + setGlowing(entity, receiver, null); + } + + /** + * Make the {@link Entity} passed as a parameter glow with the specified color. + * + * @param entity entity to make glow + * @param receiver player which will see the entity glowing + * @param color color of the glowing effect + * @throws ReflectiveOperationException + */ + public void setGlowing(Entity entity, Player receiver, ChatColor color) throws ReflectiveOperationException { + String teamID = entity instanceof Player ? entity.getName() : entity.getUniqueId().toString(); + setGlowing(entity.getEntityId(), teamID, receiver, color, Packets.getEntityFlags(entity)); + } + + /** + * Make the entity with specified entity ID glow with its default team color. + * + * @param entityID entity id of the entity to make glow + * @param teamID internal string used to add the entity to a team + * @param receiver player which will see the entity glowing + * @throws ReflectiveOperationException + */ + public void setGlowing(int entityID, String teamID, Player receiver) throws ReflectiveOperationException { + setGlowing(entityID, teamID, receiver, null, (byte) 0); + } + + /** + * Make the entity with specified entity ID glow with the specified color. + * + * @param entityID entity id of the entity to make glow + * @param teamID internal string used to add the entity to a team + * @param receiver player which will see the entity glowing + * @param color color of the glowing effect + * @throws ReflectiveOperationException + */ + public void setGlowing(int entityID, String teamID, Player receiver, ChatColor color) + throws ReflectiveOperationException { + setGlowing(entityID, teamID, receiver, color, (byte) 0); + } + + /** + * Make the entity with specified entity ID glow with the specified color, and keep some flags. + * + * @param entityID entity id of the entity to make glow + * @param teamID internal string used to add the entity to a team + * @param receiver player which will see the entity glowing + * @param color color of the glowing effect + * @param otherFlags internal flags that must be kept (on fire, crouching...). See + * wiki.vg for more informations. + * @throws ReflectiveOperationException + */ + public void setGlowing(int entityID, String teamID, Player receiver, ChatColor color, byte otherFlags) + throws ReflectiveOperationException { + ensureEnabled(); + if (color != null && !color.isColor()) + throw new IllegalArgumentException("ChatColor must be a color format"); + + PlayerData playerData = glowing.get(receiver); + if (playerData == null) { + playerData = new PlayerData(this, receiver); + Packets.addPacketsHandler(playerData); + glowing.put(receiver, playerData); + } + + GlowingData glowingData = playerData.glowingDatas.get(entityID); + if (glowingData == null) { + // the player did not have datas related to the entity: we must create the glowing status + glowingData = new GlowingData(playerData, entityID, teamID, color, otherFlags); + playerData.glowingDatas.put(entityID, glowingData); + + Packets.createGlowing(glowingData); + if (color != null) + Packets.setGlowingColor(glowingData); + } else { + // the player already had datas related to the entity: we must update the glowing status + + if (Objects.equals(glowingData.color, color)) + return; // nothing changed + + if (color == null) { + Packets.removeGlowingColor(glowingData); + glowingData.color = color; // we must set the color after in order to fetch the previous team + } else { + glowingData.color = color; + Packets.setGlowingColor(glowingData); + } + } + } + + /** + * Make the {@link Entity} passed as a parameter loose its custom glowing effect. + *

+ * This has no effect on glowing status given by another plugin or vanilla behavior. + * + * @param entity entity to remove glowing effect from + * @param receiver player which will no longer see the glowing effect + * @throws ReflectiveOperationException + */ + public void unsetGlowing(Entity entity, Player receiver) throws ReflectiveOperationException { + unsetGlowing(entity.getEntityId(), receiver); + } + + /** + * Make the entity with specified entity ID passed as a parameter loose its custom glowing effect. + *

+ * This has no effect on glowing status given by another plugin or vanilla behavior. + * + * @param entityID entity id of the entity to remove glowing effect from + * @param receiver player which will no longer see the glowing effect + * @throws ReflectiveOperationException + */ + public void unsetGlowing(int entityID, Player receiver) throws ReflectiveOperationException { + ensureEnabled(); + PlayerData playerData = glowing.get(receiver); + if (playerData == null) + return; // the player do not have any entity glowing + + GlowingData glowingData = playerData.glowingDatas.remove(entityID); + if (glowingData == null) + return; // the player did not have this entity glowing + + Packets.removeGlowing(glowingData); + + if (glowingData.color != null) + Packets.removeGlowingColor(glowingData); + + /* + * if (playerData.glowingDatas.isEmpty()) { //NOSONAR // if the player do not have any other entity + * glowing, // we can safely remove all of its data to free some memory + * Packets.removePacketsHandler(playerData); glowing.remove(receiver); } + */ + // actually no, we should not remove the player datas + // as it stores which teams did it receive. + // if we do not save this information, team would be created + // twice for the player, and BungeeCord does not like that + } + + private static class PlayerData { + + final GlowingEntities instance; + final Player player; + final Map glowingDatas; + ChannelHandler packetsHandler; + EnumSet sentColors; + + PlayerData(GlowingEntities instance, Player player) { + this.instance = instance; + this.player = player; + this.glowingDatas = new HashMap<>(); + } + + } + + private static class GlowingData { + // unfortunately this cannot be a Java Record + // as the "color" field is not final + + final PlayerData player; + final int entityID; + final String teamID; + ChatColor color; + byte otherFlags; + boolean enabled; + + GlowingData(PlayerData player, int entityID, String teamID, ChatColor color, byte otherFlags) { + this.player = player; + this.entityID = entityID; + this.teamID = teamID; + this.color = color; + this.otherFlags = otherFlags; + this.enabled = true; + } + + } + + private static class Packets { + + private static final byte GLOWING_FLAG = 1 << 6; + + private static Cache packets = + CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.SECONDS).build(); + private static Object dummy = new Object(); + + private static Logger logger; + private static int version; + private static int versionMinor; + private static String cpack = Bukkit.getServer().getClass().getPackage().getName() + "."; + private static ProtocolMappings mappings; + public static boolean enabled = false; + + private static Method getHandle; + private static Method getDataWatcher; + + private static Object watcherObjectFlags; + private static Object watcherDummy; + private static Method watcherGet; + + private static Constructor watcherItemConstructor; + private static Method watcherItemObject; + private static Method watcherItemDataGet; + + private static Method watcherBCreator; + private static Method watcherBId; + private static Method watcherBSerializer; + private static Method watcherSerializerObject; + + private static Field playerConnection; + private static Method sendPacket; + private static Field networkManager; + private static Field channelField; + + private static Class packetMetadata; + private static Constructor packetMetadataConstructor; + private static Field packetMetadataEntity; + private static Field packetMetadataItems; + private static Class packetBundle; + private static Method packetBundlePackets; + + private static EnumMap teams = new EnumMap<>(ChatColor.class); + + private static Constructor createTeamPacket; + private static Constructor createTeamPacketData; + private static Constructor createTeam; + private static Object scoreboardDummy; + private static Object pushNever; + private static Method setTeamPush; + private static Method setTeamColor; + private static Method getColorConstant; + + static { + try { + logger = new Logger("GlowingEntities", null) { + @Override + public void log(LogRecord logRecord) { + logRecord.setMessage("[GlowingEntities] " + logRecord.getMessage()); + super.log(logRecord); + } + }; + logger.setParent(Bukkit.getServer().getLogger()); + logger.setLevel(Level.ALL); + + // e.g. Bukkit.getServer().getClass().getPackage().getName() -> org.bukkit.craftbukkit.v1_17_R1 + String[] versions = + Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1).split("_"); + version = Integer.parseInt(versions[1]); // 1.X + // e.g. Bukkit.getBukkitVersion() -> 1.17.1-R0.1-SNAPSHOT + versions = Bukkit.getBukkitVersion().split("-R")[0].split("\\."); + versionMinor = versions.length <= 2 ? 0 : Integer.parseInt(versions[2]); + logger.info("Found server version 1." + version + "." + versionMinor); + + mappings = ProtocolMappings.getMappings(version); + if (mappings == null) { + mappings = ProtocolMappings.values()[ProtocolMappings.values().length - 1]; + logger.warning("Loaded not matching version of the mappings for your server version (1." + version + "." + + versionMinor + ")"); + } + logger.info("Loaded mappings " + mappings.name()); + + /* Global variables */ + + Class entityClass = getNMSClass("world.entity", "Entity"); + Class entityTypesClass = getNMSClass("world.entity", "EntityTypes"); + Object markerEntity = getNMSClass("world.entity", "Marker").getDeclaredConstructors()[0] + .newInstance(getField(entityTypesClass, mappings.getMarkerTypeId(), null), null); + + getHandle = getCraftClass("entity", "CraftEntity").getDeclaredMethod("getHandle"); + getDataWatcher = entityClass.getDeclaredMethod(mappings.getWatcherAccessor()); + + /* DataWatchers */ + + Class dataWatcherClass = getNMSClass("network.syncher", "DataWatcher"); + + watcherObjectFlags = getField(entityClass, mappings.getWatcherFlags(), null); + watcherDummy = dataWatcherClass.getDeclaredConstructor(entityClass).newInstance(markerEntity); + watcherGet = version >= 18 ? dataWatcherClass.getDeclaredMethod("a", watcherObjectFlags.getClass()) + : getMethod(dataWatcherClass, "get"); + + if (version < 19 || (version == 19 && versionMinor < 3)) { + Class watcherItem = getNMSClass("network.syncher", "DataWatcher$Item"); + watcherItemConstructor = watcherItem.getDeclaredConstructor(watcherObjectFlags.getClass(), Object.class); + watcherItemObject = watcherItem.getDeclaredMethod("a"); + watcherItemDataGet = watcherItem.getDeclaredMethod("b"); + } else { + Class watcherB = getNMSClass("network.syncher", "DataWatcher$b"); + watcherBCreator = watcherB.getDeclaredMethod("a", watcherObjectFlags.getClass(), Object.class); + watcherBId = watcherB.getDeclaredMethod("a"); + watcherBSerializer = watcherB.getDeclaredMethod("b"); + watcherItemDataGet = watcherB.getDeclaredMethod("c"); + watcherSerializerObject = + getNMSClass("network.syncher", "DataWatcherSerializer").getDeclaredMethod("a", int.class); + } + + /* Connections */ + + playerConnection = + getNMSClass("server.level", "EntityPlayer").getDeclaredField(mappings.getPlayerConnection()); + sendPacket = getNMSClass("server.network", "PlayerConnection").getMethod(mappings.getSendPacket(), + getNMSClass("network.protocol", "Packet")); + networkManager = + getNMSClass("server.network", "PlayerConnection").getDeclaredField(mappings.getNetworkManager()); + networkManager.setAccessible(true); + channelField = getNMSClass("network", "NetworkManager").getDeclaredField(mappings.getChannel()); + + /* Metadata */ + + packetMetadata = getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata"); + packetMetadataEntity = getField(packetMetadata, mappings.getMetadataEntity()); + packetMetadataItems = getField(packetMetadata, mappings.getMetadataItems()); + if (version < 19 || (version == 19 && versionMinor < 3)) { + packetMetadataConstructor = + packetMetadata.getDeclaredConstructor(int.class, dataWatcherClass, boolean.class); + } else { + packetMetadataConstructor = packetMetadata.getDeclaredConstructor(int.class, List.class); + } + + if (version > 19 || (version == 19 && versionMinor >= 4)) { + packetBundle = getNMSClass("network.protocol.game", "ClientboundBundlePacket"); + packetBundlePackets = packetBundle.getMethod("a"); + } + + /* Teams */ + + Class scoreboardClass = getNMSClass("world.scores", "Scoreboard"); + Class teamClass = getNMSClass("world.scores", "ScoreboardTeam"); + Class pushClass = getNMSClass("world.scores", "ScoreboardTeamBase$EnumTeamPush"); + Class chatFormatClass = getNMSClass("EnumChatFormat"); + + createTeamPacket = getNMSClass("network.protocol.game", "PacketPlayOutScoreboardTeam") + .getDeclaredConstructor(String.class, int.class, Optional.class, Collection.class); + createTeamPacket.setAccessible(true); + createTeamPacketData = getNMSClass("network.protocol.game", "PacketPlayOutScoreboardTeam$b") + .getDeclaredConstructor(teamClass); + createTeam = teamClass.getDeclaredConstructor(scoreboardClass, String.class); + scoreboardDummy = scoreboardClass.getDeclaredConstructor().newInstance(); + pushNever = pushClass.getDeclaredField("b").get(null); + setTeamPush = teamClass.getDeclaredMethod(mappings.getTeamSetCollision(), pushClass); + setTeamColor = teamClass.getDeclaredMethod(mappings.getTeamSetColor(), chatFormatClass); + getColorConstant = chatFormatClass.getDeclaredMethod("a", char.class); + + enabled = true; + } catch (Exception ex) { + String errorMsg = + "Glowing Entities reflection failed to initialize. The util is disabled. Please ensure your version (" + + Bukkit.getServer().getClass().getPackage().getName() + ") is supported."; + if (logger == null) { + ex.printStackTrace(); + System.err.println(errorMsg); + } else { + logger.log(Level.SEVERE, errorMsg, ex); + } + } + } + + public static void sendPackets(Player p, Object... packets) throws ReflectiveOperationException { + Object connection = playerConnection.get(getHandle.invoke(p)); + for (Object packet : packets) { + if (packet == null) + continue; + sendPacket.invoke(connection, packet); + } + } + + public static byte getEntityFlags(Entity entity) throws ReflectiveOperationException { + Object nmsEntity = getHandle.invoke(entity); + Object dataWatcher = getDataWatcher.invoke(nmsEntity); + return (byte) watcherGet.invoke(dataWatcher, watcherObjectFlags); + } + + public static void createGlowing(GlowingData glowingData) throws ReflectiveOperationException { + setMetadata(glowingData, computeFlags(glowingData)); + } + + private static byte computeFlags(GlowingData glowingData) { + byte newFlags = glowingData.otherFlags; + if (glowingData.enabled) { + newFlags |= GLOWING_FLAG; + } else { + newFlags &= ~GLOWING_FLAG; + } + return newFlags; + } + + public static Object createFlagWatcherItem(byte newFlags) throws ReflectiveOperationException { + return watcherItemConstructor != null ? watcherItemConstructor.newInstance(watcherObjectFlags, newFlags) + : watcherBCreator.invoke(null, watcherObjectFlags, newFlags); + } + + public static void removeGlowing(GlowingData glowingData) throws ReflectiveOperationException { + setMetadata(glowingData, glowingData.otherFlags); + } + + public static void updateGlowingState(GlowingData glowingData) throws ReflectiveOperationException { + if (glowingData.enabled) + createGlowing(glowingData); + else + removeGlowing(glowingData); + } + + @SuppressWarnings("squid:S3011") + private static void setMetadata(GlowingData glowingData, byte flags) throws ReflectiveOperationException { + List dataItems = new ArrayList<>(1); + dataItems.add(watcherItemConstructor != null ? watcherItemConstructor.newInstance(watcherObjectFlags, flags) + : watcherBCreator.invoke(null, watcherObjectFlags, flags)); + + Object packetMetadata; + if (version < 19 || (version == 19 && versionMinor < 3)) { + packetMetadata = packetMetadataConstructor.newInstance(glowingData.entityID, watcherDummy, false); + packetMetadataItems.set(packetMetadata, dataItems); + } else { + packetMetadata = packetMetadataConstructor.newInstance(glowingData.entityID, dataItems); + } + packets.put(packetMetadata, dummy); + sendPackets(glowingData.player.player, packetMetadata); + } + + public static void setGlowingColor(GlowingData glowingData) throws ReflectiveOperationException { + boolean sendCreation = false; + if (glowingData.player.sentColors == null) { + glowingData.player.sentColors = EnumSet.of(glowingData.color); + sendCreation = true; + } else if (glowingData.player.sentColors.add(glowingData.color)) { + sendCreation = true; + } + + TeamData teamData = teams.get(glowingData.color); + if (teamData == null) { + teamData = new TeamData(glowingData.player.instance.uuid, glowingData.color); + teams.put(glowingData.color, teamData); + } + + Object entityAddPacket = teamData.getEntityAddPacket(glowingData.teamID); + if (sendCreation) { + sendPackets(glowingData.player.player, teamData.creationPacket, entityAddPacket); + } else { + sendPackets(glowingData.player.player, entityAddPacket); + } + } + + public static void removeGlowingColor(GlowingData glowingData) throws ReflectiveOperationException { + TeamData teamData = teams.get(glowingData.color); + if (teamData == null) + return; // must not happen; this means the color has not been set previously + + sendPackets(glowingData.player.player, teamData.getEntityRemovePacket(glowingData.teamID)); + } + + private static Channel getChannel(Player player) throws ReflectiveOperationException { + return (Channel) channelField.get(networkManager.get(playerConnection.get(getHandle.invoke(player)))); + } + + public static void addPacketsHandler(PlayerData playerData) throws ReflectiveOperationException { + playerData.packetsHandler = new ChannelDuplexHandler() { + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (msg.getClass().equals(packetMetadata) && packets.asMap().remove(msg) == null) { + int entityID = packetMetadataEntity.getInt(msg); + GlowingData glowingData = playerData.glowingDatas.get(entityID); + if (glowingData != null) { + + List items = (List) packetMetadataItems.get(msg); + if (items != null) { + + boolean containsFlags = false; + boolean edited = false; + for (int i = 0; i < items.size(); i++) { + Object item = items.get(i); + Object watcherObject; + if (watcherItemObject != null) { + watcherObject = watcherItemObject.invoke(item); + } else { + Object serializer = watcherBSerializer.invoke(item); + watcherObject = watcherSerializerObject.invoke(serializer, watcherBId.invoke(item)); + } + + if (watcherObject.equals(watcherObjectFlags)) { + containsFlags = true; + byte flags = (byte) watcherItemDataGet.invoke(item); + glowingData.otherFlags = flags; + byte newFlags = computeFlags(glowingData); + if (newFlags != flags) { + edited = true; + items = new ArrayList<>(items); + // we cannot simply edit the item as it may be backed in the datawatcher, so we + // make a copy of the list + items.set(i, createFlagWatcherItem(newFlags)); + break; + // we can break right now as the "flags" datawatcher object may not be present + // twice in the same packet + } + } + } + + if (!edited && !containsFlags) { + // if the packet does not contain any flag information, we are unsure if it is a packet + // simply containing informations about another object's data update OR if it is a packet + // containing all non-default informations of the entity. Such as packet can be sent when + // the player has got far away from the entity and come in sight distance again. + // In this case, we must add manually the "flags" object, otherwise it would stay 0 and + // the entity would not be glowing. + // Ideally, we should listen for an "entity add" packet to be sure we are in the case + // above, but honestly it's annoying because there are multiple types of "entity add" + // packets, so we do like this instead. Less performant, but not by far. + byte flags = computeFlags(glowingData); + if (flags != 0) { + edited = true; + items = new ArrayList<>(items); + items.add(createFlagWatcherItem(flags)); + } + } + + if (edited) { + // some of the metadata packets are broadcasted to all players near the target entity. + // hence, if we directly edit the packet, some users that were not intended to see the + // glowing color will be able to see it. We should send a new packet to the viewer only. + + Object newMsg; + if (version < 19 || (version == 19 && versionMinor < 3)) { + newMsg = packetMetadataConstructor.newInstance(entityID, watcherDummy, false); + packetMetadataItems.set(newMsg, items); + } else { + newMsg = packetMetadataConstructor.newInstance(entityID, items); + } + packets.put(newMsg, dummy); + sendPackets(playerData.player, newMsg); + + return; // we cancel the send of this packet + } + } + } + } else if (packetBundle != null && msg.getClass().equals(packetBundle)) { + handlePacketBundle(msg); + } + super.write(ctx, msg, promise); + } + + private void handlePacketBundle(Object bundle) throws ReflectiveOperationException { + Iterable subPackets = (Iterable) packetBundlePackets.invoke(bundle); + for (Iterator iterator = subPackets.iterator(); iterator.hasNext();) { + Object packet = iterator.next(); + + if (packet.getClass().equals(packetMetadata)) { + int entityID = packetMetadataEntity.getInt(packet); + GlowingData glowingData = playerData.glowingDatas.get(entityID); + if (glowingData != null) { + // means the bundle packet contains metadata about an entity that must be glowing. + // editing a bundle packet is annoying, so we'll let it go to the player + // and then send a metadata packet containing the correct glowing flag. + + Bukkit.getScheduler().runTaskLaterAsynchronously(playerData.instance.plugin, () -> { + try { + updateGlowingState(glowingData); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + }, 1L); + return; + } + } + } + } + + }; + + getChannel(playerData.player).pipeline().addBefore("packet_handler", null, playerData.packetsHandler); + } + + public static void removePacketsHandler(PlayerData playerData) throws ReflectiveOperationException { + if (playerData.packetsHandler != null) { + getChannel(playerData.player).pipeline().remove(playerData.packetsHandler); + } + } + + /* Reflection utils */ + private static Method getMethod(Class clazz, String name) throws NoSuchMethodException { + for (Method m : clazz.getDeclaredMethods()) { + if (m.getName().equals(name)) + return m; + } + throw new NoSuchMethodException(name + " in " + clazz.getName()); + } + + @Deprecated + private static Object getField(Class clazz, String name, Object instance) throws ReflectiveOperationException { + return getField(clazz, name).get(instance); + } + + private static Field getField(Class clazz, String name) throws ReflectiveOperationException { + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + return field; + } + + private static Class getCraftClass(String craftPackage, String className) throws ClassNotFoundException { + return Class.forName(cpack + craftPackage + "." + className); + } + + private static Class getNMSClass(String className) throws ClassNotFoundException { + return Class.forName("net.minecraft." + className); + } + + private static Class getNMSClass(String nmPackage, String className) throws ClassNotFoundException { + return Class.forName("net.minecraft." + nmPackage + "." + className); + } + + private static class TeamData { + + private final String id; + private final Object creationPacket; + + private final Cache addPackets = + CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(); + private final Cache removePackets = + CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(); + + public TeamData(int uuid, ChatColor color) throws ReflectiveOperationException { + if (!color.isColor()) + throw new IllegalArgumentException(); + id = "glow-" + uuid + color.getChar(); + Object team = createTeam.newInstance(scoreboardDummy, id); + setTeamPush.invoke(team, pushNever); + setTeamColor.invoke(team, getColorConstant.invoke(null, color.getChar())); + Object packetData = createTeamPacketData.newInstance(team); + creationPacket = createTeamPacket.newInstance(id, 0, Optional.of(packetData), Collections.EMPTY_LIST); + } + + public Object getEntityAddPacket(String teamID) throws ReflectiveOperationException { + Object packet = addPackets.getIfPresent(teamID); + if (packet == null) { + packet = createTeamPacket.newInstance(id, 3, Optional.empty(), Arrays.asList(teamID)); + addPackets.put(teamID, packet); + } + return packet; + } + + public Object getEntityRemovePacket(String teamID) throws ReflectiveOperationException { + Object packet = removePackets.getIfPresent(teamID); + if (packet == null) { + packet = createTeamPacket.newInstance(id, 4, Optional.empty(), Arrays.asList(teamID)); + removePackets.put(teamID, packet); + } + return packet; + } + + } + + private enum ProtocolMappings { + + V1_17( + 17, + "Z", + "Y", + "getDataWatcher", + "b", + "a", + "sendPacket", + "k", + "setCollisionRule", + "setColor", + "a", + "b"), + V1_18( + 18, + "Z", + "Y", + "ai", + "b", + "a", + "a", + "m", + "a", + "a", + "a", + "b"), + V1_19( + 19, + null, + "ab", + null, + "b", + null, + "a", + "m", + "a", + "a", + null, + null) { + @Override + public String getNetworkManager() { + return versionMinor < 4 ? "b" : "h"; + } + + @Override + public String getWatcherFlags() { + return versionMinor < 4 ? "Z" : "an"; + } + + @Override + public String getWatcherAccessor() { + if (versionMinor < 3) + return "ai"; + else if (versionMinor == 3) + return "al"; + else + return "aj"; + } + + @Override + public String getMetadataEntity() { + return versionMinor < 3 ? "a" : "b"; + } + + @Override + public String getMetadataItems() { + return versionMinor < 3 ? "b" : "c"; + } + }; + + private final int major; + private final String watcherFlags; + private final String markerTypeId; + private final String watcherAccessor; + private final String playerConnection; + private final String networkManager; + private final String sendPacket; + private final String channel; + private final String teamSetCollsion; + private final String teamSetColor; + private final String metadataEntity; + private final String metadataItems; + + private ProtocolMappings(int major, String watcherFlags, String markerTypeId, String watcherAccessor, + String playerConnection, String networkManager, String sendPacket, String channel, + String teamSetCollsion, String teamSetColor, String metdatataEntity, String metadataItems) { + this.major = major; + this.watcherFlags = watcherFlags; + this.markerTypeId = markerTypeId; + this.watcherAccessor = watcherAccessor; + this.playerConnection = playerConnection; + this.networkManager = networkManager; + this.sendPacket = sendPacket; + this.channel = channel; + this.teamSetCollsion = teamSetCollsion; + this.teamSetColor = teamSetColor; + this.metadataEntity = metdatataEntity; + this.metadataItems = metadataItems; + } + + public int getMajor() { + return major; + } + + public String getWatcherFlags() { + return watcherFlags; + } + + public String getMarkerTypeId() { + return markerTypeId; + } + + public String getWatcherAccessor() { + return watcherAccessor; + } + + public String getPlayerConnection() { + return playerConnection; + } + + public String getNetworkManager() { + return networkManager; + } + + public String getSendPacket() { + return sendPacket; + } + + public String getChannel() { + return channel; + } + + public String getTeamSetCollision() { + return teamSetCollsion; + } + + public String getTeamSetColor() { + return teamSetColor; + } + + public String getMetadataEntity() { + return metadataEntity; + } + + public String getMetadataItems() { + return metadataItems; + } + + public static ProtocolMappings getMappings(int major) { + for (ProtocolMappings map : values()) { + if (major == map.getMajor()) + return map; + } + return null; + } + + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/volmit/adapt/nms/NMS_1_19_4.java b/src/main/java/com/volmit/adapt/nms/NMS_1_19_4.java index 064a7b65..e7fddd79 100644 --- a/src/main/java/com/volmit/adapt/nms/NMS_1_19_4.java +++ b/src/main/java/com/volmit/adapt/nms/NMS_1_19_4.java @@ -74,4 +74,6 @@ private void sendPacket(Player player, Packet packet) { private Item notchianItem(Material m) { return CraftMagicNumbers.getItem(m); } + + } diff --git a/src/main/resources/en_US.json b/src/main/resources/en_US.json index b26dd9ec..2c8890cf 100644 --- a/src/main/resources/en_US.json +++ b/src/main/resources/en_US.json @@ -661,6 +661,14 @@ "lore1": "Gain Haste while excavating", "lore2": "x Levels of haste when you start mining ANY block." }, + "spelunker": { + "name": "Super-Seeing Spelunker!", + "description": "See Ores with your eyes, but through the ground!", + "lore1": "Ore in your offhand, Glowberries in your main hand, and Sneak!", + "lore2": "Block Range: ", + "lore3": "Consumes Glowberry on use", + "lore4": "8 of the Ore's Drop and 1 stone to craft an ore block (shapeless)" + }, "droptoinventory": { "name": "Shovel Drop-To-Inventory" }, From c43f67ac2ed15b34ae0613eb935ec8bb03733184 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Tue, 18 Apr 2023 14:49:25 -0400 Subject: [PATCH 2/5] dw --- .../crafting/CraftingReconstruction.java | 335 ++++++++++++++++++ .../excavation/ExcavationSpelunker.java | 260 +------------- .../adapt/content/skill/SkillCrafting.java | 1 + src/main/resources/en_US.json | 11 +- 4 files changed, 348 insertions(+), 259 deletions(-) create mode 100644 src/main/java/com/volmit/adapt/content/adaptation/crafting/CraftingReconstruction.java diff --git a/src/main/java/com/volmit/adapt/content/adaptation/crafting/CraftingReconstruction.java b/src/main/java/com/volmit/adapt/content/adaptation/crafting/CraftingReconstruction.java new file mode 100644 index 00000000..85034da5 --- /dev/null +++ b/src/main/java/com/volmit/adapt/content/adaptation/crafting/CraftingReconstruction.java @@ -0,0 +1,335 @@ +/*------------------------------------------------------------------------------ + - Adapt is a Skill/Integration plugin for Minecraft Bukkit Servers + - Copyright (c) 2022 Arcane Arts (Volmit Software) + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation, either version 3 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see . + -----------------------------------------------------------------------------*/ + +package com.volmit.adapt.content.adaptation.crafting; + +import com.volmit.adapt.api.adaptation.SimpleAdaptation; +import com.volmit.adapt.api.recipe.AdaptRecipe; +import com.volmit.adapt.util.C; +import com.volmit.adapt.util.Element; +import com.volmit.adapt.util.Localizer; +import lombok.NoArgsConstructor; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + + +public class CraftingReconstruction extends SimpleAdaptation { + public CraftingReconstruction() { + super("crafting-reconstruction"); + registerConfiguration(Config.class); + setDescription(Localizer.dLocalize("crafting", "reconstruction", "description")); + setDisplayName(Localizer.dLocalize("crafting", "reconstruction", "name")); + setIcon(Material.COAL_ORE); + setBaseCost(getConfig().baseCost); + setCostFactor(getConfig().costFactor); + setMaxLevel(getConfig().maxLevel); + setInitialCost(getConfig().initialCost); + setInterval(80248); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-iron-ore") + .ingredient(Material.STONE) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .result(new ItemStack(Material.IRON_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-gold-ore") + .ingredient(Material.STONE) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-copper-ore") + .ingredient(Material.STONE) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .result(new ItemStack(Material.COPPER_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-lapis-ore") + .ingredient(Material.STONE) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .result(new ItemStack(Material.LAPIS_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-redstone-ore") + .ingredient(Material.STONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .result(new ItemStack(Material.REDSTONE_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-emerald-ore") + .ingredient(Material.STONE) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .result(new ItemStack(Material.EMERALD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-diamond-ore") + .ingredient(Material.STONE) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .result(new ItemStack(Material.DIAMOND_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-coal-ore") + .ingredient(Material.STONE) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .result(new ItemStack(Material.COAL_ORE)) + .build()); + + // Use Deepslate + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-iron-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .ingredient(Material.IRON_INGOT) + .result(new ItemStack(Material.DEEPSLATE_IRON_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-gold-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.DEEPSLATE_GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-copper-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .ingredient(Material.COPPER_INGOT) + .result(new ItemStack(Material.DEEPSLATE_COPPER_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-lapis-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .ingredient(Material.LAPIS_LAZULI) + .result(new ItemStack(Material.DEEPSLATE_LAPIS_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-redstone-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .ingredient(Material.REDSTONE) + .result(new ItemStack(Material.DEEPSLATE_REDSTONE_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-emerald-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .ingredient(Material.EMERALD) + .result(new ItemStack(Material.DEEPSLATE_EMERALD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-diamond-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .ingredient(Material.DIAMOND) + .result(new ItemStack(Material.DEEPSLATE_DIAMOND_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-deepslate-coal-ore") + .ingredient(Material.DEEPSLATE) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .ingredient(Material.COAL) + .result(new ItemStack(Material.DEEPSLATE_COAL_ORE)) + .build()); + +// Use Nether Bricks + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-nether-gold-ore") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .ingredient(Material.GOLD_INGOT) + .result(new ItemStack(Material.NETHER_GOLD_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-nether-quartz-ore") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .ingredient(Material.QUARTZ) + .result(new ItemStack(Material.NETHER_QUARTZ_ORE)) + .build()); + registerRecipe(AdaptRecipe.shapeless() + .key("reconstruction-ancient-debris") + .ingredient(Material.NETHER_BRICKS) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .ingredient(Material.NETHERITE_SCRAP) + .result(new ItemStack(Material.ANCIENT_DEBRIS)) + .build()); + } + + @Override + public void addStats(int level, Element v) { + v.addLore(C.GREEN + Localizer.dLocalize("crafting", "reconstruction", "lore1")); + v.addLore(C.UNDERLINE + Localizer.dLocalize("crafting", "reconstruction", "lore2")); + v.addLore(C.YELLOW + Localizer.dLocalize("crafting", "reconstruction", "lore3")); + v.addLore(C.YELLOW + Localizer.dLocalize("crafting", "reconstruction", "lore4")); + } + + @EventHandler + public void on(PlayerInteractEvent e) { + + } + + @Override + public void onTick() { + + } + + @Override + public boolean isEnabled() { + return getConfig().enabled; + } + + @Override + public boolean isPermanent() { + return getConfig().permanent; + } + + @NoArgsConstructor + protected static class Config { + boolean permanent = true; + boolean enabled = true; + int baseCost = 5; + int maxLevel = 1; + int initialCost = 2; + double costFactor = 1; + } +} \ No newline at end of file diff --git a/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java b/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java index 6a4922e1..d616b682 100644 --- a/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java +++ b/src/main/java/com/volmit/adapt/content/adaptation/excavation/ExcavationSpelunker.java @@ -20,7 +20,6 @@ import com.volmit.adapt.Adapt; import com.volmit.adapt.api.adaptation.SimpleAdaptation; -import com.volmit.adapt.api.recipe.AdaptRecipe; import com.volmit.adapt.content.item.ItemListings; import com.volmit.adapt.nms.GlowingEntities; import com.volmit.adapt.util.C; @@ -59,258 +58,6 @@ public ExcavationSpelunker() { setMaxLevel(getConfig().maxLevel); setInitialCost(getConfig().initialCost); setCostFactor(getConfig().costFactor); - // Use Stone as base - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-iron-ore") - .ingredient(Material.STONE) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .result(new ItemStack(Material.IRON_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-gold-ore") - .ingredient(Material.STONE) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .result(new ItemStack(Material.GOLD_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-copper-ore") - .ingredient(Material.STONE) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .result(new ItemStack(Material.COPPER_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-lapis-ore") - .ingredient(Material.STONE) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .result(new ItemStack(Material.LAPIS_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-redstone-ore") - .ingredient(Material.STONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .result(new ItemStack(Material.REDSTONE_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-emerald-ore") - .ingredient(Material.STONE) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .result(new ItemStack(Material.EMERALD_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-diamond-ore") - .ingredient(Material.STONE) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .result(new ItemStack(Material.DIAMOND_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-coal-ore") - .ingredient(Material.STONE) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .result(new ItemStack(Material.COAL_ORE)) - .build()); - - // Use Deepslate - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-iron-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .ingredient(Material.IRON_INGOT) - .result(new ItemStack(Material.DEEPSLATE_IRON_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-gold-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .result(new ItemStack(Material.DEEPSLATE_GOLD_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-copper-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .ingredient(Material.COPPER_INGOT) - .result(new ItemStack(Material.DEEPSLATE_COPPER_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-lapis-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .ingredient(Material.LAPIS_LAZULI) - .result(new ItemStack(Material.DEEPSLATE_LAPIS_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-redstone-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .ingredient(Material.REDSTONE) - .result(new ItemStack(Material.DEEPSLATE_REDSTONE_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-emerald-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .ingredient(Material.EMERALD) - .result(new ItemStack(Material.DEEPSLATE_EMERALD_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-diamond-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .ingredient(Material.DIAMOND) - .result(new ItemStack(Material.DEEPSLATE_DIAMOND_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-deepslate-coal-ore") - .ingredient(Material.DEEPSLATE) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .ingredient(Material.COAL) - .result(new ItemStack(Material.DEEPSLATE_COAL_ORE)) - .build()); - -// Use Nether Bricks - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-nether-gold-ore") - .ingredient(Material.NETHER_BRICKS) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .ingredient(Material.GOLD_INGOT) - .result(new ItemStack(Material.NETHER_GOLD_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-nether-quartz-ore") - .ingredient(Material.NETHER_BRICKS) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .ingredient(Material.QUARTZ) - .result(new ItemStack(Material.NETHER_QUARTZ_ORE)) - .build()); - registerRecipe(AdaptRecipe.shapeless() - .key("spelunker-ancient-debris") - .ingredient(Material.NETHER_BRICKS) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .ingredient(Material.NETHERITE_SCRAP) - .result(new ItemStack(Material.ANCIENT_DEBRIS)) - .build()); cooldowns = new HashMap<>(); } @@ -320,7 +67,6 @@ public void addStats(int level, Element v) { v.addLore(C.GREEN + Localizer.dLocalize("excavation", "spelunker", "lore1")); v.addLore(C.YELLOW + Localizer.dLocalize("excavation", "spelunker", "lore2") + getConfig().rangeMultiplier * level); v.addLore(C.YELLOW + Localizer.dLocalize("excavation", "spelunker", "lore3")); - v.addLore(C.BOLD + Localizer.dLocalize("excavation", "spelunker", "lore4")); } @EventHandler(priority = EventPriority.HIGH) @@ -460,9 +206,9 @@ protected static class Config { boolean permanent = false; boolean enabled = true; double cooldown =6.0; - int baseCost = 3; - int initialCost = 3; - double costFactor = 0.3; + int baseCost = 5; + int initialCost = 10; + double costFactor = 1; int maxLevel = 5; int rangeMultiplier = 5; } diff --git a/src/main/java/com/volmit/adapt/content/skill/SkillCrafting.java b/src/main/java/com/volmit/adapt/content/skill/SkillCrafting.java index f09624d2..f914692b 100644 --- a/src/main/java/com/volmit/adapt/content/skill/SkillCrafting.java +++ b/src/main/java/com/volmit/adapt/content/skill/SkillCrafting.java @@ -60,6 +60,7 @@ public SkillCrafting() { registerAdaptation(new CraftingSkulls()); registerAdaptation(new CraftingBackpacks()); registerAdaptation(new CraftingStations()); + registerAdaptation(new CraftingReconstruction()); registerAdvancement(AdaptAdvancement.builder() .icon(Material.CRAFTING_TABLE).key("challenge_craft_1k") .title(Localizer.dLocalize("advancement", "challenge_craft_1k", "title")) diff --git a/src/main/resources/en_US.json b/src/main/resources/en_US.json index 2c8890cf..17be8e16 100644 --- a/src/main/resources/en_US.json +++ b/src/main/resources/en_US.json @@ -575,6 +575,14 @@ "description": "Gain passive XP when crafting", "lore1": "Gain XP when crafting" }, + "reconstruction": { + "name": "Ore Reconstruction", + "description": "Recraft ores from their base components!", + "lore1": "8 of the Drops and 1 Host = 1 Ore (shapeless)", + "lore2": "Drops must be smelted (if applicable)", + "lore3": "Not including: Scraps, Quarts, and Emeralds etc...", + "lore4": "Host = Encasement. ie: Stone, Netherack, Deepslate" + }, "leather": { "name": "Craftable Leather", "description": "Craft Leather from Rotten Flesh", @@ -666,8 +674,7 @@ "description": "See Ores with your eyes, but through the ground!", "lore1": "Ore in your offhand, Glowberries in your main hand, and Sneak!", "lore2": "Block Range: ", - "lore3": "Consumes Glowberry on use", - "lore4": "8 of the Ore's Drop and 1 stone to craft an ore block (shapeless)" + "lore3": "Consumes Glowberry on use" }, "droptoinventory": { "name": "Shovel Drop-To-Inventory" From 22a4307ccb22317e6e64c085cfee87522f284e34 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Wed, 19 Apr 2023 23:54:26 -0400 Subject: [PATCH 3/5] Added Tragoul Globe --- build.gradle | 2 - .../java/com/volmit/adapt/api/Component.java | 45 +++++- .../adaptation/tragoul/TragoulGlobe.java | 137 ++++++++++++++++++ .../adapt/content/skill/SkillTragOul.java | 2 + src/main/resources/en_US.json | 9 +- 5 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java diff --git a/build.gradle b/build.gradle index 422c063d..c1730adc 100644 --- a/build.gradle +++ b/build.gradle @@ -152,9 +152,7 @@ dependencies { implementation 'io.th0rgal:oraxen:1.94.0' implementation 'com.massivecraft:Factions:1.6.9.5-U0.6.21' - // Shaded - implementation 'io.papermc:paperlib:1.0.5' implementation 'net.kyori:adventure-text-minimessage:4.12.0' implementation 'net.kyori:adventure-platform-bukkit:4.1.2' implementation 'net.kyori:adventure-api:4.12.0' diff --git a/src/main/java/com/volmit/adapt/api/Component.java b/src/main/java/com/volmit/adapt/api/Component.java index b2be4d13..9006e8e0 100644 --- a/src/main/java/com/volmit/adapt/api/Component.java +++ b/src/main/java/com/volmit/adapt/api/Component.java @@ -46,12 +46,11 @@ import org.bukkit.util.Vector; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; +import static xyz.xenondevs.particle.utils.MathUtils.RANDOM; + public interface Component { default void wisdom(Player p, long w) { XP.wisdom(p, w); @@ -428,6 +427,44 @@ default void vfxPrismOutline(Location placer, double outset, Particle particle, } } + default void vfxCreateSphereAlt(Location center, double range, Color color, int particleCount) { + Particle.DustOptions dustOptions = new Particle.DustOptions(color, 1); + World world = center.getWorld(); + + for (int i = 0; i < particleCount; i++) { + double x, y, z; + do { + x = RANDOM.nextDouble() * 2 - 1; + y = RANDOM.nextDouble() * 2 - 1; + z = RANDOM.nextDouble() * 2 - 1; + } while (x * x + y * y + z * z > 1); + + double magnitude = Math.sqrt(x * x + y * y + z * z); + x = x / magnitude * range; + y = y / magnitude * range; + z = z / magnitude * range; + + Location particleLocation = center.clone().add(x, y, z); + world.spawnParticle(Particle.REDSTONE, particleLocation, 0, 0, 0, 0, dustOptions); + } + } + + default void vfxCreateSphere(Location center, double range, Color color, int particleCount) { + Particle.DustOptions dustOptions = new Particle.DustOptions(color, 1); + World world = center.getWorld(); + + for (int i = 0; i < particleCount; i++) { + double theta = 2 * Math.PI * RANDOM.nextDouble(); + double phi = Math.acos(2 * RANDOM.nextDouble() - 1); + double x = range * Math.sin(phi) * Math.cos(theta); + double y = range * Math.sin(phi) * Math.sin(theta); + double z = range * Math.cos(phi); + + Location particleLocation = center.clone().add(x, y, z); + world.spawnParticle(Particle.REDSTONE, particleLocation, 0, 0, 0, 0, dustOptions); + } + } + default void vfxLevelUp(Player p) { p.spawnParticle(Particle.REVERSE_PORTAL, p.getLocation().clone().add(0, 1.7, 0), 100, 0.1, 0.1, 0.1, 4.1); diff --git a/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java b/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java new file mode 100644 index 00000000..066a68a8 --- /dev/null +++ b/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java @@ -0,0 +1,137 @@ +/*------------------------------------------------------------------------------ + - Adapt is a Skill/Integration plugin for Minecraft Bukkit Servers + - Copyright (c) 2022 Arcane Arts (Volmit Software) + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation, either version 3 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see . + -----------------------------------------------------------------------------*/ + +package com.volmit.adapt.content.adaptation.tragoul; + +import com.volmit.adapt.api.adaptation.SimpleAdaptation; +import com.volmit.adapt.util.C; +import com.volmit.adapt.util.Element; +import com.volmit.adapt.util.J; +import com.volmit.adapt.util.Localizer; +import lombok.NoArgsConstructor; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TragoulGlobe extends SimpleAdaptation { + private final Map cooldowns; + + public TragoulGlobe() { + super("tragoul-globe"); + registerConfiguration(TragoulGlobe.Config.class); + setDescription(Localizer.dLocalize("tragoul", "globe", "description")); + setDisplayName(Localizer.dLocalize("tragoul", "globe", "name")); + setIcon(Material.ENDER_PEARL); + setInterval(25000); + setBaseCost(getConfig().baseCost); + setMaxLevel(getConfig().maxLevel); + setInitialCost(getConfig().initialCost); + setCostFactor(getConfig().costFactor); + cooldowns = new HashMap<>(); + } + + @Override + public void addStats(int level, Element v) { + v.addLore(C.GREEN + Localizer.dLocalize("tragoul", "globe", "lore1")); + v.addLore(C.YELLOW + Localizer.dLocalize("tragoul", "globe", "lore2") + ((getConfig().rangePerLevel * level) + getConfig().initalRange)); + v.addLore(C.YELLOW + Localizer.dLocalize("tragoul", "globe", "lore3") + (getConfig().bonusDamagePerLevel * level)); + } + + @EventHandler + public void on(EntityDamageByEntityEvent e) { + if (e.isCancelled()) { + return; + } + if (e.getDamager() instanceof Player p && hasAdaptation(p)) { + if (cooldowns.containsKey(p)) { + if (cooldowns.get(p) + (1000 * getConfig().cooldown) > System.currentTimeMillis()) { + return; + } else { + cooldowns.remove(p); + } + } + + cooldowns.put(p, System.currentTimeMillis()); + double range = (getConfig().rangePerLevel * getLevel(p)) + getConfig().initalRange; + List entitiesInRange = p.getNearbyEntities(range, range, range).stream() + .filter(entity -> entity instanceof LivingEntity && !entity.equals(p)) + .toList(); + + if (entitiesInRange.size() <=1) { + return; + } + + if (!entitiesInRange.isEmpty()) { + double damagePerEntity = e.getDamage() / entitiesInRange.size() + (getConfig().bonusDamagePerLevel * getLevel(p)); + e.setDamage(damagePerEntity); + + for (Entity entity : entitiesInRange) { + ((LivingEntity) entity).damage(damagePerEntity, p); + } + + if (getConfig().showParticles) { + J.s(() -> { + vfxCreateSphere(p.getLocation(), range, Color.BLACK, 500); + for (Entity entity : entitiesInRange) { + vfxParticleLine(p.getLocation(), entity.getLocation(), Particle.ASH, 15, 1, 0.0D, 0D, 0.0D, 0D, null, true, l -> l.getBlock().isPassable()); + } + }); + } + } + } + } + + @Override + public boolean isEnabled() { + return getConfig().enabled; + } + + @Override + public void onTick() { + } + + @Override + public boolean isPermanent() { + return getConfig().permanent; + } + + + @NoArgsConstructor + protected static class Config { + boolean permanent = false; + boolean enabled = true; + boolean showParticles = true; + int baseCost = 5; + int maxLevel = 5; + int initialCost = 5; + double cooldown = 1; + double rangePerLevel = 3.0; + double initalRange = 5.0; + double costFactor = 1.10; + double bonusDamagePerLevel = 1; + } +} diff --git a/src/main/java/com/volmit/adapt/content/skill/SkillTragOul.java b/src/main/java/com/volmit/adapt/content/skill/SkillTragOul.java index 4f92029a..9d292464 100644 --- a/src/main/java/com/volmit/adapt/content/skill/SkillTragOul.java +++ b/src/main/java/com/volmit/adapt/content/skill/SkillTragOul.java @@ -23,6 +23,7 @@ import com.volmit.adapt.api.skill.SimpleSkill; import com.volmit.adapt.api.world.AdaptPlayer; import com.volmit.adapt.api.world.PlayerAdaptation; +import com.volmit.adapt.content.adaptation.tragoul.TragoulGlobe; import com.volmit.adapt.content.adaptation.tragoul.TragoulThorns; import com.volmit.adapt.util.C; import com.volmit.adapt.util.Localizer; @@ -51,6 +52,7 @@ public SkillTragOul() { setIcon(Material.CRIMSON_ROOTS); cooldowns = new HashMap<>(); registerAdaptation(new TragoulThorns()); + registerAdaptation(new TragoulGlobe()); } diff --git a/src/main/resources/en_US.json b/src/main/resources/en_US.json index 17be8e16..5bc31a4e 100644 --- a/src/main/resources/en_US.json +++ b/src/main/resources/en_US.json @@ -925,7 +925,7 @@ "name": "Anti-Levitation", "description": "Are you tired of being stuck in the air? This is the skill for you!", "lore1": "Just Sneak to descend, and you will fall at a less than normal rate!", - "lore2": "Cooldown:" + "lore2": "Cooldown:" }, "gate": { "name": "Rift Gate", @@ -1041,6 +1041,13 @@ "name": "Thorns", "description": "Reflect damage back to your attacker!", "lore1": "Damage retaliated when struck" + }, + "globe": { + "name": "Globe of Pain", + "description": "Divide the Damage you deal based on the number of enemies around you!", + "lore1": "The more enemies around you, the less damage you deal to each of them", + "lore2": "Range: ", + "lore3": "Added Damage to all Entities: " } }, "unarmed": { From 2cfc15f0ac44d56447249ab618472085630c9ef4 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 20 Apr 2023 00:07:51 -0400 Subject: [PATCH 4/5] cool VFX --- .../java/com/volmit/adapt/api/Component.java | 18 +++++++++++++- .../adaptation/tragoul/TragoulGlobe.java | 24 ++++++++++--------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/volmit/adapt/api/Component.java b/src/main/java/com/volmit/adapt/api/Component.java index 9006e8e0..4e47a3ac 100644 --- a/src/main/java/com/volmit/adapt/api/Component.java +++ b/src/main/java/com/volmit/adapt/api/Component.java @@ -266,6 +266,22 @@ default double getValue(Block block) { return MaterialValue.getValue(block.getType()); } + default void vfxDome(Location center, double range, Color color, int particleCount) { + Particle.DustOptions dustOptions = new Particle.DustOptions(color, 1); + World world = center.getWorld(); + + for (int i = 0; i < particleCount; i++) { + double theta = 2 * Math.PI * RANDOM.nextDouble(); + double phi = Math.PI / 2 * RANDOM.nextDouble(); // Adjusted range of phi to create a dome + double x = range * Math.sin(phi) * Math.cos(theta); + double y = range * Math.sin(phi) * Math.sin(theta); + double z = range * Math.cos(phi); + + Location particleLocation = center.clone().add(x, y, z); + world.spawnParticle(Particle.REDSTONE, particleLocation, 0, 0, 0, 0, dustOptions); + } + } + default void vfxSphereV1(Player p, Location l, double radius, Particle particle, int verticalDensity, int radialDensity) { for (double phi = 0; phi <= Math.PI; phi += Math.PI / verticalDensity) { for (double theta = 0; theta <= 2 * Math.PI; theta += Math.PI / radialDensity) { @@ -449,7 +465,7 @@ default void vfxCreateSphereAlt(Location center, double range, Color color, int } } - default void vfxCreateSphere(Location center, double range, Color color, int particleCount) { + default void vfxSphereV3(Location center, double range, Color color, int particleCount) { Particle.DustOptions dustOptions = new Particle.DustOptions(color, 1); World world = center.getWorld(); diff --git a/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java b/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java index 066a68a8..e6f6c63a 100644 --- a/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java +++ b/src/main/java/com/volmit/adapt/content/adaptation/tragoul/TragoulGlobe.java @@ -85,22 +85,24 @@ public void on(EntityDamageByEntityEvent e) { return; } - if (!entitiesInRange.isEmpty()) { - double damagePerEntity = e.getDamage() / entitiesInRange.size() + (getConfig().bonusDamagePerLevel * getLevel(p)); - e.setDamage(damagePerEntity); + double damagePerEntity = e.getDamage() / entitiesInRange.size() + (getConfig().bonusDamagePerLevel * getLevel(p)); + e.setDamage(damagePerEntity); - for (Entity entity : entitiesInRange) { - ((LivingEntity) entity).damage(damagePerEntity, p); - } + for (Entity entity : entitiesInRange) { + ((LivingEntity) entity).damage(damagePerEntity, p); + } - if (getConfig().showParticles) { - J.s(() -> { - vfxCreateSphere(p.getLocation(), range, Color.BLACK, 500); + if (getConfig().showParticles) { + J.s(() -> { + if (getConfig().showParticles) { + vfxSphereV3(p.getLocation(), range, Color.BLACK, 100); + vfxDome(p.getLocation(), range, Color.BLACK, 300); + vfxFastRing(p.getLocation(), range, Particle.DRIP_LAVA); for (Entity entity : entitiesInRange) { vfxParticleLine(p.getLocation(), entity.getLocation(), Particle.ASH, 15, 1, 0.0D, 0D, 0.0D, 0D, null, true, l -> l.getBlock().isPassable()); } - }); - } + } + }); } } } From d02e3b8ee038a7e8a4c263f6441c12f559da71e4 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 20 Apr 2023 00:26:44 -0400 Subject: [PATCH 5/5] v+ --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c1730adc..88641948 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id "de.undercouch.download" version "5.0.1" } -version '1.7.1-1.19.4' +version '1.7.2-1.19.4' def nmsVersion = "1.19.4" //[NMS] def apiVersion = '1.19' def specialSourceVersion = '1.11.0' //[NMS]