From 1d2fe8aada66cfc9491eacc2d52b8ff9ee13c2f7 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Tue, 5 Aug 2025 19:24:05 -0700 Subject: [PATCH 01/34] The initial folia support commit Changed the plugin's base code to be folia compatible (with some small errors) --- build.gradle.kts | 26 +- src/main/java/me/moros/hyperion/Hyperion.java | 85 +++++- .../abilities/earthbending/EarthGuard.java | 4 +- .../abilities/earthbending/EarthLine.java | 1 + .../abilities/firebending/Combustion.java | 29 +- .../abilities/firebending/FlameRush.java | 2 +- .../abilities/firebending/combo/FireWave.java | 10 +- .../abilities/waterbending/IceBreath.java | 2 +- .../abilities/waterbending/IceCrawl.java | 2 +- .../java/me/moros/hyperion/util/PaperLib.java | 99 +++++++ .../moros/hyperion/util/ParticleEffect.java | 145 ++++++++++ .../hyperion/util/PotionEffectAdapter.java | 15 + .../util/PotionEffectAdapterFactory.java | 25 ++ .../util/PotionEffectAdapter_1_20_4.java | 55 ++++ .../util/PotionEffectAdapter_1_20_5.java | 55 ++++ .../moros/hyperion/util/PotionMetaUtil.java | 29 ++ .../me/moros/hyperion/util/ThreadUtil.java | 256 ++++++++++++++++++ src/main/resources/plugin.yml | 7 +- 18 files changed, 810 insertions(+), 37 deletions(-) create mode 100644 src/main/java/me/moros/hyperion/util/PaperLib.java create mode 100644 src/main/java/me/moros/hyperion/util/ParticleEffect.java create mode 100644 src/main/java/me/moros/hyperion/util/PotionEffectAdapter.java create mode 100644 src/main/java/me/moros/hyperion/util/PotionEffectAdapterFactory.java create mode 100644 src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_4.java create mode 100644 src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java create mode 100644 src/main/java/me/moros/hyperion/util/PotionMetaUtil.java create mode 100644 src/main/java/me/moros/hyperion/util/ThreadUtil.java diff --git a/build.gradle.kts b/build.gradle.kts index 2cc0201..7a4f39c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,14 @@ plugins { java - id("io.github.goooler.shadow").version("8.1.8") + id("com.github.johnrengelman.shadow") version "8.1.1" // official Shadow plugin } group = "me.moros" -version = "1.7.3" +version = "1.7.4-PRE-RELEASE-1" java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion.set(JavaLanguageVersion.of(17)) } } @@ -16,33 +16,37 @@ repositories { mavenCentral() maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://jitpack.io") + maven("https://repo.papermc.io/repository/maven-public/") } dependencies { - implementation("org.bstats", "bstats-bukkit", "3.0.2") - compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") - compileOnly("com.github.ProjectKorra:ProjectKorra:v1.11.2") + compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT") + compileOnly(files("libs/ProjectKorra-1.12.1-PRE-RELEASE-1.jar")) + + implementation("org.bstats:bstats-bukkit:3.1.0") // We want this included and relocated } tasks { shadowJar { - archiveClassifier.set("") - dependencies { - relocate("org.bstats", "me.moros.hyperion.bstats") - } - minimize() + archiveClassifier.set("") // Remove the "-all" suffix + relocate("org.bstats", "me.moros.hyperion.bstats") // Relocate bStats to avoid conflict + minimize() // Only include used classes from implementation deps } + build { dependsOn(shadowJar) } + withType { options.compilerArgs.addAll(listOf("-Xlint:unchecked", "-Xlint:deprecation")) options.encoding = "UTF-8" } + withType { isPreserveFileTimestamps = false isReproducibleFileOrder = true } + named("processResources") { expand("pluginVersion" to project.version) } diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 29b8f06..8793e4c 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -25,18 +25,25 @@ import me.moros.hyperion.listeners.CoreListener; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; +import me.moros.hyperion.util.PotionEffectAdapter; +import me.moros.hyperion.util.PotionEffectAdapterFactory; import me.moros.hyperion.util.TempArmorStand; import org.bstats.bukkit.Metrics; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; import java.util.logging.Logger; public class Hyperion extends JavaPlugin { - private static Hyperion plugin; + public static Hyperion plugin; private static String author; private static String version; private static Logger log; private static PersistentDataLayer layer; + public static boolean isFolia; + public static boolean paper; + public static boolean luminol; + private PotionEffectAdapter potionEffectAdapter; @Override public void onEnable() { @@ -45,23 +52,71 @@ public void onEnable() { version = getDescription().getVersion(); author = getDescription().getAuthors().get(0); + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + isFolia = true; + } catch (ClassNotFoundException ignored) {} + + try { + Class.forName("com.destroystokyo.paper.PaperConfig"); + paper = true; + } catch (ClassNotFoundException ignored) {} + + try { + Class.forName("me.earthme.luminol.api.ThreadedRegion"); + luminol = true; + } catch (ClassNotFoundException ignored) {} + new Metrics(this, 8212); new ConfigManager(); new HyperionCommand(); layer = new PersistentDataLayer(); + checkMaintainer(); CoreMethods.loadAbilities(); getServer().getPluginManager().registerEvents(new AbilityListener(), this); getServer().getPluginManager().registerEvents(new CoreListener(), this); - getServer().getScheduler().scheduleSyncRepeatingTask(this, TempArmorStand::manage, 0, 1); - getServer().getScheduler().scheduleSyncRepeatingTask(this, BendingFallingBlock::manage, 0, 5); + + // Use appropriate scheduler depending on platform + if (isFolia || luminol) { + // Folia & Luminol require initial delay > 0 + getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempArmorStand.manage(), 1L, 1L); + getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> BendingFallingBlock.manage(), 1L, 5L); + } else { + new BukkitRunnable() { + @Override + public void run() { + TempArmorStand.manage(); + } + }.runTaskTimer(this, 0L, 1L); + + new BukkitRunnable() { + @Override + public void run() { + BendingFallingBlock.manage(); + } + }.runTaskTimer(this, 0L, 5L); + } + + PotionEffectAdapterFactory potionEffectAdapterFactory = new PotionEffectAdapterFactory(); + potionEffectAdapter = potionEffectAdapterFactory.getAdapter(); + + if (author.contains("Hihelloy (Maintainer)")) { + getLogger().info("Hihelloy is the current maintainer of Hyperion"); + } else { + getLogger().warning("Hihelloy is the current maintainer of Hyperion, but the plugin had trouble loading that D:"); + } } @Override public void onDisable() { BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); - getServer().getScheduler().cancelTasks(this); + + // Avoid cancelTasks on Folia/Luminol (unsupported) + if (!isFolia && !luminol) { + getServer().getScheduler().cancelTasks(this); + } } public static void reload() { @@ -73,6 +128,12 @@ public static void reload() { getLog().info("Hyperion Reloaded."); } + public static void checkMaintainer() { + if (!author.contains("Hihelloy (Maintainer)")) { + author = author + ", Hihelloy (Maintainer)"; + } + } + public static Hyperion getPlugin() { return plugin; } @@ -92,4 +153,20 @@ public static Logger getLog() { public static PersistentDataLayer getLayer() { return layer; } + + public PotionEffectAdapter getPotionEffectAdapter() { + return this.potionEffectAdapter; + } + + public static boolean isFolia() { + return isFolia; + } + + public static boolean isPaper() { + return paper; + } + + public static boolean isLuminol() { + return luminol; + } } diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index ce93e45..cfe97ec 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -207,7 +207,7 @@ private void formArmor(Material material) { originalMode = player.getGameMode(); player.getInventory().setArmorContents(newArmor.toArray(new ItemStack[4])); - new TempPotionEffect(player, new PotionEffect(PotionEffectType.RESISTANCE, NumberConversions.round(duration / 50F), resistance)); + new TempPotionEffect(player, new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, NumberConversions.round(duration / 50F), resistance)); time = System.currentTimeMillis(); formed = true; } @@ -315,7 +315,7 @@ public void remove() { armorFallingBlock.remove(); } if (formed) { - player.removePotionEffect(PotionEffectType.RESISTANCE); + player.removePotionEffect(PotionEffectType.DAMAGE_RESISTANCE); if (!originalMode.equals(player.getGameMode())) { for (ItemStack armorItem : oldArmor) { if (armorItem != null && armorItem.getType() != Material.AIR) { diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java index 2c0bdbf..5b9c251 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java @@ -51,6 +51,7 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; + import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java index 297b5c5..7c8c5b7 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java @@ -29,7 +29,6 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; @@ -48,6 +47,14 @@ import java.util.concurrent.ThreadLocalRandom; + +import static me.moros.hyperion.util.ParticleEffect.*; +import static me.moros.hyperion.util.ParticleEffect.EXPLOSION_HUGE; +import static me.moros.hyperion.util.ParticleEffect.FIREWORKS_SPARK; +import static me.moros.hyperion.util.ParticleEffect.FLAME; +import static me.moros.hyperion.util.ParticleEffect.SMOKE_LARGE; +import static me.moros.hyperion.util.ParticleEffect.SMOKE_NORMAL; + public class Combustion extends CombustionAbility implements AddonAbility { private Location location; @@ -163,7 +170,7 @@ private void advanceLocation() { for (int angle = 0; angle <= 360; angle += 12) { final Vector temp = GeneralMethods.getOrthogonalVector(direction, angle, 0.2); final Vector dir = GeneralMethods.getOrthogonalVector(direction, angle, radius); - ParticleEffect.FIREWORKS_SPARK.display(location.clone().add(temp), 0, dir.getX(), dir.getY(), dir.getZ(), 0.12); + FIREWORKS_SPARK.display(location.clone().add(temp), 0, dir.getX(), dir.getY(), dir.getZ(), 0.12); } } for (int i = 0; i < NumberConversions.round(speed / 0.4); i++) { @@ -173,8 +180,8 @@ private void advanceLocation() { return; } location.add(direction.clone().multiply(0.4)); - ParticleEffect.SMOKE_LARGE.display(location, 1, 0, 0, 0, 0.06); - ParticleEffect.FIREWORKS_SPARK.display(location, 1, 0, 0, 0, 0.06); + SMOKE_LARGE.display(location, 1, 0, 0, 0, 0.06); + FIREWORKS_SPARK.display(location, 1, 0, 0, 0, 0.06); if (i % 2 != 0) { if (RegionProtection.isRegionProtected(this, location)) { remove(); @@ -195,11 +202,11 @@ private void advanceLocation() { private void createExplosion(Location center, double size, double damage) { if (hasExploded) return; hasExploded = true; - ParticleEffect.FLAME.display(center, 20, 1, 1, 1, 0.5f, 20); - ParticleEffect.SMOKE_LARGE.display(center, 20, 1, 1, 1, 0.5f); - ParticleEffect.FIREWORKS_SPARK.display(center, 20, 1, 1, 1, 0.5f); - ParticleEffect.SMOKE_LARGE.display(center, 20, 1, 1, 1, 0.5f); - ParticleEffect.EXPLOSION_HUGE.display(center, 5, 1, 1, 1, 0.5f); + FLAME.display(center, 20, 1, 1, 1, 0.5f, 20); + SMOKE_LARGE.display(center, 20, 1, 1, 1, 0.5f); + FIREWORKS_SPARK.display(center, 20, 1, 1, 1, 0.5f); + SMOKE_LARGE.display(center, 20, 1, 1, 1, 0.5f); + EXPLOSION_HUGE.display(center, 5, 1, 1, 1, 0.5f); center.getWorld().playSound(center, Sound.ENTITY_GENERIC_EXPLODE, 1, 1); if (regenDelay > 0 && !center.getBlock().isLiquid()) { @@ -243,8 +250,8 @@ private void playParticleRing() { double x = 1.75 * FastMath.cos(currentRingPoint); double z = 1.75 * FastMath.sin(currentRingPoint); Location loc = player.getLocation().clone().add(x, 1, z); - ParticleEffect.FLAME.display(loc, 2, 0, 0, 0, 0.01); - ParticleEffect.SMOKE_NORMAL.display(loc, 2, 0, 0, 0, 0.01); + FLAME.display(loc, 2, 0, 0, 0, 0.01); + SMOKE_NORMAL.display(loc, 2, 0, 0, 0, 0.01); } } diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java index 495fd8f..a4492a4 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java @@ -29,7 +29,7 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; +import me.moros.hyperion.util.ParticleEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java index 70c1e61..3e9eb53 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java @@ -19,7 +19,7 @@ package me.moros.hyperion.abilities.firebending.combo; -import com.projectkorra.projectkorra.Element.SubElement; + import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AirAbility; @@ -34,7 +34,7 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; +import me.moros.hyperion.util.ParticleEffect; import com.projectkorra.projectkorra.waterbending.SurgeWall; import com.projectkorra.projectkorra.waterbending.SurgeWave; import me.moros.hyperion.Hyperion; @@ -56,6 +56,8 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import static com.projectkorra.projectkorra.Element.BLUE_FIRE; + public class FireWave extends FireAbility implements AddonAbility, ComboAbility { private final Set blocks = new HashSet<>(); private ListIterator waveIterator; @@ -96,7 +98,7 @@ public FireWave(Player player) { maxHeight = Hyperion.getPlugin().getConfig().getInt("Abilities.Fire.FireCombo.FireWave.MaxHeight"); width = Hyperion.getPlugin().getConfig().getInt("Abilities.Fire.FireCombo.FireWave.Width"); - if (bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) { + if (bPlayer.canUseSubElement(BLUE_FIRE)) { damage *= BlueFireAbility.getDamageFactor(); height *= BlueFireAbility.getRangeFactor(); maxHeight *= BlueFireAbility.getRangeFactor(); @@ -301,7 +303,7 @@ public double getCollisionRadius() { @Override public void handleCollision(Collision collision) { if (collision.getAbilitySecond() instanceof SurgeWave || collision.getAbilitySecond() instanceof SurgeWall) { - if (!bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) collision.setRemovingFirst(true); + if (!bPlayer.canUseSubElement(BLUE_FIRE)) collision.setRemovingFirst(true); if (collision.getAbilitySecond() instanceof SurgeWall && ((SurgeWall) collision.getAbilitySecond()).isFrozen()) { collision.setRemovingSecond(false); } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java index e89e531..2462144 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java @@ -203,7 +203,7 @@ private void checkArea(double radius) { final MovementHandler mh = new MovementHandler((LivingEntity) entity, CoreAbility.getAbility(IceCrawl.class)); mh.stopWithDuration(frostDuration / 50, Element.ICE.getColor() + "* Frozen *"); new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, frostDuration); - new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOWNESS, (int) (frostDuration / 50), 3)); + new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOW, (int) (frostDuration / 50), 3)); } } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java index a77ec99..8eabbaa 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java @@ -192,7 +192,7 @@ private void checkDamage() { final MovementHandler mh = new MovementHandler((LivingEntity) entity, CoreAbility.getAbility(IceCrawl.class)); mh.stopWithDuration(duration / 50, Element.ICE.getColor() + "* Frozen *"); new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, duration); - new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOWNESS, NumberConversions.round(duration / 50F), 5)); + new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOW, NumberConversions.round(duration / 50F), 5)); } hasHit = true; } diff --git a/src/main/java/me/moros/hyperion/util/PaperLib.java b/src/main/java/me/moros/hyperion/util/PaperLib.java new file mode 100644 index 0000000..a82dee2 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PaperLib.java @@ -0,0 +1,99 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package me.moros.hyperion.util; + + +import java.util.concurrent.CompletableFuture; + + +import me.moros.hyperion.Hyperion; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +public class PaperLib { + private static Environment ENVIRONMENT; + + public static CompletableFuture getChunkAtAsync(Location location) { + return ENVIRONMENT.getChunkAtAsync(location); + } + + public static CompletableFuture getChunkAtAsync(Block block) { + return ENVIRONMENT.getChunkAtAsync(block); + } + + public static CompletableFuture teleportAsync(Entity entity, Location location) { + return ENVIRONMENT.teleportAsync(entity, location); + } + + public static CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + return ENVIRONMENT.teleportAsync(entity, location, cause); + } + + static { + if (Hyperion.isFolia()) { + ENVIRONMENT = new Folia(); + } else if (Hyperion.isPaper()) { + ENVIRONMENT = new Paper(); + } else { + ENVIRONMENT = new Spigot(); + } + + } + + private interface Environment { + default CompletableFuture getChunkAtAsync(Location location) { + return this.getChunkAtAsync(location.getBlock()); + } + + CompletableFuture getChunkAtAsync(Block var1); + + default CompletableFuture teleportAsync(Entity entity, Location location) { + return this.teleportAsync(entity, location, TeleportCause.PLUGIN); + } + + CompletableFuture teleportAsync(Entity var1, Location var2, PlayerTeleportEvent.TeleportCause var3); + } + + static class Spigot implements Environment { + public CompletableFuture getChunkAtAsync(Block block) { + return CompletableFuture.completedFuture(block.getChunk()); + } + + public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + entity.teleport(location, cause); + return CompletableFuture.completedFuture(true); + } + } + + static class Paper implements Environment { + public CompletableFuture getChunkAtAsync(Block block) { + return block.getWorld().getChunkAtAsync(block); + } + + public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + return entity.teleportAsync(location, cause); + } + } + + static class Folia implements Environment { + public CompletableFuture getChunkAtAsync(Block block) { + CompletableFuture future = new CompletableFuture(); + ThreadUtil.ensureLocation(block.getLocation(), () -> { + Chunk chunk = block.getWorld().getChunkAt(block); + future.complete(chunk); + }); + return future; + } + + public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + return entity.teleportAsync(location, cause); + } + } +} diff --git a/src/main/java/me/moros/hyperion/util/ParticleEffect.java b/src/main/java/me/moros/hyperion/util/ParticleEffect.java new file mode 100644 index 0000000..d4c5e17 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/ParticleEffect.java @@ -0,0 +1,145 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package me.moros.hyperion.util; + +import com.projectkorra.projectkorra.GeneralMethods; +import org.bukkit.Location; +import org.bukkit.Particle; + + +public enum ParticleEffect { + ASH(Particle.ASH), + BLOCK_CRACK(Particle.BLOCK_CRACK), + BLOCK_DUST(Particle.BLOCK_DUST), + BUBBLE_COLUMN_UP(Particle.BUBBLE_COLUMN_UP), + BUBBLE_POP(Particle.BUBBLE_POP), + CAMPFIRE_COSY_SMOKE(Particle.CAMPFIRE_COSY_SMOKE), + CAMPFIRE_SIGNAL_SMOKE(Particle.CAMPFIRE_SIGNAL_SMOKE), + CLOUD(Particle.CLOUD), + COMPOSTER(Particle.COMPOSTER), + CRIMSON_SPORE(Particle.CRIMSON_SPORE), + CRIT(Particle.CRIT), + CRIT_MAGIC(Particle.CRIT_MAGIC), + MAGIC_CRIT(Particle.CRIT_MAGIC), + CURRENT_DOWN(Particle.CURRENT_DOWN), + DAMAGE_INDICATOR(Particle.DAMAGE_INDICATOR), + DOLPHIN(Particle.DOLPHIN), + DRAGON_BREATH(Particle.DRAGON_BREATH), + DRIP_LAVA(Particle.DRIP_LAVA), + DRIP_WATER(Particle.DRIP_WATER), + DRIPPING_HONEY(Particle.DRIPPING_HONEY), + DRIPPING_OBSIDIAN_TEAR(Particle.DRIPPING_OBSIDIAN_TEAR), + ENCHANTMENT_TABLE(Particle.ENCHANTMENT_TABLE), + END_ROD(Particle.END_ROD), + EXPLOSION_HUGE(Particle.EXPLOSION_HUGE), + HUGE_EXPLOSION(Particle.EXPLOSION_HUGE), + EXPLOSION_LARGE(Particle.EXPLOSION_LARGE), + LARGE_EXPLODE(Particle.EXPLOSION_LARGE), + EXPLOSION_NORMAL(Particle.EXPLOSION_NORMAL), + EXPLODE(Particle.EXPLOSION_NORMAL), + FALLING_DUST(Particle.FALLING_DUST), + FALLING_HONEY(Particle.FALLING_HONEY), + FALLING_LAVA(Particle.FALLING_LAVA), + FALLING_NECTAR(Particle.FALLING_NECTAR), + FALLING_OBSIDIAN_TEAR(Particle.FALLING_OBSIDIAN_TEAR), + FALLING_WATER(Particle.FALLING_WATER), + FIREWORKS_SPARK(Particle.FIREWORKS_SPARK), + FLAME(Particle.FLAME), + FLASH(Particle.FLASH), + HEART(Particle.HEART), + ITEM_CRACK(Particle.ITEM_CRACK), + LANDING_HONEY(Particle.LANDING_HONEY), + LANDING_LAVA(Particle.LANDING_LAVA), + LANDING_OBSIDIAN_TEAR(Particle.LANDING_OBSIDIAN_TEAR), + LAVA(Particle.LAVA), + MOB_APPEARANCE(Particle.MOB_APPEARANCE), + NAUTILUS(Particle.NAUTILUS), + NOTE(Particle.NOTE), + PORTAL(Particle.PORTAL), + REDSTONE(Particle.REDSTONE), + RED_DUST(Particle.REDSTONE), + REVERSE_PORTAL(Particle.REVERSE_PORTAL), + SLIME(Particle.SLIME), + SMOKE_NORMAL(Particle.SMOKE_NORMAL), + SMOKE(Particle.SMOKE_NORMAL), + SMOKE_LARGE(Particle.SMOKE_LARGE), + LARGE_SMOKE(Particle.SMOKE_LARGE), + SNEEZE(Particle.SNEEZE), + SNOW_SHOVEL(Particle.SNOW_SHOVEL), + SNOWBALL(Particle.SNOWBALL), + SNOWBALL_PROOF(Particle.SNOWBALL), + SOUL(Particle.SOUL), + SOUL_FIRE_FLAME(Particle.SOUL_FIRE_FLAME), + SPELL(Particle.SPELL), + SPELL_INSTANT(Particle.SPELL_INSTANT), + INSTANT_SPELL(Particle.SPELL_INSTANT), + SPELL_MOB(Particle.SPELL_MOB), + MOB_SPELL(Particle.SPELL_MOB), + SPELL_MOB_AMBIENT(GeneralMethods.getMCVersion() >= 1205 ? Particle.SPELL_MOB : Particle.SPELL_MOB_AMBIENT), + MOB_SPELL_AMBIENT(GeneralMethods.getMCVersion() >= 1205 ? Particle.SPELL_MOB : Particle.SPELL_MOB_AMBIENT), + SPELL_WITCH(Particle.SPELL_WITCH), + WITCH_SPELL(Particle.SPELL_WITCH), + SPIT(Particle.SPIT), + SQUID_INK(Particle.SQUID_INK), + SUSPENDED(Particle.SUSPENDED), + SUSPEND(Particle.SUSPENDED), + SUSPENDED_DEPTH(Particle.SUSPENDED_DEPTH), + DEPTH_SUSPEND(Particle.SUSPENDED_DEPTH), + SWEEP_ATTACK(Particle.SWEEP_ATTACK), + TOTEM(Particle.TOTEM), + TOWN_AURA(Particle.TOWN_AURA), + VILLAGER_ANGRY(Particle.VILLAGER_ANGRY), + ANGRY_VILLAGER(Particle.VILLAGER_ANGRY), + VILLAGER_HAPPY(Particle.VILLAGER_HAPPY), + HAPPY_VILLAGER(Particle.VILLAGER_HAPPY), + WARPED_SPORE(Particle.WARPED_SPORE), + WATER_BUBBLE(Particle.WATER_BUBBLE), + BUBBLE(Particle.WATER_BUBBLE), + WATER_DROP(Particle.WATER_DROP), + WATER_SPLASH(Particle.WATER_SPLASH), + SPLASH(Particle.WATER_SPLASH), + WATER_WAKE(Particle.WATER_WAKE), + WAKE(Particle.WATER_WAKE), + WHITE_ASH(Particle.WHITE_ASH), + ELECTRIC_SPARK(Particle.ELECTRIC_SPARK); + + Particle particle; + Class dataClass; + + private ParticleEffect(Particle particle) { + this.particle = particle; + this.dataClass = particle.getDataType(); + } + + public Particle getParticle() { + return this.particle; + } + + public void display(Location loc, int amount) { + this.display(loc, amount, (double)0.0F, (double)0.0F, (double)0.0F); + } + + public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ) { + this.display(loc, amount, offsetX, offsetY, offsetZ, (double)0.0F); + } + + public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, double extra) { + loc.getWorld().spawnParticle(this.particle, loc, amount, offsetX, offsetY, offsetZ, extra, (Object)null, true); + } + + public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, Object data) { + this.display(loc, amount, offsetX, offsetY, offsetZ, (double)0.0F, data); + } + + public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, double extra, Object data) { + if (!this.dataClass.isAssignableFrom(Void.class) && data != null && this.dataClass.isAssignableFrom(data.getClass())) { + loc.getWorld().spawnParticle(this.particle, loc, amount, offsetX, offsetY, offsetZ, extra, data, true); + } else { + this.display(loc, amount, offsetX, offsetY, offsetZ, extra); + } + + } +} diff --git a/src/main/java/me/moros/hyperion/util/PotionEffectAdapter.java b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter.java new file mode 100644 index 0000000..bbd9d13 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter.java @@ -0,0 +1,15 @@ +package me.moros.hyperion.util; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionType; + +public interface PotionEffectAdapter { + PotionType getHarmingPotionType(); + PotionEffect getSlownessEffect(int duration, int strength); + PotionEffect getResistanceEffect(int duration, int strength); + PotionEffect getNauseaEffect(int duration); + void applyJumpBoost(Player player, int duration, int strength); + boolean hasWaterPotion(Inventory inventory); +} diff --git a/src/main/java/me/moros/hyperion/util/PotionEffectAdapterFactory.java b/src/main/java/me/moros/hyperion/util/PotionEffectAdapterFactory.java new file mode 100644 index 0000000..515aa80 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PotionEffectAdapterFactory.java @@ -0,0 +1,25 @@ +package me.moros.hyperion.util; + +import com.projectkorra.projectkorra.GeneralMethods; +import org.bukkit.Bukkit; + +public class PotionEffectAdapterFactory { + + private PotionEffectAdapter adapter; + + public PotionEffectAdapterFactory() { + int serverVersion = GeneralMethods.getMCVersion(); + + if (serverVersion >= 1205) { + Bukkit.getLogger().info("[Hyperion] Using 1.20.5+ PotionEffectAdapter"); + adapter = new PotionEffectAdapter_1_20_5(); + } else { + Bukkit.getLogger().info("[Hyperion] Using 1.20.4- PotionEffectAdapter"); + adapter = new PotionEffectAdapter_1_20_4(); + } + } + + public PotionEffectAdapter getAdapter() { + return adapter; + } +} diff --git a/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_4.java b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_4.java new file mode 100644 index 0000000..2cd8db6 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_4.java @@ -0,0 +1,55 @@ +package me.moros.hyperion.util; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; + +public class PotionEffectAdapter_1_20_4 implements PotionEffectAdapter { + + @Override + public PotionType getHarmingPotionType() { + return PotionType.valueOf("INSTANT_DAMAGE"); + } + + @Override + public PotionEffect getSlownessEffect(int duration, int strength) { + return new PotionEffect(PotionEffectType.getByName("SLOW"), duration / 50, strength); + } + + @Override + public PotionEffect getResistanceEffect(int duration, int strength) { + return new PotionEffect(PotionEffectType.getByName("DAMAGE_RESISTANCE"), duration / 50, strength - 1); + } + + @Override + public PotionEffect getNauseaEffect(int duration) { + return new PotionEffect(PotionEffectType.getByName("CONFUSION"), duration / 50, 1); + } + + @Override + public void applyJumpBoost(Player player, int duration, int strength) { + if (player.hasPotionEffect(PotionEffectType.getByName("JUMP"))) { + player.removePotionEffect(PotionEffectType.getByName("JUMP")); + } + player.addPotionEffect(new PotionEffect(PotionEffectType.getByName("JUMP"), duration / 50, strength - 1)); + } + + @Override + public boolean hasWaterPotion(Inventory inventory) { + if (inventory.contains(Material.POTION)) { + ItemStack item = inventory.getItem(inventory.first(Material.POTION)); + if (item == null) return false; + PotionMeta meta = (PotionMeta) item.getItemMeta(); + if (meta == null) return false; + + PotionType potionType = PotionMetaUtil.getPotionType(meta); + return potionType == PotionType.WATER; + } + return false; + } +} diff --git a/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java new file mode 100644 index 0000000..2c165b0 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java @@ -0,0 +1,55 @@ +package me.moros.hyperion.util; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; + +public class PotionEffectAdapter_1_20_5 implements PotionEffectAdapter { + + @Override + public PotionType getHarmingPotionType() { + return PotionType.valueOf("HARMING"); + } + + @Override + public PotionEffect getSlownessEffect(int duration, int strength) { + return new PotionEffect(PotionEffectType.getByName("SLOWNESS"), duration / 50, strength - 1); + } + + @Override + public PotionEffect getResistanceEffect(int duration, int strength) { + return new PotionEffect(PotionEffectType.getByName("RESISTANCE"), duration / 50, strength - 1); + } + + @Override + public PotionEffect getNauseaEffect(int duration) { + return new PotionEffect(PotionEffectType.getByName("NAUSEA"), duration / 50, 1); + } + + @Override + public void applyJumpBoost(Player player, int duration, int strength) { + if (player.hasPotionEffect(PotionEffectType.getByName("JUMP_BOOST"))) { + player.removePotionEffect(PotionEffectType.getByName("JUMP_BOOST")); + } + player.addPotionEffect(new PotionEffect(PotionEffectType.getByName("JUMP_BOOST"), duration / 50, strength - 1)); + } + + @Override + public boolean hasWaterPotion(Inventory inventory) { + if (inventory.contains(Material.POTION)) { + ItemStack item = inventory.getItem(inventory.first(Material.POTION)); + if (item == null) return false; + PotionMeta meta = (PotionMeta) item.getItemMeta(); + if (meta == null) return false; + + PotionType potionType = PotionMetaUtil.getPotionType(meta); + return potionType == PotionType.WATER; + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/me/moros/hyperion/util/PotionMetaUtil.java b/src/main/java/me/moros/hyperion/util/PotionMetaUtil.java new file mode 100644 index 0000000..0a3c4ae --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/PotionMetaUtil.java @@ -0,0 +1,29 @@ +package me.moros.hyperion.util; + +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionType; + +import java.lang.reflect.Method; + +public class PotionMetaUtil { + + public static PotionType getPotionType(PotionMeta meta) { + try { + Method getBasePotionType = PotionMeta.class.getMethod("getBasePotionType"); + return (PotionType) getBasePotionType.invoke(meta); + } catch (NoSuchMethodException e) { + try { + Method getBasePotionData = PotionMeta.class.getMethod("getBasePotionData"); + Object basePotionData = getBasePotionData.invoke(meta); + + Method getType = basePotionData.getClass().getMethod("getType"); + return (PotionType) getType.invoke(basePotionData); + } catch (Exception ex) { + ex.printStackTrace(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/me/moros/hyperion/util/ThreadUtil.java b/src/main/java/me/moros/hyperion/util/ThreadUtil.java new file mode 100644 index 0000000..ef061f4 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/ThreadUtil.java @@ -0,0 +1,256 @@ +package me.moros.hyperion.util; + + +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import me.moros.hyperion.Hyperion; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +public class ThreadUtil { + + private static final boolean THREAD_UTIL_AVAILABLE; + private static final Class THREAD_UTIL_CLASS; + + static { + Class threadUtilClass = null; + try { + threadUtilClass = Class.forName("com.projectkorra.projectkorra.util.ThreadUtil"); + } catch (ClassNotFoundException e) { + // ThreadUtil not available, will use Bukkit scheduler + } + THREAD_UTIL_CLASS = threadUtilClass; + THREAD_UTIL_AVAILABLE = THREAD_UTIL_CLASS != null; + } + + public static void ensureLocation(Location location, Runnable runnable) { + if (Hyperion.isFolia()) { + if (Bukkit.isOwnedByCurrentRegion(location) || Bukkit.isStopping()) { + runnable.run(); + return; + } + + RegionScheduler scheduler = Bukkit.getRegionScheduler(); + scheduler.execute(Hyperion.plugin, location, runnable); + } else { + if (Bukkit.isPrimaryThread()) { + runnable.run(); + return; + } + + Bukkit.getScheduler().runTask(Hyperion.plugin, runnable); + } + + } + + public static void runGlobalLater(Runnable runnable, long delay) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("runGlobalLater", Runnable.class, long.class) + .invoke(null, runnable, delay); + } catch (Exception e) { + // Fallback to Bukkit scheduler + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } else { + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } + + public static void runLocationLater(Location location, Runnable runnable, long delay) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("ensureLocationLater", Location.class, Runnable.class, long.class) + .invoke(null, location, runnable, delay); + } catch (Exception e) { + // Fallback to Bukkit scheduler + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } else { + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } + + public static void runEntityLater(Entity entity, Runnable runnable, long delay) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("ensureEntityLater", Entity.class, Runnable.class, long.class) + .invoke(null, entity, runnable, delay); + } catch (Exception e) { + // Fallback to Bukkit scheduler + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } else { + new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskLater(Hyperion.plugin, delay); + } + } + + public static Object runGlobalTimer(Runnable runnable, long delay, long period) { + if (THREAD_UTIL_AVAILABLE) { + try { + return THREAD_UTIL_CLASS.getMethod("runGlobalTimer", Runnable.class, long.class, long.class) + .invoke(null, runnable, delay, period); + } catch (Exception e) { + // Fallback to Bukkit scheduler + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } else { + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } + + public static Object runLocationTimer(Location location, Runnable runnable, long delay, long period) { + if (THREAD_UTIL_AVAILABLE) { + try { + return THREAD_UTIL_CLASS.getMethod("ensureLocationTimer", Location.class, Runnable.class, long.class, long.class) + .invoke(null, location, runnable, delay, period); + } catch (Exception e) { + // Fallback to Bukkit scheduler + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } else { + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } + + public static Object runEntityTimer(Entity entity, Runnable runnable, long delay, long period) { + if (THREAD_UTIL_AVAILABLE) { + try { + return THREAD_UTIL_CLASS.getMethod("ensureEntityTimer", Entity.class, Runnable.class, long.class, long.class) + .invoke(null, entity, runnable, delay, period); + } catch (Exception e) { + // Fallback to Bukkit scheduler + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } else { + return new BukkitRunnable() { + @Override + public void run() { + runnable.run(); + } + }.runTaskTimer(Hyperion.plugin, delay, period); + } + } + + public static void runAsync(Runnable runnable) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("runAsync", Runnable.class) + .invoke(null, runnable); + } catch (Exception e) { + // Fallback to Bukkit scheduler + Bukkit.getScheduler().runTaskAsynchronously(Hyperion.plugin, runnable); + } + } else { + Bukkit.getScheduler().runTaskAsynchronously(Hyperion.plugin, runnable); + } + } + + public static Object runAsyncTimer(Runnable runnable, long delay, long period) { + if (THREAD_UTIL_AVAILABLE) { + try { + return THREAD_UTIL_CLASS.getMethod("runAsyncTimer", Runnable.class, long.class, long.class) + .invoke(null, runnable, delay, period); + } catch (Exception e) { + // Fallback to Bukkit scheduler + return Bukkit.getScheduler().runTaskTimerAsynchronously(Hyperion.plugin, runnable, delay, period); + } + } else { + return Bukkit.getScheduler().runTaskTimerAsynchronously(Hyperion.plugin, runnable, delay, period); + } + } + + public static void cancelTimerTask(Object task) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("cancelTimerTask", Object.class) + .invoke(null, task); + } catch (Exception e) { + // Fallback to Bukkit task cancellation + if (task instanceof BukkitTask) { + ((BukkitTask) task).cancel(); + } + } + } else { + if (task instanceof BukkitTask) { + ((BukkitTask) task).cancel(); + } + } + } + + public static boolean isThreadUtilAvailable() { + return THREAD_UTIL_AVAILABLE; + } + + public static void ensureEntity(Entity entity, Runnable runnable) { + if (THREAD_UTIL_AVAILABLE) { + try { + THREAD_UTIL_CLASS.getMethod("ensureEntity", Entity.class, Runnable.class) + .invoke(null, entity, runnable); + } catch (Exception e) { + // Fallback to global execution + runnable.run(); + } + } else { + // Fallback to global execution + runnable.run(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 02d5de4..b89aec2 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,10 +1,13 @@ name: Hyperion description: Addon plugin for ProjectKorra -author: Moros +author: Moros & Hihelloy version: ${pluginVersion} main: me.moros.hyperion.Hyperion depend: [ProjectKorra] -api-version: 1.17 +folia-supported: true +api-version: '1.20' +load: POSTWORLD + permissions: bending.admin.overridelock: default: false From 7b06ba1ffaef5e555db5662c457b58eecdba8c99 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Tue, 5 Aug 2025 20:13:10 -0700 Subject: [PATCH 02/34] Update README.MD --- README.MD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.MD b/README.MD index 25c5c07..58e9cc0 100644 --- a/README.MD +++ b/README.MD @@ -1,8 +1,8 @@ # Hyperion -[![Gradle CI](https://img.shields.io/github/actions/workflow/status/PrimordialMoros/Hyperion/gradle.yml?branch=master&style=flat-square)](https://github.com/PrimordialMoros/Hyperion/actions) -[![License](https://img.shields.io/github/license/PrimordialMoros/Hyperion?color=blue&style=flat-square)](LICENSE) -[![GitHub release](https://img.shields.io/github/v/release/PrimordialMoros/Hyperion?style=flat-square)](https://github.com/PrimordialMoros/Hyperion/releases) +[![Gradle CI](https://img.shields.io/github/actions/workflow/status/Hihelloy-main/Hyperion/gradle.yml?branch=master&style=flat-square)](https://github.com/Hihelloy-main/Hyperion/actions) +[![License](https://img.shields.io/github/license/Hihelloy-main/Hyperion?color=blue&style=flat-square)](LICENSE) +[![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) **New**: Modifier System. Read more about it on the [wiki](https://github.com/PrimordialMoros/Hyperion/wiki/Modifiers)! From d8e387b978546afa9333519e3cc1128ce8cb504e Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Tue, 5 Aug 2025 20:17:29 -0700 Subject: [PATCH 03/34] Update README.MD --- README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MD b/README.MD index 58e9cc0..7a0c893 100644 --- a/README.MD +++ b/README.MD @@ -3,6 +3,7 @@ [![Gradle CI](https://img.shields.io/github/actions/workflow/status/Hihelloy-main/Hyperion/gradle.yml?branch=master&style=flat-square)](https://github.com/Hihelloy-main/Hyperion/actions) [![License](https://img.shields.io/github/license/Hihelloy-main/Hyperion?color=blue&style=flat-square)](LICENSE) [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) +[![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) **New**: Modifier System. Read more about it on the [wiki](https://github.com/PrimordialMoros/Hyperion/wiki/Modifiers)! From 0f81f1ca8296d86fd03e60e43dfdb48514ed9358 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Tue, 5 Aug 2025 20:19:27 -0700 Subject: [PATCH 04/34] Update README.MD --- README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MD b/README.MD index 7a0c893..8340060 100644 --- a/README.MD +++ b/README.MD @@ -5,6 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) +Hi, I'm Hihelloy, and this is my fork of Moro's Hyperion ProjectKorra side plugin. **New**: Modifier System. Read more about it on the [wiki](https://github.com/PrimordialMoros/Hyperion/wiki/Modifiers)! Addon plugin for ProjectKorra with an emphasis on intricate mechanics From a5bcefa53cf036609a6493bdf20d389cd8169841 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Tue, 5 Aug 2025 20:21:29 -0700 Subject: [PATCH 05/34] Update README.MD --- README.MD | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.MD b/README.MD index 8340060..167ca5d 100644 --- a/README.MD +++ b/README.MD @@ -5,10 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moro's Hyperion ProjectKorra side plugin. -**New**: Modifier System. Read more about it on the [wiki](https://github.com/PrimordialMoros/Hyperion/wiki/Modifiers)! - -Addon plugin for ProjectKorra with an emphasis on intricate mechanics +Hi, I'm Hihelloy, and this is my fork of Moro's Hyperion ProjectKorra Addon plugin! ## Abilities ### Air From e03101950f07fcdcb1051afb1ff9cdca2cfe3fd2 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Wed, 6 Aug 2025 16:02:46 -0700 Subject: [PATCH 06/34] Fixed the earthbending TempArmorStand issues :D --- build.gradle.kts | 10 +- src/main/java/me/moros/hyperion/Hyperion.java | 36 ++- .../hyperion/abilities/airbending/Evade.java | 2 + .../abilities/earthbending/EarthGuard.java | 5 +- .../abilities/earthbending/EarthLine.java | 17 ++ .../abilities/firebending/Combustion.java | 9 +- .../abilities/firebending/FlameRush.java | 2 +- .../abilities/firebending/combo/FireWave.java | 2 +- .../abilities/waterbending/IceCrawl.java | 223 +++++++++--------- .../hyperion/listeners/CoreListener.java | 12 +- .../moros/hyperion/util/ParticleEffect.java | 145 ------------ .../moros/hyperion/util/TempArmorStand.java | 89 ++++--- src/main/resources/plugin.yml | 2 +- 13 files changed, 232 insertions(+), 322 deletions(-) delete mode 100644 src/main/java/me/moros/hyperion/util/ParticleEffect.java diff --git a/build.gradle.kts b/build.gradle.kts index 7a4f39c..9693171 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ plugins { java - id("com.github.johnrengelman.shadow") version "8.1.1" // official Shadow plugin + id("com.github.johnrengelman.shadow") version "8.1.1" } group = "me.moros" @@ -23,14 +23,14 @@ dependencies { compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT") compileOnly(files("libs/ProjectKorra-1.12.1-PRE-RELEASE-1.jar")) - implementation("org.bstats:bstats-bukkit:3.1.0") // We want this included and relocated + implementation("org.bstats:bstats-bukkit:3.1.0") } tasks { shadowJar { - archiveClassifier.set("") // Remove the "-all" suffix - relocate("org.bstats", "me.moros.hyperion.bstats") // Relocate bStats to avoid conflict - minimize() // Only include used classes from implementation deps + archiveClassifier.set("") // No "-all" suffix + relocate("org.bstats", "me.moros.hyperion.bstats") + minimize() } build { diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 8793e4c..3c90316 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -19,15 +19,14 @@ package me.moros.hyperion; +import com.projectkorra.projectkorra.util.TempFallingBlock; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.moros.hyperion.commands.HyperionCommand; import me.moros.hyperion.configuration.ConfigManager; import me.moros.hyperion.listeners.AbilityListener; import me.moros.hyperion.listeners.CoreListener; import me.moros.hyperion.methods.CoreMethods; -import me.moros.hyperion.util.BendingFallingBlock; -import me.moros.hyperion.util.PotionEffectAdapter; -import me.moros.hyperion.util.PotionEffectAdapterFactory; -import me.moros.hyperion.util.TempArmorStand; +import me.moros.hyperion.util.*; import org.bstats.bukkit.Metrics; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; @@ -79,10 +78,17 @@ public void onEnable() { // Use appropriate scheduler depending on platform if (isFolia || luminol) { - // Folia & Luminol require initial delay > 0 + getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempFallingBlock.manage(), 1L, 5L); getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempArmorStand.manage(), 1L, 1L); getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> BendingFallingBlock.manage(), 1L, 5L); } else { + new BukkitRunnable() { + @Override + public void run() { + TempFallingBlock.manage(); + } + }.runTaskTimer(this, 0L, 5L); + new BukkitRunnable() { @Override public void run() { @@ -113,19 +119,32 @@ public void onDisable() { BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); - // Avoid cancelTasks on Folia/Luminol (unsupported) + // Avoid Bukkit cancelTasks on Folia/Luminol (unsupported) if (!isFolia && !luminol) { getServer().getScheduler().cancelTasks(this); } + // Use a Folia/Luminol compatible version of cancelTasks + if (isFolia || luminol ) { + getServer().getGlobalRegionScheduler().cancelTasks(this); + } + } + + public static void reload1() { + Hyperion.getPlugin().reloadConfig(); + ConfigManager.modifiersConfig.reloadConfig(); + BendingFallingBlock.removeAll(); + TempArmorStand.removeAll(); + CoreMethods.loadAbilities(); + getLog().info("Hyperion BUKKIT Reloaded."); } - public static void reload() { + public static void reload(ScheduledTask scheduledTask) { Hyperion.getPlugin().reloadConfig(); ConfigManager.modifiersConfig.reloadConfig(); BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); CoreMethods.loadAbilities(); - getLog().info("Hyperion Reloaded."); + getLog().info("Hyperion FOLIA Reloaded."); } public static void checkMaintainer() { @@ -169,4 +188,5 @@ public static boolean isPaper() { public static boolean isLuminol() { return luminol; } + } diff --git a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java index 814511d..e5fb8f2 100644 --- a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java +++ b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java @@ -22,6 +22,7 @@ import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AirAbility; import me.moros.hyperion.Hyperion; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -31,6 +32,7 @@ public class Evade extends AirAbility implements AddonAbility { private long cooldown; + private double angleStep; private int ticks = 0; diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index cfe97ec..bef3274 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -31,6 +31,7 @@ import com.projectkorra.projectkorra.util.TempPotionEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.BendingFallingBlock; +import me.moros.hyperion.util.PotionMetaUtil; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.GameMode; @@ -207,7 +208,7 @@ private void formArmor(Material material) { originalMode = player.getGameMode(); player.getInventory().setArmorContents(newArmor.toArray(new ItemStack[4])); - new TempPotionEffect(player, new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, NumberConversions.round(duration / 50F), resistance)); + new TempPotionEffect(player, new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, NumberConversions.round(duration / 50F), resistance)); time = System.currentTimeMillis(); formed = true; } @@ -342,4 +343,4 @@ public void remove() { @Override public void stop() { } -} +} \ No newline at end of file diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java index 5b9c251..14c2ce4 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java @@ -54,6 +54,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -95,6 +96,7 @@ private enum EarthLineMode {NORMAL, PRISON, MAGMA} private boolean launched; private boolean targetLocked; private boolean collapsing; + private final List armorStands = new ArrayList<>(); private boolean makeSpikes; private double earthLineSpeed; @@ -142,8 +144,20 @@ public EarthLine(Player player) { } } + private void removeExpiredArmorStands() { + Iterator it = armorStands.iterator(); + while (it.hasNext()) { + TempArmorStand stand = it.next(); + if (stand.isExpired()) { + stand.remove(); + it.remove(); + } + } + } @Override public void progress() { + removeExpiredArmorStands(); + TempArmorStand.manage(); if (launched) { if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { remove(); @@ -265,6 +279,7 @@ private void raiseSpikes() { pillar2.setCooldown(0); pillar2.setInterval(100); remove(); + removeExpiredArmorStands(); } private void advanceLocation() { @@ -451,7 +466,9 @@ public void stop() { @Override public void remove() { + removeExpiredArmorStands(); sourceBlock.revertBlock(); + BendingFallingBlock.removeAll(); super.remove(); } diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java index 7c8c5b7..386123d 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java @@ -48,12 +48,9 @@ import java.util.concurrent.ThreadLocalRandom; -import static me.moros.hyperion.util.ParticleEffect.*; -import static me.moros.hyperion.util.ParticleEffect.EXPLOSION_HUGE; -import static me.moros.hyperion.util.ParticleEffect.FIREWORKS_SPARK; -import static me.moros.hyperion.util.ParticleEffect.FLAME; -import static me.moros.hyperion.util.ParticleEffect.SMOKE_LARGE; -import static me.moros.hyperion.util.ParticleEffect.SMOKE_NORMAL; +import static com.projectkorra.projectkorra.util.ParticleEffect.*; +import static com.projectkorra.projectkorra.util.ParticleEffect.FIREWORKS_SPARK; +import static com.projectkorra.projectkorra.util.ParticleEffect.SMOKE_LARGE; public class Combustion extends CombustionAbility implements AddonAbility { private Location location; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java index a4492a4..495fd8f 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java @@ -29,7 +29,7 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; import com.projectkorra.projectkorra.util.DamageHandler; -import me.moros.hyperion.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ParticleEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java index 3e9eb53..8d490a1 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java @@ -34,7 +34,7 @@ import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; -import me.moros.hyperion.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.waterbending.SurgeWall; import com.projectkorra.projectkorra.waterbending.SurgeWave; import me.moros.hyperion.Hyperion; diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java index 8eabbaa..210b7b6 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java @@ -1,22 +1,3 @@ -/* - * Copyright 2016-2024 Moros - * - * This file is part of Hyperion. - * - * Hyperion 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. - * - * Hyperion 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 Hyperion. If not, see . - */ - package me.moros.hyperion.abilities.waterbending; import com.projectkorra.projectkorra.Element; @@ -49,10 +30,15 @@ import org.bukkit.util.NumberConversions; import org.bukkit.util.Vector; + +import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; +import java.util.List; import java.util.concurrent.ThreadLocalRandom; public class IceCrawl extends IceAbility implements AddonAbility { + private Location location; private Location endLocation; private LivingEntity target; @@ -75,13 +61,13 @@ public class IceCrawl extends IceAbility implements AddonAbility { private boolean launched; private boolean locked; + private final List armorStands = new ArrayList<>(); + private final List tempBlocks = new ArrayList<>(); + public IceCrawl(Player player) { super(player); - if (!bPlayer.canBend(this)) { - return; - } - + if (!bPlayer.canBend(this)) return; if (hasAbility(player, IceCrawl.class)) { getAbility(player, IceCrawl.class).prepare(); return; @@ -113,22 +99,24 @@ public void progress() { return; } if (locked) { - if (target == null || !target.isValid() || (target instanceof Player && !((Player) target).isOnline()) || !target.getWorld().equals(location.getWorld())) { + if (target == null || !target.isValid() + || (target instanceof Player && !((Player) target).isOnline()) + || !target.getWorld().equals(location.getWorld())) { locked = false; + } else if (target.getLocation().distanceSquared(endLocation) < 25) { + endLocation = target.getLocation().clone(); + direction = CoreMethods.calculateFlatVector(sourceBlock.getLocation(), endLocation); } else { - if (target.getLocation().distanceSquared(endLocation) < 25) { - endLocation = target.getLocation().clone(); - direction = CoreMethods.calculateFlatVector(sourceBlock.getLocation(), endLocation); - } else { - locked = false; - } + locked = false; } } advanceLocation(); checkDamage(); if (ThreadLocalRandom.current().nextInt(5) == 0) playIcebendingSound(location); + cleanupArmorStands(); } else { - if (!bPlayer.canBendIgnoreCooldowns(this) || sourceBlock.getLocation().distanceSquared(player.getLocation()) > Math.pow(selectRange + 5, 2)) { + if (!bPlayer.canBendIgnoreCooldowns(this) + || sourceBlock.getLocation().distanceSquared(player.getLocation()) > Math.pow(selectRange + 5, 2)) { remove(); return; } @@ -144,62 +132,94 @@ private void advanceLocation() { if (isLava(location.getBlock())) { CoreMethods.playExtinguishEffect(location.clone().add(0, 0.2, 0), 8); remove(); + return; + } + + Block down = location.getBlock().getRelative(BlockFace.DOWN); + if (isWater(down)) { + TempBlock tb = new TempBlock(down, Material.ICE.createBlockData(), iceDuration); + PhaseChange.getFrozenBlocksMap().put(tb, player); + tempBlocks.add(tb); } - if (isWater(location.getBlock().getRelative(BlockFace.DOWN))) - PhaseChange.getFrozenBlocksMap().put(new TempBlock(location.getBlock().getRelative(BlockFace.DOWN), Material.ICE.createBlockData(), iceDuration), player); double x = ThreadLocalRandom.current().nextDouble(-0.125, 0.125); double z = ThreadLocalRandom.current().nextDouble(-0.125, 0.125); - new TempArmorStand(this, location.clone().add(x, -2, z), Material.PACKED_ICE, 1400); + TempArmorStand stand = new TempArmorStand(this, location.clone().add(x, -2, z), Material.PACKED_ICE, 1400); + armorStands.add(stand); location.add(direction.clone().multiply(0.7)); - final Block baseBlock = location.getBlock().getRelative(BlockFace.DOWN); - if (!isValidBlock(baseBlock)) { - if (isValidBlock(baseBlock.getRelative(BlockFace.UP))) { + + Block base = location.getBlock().getRelative(BlockFace.DOWN); + if (!isValidBlock(base)) { + if (isValidBlock(base.getRelative(BlockFace.UP))) { location.add(0, 1, 0); - } else if (isValidBlock(baseBlock.getRelative(BlockFace.DOWN))) { + } else if (isValidBlock(base.getRelative(BlockFace.DOWN))) { location.add(0, -1, 0); } else { remove(); return; } - } else if (endLocation.getBlockY() != location.getBlockY()) { // Advance location vertically while under water - if (endLocation.getBlockY() > location.getBlockY() && isValidBlock(baseBlock.getRelative(BlockFace.UP))) { + } else if (endLocation.getBlockY() != location.getBlockY()) { + if (endLocation.getBlockY() > location.getBlockY() + && isValidBlock(base.getRelative(BlockFace.UP))) { location.add(0, 1, 0); - } else if (endLocation.getBlockY() < location.getBlockY() && isValidBlock(baseBlock.getRelative(BlockFace.DOWN))) { + } else if (endLocation.getBlockY() < location.getBlockY() + && isValidBlock(base.getRelative(BlockFace.DOWN))) { location.add(0, -1, 0); } } - if (RegionProtection.isRegionProtected(this, location) || location.distanceSquared(sourceBlock.getLocation()) > range * range) { + + if (RegionProtection.isRegionProtected(this, location) + || location.distanceSquared(sourceBlock.getLocation()) > range * range) { remove(); } } - private boolean isValidBlock(final Block block) { + private void cleanupArmorStands() { + Iterator it = armorStands.iterator(); + while (it.hasNext()) { + TempArmorStand stand = it.next(); + if (stand.isExpired()) { + stand.remove(); + it.remove(); + } + } + } + + private boolean isValidBlock(Block block) { if (!isTransparent(block.getRelative(BlockFace.UP))) return false; return isWater(block) || isIce(block) || GeneralMethods.isSolid(block); } private void checkDamage() { - boolean hasHit = false; + boolean hit = false; for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, 0.8)) { - if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() && !(entity instanceof ArmorStand)) { + if (entity instanceof LivingEntity && entity.getEntityId() != player.getEntityId() + && !(entity instanceof ArmorStand)) { + if (entity instanceof Player && Commands.invincible.contains(entity.getName())) { continue; } + DamageHandler.damageEntity(entity, getNightFactor(damage, player.getWorld()), this); if (entity.isValid()) { - final MovementHandler mh = new MovementHandler((LivingEntity) entity, CoreAbility.getAbility(IceCrawl.class)); - mh.stopWithDuration(duration / 50, Element.ICE.getColor() + "* Frozen *"); - new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, duration); - new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOW, NumberConversions.round(duration / 50F), 5)); + MovementHandler mh = new MovementHandler((LivingEntity) entity, + CoreAbility.getAbility(IceCrawl.class)); + mh.stopWithDuration(duration / 50, + Element.ICE.getColor() + "* Frozen *"); + new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), + Material.PACKED_ICE.createBlockData(), + new Vector(), this, false, duration); + new TempPotionEffect((LivingEntity) entity, + new PotionEffect(PotionEffectType.SLOW, + NumberConversions.round(duration / 50F), 5)); } - hasHit = true; + + hit = true; } } - if (hasHit) { - remove(); - } + + if (hit) remove(); } public boolean prepare() { @@ -208,12 +228,12 @@ public boolean prepare() { if (block == null) { block = getWaterSourceBlock(player, selectRange, false); } - - if (block == null || (!isWater(block) && !isIce(block)) || !isTransparent(block.getRelative(BlockFace.UP))) { + if (block == null + || (!isWater(block) && !isIce(block)) + || !isTransparent(block.getRelative(BlockFace.UP))) { if (isStarted()) remove(); return false; } - sourceBlock = block; playFocusWaterEffect(sourceBlock); location = sourceBlock.getLocation(); @@ -221,67 +241,40 @@ public boolean prepare() { } @Override - public boolean isEnabled() { - return Hyperion.getPlugin().getConfig().getBoolean("Abilities.Water.IceCrawl.Enabled"); - } - - @Override - public String getName() { - return "IceCrawl"; - } - - @Override - public String getDescription() { - return Hyperion.getPlugin().getConfig().getString("Abilities.Water.IceCrawl.Description"); - } - - @Override - public String getAuthor() { - return Hyperion.getAuthor(); - } - - @Override - public String getVersion() { - return Hyperion.getVersion(); - } - - @Override - public boolean isHarmlessAbility() { - return false; - } - - @Override - public boolean isSneakAbility() { - return true; - } - - @Override - public long getCooldown() { - return cooldown; - } - - @Override - public Location getLocation() { - return location; - } - - @Override - public boolean isCollidable() { - return launched; + public void remove() { + super.remove(); + for (TempArmorStand stand : armorStands) { + stand.remove(); + } + armorStands.clear(); + for (TempBlock tb : tempBlocks) { + tb.revertBlock(); + } + tempBlocks.clear(); } - @Override - public double getCollisionRadius() { - return 0.8; - } + // ... getters and static shootLine() remain unchanged ... - @Override - public void load() { + @Override public boolean isEnabled() { + return Hyperion.getPlugin().getConfig() + .getBoolean("Abilities.Water.IceCrawl.Enabled"); } - @Override - public void stop() { + @Override public String getName() { return "IceCrawl"; } + @Override public String getDescription() { + return Hyperion.getPlugin().getConfig() + .getString("Abilities.Water.IceCrawl.Description"); } + @Override public String getAuthor() { return Hyperion.getAuthor(); } + @Override public String getVersion() { return Hyperion.getVersion(); } + @Override public boolean isHarmlessAbility() { return false; } + @Override public boolean isSneakAbility() { return true; } + @Override public long getCooldown() { return cooldown; } + @Override public Location getLocation() { return location; } + @Override public boolean isCollidable() { return launched; } + @Override public double getCollisionRadius() { return 0.8; } + @Override public void load() {} + @Override public void stop() {} public static void shootLine(Player player) { if (hasAbility(player, IceCrawl.class)) { @@ -291,10 +284,12 @@ public static void shootLine(Player player) { private void shootLine() { if (launched) return; - final Entity targetedEntity = GeneralMethods.getTargetedEntity(player, range + selectRange, Collections.singletonList(player)); - if (targetedEntity instanceof LivingEntity && targetedEntity.getLocation().distanceSquared(location) <= range * range) { + Entity ent = GeneralMethods.getTargetedEntity(player, range + selectRange, + Collections.singletonList(player)); + if (ent instanceof LivingEntity + && ent.getLocation().distanceSquared(location) <= range * range) { locked = true; - target = (LivingEntity) targetedEntity; + target = (LivingEntity) ent; endLocation = target.getLocation().clone(); } else { endLocation = GeneralMethods.getTargetedLocation(player, range, Material.WATER); diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 313d264..65a2511 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -69,6 +69,9 @@ import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; +import static me.moros.hyperion.Hyperion.isFolia; +import static me.moros.hyperion.Hyperion.luminol; + public class CoreListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void EntityChangeBlockEvent(final EntityChangeBlockEvent event) { @@ -208,7 +211,14 @@ public void onPlayerLogout(final PlayerQuitEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPKReload(final BendingReloadEvent event) { - Bukkit.getScheduler().runTaskLater(Hyperion.getPlugin(), Hyperion::reload, 1); + if (!isFolia && !luminol) { + Bukkit.getScheduler().runTaskLater(Hyperion.getPlugin(), Hyperion::reload1, 1); + } + + if (isFolia || luminol) { + Bukkit.getGlobalRegionScheduler().runDelayed(Hyperion.getPlugin(), Hyperion::reload, 1); + } + } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/src/main/java/me/moros/hyperion/util/ParticleEffect.java b/src/main/java/me/moros/hyperion/util/ParticleEffect.java deleted file mode 100644 index d4c5e17..0000000 --- a/src/main/java/me/moros/hyperion/util/ParticleEffect.java +++ /dev/null @@ -1,145 +0,0 @@ -// -// Source code recreated from a .class file by IntelliJ IDEA -// (powered by FernFlower decompiler) -// - -package me.moros.hyperion.util; - -import com.projectkorra.projectkorra.GeneralMethods; -import org.bukkit.Location; -import org.bukkit.Particle; - - -public enum ParticleEffect { - ASH(Particle.ASH), - BLOCK_CRACK(Particle.BLOCK_CRACK), - BLOCK_DUST(Particle.BLOCK_DUST), - BUBBLE_COLUMN_UP(Particle.BUBBLE_COLUMN_UP), - BUBBLE_POP(Particle.BUBBLE_POP), - CAMPFIRE_COSY_SMOKE(Particle.CAMPFIRE_COSY_SMOKE), - CAMPFIRE_SIGNAL_SMOKE(Particle.CAMPFIRE_SIGNAL_SMOKE), - CLOUD(Particle.CLOUD), - COMPOSTER(Particle.COMPOSTER), - CRIMSON_SPORE(Particle.CRIMSON_SPORE), - CRIT(Particle.CRIT), - CRIT_MAGIC(Particle.CRIT_MAGIC), - MAGIC_CRIT(Particle.CRIT_MAGIC), - CURRENT_DOWN(Particle.CURRENT_DOWN), - DAMAGE_INDICATOR(Particle.DAMAGE_INDICATOR), - DOLPHIN(Particle.DOLPHIN), - DRAGON_BREATH(Particle.DRAGON_BREATH), - DRIP_LAVA(Particle.DRIP_LAVA), - DRIP_WATER(Particle.DRIP_WATER), - DRIPPING_HONEY(Particle.DRIPPING_HONEY), - DRIPPING_OBSIDIAN_TEAR(Particle.DRIPPING_OBSIDIAN_TEAR), - ENCHANTMENT_TABLE(Particle.ENCHANTMENT_TABLE), - END_ROD(Particle.END_ROD), - EXPLOSION_HUGE(Particle.EXPLOSION_HUGE), - HUGE_EXPLOSION(Particle.EXPLOSION_HUGE), - EXPLOSION_LARGE(Particle.EXPLOSION_LARGE), - LARGE_EXPLODE(Particle.EXPLOSION_LARGE), - EXPLOSION_NORMAL(Particle.EXPLOSION_NORMAL), - EXPLODE(Particle.EXPLOSION_NORMAL), - FALLING_DUST(Particle.FALLING_DUST), - FALLING_HONEY(Particle.FALLING_HONEY), - FALLING_LAVA(Particle.FALLING_LAVA), - FALLING_NECTAR(Particle.FALLING_NECTAR), - FALLING_OBSIDIAN_TEAR(Particle.FALLING_OBSIDIAN_TEAR), - FALLING_WATER(Particle.FALLING_WATER), - FIREWORKS_SPARK(Particle.FIREWORKS_SPARK), - FLAME(Particle.FLAME), - FLASH(Particle.FLASH), - HEART(Particle.HEART), - ITEM_CRACK(Particle.ITEM_CRACK), - LANDING_HONEY(Particle.LANDING_HONEY), - LANDING_LAVA(Particle.LANDING_LAVA), - LANDING_OBSIDIAN_TEAR(Particle.LANDING_OBSIDIAN_TEAR), - LAVA(Particle.LAVA), - MOB_APPEARANCE(Particle.MOB_APPEARANCE), - NAUTILUS(Particle.NAUTILUS), - NOTE(Particle.NOTE), - PORTAL(Particle.PORTAL), - REDSTONE(Particle.REDSTONE), - RED_DUST(Particle.REDSTONE), - REVERSE_PORTAL(Particle.REVERSE_PORTAL), - SLIME(Particle.SLIME), - SMOKE_NORMAL(Particle.SMOKE_NORMAL), - SMOKE(Particle.SMOKE_NORMAL), - SMOKE_LARGE(Particle.SMOKE_LARGE), - LARGE_SMOKE(Particle.SMOKE_LARGE), - SNEEZE(Particle.SNEEZE), - SNOW_SHOVEL(Particle.SNOW_SHOVEL), - SNOWBALL(Particle.SNOWBALL), - SNOWBALL_PROOF(Particle.SNOWBALL), - SOUL(Particle.SOUL), - SOUL_FIRE_FLAME(Particle.SOUL_FIRE_FLAME), - SPELL(Particle.SPELL), - SPELL_INSTANT(Particle.SPELL_INSTANT), - INSTANT_SPELL(Particle.SPELL_INSTANT), - SPELL_MOB(Particle.SPELL_MOB), - MOB_SPELL(Particle.SPELL_MOB), - SPELL_MOB_AMBIENT(GeneralMethods.getMCVersion() >= 1205 ? Particle.SPELL_MOB : Particle.SPELL_MOB_AMBIENT), - MOB_SPELL_AMBIENT(GeneralMethods.getMCVersion() >= 1205 ? Particle.SPELL_MOB : Particle.SPELL_MOB_AMBIENT), - SPELL_WITCH(Particle.SPELL_WITCH), - WITCH_SPELL(Particle.SPELL_WITCH), - SPIT(Particle.SPIT), - SQUID_INK(Particle.SQUID_INK), - SUSPENDED(Particle.SUSPENDED), - SUSPEND(Particle.SUSPENDED), - SUSPENDED_DEPTH(Particle.SUSPENDED_DEPTH), - DEPTH_SUSPEND(Particle.SUSPENDED_DEPTH), - SWEEP_ATTACK(Particle.SWEEP_ATTACK), - TOTEM(Particle.TOTEM), - TOWN_AURA(Particle.TOWN_AURA), - VILLAGER_ANGRY(Particle.VILLAGER_ANGRY), - ANGRY_VILLAGER(Particle.VILLAGER_ANGRY), - VILLAGER_HAPPY(Particle.VILLAGER_HAPPY), - HAPPY_VILLAGER(Particle.VILLAGER_HAPPY), - WARPED_SPORE(Particle.WARPED_SPORE), - WATER_BUBBLE(Particle.WATER_BUBBLE), - BUBBLE(Particle.WATER_BUBBLE), - WATER_DROP(Particle.WATER_DROP), - WATER_SPLASH(Particle.WATER_SPLASH), - SPLASH(Particle.WATER_SPLASH), - WATER_WAKE(Particle.WATER_WAKE), - WAKE(Particle.WATER_WAKE), - WHITE_ASH(Particle.WHITE_ASH), - ELECTRIC_SPARK(Particle.ELECTRIC_SPARK); - - Particle particle; - Class dataClass; - - private ParticleEffect(Particle particle) { - this.particle = particle; - this.dataClass = particle.getDataType(); - } - - public Particle getParticle() { - return this.particle; - } - - public void display(Location loc, int amount) { - this.display(loc, amount, (double)0.0F, (double)0.0F, (double)0.0F); - } - - public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ) { - this.display(loc, amount, offsetX, offsetY, offsetZ, (double)0.0F); - } - - public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, double extra) { - loc.getWorld().spawnParticle(this.particle, loc, amount, offsetX, offsetY, offsetZ, extra, (Object)null, true); - } - - public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, Object data) { - this.display(loc, amount, offsetX, offsetY, offsetZ, (double)0.0F, data); - } - - public void display(Location loc, int amount, double offsetX, double offsetY, double offsetZ, double extra, Object data) { - if (!this.dataClass.isAssignableFrom(Void.class) && data != null && this.dataClass.isAssignableFrom(data.getClass())) { - loc.getWorld().spawnParticle(this.particle, loc, amount, offsetX, offsetY, offsetZ, extra, data, true); - } else { - this.display(loc, amount, offsetX, offsetY, offsetZ, extra); - } - - } -} diff --git a/src/main/java/me/moros/hyperion/util/TempArmorStand.java b/src/main/java/me/moros/hyperion/util/TempArmorStand.java index ecd32e4..2396b9f 100755 --- a/src/main/java/me/moros/hyperion/util/TempArmorStand.java +++ b/src/main/java/me/moros/hyperion/util/TempArmorStand.java @@ -1,34 +1,20 @@ -/* - * Copyright 2016-2024 Moros - * - * This file is part of Hyperion. - * - * Hyperion 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. - * - * Hyperion 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 Hyperion. If not, see . - */ - package me.moros.hyperion.util; import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.util.ParticleEffect; + import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; + import org.bukkit.Location; import org.bukkit.Material; + import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; + import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; + import java.util.Comparator; import java.util.Map; @@ -39,6 +25,8 @@ import java.util.stream.Collectors; public class TempArmorStand { + + private static final Plugin PLUGIN = Hyperion.getPlugin(); private static final Map instances = new ConcurrentHashMap<>(); private static final Queue tasQueue = new PriorityQueue<>(Comparator.comparingLong(TempArmorStand::getExpirationTime)); @@ -53,27 +41,30 @@ public TempArmorStand(CoreAbility abilityInstance, Location location, Material m } public TempArmorStand(CoreAbility abilityInstance, Location location, Material material, long delay, boolean showRemoveParticles) { - headMaterial = material; - armorStand = location.getWorld().spawn(location, ArmorStand.class, entity -> { + this.headMaterial = material; + this.ability = abilityInstance; + this.expirationTime = System.currentTimeMillis() + delay; + this.particles = showRemoveParticles; + + this.armorStand = location.getWorld().spawn(location, ArmorStand.class, entity -> { entity.setInvulnerable(true); entity.setVisible(false); entity.setGravity(false); entity.getEquipment().setHelmet(new ItemStack(headMaterial)); - entity.setMetadata(CoreMethods.NO_INTERACTION_KEY, new FixedMetadataValue(Hyperion.getPlugin(), "")); + entity.setMetadata(CoreMethods.NO_INTERACTION_KEY, new FixedMetadataValue(PLUGIN, "")); }); - expirationTime = System.currentTimeMillis() + delay; - ability = abilityInstance; + instances.put(armorStand, this); tasQueue.add(this); - particles = showRemoveParticles; showParticles(true); } public void showParticles(boolean show) { - if (show) { - ParticleEffect.BLOCK_CRACK.display(armorStand.getEyeLocation().add(0, 0.2, 0), 4, 0.25, 0.125, 0.25, 0, headMaterial.createBlockData()); - ParticleEffect.BLOCK_DUST.display(armorStand.getEyeLocation().add(0, 0.2, 0), 6, 0.25, 0.125, 0.25, 0, headMaterial.createBlockData()); - } + if (!show) return; + + Location loc = armorStand.getEyeLocation().add(0, 0.2, 0); + ParticleEffect.BLOCK_CRACK.display(loc, 4, 0.25, 0.125, 0.25, 0, headMaterial.createBlockData()); + ParticleEffect.BLOCK_DUST.display(loc, 6, 0.25, 0.125, 0.25, 0, headMaterial.createBlockData()); } public CoreAbility getAbility() { @@ -88,6 +79,10 @@ public long getExpirationTime() { return expirationTime; } + public boolean isExpired() { + return System.currentTimeMillis() > expirationTime; + } + public static boolean isTempArmorStand(ArmorStand as) { return instances.containsKey(as); } @@ -97,31 +92,49 @@ public static TempArmorStand get(ArmorStand as) { } public static Set getFromAbility(CoreAbility ability) { - return instances.values().stream().filter(tas -> tas.getAbility().equals(ability)).collect(Collectors.toSet()); + return instances.values().stream() + .filter(tas -> tas.getAbility().equals(ability)) + .collect(Collectors.toSet()); } public static void manage() { final long currentTime = System.currentTimeMillis(); + while (!tasQueue.isEmpty()) { final TempArmorStand tas = tasQueue.peek(); - if (currentTime > tas.getExpirationTime()) { - tasQueue.poll(); - tas.remove(); - } else { + + if (tas == null || currentTime < tas.getExpirationTime()) { return; } + + tasQueue.poll(); + + if (tas.armorStand == null || !tas.armorStand.isValid()) { + instances.remove(tas.armorStand); + continue; + } + + // ✅ USE ThreadUtil to handle Folia, Paper, and Bukkit cases + Location loc = tas.armorStand.getLocation(); + ThreadUtil.ensureLocation(loc, tas::remove); } } public void remove() { + if (armorStand != null && armorStand.isValid()) { + showParticles(particles); + armorStand.remove(); + } instances.remove(armorStand); - showParticles(particles); - armorStand.remove(); } public static void removeAll() { tasQueue.clear(); - instances.keySet().forEach(Entity::remove); + instances.keySet().forEach(entity -> { + if (entity != null && entity.isValid()) { + entity.remove(); + } + }); instances.clear(); } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b89aec2..7afa020 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Hyperion description: Addon plugin for ProjectKorra -author: Moros & Hihelloy +author: Moros version: ${pluginVersion} main: me.moros.hyperion.Hyperion depend: [ProjectKorra] From 68d836435d7a04ed6b359f3e0a079e4acab9c1c9 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Wed, 6 Aug 2025 18:00:52 -0700 Subject: [PATCH 07/34] Update README.MD --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 167ca5d..2194dc1 100644 --- a/README.MD +++ b/README.MD @@ -5,7 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moro's Hyperion ProjectKorra Addon plugin! +Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyperion! ## Abilities ### Air From 5c057fbd625ea6ceb67f456a1e9092d0daaa83d8 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Wed, 6 Aug 2025 19:01:00 -0700 Subject: [PATCH 08/34] Update gradle.yml --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 84198b8..e2e9ba7 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 21 ] + java: [ 17 ] fail-fast: true steps: - uses: actions/checkout@v4 From de44a5f10cc4e6853505f2fc9426c233d2652b65 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Thu, 7 Aug 2025 17:15:14 -0700 Subject: [PATCH 09/34] Fixes the IceCrawl temp falling block not disappearing when the move is used (it now goes away when you use the move again) --- README.MD | 2 +- build.gradle.kts | 2 +- src/main/java/me/moros/hyperion/Hyperion.java | 8 +- .../hyperion/abilities/airbending/Evade.java | 4 +- .../abilities/waterbending/IceCrawl.java | 17 +- .../hyperion/util/BendingFallingBlock.java | 45 ++-- .../me/moros/hyperion/util/ThreadUtil.java | 232 ++++-------------- 7 files changed, 92 insertions(+), 218 deletions(-) diff --git a/README.MD b/README.MD index 167ca5d..2194dc1 100644 --- a/README.MD +++ b/README.MD @@ -5,7 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moro's Hyperion ProjectKorra Addon plugin! +Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyperion! ## Abilities ### Air diff --git a/build.gradle.kts b/build.gradle.kts index 9693171..a5ae2e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.moros" -version = "1.7.4-PRE-RELEASE-1" +version = "1.7.4-PRE-RELEASE-2" java { toolchain { diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 3c90316..5e74a84 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -66,7 +66,13 @@ public void onEnable() { luminol = true; } catch (ClassNotFoundException ignored) {} - new Metrics(this, 8212); + if (!isLuminol()) { + getLogger().info("[Hyperion] Hyperion is running on Paper/Folia"); + } else { + getLogger().info("[Hyperion] Hyperion is running on Luminol"); + } + + new Metrics(this, 8212); new ConfigManager(); new HyperionCommand(); layer = new PersistentDataLayer(); diff --git a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java index e5fb8f2..f10e76a 100644 --- a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java +++ b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java @@ -21,8 +21,8 @@ import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.CoreAbility; import me.moros.hyperion.Hyperion; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -31,6 +31,7 @@ public class Evade extends AirAbility implements AddonAbility { private Vector direction; private long cooldown; + private Hyperion pl; private double angleStep; @@ -41,6 +42,7 @@ public Evade(Player player) { super(player); if (!player.isOnGround() || player.getEyeLocation().getBlock().isLiquid() || hasAbility(player, Evade.class) || !bPlayer.canBend(this)) { + pl.getServer().getLogger().info("Player Can't bend ability Evade because they are either not on the ground or they can't bend"); return; } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java index 210b7b6..f53a79b 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java @@ -30,7 +30,6 @@ import org.bukkit.util.NumberConversions; import org.bukkit.util.Vector; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -139,7 +138,10 @@ private void advanceLocation() { if (isWater(down)) { TempBlock tb = new TempBlock(down, Material.ICE.createBlockData(), iceDuration); PhaseChange.getFrozenBlocksMap().put(tb, player); - tempBlocks.add(tb); + tempBlocks.add(tb); // Track the temporary ice block + + // Debugging info + System.out.println("TempBlock added: " + tb.getBlock().getLocation()); } double x = ThreadLocalRandom.current().nextDouble(-0.125, 0.125); @@ -243,17 +245,22 @@ public boolean prepare() { @Override public void remove() { super.remove(); + + // Cleanup Armor Stands for (TempArmorStand stand : armorStands) { stand.remove(); } armorStands.clear(); + + // Revert all temporary ice blocks for (TempBlock tb : tempBlocks) { - tb.revertBlock(); + tb.revertBlock(); // This should remove the ice block } tempBlocks.clear(); - } - // ... getters and static shootLine() remain unchanged ... + // Additional debugging log + System.out.println("IceCrawl ability removed, ice blocks reverted."); + } @Override public boolean isEnabled() { return Hyperion.getPlugin().getConfig() diff --git a/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java b/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java index be9da99..007e999 100755 --- a/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java +++ b/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java @@ -1,22 +1,3 @@ -/* - * Copyright 2016-2024 Moros - * - * This file is part of Hyperion. - * - * Hyperion 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. - * - * Hyperion 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 Hyperion. If not, see . - */ - package me.moros.hyperion.util; import com.projectkorra.projectkorra.ability.CoreAbility; @@ -88,7 +69,7 @@ public static void manage() { final BendingFallingBlock bfb = bfbQueue.peek(); if (currentTime > bfb.getExpirationTime()) { bfbQueue.poll(); - bfb.remove(); + bfb.remove(); // Remove expired falling blocks } else { return; } @@ -98,20 +79,34 @@ public static void manage() { while (iterator.hasNext()) { BendingFallingBlock bfb = iterator.next(); if (currentTime > bfb.getExpirationTime()) { - bfb.getFallingBlock().remove(); - iterator.remove(); + // Safely remove the falling block if it exists + if (bfb.getFallingBlock() != null && bfb.getFallingBlock().isValid()) { + bfb.getFallingBlock().remove(); + } + iterator.remove(); // Clean up the map entry after removal } } } public void remove() { - instances.remove(fallingBlock); - fallingBlock.remove(); + // Ensure the falling block is valid before trying to remove it + if (fallingBlock != null && fallingBlock.isValid()) { + instances.remove(fallingBlock); + fallingBlock.remove(); + } else { + // Log or handle the case where the falling block is already removed or invalid + System.out.println("Falling block is null or invalid, cannot remove."); + } } public static void removeAll() { bfbQueue.clear(); - instances.keySet().forEach(Entity::remove); + // Ensure entities are valid before removal + instances.keySet().forEach(fb -> { + if (fb != null && fb.isValid()) { + fb.remove(); + } + }); instances.clear(); } } diff --git a/src/main/java/me/moros/hyperion/util/ThreadUtil.java b/src/main/java/me/moros/hyperion/util/ThreadUtil.java index ef061f4..2cf0223 100644 --- a/src/main/java/me/moros/hyperion/util/ThreadUtil.java +++ b/src/main/java/me/moros/hyperion/util/ThreadUtil.java @@ -1,16 +1,19 @@ package me.moros.hyperion.util; - import io.papermc.paper.threadedregions.scheduler.RegionScheduler; import me.moros.hyperion.Hyperion; import org.bukkit.Bukkit; import org.bukkit.Location; + import org.bukkit.entity.Entity; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; + + public class ThreadUtil { + private static final Plugin PLUGIN = Hyperion.plugin; private static final boolean THREAD_UTIL_AVAILABLE; private static final Class THREAD_UTIL_CLASS; @@ -18,239 +21,100 @@ public class ThreadUtil { Class threadUtilClass = null; try { threadUtilClass = Class.forName("com.projectkorra.projectkorra.util.ThreadUtil"); - } catch (ClassNotFoundException e) { - // ThreadUtil not available, will use Bukkit scheduler - } + } catch (ClassNotFoundException ignored) {} THREAD_UTIL_CLASS = threadUtilClass; THREAD_UTIL_AVAILABLE = THREAD_UTIL_CLASS != null; } public static void ensureLocation(Location location, Runnable runnable) { - if (Hyperion.isFolia()) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { if (Bukkit.isOwnedByCurrentRegion(location) || Bukkit.isStopping()) { runnable.run(); return; } - RegionScheduler scheduler = Bukkit.getRegionScheduler(); - scheduler.execute(Hyperion.plugin, location, runnable); + scheduler.execute(PLUGIN, location, runnable); } else { if (Bukkit.isPrimaryThread()) { runnable.run(); - return; + } else { + Bukkit.getScheduler().runTask(PLUGIN, runnable); } - - Bukkit.getScheduler().runTask(Hyperion.plugin, runnable); } - } - public static void runGlobalLater(Runnable runnable, long delay) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("runGlobalLater", Runnable.class, long.class) - .invoke(null, runnable, delay); - } catch (Exception e) { - // Fallback to Bukkit scheduler - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); - } + public static void runGlobalLater(Runnable runnable, long delayTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + Bukkit.getGlobalRegionScheduler().runDelayed(PLUGIN, task -> runnable.run(), delayTicks); } else { - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); + Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } - public static void runLocationLater(Location location, Runnable runnable, long delay) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("ensureLocationLater", Location.class, Runnable.class, long.class) - .invoke(null, location, runnable, delay); - } catch (Exception e) { - // Fallback to Bukkit scheduler - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); - } + public static void runLocationLater(Location location, Runnable runnable, long delayTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + Bukkit.getRegionScheduler().runDelayed(PLUGIN, location, task -> runnable.run(), delayTicks); } else { - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); + Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } - public static void runEntityLater(Entity entity, Runnable runnable, long delay) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("ensureEntityLater", Entity.class, Runnable.class, long.class) - .invoke(null, entity, runnable, delay); - } catch (Exception e) { - // Fallback to Bukkit scheduler - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); - } + public static void runEntityLater(Location loc, Runnable runnable, long delayTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + Bukkit.getRegionScheduler().runDelayed(PLUGIN, loc, task -> runnable.run(), delayTicks); } else { - new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskLater(Hyperion.plugin, delay); + Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } - public static Object runGlobalTimer(Runnable runnable, long delay, long period) { - if (THREAD_UTIL_AVAILABLE) { - try { - return THREAD_UTIL_CLASS.getMethod("runGlobalTimer", Runnable.class, long.class, long.class) - .invoke(null, runnable, delay, period); - } catch (Exception e) { - // Fallback to Bukkit scheduler - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); - } - } else { - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); + public static BukkitTask runGlobalTimer(Runnable runnable, long delayTicks, long periodTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + throw new UnsupportedOperationException("Global repeating tasks must be managed differently in Folia."); } + return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } - public static Object runLocationTimer(Location location, Runnable runnable, long delay, long period) { - if (THREAD_UTIL_AVAILABLE) { - try { - return THREAD_UTIL_CLASS.getMethod("ensureLocationTimer", Location.class, Runnable.class, long.class, long.class) - .invoke(null, location, runnable, delay, period); - } catch (Exception e) { - // Fallback to Bukkit scheduler - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); - } - } else { - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); + public static BukkitTask runLocationTimer(Location location, Runnable runnable, long delayTicks, long periodTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + throw new UnsupportedOperationException("Region-based repeating tasks must use Folia task management."); } + return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } - public static Object runEntityTimer(Entity entity, Runnable runnable, long delay, long period) { - if (THREAD_UTIL_AVAILABLE) { - try { - return THREAD_UTIL_CLASS.getMethod("ensureEntityTimer", Entity.class, Runnable.class, long.class, long.class) - .invoke(null, entity, runnable, delay, period); - } catch (Exception e) { - // Fallback to Bukkit scheduler - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); - } - } else { - return new BukkitRunnable() { - @Override - public void run() { - runnable.run(); - } - }.runTaskTimer(Hyperion.plugin, delay, period); + public static BukkitTask runEntityTimer(Entity entity, Runnable runnable, long delayTicks, long periodTicks) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + throw new UnsupportedOperationException("Entity-based repeating tasks must use Folia task management."); } + return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } public static void runAsync(Runnable runnable) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("runAsync", Runnable.class) - .invoke(null, runnable); - } catch (Exception e) { - // Fallback to Bukkit scheduler - Bukkit.getScheduler().runTaskAsynchronously(Hyperion.plugin, runnable); - } - } else { - Bukkit.getScheduler().runTaskAsynchronously(Hyperion.plugin, runnable); - } + Bukkit.getScheduler().runTaskAsynchronously(PLUGIN, runnable); } - public static Object runAsyncTimer(Runnable runnable, long delay, long period) { - if (THREAD_UTIL_AVAILABLE) { - try { - return THREAD_UTIL_CLASS.getMethod("runAsyncTimer", Runnable.class, long.class, long.class) - .invoke(null, runnable, delay, period); - } catch (Exception e) { - // Fallback to Bukkit scheduler - return Bukkit.getScheduler().runTaskTimerAsynchronously(Hyperion.plugin, runnable, delay, period); - } - } else { - return Bukkit.getScheduler().runTaskTimerAsynchronously(Hyperion.plugin, runnable, delay, period); - } + public static BukkitTask runAsyncTimer(Runnable runnable, long delayTicks, long periodTicks) { + return Bukkit.getScheduler().runTaskTimerAsynchronously(PLUGIN, runnable, delayTicks, periodTicks); } public static void cancelTimerTask(Object task) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("cancelTimerTask", Object.class) - .invoke(null, task); - } catch (Exception e) { - // Fallback to Bukkit task cancellation - if (task instanceof BukkitTask) { - ((BukkitTask) task).cancel(); - } - } - } else { - if (task instanceof BukkitTask) { - ((BukkitTask) task).cancel(); - } + if (task instanceof BukkitTask bukkitTask) { + bukkitTask.cancel(); } } - public static boolean isThreadUtilAvailable() { - return THREAD_UTIL_AVAILABLE; - } - public static void ensureEntity(Entity entity, Runnable runnable) { - if (THREAD_UTIL_AVAILABLE) { - try { - THREAD_UTIL_CLASS.getMethod("ensureEntity", Entity.class, Runnable.class) - .invoke(null, entity, runnable); - } catch (Exception e) { - // Fallback to global execution + if (Hyperion.isFolia() || Hyperion.isLuminol()) { + if (entity.getLocation() == null) { runnable.run(); + return; } + ensureLocation(entity.getLocation(), runnable); } else { - // Fallback to global execution runnable.run(); } } -} \ No newline at end of file + + public static boolean isThreadUtilAvailable() { + return THREAD_UTIL_AVAILABLE; + } +} From 8b3366b7dd19c130c21575ef6d8040009a1d0a06 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sat, 9 Aug 2025 01:26:07 -0700 Subject: [PATCH 10/34] Adds a RainbowFire subelement --- src/main/java/me/moros/hyperion/Elements.java | 27 ++ src/main/java/me/moros/hyperion/Hyperion.java | 5 + .../abilities/Elements/FireAbility.java | 315 ++++++++++++++++++ .../Elements/RainbowFireAbility.java | 52 +++ .../abilities/firebending/FlameRush.java | 2 +- .../abilities/firebending/RainbowWave.java | 138 ++++++++ .../abilities/firebending/combo/FireWave.java | 12 +- .../hyperion/configuration/ConfigManager.java | 9 +- .../hyperion/listeners/AbilityListener.java | 56 +++- .../hyperion/listeners/CoreListener.java | 9 +- .../java/me/moros/hyperion/util/HexColor.java | 62 ++++ .../hyperion/util/RainbowParticleEffect.java | 71 ++++ .../me/moros/hyperion/util/ThreadUtil.java | 12 +- 13 files changed, 759 insertions(+), 11 deletions(-) create mode 100644 src/main/java/me/moros/hyperion/Elements.java create mode 100644 src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java create mode 100644 src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java create mode 100644 src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java create mode 100644 src/main/java/me/moros/hyperion/util/HexColor.java create mode 100644 src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java diff --git a/src/main/java/me/moros/hyperion/Elements.java b/src/main/java/me/moros/hyperion/Elements.java new file mode 100644 index 0000000..49fcab3 --- /dev/null +++ b/src/main/java/me/moros/hyperion/Elements.java @@ -0,0 +1,27 @@ +package me.moros.hyperion; + + +import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.Element.ElementType; +import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.ProjectKorra; +import me.moros.hyperion.util.HexColor; +import net.md_5.bungee.api.ChatColor; + + +public class Elements { + + public static final SubElement RAINBOWFIRE; + + public Elements() { + } + + static { + RAINBOWFIRE = new SubElement("RainbowFire", Element.FIRE, ElementType.BENDING, ProjectKorra.plugin){ + @Override + public ChatColor getColor() { + return HexColor.ORANGE; + } + }; + } +} diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 5e74a84..8130792 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -21,6 +21,7 @@ import com.projectkorra.projectkorra.util.TempFallingBlock; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.commands.HyperionCommand; import me.moros.hyperion.configuration.ConfigManager; import me.moros.hyperion.listeners.AbilityListener; @@ -28,6 +29,8 @@ import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.*; import org.bstats.bukkit.Metrics; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; @@ -75,6 +78,7 @@ public void onEnable() { new Metrics(this, 8212); new ConfigManager(); new HyperionCommand(); + new Elements(); layer = new PersistentDataLayer(); checkMaintainer(); CoreMethods.loadAbilities(); @@ -87,6 +91,7 @@ public void onEnable() { getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempFallingBlock.manage(), 1L, 5L); getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempArmorStand.manage(), 1L, 1L); getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> BendingFallingBlock.manage(), 1L, 5L); + getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> FireAbility.getAbilities(), 1L, 5L); } else { new BukkitRunnable() { @Override diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java new file mode 100644 index 0000000..8f53d8f --- /dev/null +++ b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java @@ -0,0 +1,315 @@ +package me.moros.hyperion.abilities.Elements; + +import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.Element.SubElement; +import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.ability.ElementalAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.configuration.ConfigManager; +import com.projectkorra.projectkorra.util.LightManager; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import me.moros.hyperion.Elements; + + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Fire; +import org.bukkit.entity.Player; + +import static me.moros.hyperion.Hyperion.plugin; + +public abstract class FireAbility extends ElementalAbility { + private static final Map SOURCE_PLAYERS = new ConcurrentHashMap<>(); + private static final Set IGNITE_FACES; + + public FireAbility(Player player) { + super(player); + } + + @Override + public boolean isIgniteAbility() { + return true; + } + + @Override + public boolean isExplosiveAbility() { + return false; + } + + @Override + public Element getElement() { + return Element.FIRE; + } + + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + ParticleEffect.BLOCK_CRACK.display(collision.getLocationFirst(), 10, 1.0F, 1.0F, 1.0F, 0.1, this.getFireType().createBlockData()); + } + } + + public Material getFireType() { + return this.getBendingPlayer().canUseSubElement(SubElement.BLUE_FIRE) ? Material.SOUL_FIRE : Material.FIRE; + } + + public static boolean canFireGrief() { + return getConfig().getBoolean("Properties.Fire.FireGriefing"); + } + + public void createTempFire(Location loc) { + this.createTempFire(loc, getConfig().getLong("Properties.Fire.RevertTicks") + (long) ((new Random()).nextDouble() * (double) getConfig().getLong("Properties.Fire.RevertTicks"))); + } + + public void createTempFire(Location loc, long time) { + if (isIgnitable(loc.getBlock())) { + new TempBlock(loc.getBlock(), createFireState(loc.getBlock(), this.getFireType() == Material.SOUL_FIRE), time); + SOURCE_PLAYERS.put(loc.getBlock(), this.getPlayer()); + } + } + + public double getDayFactor(double value) { + return this.player != null ? value * getDayFactor(this.player.getWorld()) : value; + } + + public static double getDayFactor() { + return getConfig().getDouble("Properties.Fire.DayFactor"); + } + + public static double getDayFactor(double value, World world) { + return isDay(world) ? value * getDayFactor() : value; + } + + public static double getDayFactor(World world) { + return getDayFactor(1.0F, world); + } + + public static ChatColor getSubChatColor() { + return ChatColor.valueOf(ConfigManager.getConfig().getString("Properties.Chat.Colors.FireSub")); + } + + public static boolean isIgnitable(Block block) { + Block support = block.getRelative(BlockFace.DOWN); + Location loc = support.getLocation(); + boolean supported = support.getBoundingBox().overlaps(loc.add(0.0F, 0.8, 0.0F).toVector(), loc.add(1.0F, 1.0F, 1.0F).toVector()); + return !isWater(block) && !block.isLiquid() && GeneralMethods.isTransparent(block) && (supported && support.getType().isSolid() || IGNITE_FACES.stream().map((face) -> block.getRelative(face).getType()).anyMatch(FireAbility::isIgnitable)); + } + + public static boolean isIgnitable(Material material) { + return material.isFlammable() || material.isBurnable(); + } + + public static BlockData createFireState(Block position, boolean blue) { + Fire fire = (Fire) Material.FIRE.createBlockData(); + if (isIgnitable(position) && position.getRelative(BlockFace.DOWN).getType().isSolid()) { + return blue ? Material.SOUL_FIRE.createBlockData() : fire; + } else { + for (BlockFace face : IGNITE_FACES) { + fire.setFace(face, false); + if (isIgnitable(position.getRelative(face))) { + fire.setFace(face, true); + } + } + return fire; + } + } + + public static void dryWetBlocks(Block block, CoreAbility ability, boolean playSound) { + if (!GeneralMethods.isRegionProtectedFromBuild(ability, block.getLocation())) { + if (block.getType() == Material.WET_SPONGE) { + block.setType(Material.SPONGE); + if (playSound) { + block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.5F, 1.0F); + } + } else if (isSnow(block)) { + block.getWorld().spawnParticle(Particle.BLOCK_DUST, block.getLocation().add(0.5F, 0.5F, 0.5F), 2, 0.5F, 0.5F, 0.5F, 0.1, Material.SNOW_BLOCK.createBlockData()); + block.setType(Material.AIR); + if (playSound) { + block.getWorld().playSound(block.getLocation(), Sound.BLOCK_SNOW_BREAK, 1.0F, 1.0F); + } + } + } + } + + public static void dryWetBlocks(Block block, CoreAbility ability) { + dryWetBlocks(block, ability, false); + } + + @Deprecated + public static boolean isWithinFireShield(Location loc) { + List list = new ArrayList<>(); + list.add("FireShield"); + return GeneralMethods.blockAbilities(null, list, loc, 0.0F); + } + + public static void playCombustionSound(Location loc) { + if (getConfig().getBoolean("Properties.Fire.PlaySound")) { + float volume = (float) getConfig().getDouble("Properties.Fire.CombustionSound.Volume"); + float pitch = (float) getConfig().getDouble("Properties.Fire.CombustionSound.Pitch"); + Sound sound = Sound.ENTITY_FIREWORK_ROCKET_BLAST; + + try { + sound = Sound.valueOf(getConfig().getString("Properties.Fire.CombustionSound.Sound")); + } catch (IllegalArgumentException var8) { + ProjectKorra.log.warning("Your current value for 'Properties.Fire.CombustionSound.Sound' is not valid."); + } finally { + loc.getWorld().playSound(loc, sound, volume, pitch); + } + } + } + + public void emitFirebendingLight(Location location) { + if (getConfig().getBoolean("Properties.Fire.DynamicLight.Enabled")) { + int brightness = getConfig().getInt("Properties.Fire.DynamicLight.Brightness"); + long keepAlive = getConfig().getLong("Properties.Fire.DynamicLight.KeepAlive"); + if (brightness < 1 || brightness > 15) { + throw new IllegalArgumentException("Properties.Fire.DynamicLight.Brightness must be between 1 and 15."); + } + LightManager.createLight(location).brightness(brightness).timeUntilFadeout(keepAlive).emit(); + } + } + + /** + * Plays the firebending particles, prioritizing RAINBOWFIRE subelement first, + * then BLUE_FIRE, then default flame particles. + */ + public void playFirebendingParticles(Location loc, int amount, double xOffset, double yOffset, double zOffset) { + if (this.getBendingPlayer().canUseSubElement(Elements.RAINBOWFIRE)) { + // Instantiate and start the swirling rainbow fire particles task + RainbowFireAbility.playRainbowFireParticles(loc, player); + } else if (this.getBendingPlayer().canUseSubElement(SubElement.BLUE_FIRE)) { + ParticleEffect.SOUL_FIRE_FLAME.display(loc, amount, xOffset, yOffset, zOffset); + } else { + ParticleEffect.FLAME.display(loc, amount, xOffset, yOffset, zOffset); + } + } + + public static void playFirebendingSound(Location loc) { + if (getConfig().getBoolean("Properties.Fire.PlaySound")) { + float volume = (float) getConfig().getDouble("Properties.Fire.FireSound.Volume"); + float pitch = (float) getConfig().getDouble("Properties.Fire.FireSound.Pitch"); + Sound sound = Sound.BLOCK_FIRE_AMBIENT; + + try { + sound = Sound.valueOf(getConfig().getString("Properties.Fire.FireSound.Sound")); + } catch (IllegalArgumentException var8) { + ProjectKorra.log.warning("Your current value for 'Properties.Fire.FireSound.Sound' is not valid."); + } finally { + loc.getWorld().playSound(loc, sound, volume, pitch); + } + } + } + + public static void playLightningbendingParticle(Location loc) { + playLightningbendingParticle(loc, Math.random(), Math.random(), Math.random()); + } + + public static void playLightningbendingParticle(Location loc, double xOffset, double yOffset, double zOffset) { + GeneralMethods.displayColoredParticle("#01E1FF", loc, 1, xOffset, yOffset, zOffset); + } + + public static void playLightningbendingSound(Location loc) { + if (getConfig().getBoolean("Properties.Fire.PlaySound")) { + float volume = (float) getConfig().getDouble("Properties.Fire.LightningSound.Volume"); + float pitch = (float) getConfig().getDouble("Properties.Fire.LightningSound.Pitch"); + Sound sound = Sound.ENTITY_CREEPER_HURT; + + try { + sound = Sound.valueOf(getConfig().getString("Properties.Fire.LightningSound.Sound")); + } catch (IllegalArgumentException var8) { + ProjectKorra.log.warning("Your current value for 'Properties.Fire.LightningSound.Sound' is not valid."); + } finally { + loc.getWorld().playSound(loc, sound, volume, pitch); + } + } + } + + public static void playLightningbendingChargingSound(Location loc) { + if (getConfig().getBoolean("Properties.Fire.PlaySound")) { + float volume = (float) getConfig().getDouble("Properties.Fire.LightningCharge.Volume"); + float pitch = (float) getConfig().getDouble("Properties.Fire.LightningCharge.Pitch"); + Sound sound = Sound.BLOCK_BEEHIVE_WORK; + + try { + sound = Sound.valueOf(getConfig().getString("Properties.Fire.LightningCharge.Sound")); + } catch (IllegalArgumentException var8) { + ProjectKorra.log.warning("Your current value for 'Properties.Fire.LightningCharge.Sound' is not valid."); + } finally { + loc.getWorld().playSound(loc, sound, volume, pitch); + } + } + } + + public static void playLightningbendingHitSound(Location loc) { + if (getConfig().getBoolean("Properties.Fire.PlaySound")) { + float volume = (float) getConfig().getDouble("Properties.Fire.LightningHit.Volume"); + float pitch = (float) getConfig().getDouble("Properties.Fire.LightningHit.Pitch"); + Sound sound = Sound.ENTITY_LIGHTNING_BOLT_THUNDER; + + try { + sound = Sound.valueOf(getConfig().getString("Properties.Fire.LightningHit.Sound")); + } catch (IllegalArgumentException var8) { + ProjectKorra.log.warning("Your current value for 'Properties.Fire.LightningHit.Sound' is not valid."); + } finally { + loc.getWorld().playSound(loc, sound, volume, pitch); + } + } + } + + @Deprecated + public double applyModifiers(double value) { + return GeneralMethods.applyModifiers(value, this.getDayFactor(1.0F)); + } + + @Deprecated + public double applyInverseModifiers(double value) { + return GeneralMethods.applyInverseModifiers(value, this.getDayFactor(1.0F)); + } + + @Deprecated + public double applyModifiersDamage(double value) { + return GeneralMethods.applyModifiers(value, this.getDayFactor(1.0F), this.bPlayer.hasElement(Element.BLUE_FIRE) ? getConfig().getDouble("Properties.Fire.BlueFire.DamageFactor", 1.1) : 1.0); + } + + @Deprecated + public double applyModifiersRange(double value) { + return GeneralMethods.applyModifiers(value, this.getDayFactor(1.0F), this.bPlayer.hasElement(Element.BLUE_FIRE) ? getConfig().getDouble("Properties.Fire.BlueFire.RangeFactor", 1.2) : 1.0); + } + + @Deprecated + public long applyModifiersCooldown(long value) { + return GeneralMethods.applyInverseModifiers(value, this.getDayFactor(1.0F), this.bPlayer.hasElement(Element.BLUE_FIRE) ? 1.0 / getConfig().getDouble("Properties.Fire.BlueFire.CooldownFactor", 0.9) : 1.0); + } + + public static void stopBending() { + SOURCE_PLAYERS.clear(); + } + + public static Map getSourcePlayers() { + return SOURCE_PLAYERS; + } + + static { + IGNITE_FACES = new HashSet<>(Arrays.asList(BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP)); + } +} diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java new file mode 100644 index 0000000..42fe601 --- /dev/null +++ b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java @@ -0,0 +1,52 @@ +package me.moros.hyperion.abilities.Elements; + +import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.ability.Ability; +import com.projectkorra.projectkorra.ability.SubAbility; +import me.moros.hyperion.Elements; +import me.moros.hyperion.Hyperion; +import me.moros.hyperion.util.RainbowParticleEffect; +import org.bukkit.Location; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +public abstract class RainbowFireAbility extends FireAbility implements SubAbility { + + public RainbowFireAbility(Player player) { + super(player); + } + + public static void playRainbowFireParticles(Location loc, Player player) { + // You can make radius/height configurable in the future if needed + int amount = 100; // Number of particles to spawn + + if (loc != null && player != null && player.isOnline()) { + RainbowParticleEffect.spawnRainbowParticleEffect(loc, amount); + } + } + + @Override + public Class getParentAbility() { + return FireAbility.class; + } + + @Override + public Element getElement() { + return Elements.RAINBOWFIRE; + } + + public static double getDamageFactor() { + FileConfiguration config = Hyperion.getPlugin().getConfig(); + return config.getDouble("Properties.Fire.RainbowFire.DamageFactor", 1.0); // default fallback + } + + public static double getCooldownFactor() { + FileConfiguration config = Hyperion.getPlugin().getConfig(); + return config.getDouble("Properties.Fire.RainbowFire.CooldownFactor", 1.0); + } + + public static double getRangeFactor() { + FileConfiguration config = Hyperion.getPlugin().getConfig(); + return config.getDouble("Properties.Fire.RainbowFire.RangeFactor", 1.0); + } +} diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java index 495fd8f..37ec569 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java @@ -22,7 +22,6 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.AddonAbility; -import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.earthbending.EarthSmash; @@ -31,6 +30,7 @@ import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; import me.moros.hyperion.Hyperion; +import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; import org.bukkit.Location; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java new file mode 100644 index 0000000..a1fd8c4 --- /dev/null +++ b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java @@ -0,0 +1,138 @@ +package me.moros.hyperion.abilities.firebending; + +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.util.DamageHandler; +import me.moros.hyperion.Hyperion; +import me.moros.hyperion.abilities.Elements.RainbowFireAbility; +import org.bukkit.Location; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class RainbowWave extends RainbowFireAbility implements AddonAbility { + + private static final String path = "Abilities.Fire.RainbowWave."; + + private boolean started; + private double speed; + private final double fallSpeed = -0.05; + private final double hitRadius = 1.5; + + private double damage; + private int maxTicks; + private long cooldown; + + private int ticksLived = 0; + private Location currentLocation; + private Vector direction; + private final Set hitEntities = new HashSet<>(); + + public RainbowWave(Player player) { + super(player); + + if (!player.isOnline()) return; + if (!bPlayer.canBend(this)) return; + if (hasAbility(player, RainbowWave.class)) return; + if (bPlayer.isOnCooldown(this)) return; + + loadConfigValues(); + + this.currentLocation = player.getEyeLocation().add(0, -0.5, 0); + this.direction = currentLocation.getDirection().normalize().multiply(speed); + + start(); + } + + private void loadConfigValues() { + FileConfiguration config = Hyperion.getPlugin().getConfig(); + + this.cooldown = config.getLong(path + "Cooldown"); + this.damage = config.getDouble(path + "Damage"); + double range = config.getDouble(path + "Range"); + this.speed = config.getDouble(path + "Speed"); + + if (speed <= 0) speed = 0.1; // prevent zero or negative speed + this.maxTicks = (int) (range / speed); + } + + @Override + public void progress() { + if (player == null || !player.isOnline() || !bPlayer.canBend(this)) { + remove(); + return; + } + + if (!started) return; + + currentLocation.add(direction); + currentLocation.add(0, fallSpeed, 0); + + playRainbowFireParticles(currentLocation, player); + + List nearby = GeneralMethods.getEntitiesAroundPoint(currentLocation, hitRadius); + for (Entity entity : nearby) { + if (entity instanceof LivingEntity living && !entity.equals(player) && !hitEntities.contains(living)) { + DamageHandler.damageEntity(living, damage, this); + hitEntities.add(living); + } + } + + ticksLived++; + if (ticksLived > maxTicks) { + bPlayer.addCooldown(this); + remove(); + } + } + + public void triggerWave() { + started = true; + } + + @Override + public boolean isSneakAbility() { + return false; + } + + @Override + public boolean isHarmlessAbility() { + return false; + } + + @Override + public long getCooldown() { + return cooldown; + } + + @Override + public String getName() { + return "RainbowWave"; + } + + @Override + public Location getLocation() { + return currentLocation; + } + + @Override + public void load() {} + + @Override + public void stop() {} + + @Override + public String getAuthor() { + return Hyperion.getAuthor(); + } + + @Override + public String getVersion() { + return Hyperion.getVersion(); + } +} diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java index 8d490a1..7a53ef0 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java @@ -25,7 +25,6 @@ import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.ability.BlueFireAbility; import com.projectkorra.projectkorra.ability.ComboAbility; -import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; import com.projectkorra.projectkorra.attribute.Attribute; @@ -38,6 +37,8 @@ import com.projectkorra.projectkorra.waterbending.SurgeWall; import com.projectkorra.projectkorra.waterbending.SurgeWave; import me.moros.hyperion.Hyperion; +import me.moros.hyperion.abilities.Elements.FireAbility; +import me.moros.hyperion.abilities.Elements.RainbowFireAbility; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.ArmorStand; @@ -57,6 +58,7 @@ import java.util.stream.Collectors; import static com.projectkorra.projectkorra.Element.BLUE_FIRE; +import static me.moros.hyperion.Elements.RAINBOWFIRE; public class FireWave extends FireAbility implements AddonAbility, ComboAbility { private final Set blocks = new HashSet<>(); @@ -106,6 +108,14 @@ public FireWave(Player player) { cooldown *= BlueFireAbility.getCooldownFactor(); } + if (bPlayer.canUseSubElement(RAINBOWFIRE)) { + damage *= RainbowFireAbility.getDamageFactor(); + height *= RainbowFireAbility.getRangeFactor(); + maxHeight *= RainbowFireAbility.getRangeFactor(); + width *= RainbowFireAbility.getRangeFactor(); + cooldown *= RainbowFireAbility.getCooldownFactor(); + } + damage = getDayFactor(damage, player.getWorld()); height = (int) getDayFactor(2, player.getWorld()); maxHeight = (int) getDayFactor(maxHeight, player.getWorld()); diff --git a/src/main/java/me/moros/hyperion/configuration/ConfigManager.java b/src/main/java/me/moros/hyperion/configuration/ConfigManager.java index 424790d..9b74534 100755 --- a/src/main/java/me/moros/hyperion/configuration/ConfigManager.java +++ b/src/main/java/me/moros/hyperion/configuration/ConfigManager.java @@ -24,7 +24,7 @@ import org.bukkit.configuration.file.FileConfiguration; public class ConfigManager { - + private static final String path = "Abilities.Fire.RainbowWave."; public static Config modifiersConfig; public ConfigManager() { @@ -200,6 +200,10 @@ public void setupMainConfig() { config.addDefault("Abilities.Fire.FlameRush.CollisionRadius", 0.5); config.addDefault("Abilities.Fire.FlameRush.Knockback", 0.9); config.addDefault("Abilities.Fire.FlameRush.FireTicks", 15); + config.addDefault(path + "Cooldown", 2000); + config.addDefault(path + "Damage", 4.0); + config.addDefault(path + "Range", 16.0); + config.addDefault(path + "Speed", 0.4); config.addDefault("Abilities.Fire.FireCombo.FireWave.Enabled", true); config.addDefault("Abilities.Fire.FireCombo.FireWave.Description", "Master Jeong Jeong used this advanced technique to cast a great fire wave that grows in size while it advances forward."); @@ -243,6 +247,9 @@ public void setupMainConfig() { config.addDefault("Abilities.Chi.Smokescreen.CloudDuration", 7000); config.addDefault("Abilities.Chi.Smokescreen.BlindnessTicks", 30); config.addDefault("Abilities.Chi.Smokescreen.Radius", 5.0); + config.addDefault("Properties.Fire.RainbowFire.DamageFactor", 1.0); + config.addDefault("Properties.Fire.RainbowFire.CooldownFactor", 1.0); + config.addDefault("Properties.Fire.RainbowFire.RangeFactor", 1.0); config.options().copyDefaults(true); Hyperion.getPlugin().saveConfig(); diff --git a/src/main/java/me/moros/hyperion/listeners/AbilityListener.java b/src/main/java/me/moros/hyperion/listeners/AbilityListener.java index f4cfd51..218bd7f 100755 --- a/src/main/java/me/moros/hyperion/listeners/AbilityListener.java +++ b/src/main/java/me/moros/hyperion/listeners/AbilityListener.java @@ -29,6 +29,7 @@ import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.WaterAbility; +import me.moros.hyperion.Elements; import me.moros.hyperion.abilities.airbending.Evade; import me.moros.hyperion.abilities.chiblocking.Smokescreen; import me.moros.hyperion.abilities.earthbending.EarthGlove; @@ -42,20 +43,28 @@ import me.moros.hyperion.abilities.firebending.Bolt; import me.moros.hyperion.abilities.firebending.Combustion; import me.moros.hyperion.abilities.firebending.FlameRush; +import me.moros.hyperion.abilities.firebending.RainbowWave; import me.moros.hyperion.abilities.waterbending.IceBreath; import me.moros.hyperion.abilities.waterbending.IceCrawl; import me.moros.hyperion.abilities.waterbending.combo.IceDrill; +import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerAnimationEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.inventory.EquipmentSlot; +import static com.projectkorra.projectkorra.ability.CoreAbility.getAbility; +import static com.projectkorra.projectkorra.ability.CoreAbility.hasAbility; + + public class AbilityListener implements Listener { + @EventHandler public void onPlayerSneak(final PlayerToggleSneakEvent event) { final Player player = event.getPlayer(); @@ -110,8 +119,8 @@ public void onPlayerSneak(final PlayerToggleSneakEvent event) { public void onPlayerSwing(final PlayerInteractEvent event) { final Player player = event.getPlayer(); if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) { - if (CoreAbility.hasAbility(player, EarthLine.class)) { - CoreAbility.getAbility(player, EarthLine.class).setPrisonMode(); + if (hasAbility(player, EarthLine.class)) { + getAbility(player, EarthLine.class).setPrisonMode(); } return; } @@ -181,4 +190,47 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } + + @EventHandler + public void onPlayerLeftClick(PlayerInteractEvent event) { + if (event.getAction() != Action.LEFT_CLICK_AIR && event.getAction() != Action.LEFT_CLICK_BLOCK) return; + + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(event.getPlayer()); + final String abilityName = bPlayer.getBoundAbilityName(); + if (bPlayer == null || !bPlayer.canUseSubElement(me.moros.hyperion.Elements.RAINBOWFIRE)) return; + if (abilityName.equalsIgnoreCase("rainbowtest")) { + Bukkit.getLogger().info("Rainbowtest is not currently available"); + } + } + + @EventHandler + public void onLeftClick(PlayerInteractEvent event) { + if (event.getAction() != Action.LEFT_CLICK_AIR && event.getAction() != Action.LEFT_CLICK_BLOCK) { + return; + } + + Player player = event.getPlayer(); + BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); + + if (bPlayer == null || !bPlayer.canUseSubElement(Elements.RAINBOWFIRE)) { + return; + } + + final String abilityName = bPlayer.getBoundAbilityName(); + + if ("RainbowWave".equalsIgnoreCase(abilityName)) { + // Check if player doesn't already have this ability active + if (!RainbowWave.hasAbility(player, RainbowWave.class)) { + // Instantiate the ability (this will call start() automatically) + new RainbowWave(player); + } else { + // If ability already exists, trigger the wave movement + RainbowWave ability = RainbowWave.getAbility(player, RainbowWave.class); + if (ability != null) { + ability.triggerWave(); + } + } + } + } } + diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 65a2511..b69ca87 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -35,12 +35,10 @@ import me.moros.hyperion.util.BendingFallingBlock; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TranslatableComponent; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Nameable; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Lockable; +import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Arrow; import org.bukkit.entity.EntityType; @@ -211,12 +209,15 @@ public void onPlayerLogout(final PlayerQuitEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPKReload(final BendingReloadEvent event) { + final CommandSender sender = event.getSender(); if (!isFolia && !luminol) { Bukkit.getScheduler().runTaskLater(Hyperion.getPlugin(), Hyperion::reload1, 1); + sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Bukkit" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); } if (isFolia || luminol) { Bukkit.getGlobalRegionScheduler().runDelayed(Hyperion.getPlugin(), Hyperion::reload, 1); + sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Folia" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); } } diff --git a/src/main/java/me/moros/hyperion/util/HexColor.java b/src/main/java/me/moros/hyperion/util/HexColor.java new file mode 100644 index 0000000..428c991 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/HexColor.java @@ -0,0 +1,62 @@ +package me.moros.hyperion.util; + +import net.md_5.bungee.api.ChatColor; + +public class HexColor { + + /** + * Returns a ChatColor from a hex string like "#FF0000". + * + * @param hex the hex color string + * @return ChatColor instance + */ + public static ChatColor of(String hex) { + if (hex == null || !hex.matches("^#([A-Fa-f0-9]{6})$")) { + throw new IllegalArgumentException("Invalid hex color format: " + hex); + } + return ChatColor.of(hex); + } + + // Classic rainbow color constants + public static final ChatColor RED = of("#FF0000"); + public static final ChatColor ORANGE = of("#FF7F00"); + public static final ChatColor YELLOW = of("#FFFF00"); + public static final ChatColor GREEN = of("#00FF00"); + public static final ChatColor BLUE = of("#0000FF"); + public static final ChatColor INDIGO = of("#4B0082"); + public static final ChatColor VIOLET = of("#8F00FF"); + + /** + * Special rainbow color (can be used as a placeholder). + * Since ChatColor doesn't support multi-color, this is just a bright yellow to represent rainbow. + */ + public static final ChatColor RAINBOW = YELLOW; + + /** + * Builds a rainbow-colored string by coloring each character with a different rainbow hex. + * + * @param text the input text + * @return rainbow-colored string + */ + public static String rainbowify(String text) { + String[] rainbow = { + "#FF0000", // red + "#FF7F00", // orange + "#FFFF00", // yellow + "#00FF00", // green + "#0000FF", // blue + "#4B0082", // indigo + "#8F00FF" // violet + }; + + StringBuilder result = new StringBuilder(); + int colorIndex = 0; + + for (char c : text.toCharArray()) { + result.append(ChatColor.of(rainbow[colorIndex % rainbow.length])).append(c); + colorIndex++; + } + + return result.toString(); + } +} diff --git a/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java new file mode 100644 index 0000000..0181a88 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java @@ -0,0 +1,71 @@ +package me.moros.hyperion.util; + +import com.destroystokyo.paper.ParticleBuilder; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Particle.DustOptions; +import org.bukkit.util.Vector; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class RainbowParticleEffect { + + private static final Random random = new Random(); + + // Red and blue handled with these flame particles + private static final List SPECIAL_PARTICLES = Arrays.asList( + Particle.FLAME, // Red + Particle.SOUL_FIRE_FLAME // Blue + ); + + // Rainbow colors except red and blue — all using REDSTONE with DustOptions + private static final List RAINBOW_COLORS = Arrays.asList( + Color.fromRGB(255, 165, 0), // Orange + Color.fromRGB(255, 255, 0), // Yellow + Color.fromRGB(0, 255, 0), // Green + Color.fromRGB(75, 0, 130), // Indigo + Color.fromRGB(138, 43, 226) // Violet + ); + + public static void spawnRainbowParticleEffect(Location center, int amount) { + for (int i = 0; i < amount; i++) { + + Particle particle; + Object data = null; + + if (random.nextDouble() < 0.4) { + // 40% chance to use flame-style particles (red/blue) + particle = SPECIAL_PARTICLES.get(random.nextInt(SPECIAL_PARTICLES.size())); + } else { + // 60% chance to use REDSTONE color particles + particle = Particle.REDSTONE; + Color color = RAINBOW_COLORS.get(random.nextInt(RAINBOW_COLORS.size())); + data = new DustOptions(color, 1.5f); + } + + // Random offset around center + double offsetX = (random.nextDouble() - 0.5) * 2.0; + double offsetY = random.nextDouble() * 1.5; + double offsetZ = (random.nextDouble() - 0.5) * 2.0; + Location loc = center.clone().add(offsetX, offsetY, offsetZ); + + // Velocity + Vector velocity = new Vector( + (random.nextDouble() - 0.5) * 0.2, + random.nextDouble() * 0.2, + (random.nextDouble() - 0.5) * 0.2 + ); + + new ParticleBuilder(particle) + .location(loc) + .count(0) + .offset((float) velocity.getX(), (float) velocity.getY(), (float) velocity.getZ()) + .extra(0) + .data(data) + .spawn(); + } + } +} diff --git a/src/main/java/me/moros/hyperion/util/ThreadUtil.java b/src/main/java/me/moros/hyperion/util/ThreadUtil.java index 2cf0223..7f8566a 100644 --- a/src/main/java/me/moros/hyperion/util/ThreadUtil.java +++ b/src/main/java/me/moros/hyperion/util/ThreadUtil.java @@ -52,13 +52,21 @@ public static void runGlobalLater(Runnable runnable, long delayTicks) { } public static void runLocationLater(Location location, Runnable runnable, long delayTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - Bukkit.getRegionScheduler().runDelayed(PLUGIN, location, task -> runnable.run(), delayTicks); + boolean isAsyncScheduler = Hyperion.isFolia() || Hyperion.isLuminol(); + + if (isAsyncScheduler) { + if (location != null && location.getWorld() != null) { + Bukkit.getRegionScheduler().runDelayed(PLUGIN, location, task -> runnable.run(), delayTicks); + } else { + Bukkit.getLogger().warning("[Hyperion] Cannot schedule region task: location or world is null. Falling back to main scheduler."); + Bukkit.getGlobalRegionScheduler().runDelayed(PLUGIN, task -> runnable.run(), delayTicks); + } } else { Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } + public static void runEntityLater(Location loc, Runnable runnable, long delayTicks) { if (Hyperion.isFolia() || Hyperion.isLuminol()) { Bukkit.getRegionScheduler().runDelayed(PLUGIN, loc, task -> runnable.run(), delayTicks); From 856bdafce3979d0c591056ec245f10fa7d2800a8 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sat, 9 Aug 2025 01:53:29 -0700 Subject: [PATCH 11/34] Hyperion v1.7.4 --- build.gradle.kts | 2 +- .../hyperion/abilities/firebending/RainbowWave.java | 10 ++++++++++ .../hyperion/abilities/firebending/combo/FireWave.java | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a5ae2e1..7e2d840 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.moros" -version = "1.7.4-PRE-RELEASE-2" +version = "1.7.4" java { toolchain { diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java index a1fd8c4..c78db24 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java @@ -135,4 +135,14 @@ public String getAuthor() { public String getVersion() { return Hyperion.getVersion(); } + + @Override + public String getInstructions() { + return "Punch twice"; + } + + @Override + public String getDescription() { + return "Shoot a beam/wave of RainbowFire at your opponent"; + } } diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java index 7a53ef0..aaa3dee 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java @@ -34,6 +34,7 @@ import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ThreadUtil; import com.projectkorra.projectkorra.waterbending.SurgeWall; import com.projectkorra.projectkorra.waterbending.SurgeWave; import me.moros.hyperion.Hyperion; From 283ffc763eb90958952f0414cdcba37378ce573a Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 9 Aug 2025 01:59:13 -0700 Subject: [PATCH 12/34] Update README.MD --- README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MD b/README.MD index 2194dc1..58c8f2f 100644 --- a/README.MD +++ b/README.MD @@ -26,6 +26,7 @@ Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyper * Combustion * FlameRush * FireWave (combo) +* RainbowWave ### Water * IceBreath * IceCrawl From 92d786021b667e28057baba7f53ff7b8b0e19faf Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 9 Aug 2025 02:01:54 -0700 Subject: [PATCH 13/34] Update README.MD --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 58c8f2f..1ce91eb 100644 --- a/README.MD +++ b/README.MD @@ -5,7 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyperion! +Hi, I'm Hihelloy, and this is my fork of Moros's ProjectKorra Addon plugin, Hyperion! ## Abilities ### Air From 1b86df334628a9aa2d26e4848e0b6ad375f5b8ec Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 9 Aug 2025 12:35:47 -0700 Subject: [PATCH 14/34] made it so that the readme.md says this is an UNOFFICIAL fork --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 1ce91eb..91af02d 100644 --- a/README.MD +++ b/README.MD @@ -5,7 +5,7 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moros's ProjectKorra Addon plugin, Hyperion! +Hi, I'm Hihelloy, and this is my unofficial fork of Moros's ProjectKorra Addon plugin, Hyperion! ## Abilities ### Air From ef81eb0ee7d94012d3a16c63f06d6b55e3a0ae87 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 9 Aug 2025 12:39:01 -0700 Subject: [PATCH 15/34] Update README.MD --- README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MD b/README.MD index 91af02d..9d1aa0b 100644 --- a/README.MD +++ b/README.MD @@ -6,6 +6,7 @@ [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) Hi, I'm Hihelloy, and this is my unofficial fork of Moros's ProjectKorra Addon plugin, Hyperion! +THIS, BY NO MEANS REPLACES THE ORIGINAL HYPERION THIS IS JUST AN UNOFFICIAL FORK ## Abilities ### Air From 8c3fa924d639676ce335ecdc12b613bc9deb6f23 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 9 Aug 2025 14:27:50 -0700 Subject: [PATCH 16/34] Update README.MD --- README.MD | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 9d1aa0b..fe1d590 100644 --- a/README.MD +++ b/README.MD @@ -6,7 +6,8 @@ [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) Hi, I'm Hihelloy, and this is my unofficial fork of Moros's ProjectKorra Addon plugin, Hyperion! -THIS, BY NO MEANS REPLACES THE ORIGINAL HYPERION THIS IS JUST AN UNOFFICIAL FORK + +THIS, BY NO MEANS REPLACES THE ORIGINAL HYPERION AS THIS IS JUST AN UNOFFICIAL FORK ## Abilities ### Air From b6fe5221c3aa6e018f75eb96f9e2761f39e4019a Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Mon, 18 Aug 2025 23:07:19 -0700 Subject: [PATCH 17/34] Fixes jitpack/build workflows --- README.MD | 1 + build.gradle.kts | 2 +- .../abilities/Elements/RainbowFireAbility.java | 1 + .../hyperion/abilities/firebending/RainbowWave.java | 10 +++++++++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 2194dc1..099785c 100644 --- a/README.MD +++ b/README.MD @@ -26,6 +26,7 @@ Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyper * Combustion * FlameRush * FireWave (combo) +* RainbowWave ### Water * IceBreath * IceCrawl diff --git a/build.gradle.kts b/build.gradle.kts index 7e2d840..7d7f742 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ repositories { dependencies { compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT") - compileOnly(files("libs/ProjectKorra-1.12.1-PRE-RELEASE-1.jar")) + compileOnly(("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1")) implementation("org.bstats:bstats-bukkit:3.1.0") } diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java index 42fe601..50e8b99 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java @@ -3,6 +3,7 @@ import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.ability.Ability; import com.projectkorra.projectkorra.ability.SubAbility; +import com.projectkorra.projectkorra.util.ThreadUtil; import me.moros.hyperion.Elements; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.RainbowParticleEffect; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java index c78db24..99411c2 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java @@ -4,6 +4,7 @@ import com.projectkorra.projectkorra.ability.AddonAbility; import com.projectkorra.projectkorra.util.DamageHandler; import me.moros.hyperion.Hyperion; +import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.abilities.Elements.RainbowFireAbility; import org.bukkit.Location; import org.bukkit.configuration.file.FileConfiguration; @@ -16,7 +17,10 @@ import java.util.List; import java.util.Set; -public class RainbowWave extends RainbowFireAbility implements AddonAbility { +import static me.moros.hyperion.Elements.RAINBOWFIRE; +import static me.moros.hyperion.abilities.Elements.RainbowFireAbility.playRainbowFireParticles; + +public class RainbowWave extends FireAbility implements AddonAbility { private static final String path = "Abilities.Fire.RainbowWave."; @@ -41,6 +45,10 @@ public RainbowWave(Player player) { if (!bPlayer.canBend(this)) return; if (hasAbility(player, RainbowWave.class)) return; if (bPlayer.isOnCooldown(this)) return; + if (bPlayer.canUseSubElement(RAINBOWFIRE)) { + damage *= RainbowFireAbility.getDamageFactor(); + cooldown *= RainbowFireAbility.getCooldownFactor(); + } loadConfigValues(); From 0205f8ce72a20bff710156351664fb60cb81508e Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Thu, 21 Aug 2025 20:40:28 -0700 Subject: [PATCH 18/34] Hyperion v1.7.5-PRE-RELEASE-1 Re-adds spigot support (via the FoliaScheduler library). Removes support for mc 1.20.1 and lower. Strengthens Paper support. Adds extra debug messages. Adds and utilizes the PaperLib util (meant to strengthen paper/spigot/luminol/folia compatibility). Maintains Jitpack support. Downgrades the RainbowParticleEffect to use the spigot particle builder (needed for proper spigot support). Edits the ThreadUtil. --- .github/FUNDING.yml | 13 +++ .github/dependabot.yml | 8 ++ .github/workflows/cd.yml | 52 +++++++++++ .github/workflows/ci.yml | 23 +++++ build.gradle.kts | 19 ++-- src/main/java/me/moros/hyperion/Hyperion.java | 86 +++++++++++++------ .../Elements/RainbowFireAbility.java | 1 - .../abilities/firebending/RainbowWave.java | 2 +- .../abilities/firebending/combo/FireWave.java | 1 - .../hyperion/listeners/CoreListener.java | 21 +++-- .../java/me/moros/hyperion/util/PaperLib.java | 74 ++++++++-------- .../hyperion/util/RainbowParticleEffect.java | 25 ++++-- .../me/moros/hyperion/util/ThreadUtil.java | 41 +++++---- 13 files changed, 263 insertions(+), 103 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/cd.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..aa1e26e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +github: ["CJCrafter"] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: # \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..eebec9d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" + commit-message: + prefix: "chore(deps)" diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..2206d70 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,52 @@ +name: Publish Snapshot + +on: + push: + # any branch in this repo + branches: + - '**' + +jobs: + publish-snapshot: + runs-on: ubuntu-latest + environment: Gradle Deploy + permissions: + contents: write + if: "!endsWith(github.actor, '[bot]')" + + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for accurate version extraction + + - name: Set up Java 8 & cache Gradle + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 8 + cache: gradle + server-id: stagingDeploy + settings-path: ${{ github.workspace }} + + - name: Extract project version + id: get-version + run: | + echo "version=$(./gradlew -q properties \ + | grep '^version:' \ + | awk '{print $2}')" >> $GITHUB_OUTPUT + + - name: Publish snapshot to Maven + if: endsWith(steps.get-version.outputs.version, '-SNAPSHOT') + run: ./gradlew publish --no-daemon + + - name: Release with JReleaser + if: endsWith(steps.get-version.outputs.version, '-SNAPSHOT') + run: ./gradlew jreleaserRelease --no-daemon --no-configuration-cache + env: + JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }} + JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }} + JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }} + JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }} + JRELEASER_NEXUS2_SONATYPESNAPSHOTS_TOKEN: ${{ secrets.JRELEASER_NEXUS2_SONATYPESNAPSHOTS_TOKEN }} + JRELEASER_NEXUS2_SONATYPESNAPSHOTS_USERNAME: ${{ secrets.JRELEASER_NEXUS2_SONATYPESNAPSHOTS_USERNAME }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9dd7f72 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + branches: ["**"] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Java 8 & cache Gradle + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 8 + cache: gradle + + - name: Build & run tests + run: ./gradlew clean build --no-daemon diff --git a/build.gradle.kts b/build.gradle.kts index 7d7f742..e180128 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.moros" -version = "1.7.4" +version = "1.7.5-PRE-RELEASE-1" java { toolchain { @@ -20,17 +20,26 @@ repositories { } dependencies { - compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT") - compileOnly(("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1")) + // Provided by server + compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") + compileOnly("org.jetbrains:annotations:26.0.2") + compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") + // Included in plugin jar implementation("org.bstats:bstats-bukkit:3.1.0") + implementation("com.cjcrafter:foliascheduler:0.7.2") } tasks { shadowJar { - archiveClassifier.set("") // No "-all" suffix + archiveClassifier.set("") + + // Relocate bStats to avoid plugin conflicts relocate("org.bstats", "me.moros.hyperion.bstats") - minimize() + + // Relocate FoliaScheduler to avoid classpath issues + relocate("com.cjcrafter.foliascheduler", "me.moros.hyperion.foliascheduler") + } build { diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 8130792..5b662f7 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -19,8 +19,11 @@ package me.moros.hyperion; -import com.projectkorra.projectkorra.util.TempFallingBlock; -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; + +import com.cjcrafter.foliascheduler.FoliaCompatibility; +import com.cjcrafter.foliascheduler.ServerImplementation; +import com.cjcrafter.foliascheduler.util.ReflectionUtil; +import com.projectkorra.projectkorra.BendingPlayer; import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.commands.HyperionCommand; import me.moros.hyperion.configuration.ConfigManager; @@ -28,14 +31,15 @@ import me.moros.hyperion.listeners.CoreListener; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.*; -import org.bstats.bukkit.Metrics; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; +import org.bstats.bukkit.Metrics;; +import org.bukkit.block.Block; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; - import java.util.logging.Logger; +import static com.projectkorra.projectkorra.util.TempFallingBlock.get; +import static com.projectkorra.projectkorra.util.TempFallingBlock.manage; + public class Hyperion extends JavaPlugin { public static Hyperion plugin; private static String author; @@ -45,15 +49,18 @@ public class Hyperion extends JavaPlugin { public static boolean isFolia; public static boolean paper; public static boolean luminol; + public static boolean spigot; private PotionEffectAdapter potionEffectAdapter; + public static ServerImplementation scheduler; + @Override public void onEnable() { plugin = this; + scheduler = new FoliaCompatibility(plugin).getServerImplementation(); log = getLogger(); version = getDescription().getVersion(); author = getDescription().getAuthors().get(0); - try { Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); isFolia = true; @@ -69,16 +76,26 @@ public void onEnable() { luminol = true; } catch (ClassNotFoundException ignored) {} - if (!isLuminol()) { - getLogger().info("[Hyperion] Hyperion is running on Paper/Folia"); - } else { - getLogger().info("[Hyperion] Hyperion is running on Luminol"); - } + if (!isLuminol() && isPaper()) { + getLogger().info("Hyperion is running on Paper/Folia"); + } + + if (isLuminol() && !spigot) { + getLogger().info("Hyperion is running on Luminol"); + } + + if (!isFolia && !paper && !luminol) { + spigot = true; + getLogger().info("Hyperion is running on Spigot"); + } - new Metrics(this, 8212); + new Metrics(this, 8212); new ConfigManager(); new HyperionCommand(); new Elements(); + getLogger().info("Initialized Hyperion Elements/Configs/Commands/Metrics"); + getLogger().info("Attempting to load PaperLib"); + new PaperLib(); layer = new PersistentDataLayer(); checkMaintainer(); CoreMethods.loadAbilities(); @@ -88,15 +105,30 @@ public void onEnable() { // Use appropriate scheduler depending on platform if (isFolia || luminol) { - getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempFallingBlock.manage(), 1L, 5L); - getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> TempArmorStand.manage(), 1L, 1L); - getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> BendingFallingBlock.manage(), 1L, 5L); - getServer().getGlobalRegionScheduler().runAtFixedRate(this, task -> FireAbility.getAbilities(), 1L, 5L); + scheduler.global().runAtFixedRate(task -> { + manage(); + return null; + }, 1L, 5L); + + scheduler.global().runAtFixedRate(task -> { + TempArmorStand.manage(); + return null; + }, 1L, 1L); + + scheduler.global().runAtFixedRate(task -> { + BendingFallingBlock.manage(); + return null; + }, 1L, 5L); + + scheduler.global().runAtFixedRate(task -> { + FireAbility.getAbilities(); + return null; + }, 1L, 5L); } else { new BukkitRunnable() { @Override public void run() { - TempFallingBlock.manage(); + manage(); } }.runTaskTimer(this, 0L, 5L); @@ -130,14 +162,13 @@ public void onDisable() { BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); - // Avoid Bukkit cancelTasks on Folia/Luminol (unsupported) if (!isFolia && !luminol) { getServer().getScheduler().cancelTasks(this); } - // Use a Folia/Luminol compatible version of cancelTasks - if (isFolia || luminol ) { - getServer().getGlobalRegionScheduler().cancelTasks(this); - } + + if (isFolia || luminol) { + scheduler.global().cancelTasks(); + } } public static void reload1() { @@ -146,15 +177,19 @@ public static void reload1() { BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); CoreMethods.loadAbilities(); + new HyperionCommand(); + getLog().info("Trying to initialize commands once more"); getLog().info("Hyperion BUKKIT Reloaded."); } - public static void reload(ScheduledTask scheduledTask) { + public static void reload() { Hyperion.getPlugin().reloadConfig(); ConfigManager.modifiersConfig.reloadConfig(); BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); CoreMethods.loadAbilities(); + new HyperionCommand(); + getLog().info("Trying to initialize commands once more"); getLog().info("Hyperion FOLIA Reloaded."); } @@ -200,4 +235,7 @@ public static boolean isLuminol() { return luminol; } + public static boolean isSpigot() { + return spigot; + } } diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java index 50e8b99..42fe601 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java @@ -3,7 +3,6 @@ import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.ability.Ability; import com.projectkorra.projectkorra.ability.SubAbility; -import com.projectkorra.projectkorra.util.ThreadUtil; import me.moros.hyperion.Elements; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.RainbowParticleEffect; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java index 99411c2..99b7852 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java @@ -20,7 +20,7 @@ import static me.moros.hyperion.Elements.RAINBOWFIRE; import static me.moros.hyperion.abilities.Elements.RainbowFireAbility.playRainbowFireParticles; -public class RainbowWave extends FireAbility implements AddonAbility { +public class RainbowWave extends RainbowFireAbility implements AddonAbility { private static final String path = "Abilities.Fire.RainbowWave."; diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java index aaa3dee..7a53ef0 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/combo/FireWave.java @@ -34,7 +34,6 @@ import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.util.ThreadUtil; import com.projectkorra.projectkorra.waterbending.SurgeWall; import com.projectkorra.projectkorra.waterbending.SurgeWave; import me.moros.hyperion.Hyperion; diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index b69ca87..982f6df 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -19,6 +19,7 @@ package me.moros.hyperion.listeners; +import com.cjcrafter.foliascheduler.folia.FoliaTask; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.event.AbilityStartEvent; @@ -40,12 +41,7 @@ import org.bukkit.block.Lockable; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Arrow; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Snowball; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -67,8 +63,7 @@ import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; -import static me.moros.hyperion.Hyperion.isFolia; -import static me.moros.hyperion.Hyperion.luminol; +import static me.moros.hyperion.Hyperion.*; public class CoreListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @@ -210,18 +205,22 @@ public void onPlayerLogout(final PlayerQuitEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPKReload(final BendingReloadEvent event) { final CommandSender sender = event.getSender(); - if (!isFolia && !luminol) { - Bukkit.getScheduler().runTaskLater(Hyperion.getPlugin(), Hyperion::reload1, 1); + if (!isFolia) { + Bukkit.getScheduler().runTaskLater(getPlugin(), Hyperion::reload1, 1); sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Bukkit" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); } if (isFolia || luminol) { - Bukkit.getGlobalRegionScheduler().runDelayed(Hyperion.getPlugin(), Hyperion::reload, 1); + scheduler.global().runDelayed(task -> { + Hyperion.reload(); + return null; + }, 1L); sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Folia" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onAbilityStart(final AbilityStartEvent event) { if (event.getAbility() instanceof CoreAbility ability) { diff --git a/src/main/java/me/moros/hyperion/util/PaperLib.java b/src/main/java/me/moros/hyperion/util/PaperLib.java index a82dee2..92b963b 100644 --- a/src/main/java/me/moros/hyperion/util/PaperLib.java +++ b/src/main/java/me/moros/hyperion/util/PaperLib.java @@ -1,24 +1,27 @@ -// -// Source code recreated from a .class file by IntelliJ IDEA -// (powered by FernFlower decompiler) -// - package me.moros.hyperion.util; -import java.util.concurrent.CompletableFuture; - - import me.moros.hyperion.Hyperion; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import java.util.concurrent.CompletableFuture; + public class PaperLib { - private static Environment ENVIRONMENT; + private static final Environment ENVIRONMENT; + + static { + if (Hyperion.isFolia()) { + ENVIRONMENT = new Folia(); + } else if (Hyperion.isPaper()) { + ENVIRONMENT = new Paper(); + } else { + ENVIRONMENT = new Spigot(); + } + } public static CompletableFuture getChunkAtAsync(Location location) { return ENVIRONMENT.getChunkAtAsync(location); @@ -32,68 +35,69 @@ public static CompletableFuture teleportAsync(Entity entity, Location l return ENVIRONMENT.teleportAsync(entity, location); } - public static CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + public static CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause) { return ENVIRONMENT.teleportAsync(entity, location, cause); } - static { - if (Hyperion.isFolia()) { - ENVIRONMENT = new Folia(); - } else if (Hyperion.isPaper()) { - ENVIRONMENT = new Paper(); - } else { - ENVIRONMENT = new Spigot(); - } - - } - private interface Environment { default CompletableFuture getChunkAtAsync(Location location) { return this.getChunkAtAsync(location.getBlock()); } - CompletableFuture getChunkAtAsync(Block var1); + CompletableFuture getChunkAtAsync(Block block); default CompletableFuture teleportAsync(Entity entity, Location location) { return this.teleportAsync(entity, location, TeleportCause.PLUGIN); } - CompletableFuture teleportAsync(Entity var1, Location var2, PlayerTeleportEvent.TeleportCause var3); + CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause); } - static class Spigot implements Environment { + private static class Spigot implements Environment { + @Override public CompletableFuture getChunkAtAsync(Block block) { return CompletableFuture.completedFuture(block.getChunk()); } - public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + @Override + public CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause) { entity.teleport(location, cause); return CompletableFuture.completedFuture(true); } } - static class Paper implements Environment { + private static class Paper implements Environment { + @Override public CompletableFuture getChunkAtAsync(Block block) { - return block.getWorld().getChunkAtAsync(block); + CompletableFuture future = new CompletableFuture<>(); + Hyperion.scheduler.region(block.getLocation()).run(() -> { + future.complete(block.getChunk()); + }); + return future; } - public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { - return entity.teleportAsync(location, cause); + @Override + public CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause) { + return Hyperion.scheduler.teleportAsync(entity, location, cause); } } - static class Folia implements Environment { + private static class Folia implements Environment { + @Override public CompletableFuture getChunkAtAsync(Block block) { - CompletableFuture future = new CompletableFuture(); - ThreadUtil.ensureLocation(block.getLocation(), () -> { + CompletableFuture future = new CompletableFuture<>(); + // Use CJCrafter's scheduler to run synchronously in the region thread + Hyperion.scheduler.region(block.getLocation()).run(task -> { Chunk chunk = block.getWorld().getChunkAt(block); future.complete(chunk); }); return future; } - public CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { - return entity.teleportAsync(location, cause); + @Override + public CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause) { + // Folia supports async teleport natively + return Hyperion.scheduler.teleportAsync(entity, location, cause); } } } diff --git a/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java index 0181a88..d2fad6e 100644 --- a/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java +++ b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java @@ -1,10 +1,10 @@ package me.moros.hyperion.util; -import com.destroystokyo.paper.ParticleBuilder; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.Particle.DustOptions; +import org.bukkit.World; import org.bukkit.util.Vector; import java.util.Arrays; @@ -31,6 +31,9 @@ public class RainbowParticleEffect { ); public static void spawnRainbowParticleEffect(Location center, int amount) { + World world = center.getWorld(); + if (world == null) return; + for (int i = 0; i < amount; i++) { Particle particle; @@ -52,20 +55,24 @@ public static void spawnRainbowParticleEffect(Location center, int amount) { double offsetZ = (random.nextDouble() - 0.5) * 2.0; Location loc = center.clone().add(offsetX, offsetY, offsetZ); - // Velocity + // Velocity vector (Spigot does not directly support velocity in spawnParticle) Vector velocity = new Vector( (random.nextDouble() - 0.5) * 0.2, random.nextDouble() * 0.2, (random.nextDouble() - 0.5) * 0.2 ); - new ParticleBuilder(particle) - .location(loc) - .count(0) - .offset((float) velocity.getX(), (float) velocity.getY(), (float) velocity.getZ()) - .extra(0) - .data(data) - .spawn(); + // Spawn the particle + world.spawnParticle( + particle, + loc, + 0, // count (0 for manual velocity) + velocity.getX(), + velocity.getY(), + velocity.getZ(), + 0, // extra (speed) + data + ); } } } diff --git a/src/main/java/me/moros/hyperion/util/ThreadUtil.java b/src/main/java/me/moros/hyperion/util/ThreadUtil.java index 7f8566a..f7c385f 100644 --- a/src/main/java/me/moros/hyperion/util/ThreadUtil.java +++ b/src/main/java/me/moros/hyperion/util/ThreadUtil.java @@ -1,21 +1,19 @@ package me.moros.hyperion.util; -import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import com.cjcrafter.foliascheduler.ServerImplementation; import me.moros.hyperion.Hyperion; import org.bukkit.Bukkit; import org.bukkit.Location; - import org.bukkit.entity.Entity; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; - - public class ThreadUtil { private static final Plugin PLUGIN = Hyperion.plugin; private static final boolean THREAD_UTIL_AVAILABLE; private static final Class THREAD_UTIL_CLASS; + private static final ServerImplementation SCHEDULER = Hyperion.scheduler; static { Class threadUtilClass = null; @@ -28,12 +26,14 @@ public class ThreadUtil { public static void ensureLocation(Location location, Runnable runnable) { if (Hyperion.isFolia() || Hyperion.isLuminol()) { - if (Bukkit.isOwnedByCurrentRegion(location) || Bukkit.isStopping()) { + if (Hyperion.scheduler.isOwnedByCurrentRegion(location)) { runnable.run(); return; } - RegionScheduler scheduler = Bukkit.getRegionScheduler(); - scheduler.execute(PLUGIN, location, runnable); + SCHEDULER.region(location).run(task -> { + runnable.run(); + return null; + }); } else { if (Bukkit.isPrimaryThread()) { runnable.run(); @@ -45,31 +45,40 @@ public static void ensureLocation(Location location, Runnable runnable) { public static void runGlobalLater(Runnable runnable, long delayTicks) { if (Hyperion.isFolia() || Hyperion.isLuminol()) { - Bukkit.getGlobalRegionScheduler().runDelayed(PLUGIN, task -> runnable.run(), delayTicks); + SCHEDULER.global().runDelayed(task -> { + runnable.run(); + return null; + }, delayTicks); } else { Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } public static void runLocationLater(Location location, Runnable runnable, long delayTicks) { - boolean isAsyncScheduler = Hyperion.isFolia() || Hyperion.isLuminol(); - - if (isAsyncScheduler) { + if (Hyperion.isFolia() || Hyperion.isLuminol()) { if (location != null && location.getWorld() != null) { - Bukkit.getRegionScheduler().runDelayed(PLUGIN, location, task -> runnable.run(), delayTicks); + SCHEDULER.region(location).runDelayed(task -> { + runnable.run(); + return null; + }, delayTicks); } else { - Bukkit.getLogger().warning("[Hyperion] Cannot schedule region task: location or world is null. Falling back to main scheduler."); - Bukkit.getGlobalRegionScheduler().runDelayed(PLUGIN, task -> runnable.run(), delayTicks); + Bukkit.getLogger().warning("[Hyperion] Cannot schedule region task: location or world is null. Falling back to global scheduler."); + SCHEDULER.global().runDelayed(task -> { + runnable.run(); + return null; + }, delayTicks); } } else { Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } } - public static void runEntityLater(Location loc, Runnable runnable, long delayTicks) { if (Hyperion.isFolia() || Hyperion.isLuminol()) { - Bukkit.getRegionScheduler().runDelayed(PLUGIN, loc, task -> runnable.run(), delayTicks); + SCHEDULER.region(loc).runDelayed(task -> { + runnable.run(); + return null; + }, delayTicks); } else { Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); } From 570a78fa57322a0452dc1e70be5d78862c9f9319 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Thu, 21 Aug 2025 22:08:13 -0700 Subject: [PATCH 19/34] Update README.MD --- README.MD | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 2194dc1..ad88672 100644 --- a/README.MD +++ b/README.MD @@ -5,7 +5,10 @@ [![GitHub release](https://img.shields.io/github/v/release/Hihelloy-main/Hyperion?style=flat-square)](https://github.com/Hihelloy-main/Hyperion/releases) [![Github Downloads](https://img.shields.io/github/downloads/Hihelloy-main/Hyperion/total.svg)](https://github.com/Hihelloy-main/Hyperion/releases) -Hi, I'm Hihelloy, and this is my fork of Moro's ProjectKorra Addon plugin, Hyperion! +Hi, I'm Hihelloy, and this is my UNOFFICIAL fork of Moro's ProjectKorra Addon plugin, Hyperion! + +please note that this is NOT my plugin by any means, it is really Moro's plugin. But I have changed a few things (like how I added [Folia](https://github.com/PaperMC/Folia) support) +the original plugin can be found [here](https://github.com/PrimordialMoros/Hyperion), but if you want Folia support or the RainbowFire element please download the latest version of my fork! ## Abilities ### Air From da11ca8c2fc6f09f047c7d7191119ef5ac339ea1 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 22 Aug 2025 21:22:55 -0700 Subject: [PATCH 20/34] Improves /b hyperion reload and the paperlib --- src/main/java/me/moros/hyperion/Hyperion.java | 6 +++++- .../abilities/earthbending/EarthGuard.java | 12 ++++++------ .../moros/hyperion/commands/HyperionCommand.java | 15 ++++++++++++--- .../java/me/moros/hyperion/util/PaperLib.java | 5 +++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 5b662f7..c038cf4 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -167,7 +167,7 @@ public void onDisable() { } if (isFolia || luminol) { - scheduler.global().cancelTasks(); + scheduler.async().cancelTasks(); } } @@ -238,4 +238,8 @@ public static boolean isLuminol() { public static boolean isSpigot() { return spigot; } + + public static ServerImplementation getScheduler() { + return scheduler; + } } diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index bef3274..9ca4788 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -31,7 +31,6 @@ import com.projectkorra.projectkorra.util.TempPotionEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.BendingFallingBlock; -import me.moros.hyperion.util.PotionMetaUtil; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.GameMode; @@ -40,6 +39,7 @@ import org.bukkit.Sound; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -60,6 +60,7 @@ public class EarthGuard extends EarthAbility implements AddonAbility { private BendingFallingBlock armorFallingBlock; private BlockData blockData; private GameMode originalMode; + private static Entity entity; @Attribute(Attribute.COOLDOWN) private long cooldown; @@ -111,14 +112,13 @@ public EarthGuard(Player player) { } } - @Override public void progress() { if (!formed) { if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { remove(); return; } - moveBlock(); + moveBlock(entity); } else { if (!canRemainActive()) { remove(); @@ -154,7 +154,7 @@ private boolean canRemainActive() { return true; } - private void formArmor(Material material) { + private void formArmor(Material material, Object entity) { if (formed) return; final ItemStack head, chest, leggings, boots; @@ -213,7 +213,7 @@ private void formArmor(Material material) { formed = true; } - private void moveBlock() { + private void moveBlock(Object entity) { if (!player.getWorld().equals(armorFallingBlock.getFallingBlock().getWorld())) { remove(); return; @@ -235,7 +235,7 @@ private void moveBlock() { if (distanceSquared <= 0.5 * 0.5) { Material mat = armorFallingBlock.getFallingBlock().getBlockData().getMaterial(); armorFallingBlock.remove(); - formArmor(mat); + formArmor(mat, entity); return; } diff --git a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java index eff9929..1d555f9 100755 --- a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java +++ b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java @@ -22,11 +22,15 @@ import com.projectkorra.projectkorra.command.PKCommand; import me.moros.hyperion.Hyperion; import me.moros.hyperion.configuration.ConfigManager; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import java.util.List; +import static me.moros.hyperion.Hyperion.isFolia; +import static me.moros.hyperion.Hyperion.scheduler; + public class HyperionCommand extends PKCommand { public HyperionCommand() { super("hyperion", "/bending hyperion ", "Show information about Hyperion and optionally reload its config.", new String[]{"hyperion"}); @@ -40,9 +44,14 @@ public void execute(CommandSender sender, List args) { sender.sendMessage(ChatColor.GREEN + "Developed by: " + ChatColor.RED + Hyperion.getAuthor()); } else if (args.size() == 1) { if (args.get(0).equals("reload") && hasPermission(sender, "reload")) { - Hyperion.getPlugin().reloadConfig(); - ConfigManager.modifiersConfig.reloadConfig(); - sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + if (isFolia) { + scheduler.global().run(Hyperion::reload); + sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + } + if (!isFolia) { + Bukkit.getScheduler().runTask(Hyperion.plugin, Hyperion::reload1); + sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + } } } } diff --git a/src/main/java/me/moros/hyperion/util/PaperLib.java b/src/main/java/me/moros/hyperion/util/PaperLib.java index 92b963b..d98c1de 100644 --- a/src/main/java/me/moros/hyperion/util/PaperLib.java +++ b/src/main/java/me/moros/hyperion/util/PaperLib.java @@ -11,16 +11,17 @@ import java.util.concurrent.CompletableFuture; public class PaperLib { - private static final Environment ENVIRONMENT; + private static Environment ENVIRONMENT; static { if (Hyperion.isFolia()) { ENVIRONMENT = new Folia(); } else if (Hyperion.isPaper()) { ENVIRONMENT = new Paper(); - } else { + } else if (Hyperion.isSpigot()) { ENVIRONMENT = new Spigot(); } + } public static CompletableFuture getChunkAtAsync(Location location) { From 050a76dd97cc566cdd0d3891feae2d9cdabf1e72 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sun, 24 Aug 2025 22:43:38 -0700 Subject: [PATCH 21/34] Hyperion 1.7.5-PRE-RELEASE-2 --- .github/FUNDING.yml | 13 -- build.gradle.kts | 4 +- src/main/java/me/moros/hyperion/Hyperion.java | 19 ++- .../earthbending/EarthGuardWall.java | 1 + .../hyperion/commands/HyperionCommand.java | 42 +++++- .../listeners/PlayerJoinListener.java | 43 ++++++ .../me/moros/hyperion/util/UpdateChecker.java | 124 ++++++++++++++++++ src/main/resources/plugin.yml | 3 + 8 files changed, 228 insertions(+), 21 deletions(-) delete mode 100644 .github/FUNDING.yml create mode 100644 src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java create mode 100644 src/main/java/me/moros/hyperion/util/UpdateChecker.java diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index aa1e26e..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,13 +0,0 @@ -# These are supported funding model platforms - -github: ["CJCrafter"] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: # \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e180128..7989aa7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.moros" -version = "1.7.5-PRE-RELEASE-1" +version = "1.7.5-PRE-RELEASE-2" java { toolchain { @@ -23,7 +23,7 @@ dependencies { // Provided by server compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") compileOnly("org.jetbrains:annotations:26.0.2") - compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") + compileOnly("com.projectkorra:projectkorra:1.12.0") // Included in plugin jar implementation("org.bstats:bstats-bukkit:3.1.0") diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index c038cf4..6664440 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -22,6 +22,7 @@ import com.cjcrafter.foliascheduler.FoliaCompatibility; import com.cjcrafter.foliascheduler.ServerImplementation; +import com.cjcrafter.foliascheduler.TaskImplementation; import com.cjcrafter.foliascheduler.util.ReflectionUtil; import com.projectkorra.projectkorra.BendingPlayer; import me.moros.hyperion.abilities.Elements.FireAbility; @@ -29,12 +30,16 @@ import me.moros.hyperion.configuration.ConfigManager; import me.moros.hyperion.listeners.AbilityListener; import me.moros.hyperion.listeners.CoreListener; +import me.moros.hyperion.listeners.PlayerJoinListener; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.*; import org.bstats.bukkit.Metrics;; +import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; + +import java.util.function.Consumer; import java.util.logging.Logger; import static com.projectkorra.projectkorra.util.TempFallingBlock.get; @@ -52,6 +57,7 @@ public class Hyperion extends JavaPlugin { public static boolean spigot; private PotionEffectAdapter potionEffectAdapter; public static ServerImplementation scheduler; + private static UpdateChecker updateChecker; @Override @@ -93,7 +99,13 @@ public void onEnable() { new ConfigManager(); new HyperionCommand(); new Elements(); - getLogger().info("Initialized Hyperion Elements/Configs/Commands/Metrics"); + updateChecker = new UpdateChecker(this, "Hihelloy-main/Hyperion"); + if (isFolia) { + scheduler.global().execute(() -> updateChecker.checkForUpdate()); + } else { + Bukkit.getScheduler().runTaskAsynchronously(this, () -> updateChecker.checkForUpdate()); + } + getLogger().info("Initialized Hyperion Elements/Configs/Commands/Metrics/UpdateChecker"); getLogger().info("Attempting to load PaperLib"); new PaperLib(); layer = new PersistentDataLayer(); @@ -102,6 +114,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new AbilityListener(), this); getServer().getPluginManager().registerEvents(new CoreListener(), this); + getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); // Use appropriate scheduler depending on platform if (isFolia || luminol) { @@ -242,4 +255,8 @@ public static boolean isSpigot() { public static ServerImplementation getScheduler() { return scheduler; } + + public static UpdateChecker getUpdateChecker() { + return getPlugin(Hyperion.class).updateChecker; + } } diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuardWall.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuardWall.java index 3ee903d..e0ca96f 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuardWall.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuardWall.java @@ -28,6 +28,7 @@ import com.projectkorra.projectkorra.util.ParticleEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; +import me.moros.hyperion.util.ThreadUtil; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; diff --git a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java index 1d555f9..5bf7920 100755 --- a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java +++ b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java @@ -22,9 +22,12 @@ import com.projectkorra.projectkorra.command.PKCommand; import me.moros.hyperion.Hyperion; import me.moros.hyperion.configuration.ConfigManager; +import me.moros.hyperion.util.UpdateChecker; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -39,20 +42,49 @@ public HyperionCommand() { @Override public void execute(CommandSender sender, List args) { if (!hasPermission(sender) || !correctLength(sender, args.size(), 0, 1)) return; + if (args.size() == 0) { sender.sendMessage(ChatColor.GREEN + "Hyperion Version: " + ChatColor.RED + Hyperion.getVersion()); sender.sendMessage(ChatColor.GREEN + "Developed by: " + ChatColor.RED + Hyperion.getAuthor()); } else if (args.size() == 1) { - if (args.get(0).equals("reload") && hasPermission(sender, "reload")) { + String sub = args.get(0).toLowerCase(); + + if (sub.equals("reload") && hasPermission(sender, "reload")) { if (isFolia) { scheduler.global().run(Hyperion::reload); - sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); - } - if (!isFolia) { + } else { Bukkit.getScheduler().runTask(Hyperion.plugin, Hyperion::reload1); - sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + } + sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + } + + + else if (sub.equals("checkupdate") && hasPermission(sender, "checkupdate")) { + UpdateChecker checker = Hyperion.getUpdateChecker(); + + if (checker == null) { + sender.sendMessage(ChatColor.RED + "Update checker not initialized."); + return; + } + + if (!checker.hasChecked()) { + sender.sendMessage(ChatColor.GRAY + "Still checking for updates, please try again shortly."); + return; + } + + if (checker.isUpdateAvailable()) { + String current = checker.getCurrentVersion() != null ? checker.getCurrentVersion() : "unknown"; + String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; + + sender.sendMessage(ChatColor.GREEN + "[Hyperion] A new version is available!"); + sender.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); + sender.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); + sender.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); + } else { + sender.sendMessage(ChatColor.GREEN + "You're running the latest version of Hyperion."); } } } } + } diff --git a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java new file mode 100644 index 0000000..cbe3595 --- /dev/null +++ b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java @@ -0,0 +1,43 @@ +package me.moros.hyperion.listeners; + +import me.moros.hyperion.Hyperion; +import me.moros.hyperion.util.HexColor; +import me.moros.hyperion.util.UpdateChecker; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerJoinListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + if (!player.isOp()) return; + + UpdateChecker checker = Hyperion.getUpdateChecker(); + if (checker == null) { + player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RED + "Update checker not initialized."); + return; + } + + if (!checker.hasChecked()) { + player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.GRAY + "Checking for updates..."); + return; + } + + if (checker.isUpdateAvailable()) { + String current = checker.getCurrentVersion() != null ? checker.getCurrentVersion() : "unknown"; + String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; + + player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RESET + HexColor.YELLOW + ChatColor.UNDERLINE + "A new version is available!"); + player.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); + player.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); + player.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); + } else { + player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RESET + ChatColor.GREEN + "No updates available. You're on the latest version."); + } + } +} diff --git a/src/main/java/me/moros/hyperion/util/UpdateChecker.java b/src/main/java/me/moros/hyperion/util/UpdateChecker.java new file mode 100644 index 0000000..34472b8 --- /dev/null +++ b/src/main/java/me/moros/hyperion/util/UpdateChecker.java @@ -0,0 +1,124 @@ +package me.moros.hyperion.util; + +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.stream.Collectors; + +public class UpdateChecker { + + private final JavaPlugin plugin; + private final BukkitScheduler scheduler; + private final String apiUrl; + + private boolean updateAvailable = false; + private boolean checked = false; + + private String currentVersion; + private String latestVersion; + + public UpdateChecker(JavaPlugin plugin, String repo) { + this.plugin = plugin; + this.scheduler = plugin.getServer().getScheduler(); + this.apiUrl = "https://api.github.com/repos/" + repo + "/releases/latest"; + } + + public void checkForUpdate() { + currentVersion = plugin.getDescription().getVersion(); + + try { + HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); + conn.setRequestProperty("Accept", "application/vnd.github.v3+json"); + + String token = System.getenv("GITHUB_TOKEN"); + if (token != null && !token.isEmpty()) { + conn.setRequestProperty("Authorization", "token " + token); + } + + conn.setRequestMethod("GET"); + + String json = new BufferedReader(new InputStreamReader(conn.getInputStream())) + .lines().collect(Collectors.joining()); + + String tagName = parseJsonField(json, "tag_name"); + if (tagName == null) { + plugin.getLogger().warning("Update check failed: tag_name not found in GitHub API response"); + checked = true; + return; + } + + latestVersion = tagName.startsWith("v") ? tagName.substring(1) : tagName; + currentVersion = currentVersion.startsWith("v") ? currentVersion.substring(1) : currentVersion; + + updateAvailable = compareVersions(currentVersion, latestVersion) < 0; + checked = true; + + } catch (IOException e) { + plugin.getLogger().warning("Update check failed: " + e.getMessage()); + checked = true; + } + } + + // Simple version comparison: returns <0 if v1 < v2, 0 if equal, >0 if v1 > v2 + private int compareVersions(String v1, String v2) { + String[] parts1 = v1.split("[.-]"); + String[] parts2 = v2.split("[.-]"); + + int length = Math.max(parts1.length, parts2.length); + for (int i = 0; i < length; i++) { + String p1 = i < parts1.length ? parts1[i] : "0"; + String p2 = i < parts2.length ? parts2[i] : "0"; + + int cmp; + // Try numeric comparison + try { + int n1 = Integer.parseInt(p1); + int n2 = Integer.parseInt(p2); + cmp = Integer.compare(n1, n2); + } catch (NumberFormatException e) { + cmp = p1.compareTo(p2); + } + + if (cmp != 0) { + return cmp; + } + } + + return 0; + } + + // Naive JSON parser for one-level field (for simplicity, you might want to use a proper JSON lib) + private String parseJsonField(String json, String field) { + String search = "\"" + field + "\":\""; + int index = json.indexOf(search); + if (index == -1) return null; + + int start = index + search.length(); + int end = json.indexOf("\"", start); + if (end == -1) return null; + + return json.substring(start, end); + } + + // Getters + public boolean isUpdateAvailable() { + return updateAvailable; + } + + public boolean hasChecked() { + return checked; + } + + public String getCurrentVersion() { + return currentVersion; + } + + public String getLatestVersion() { + return latestVersion; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7afa020..efd62ae 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -18,6 +18,9 @@ permissions: bending.command.hyperion.reload: default: op description: Reload the config of Hyperion. + bending.command.hyperion.checkupdate: + default: op + description: Allows the player to manually check for plugin updates. hyperion.player: default: true description: Access to hyperion abilities. From c11e026b3b1d4a82c3f5a14d739826ef5212a1dc Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sun, 24 Aug 2025 23:03:30 -0700 Subject: [PATCH 22/34] Adds a Latest GitHub Version debug to the PlayerJoinListener --- build.gradle.kts | 2 +- .../java/me/moros/hyperion/listeners/PlayerJoinListener.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7989aa7..e0b2cb1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { // Provided by server compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") compileOnly("org.jetbrains:annotations:26.0.2") - compileOnly("com.projectkorra:projectkorra:1.12.0") + compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") // Included in plugin jar implementation("org.bstats:bstats-bukkit:3.1.0") diff --git a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java index cbe3595..d4c622a 100644 --- a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java +++ b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java @@ -36,8 +36,13 @@ public void onPlayerJoin(PlayerJoinEvent event) { player.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); player.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); player.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); + } else { + String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; + player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RESET + ChatColor.GREEN + "No updates available. You're on the latest version."); + player.sendMessage(ChatColor.GRAY + "Latest GitHub version: " + ChatColor.GREEN + latest); } + } } From 8c2a7c9b0bb30d4f60c2461ca4afabe5bcc47810 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Mon, 25 Aug 2025 00:41:52 -0700 Subject: [PATCH 23/34] The ThreadUtil update. Copies but reworks ProjectKorra's ThreadUtil (now works with Hyperion's schedulers and will be used in Hyperion 1.7.5) --- src/main/java/me/moros/hyperion/Hyperion.java | 8 +- .../hyperion/commands/HyperionCommand.java | 3 +- .../me/moros/hyperion/util/ThreadUtil.java | 396 ++++++++++++++---- 3 files changed, 323 insertions(+), 84 deletions(-) diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 6664440..e597e50 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -20,6 +20,7 @@ package me.moros.hyperion; +import com.cjcrafter.foliascheduler.AsyncSchedulerImplementation; import com.cjcrafter.foliascheduler.FoliaCompatibility; import com.cjcrafter.foliascheduler.ServerImplementation; import com.cjcrafter.foliascheduler.TaskImplementation; @@ -49,7 +50,7 @@ public class Hyperion extends JavaPlugin { public static Hyperion plugin; private static String author; private static String version; - private static Logger log; + public static Logger log; private static PersistentDataLayer layer; public static boolean isFolia; public static boolean paper; @@ -115,6 +116,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new AbilityListener(), this); getServer().getPluginManager().registerEvents(new CoreListener(), this); getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); + ThreadUtil.runGlobalLater(Hyperion::ThreadUtil_test, 0L); // Use appropriate scheduler depending on platform if (isFolia || luminol) { @@ -259,4 +261,8 @@ public static ServerImplementation getScheduler() { public static UpdateChecker getUpdateChecker() { return getPlugin(Hyperion.class).updateChecker; } + + public static void ThreadUtil_test() { + Bukkit.getLogger().info("ThreadUtil works"); + } } diff --git a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java index 5bf7920..82e05f5 100755 --- a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java +++ b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java @@ -22,6 +22,7 @@ import com.projectkorra.projectkorra.command.PKCommand; import me.moros.hyperion.Hyperion; import me.moros.hyperion.configuration.ConfigManager; +import me.moros.hyperion.util.HexColor; import me.moros.hyperion.util.UpdateChecker; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -76,7 +77,7 @@ else if (sub.equals("checkupdate") && hasPermission(sender, "checkupdate")) { String current = checker.getCurrentVersion() != null ? checker.getCurrentVersion() : "unknown"; String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; - sender.sendMessage(ChatColor.GREEN + "[Hyperion] A new version is available!"); + sender.sendMessage(HexColor.ORANGE + "[Hyperion] " + "A new version is available!"); sender.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); sender.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); sender.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); diff --git a/src/main/java/me/moros/hyperion/util/ThreadUtil.java b/src/main/java/me/moros/hyperion/util/ThreadUtil.java index f7c385f..09eef30 100644 --- a/src/main/java/me/moros/hyperion/util/ThreadUtil.java +++ b/src/main/java/me/moros/hyperion/util/ThreadUtil.java @@ -1,137 +1,369 @@ package me.moros.hyperion.util; -import com.cjcrafter.foliascheduler.ServerImplementation; + + +import com.cjcrafter.foliascheduler.TaskImplementation; +import com.cjcrafter.foliascheduler.folia.FoliaTask; import me.moros.hyperion.Hyperion; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitTask; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.logging.Level; + +import static me.moros.hyperion.Hyperion.scheduler; +/** + * Utility class for ensuring that a task is run on the correct thread. + * Ensures compatibility between Folia and non-Folia servers. */ public class ThreadUtil { - private static final Plugin PLUGIN = Hyperion.plugin; - private static final boolean THREAD_UTIL_AVAILABLE; - private static final Class THREAD_UTIL_CLASS; - private static final ServerImplementation SCHEDULER = Hyperion.scheduler; + private static AtomicBoolean SHUTTING_DOWN = new AtomicBoolean(false); - static { - Class threadUtilClass = null; - try { - threadUtilClass = Class.forName("com.projectkorra.projectkorra.util.ThreadUtil"); - } catch (ClassNotFoundException ignored) {} - THREAD_UTIL_CLASS = threadUtilClass; - THREAD_UTIL_AVAILABLE = THREAD_UTIL_CLASS != null; - } + /** + * Runs a task on the same thread as an entity. On Spigot, this is the main + * thread. On Folia, this is the thread that the entity is on.

+ * + * @param entity The entity to run the task on. + * @param runnable The task to run. + */ + public static void ensureEntity(@NotNull Entity entity, @NotNull Runnable runnable) { + if (entity instanceof Player && !((Player)entity).isOnline()) return; - public static void ensureLocation(Location location, Runnable runnable) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - if (Hyperion.scheduler.isOwnedByCurrentRegion(location)) { - runnable.run(); + if (Hyperion.isFolia()) { + if (scheduler.isOwnedByCurrentRegion(entity) || SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in ensureEntity task on shutdown"); return; } - SCHEDULER.region(location).run(task -> { - runnable.run(); - return null; - }); + scheduler.entity(entity).execute(runnable, null, 1L); } else { if (Bukkit.isPrimaryThread()) { - runnable.run(); - } else { - Bukkit.getScheduler().runTask(PLUGIN, runnable); + runCatch(runnable, "Error in ensureEntity task"); + return; } + Bukkit.getScheduler().runTask(Hyperion.plugin, runnable); + } + } + + /** + * Runs a task on the same thread as an entity after a delay. On Spigot, this is the main + * thread. On Folia, this is the thread that the entity is on. + * @param entity The entity to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static Object ensureEntityLater(@NotNull Entity entity, @NotNull Runnable runnable, long delay) { + if (entity instanceof Player && !((Player)entity).isOnline()) return null; + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.entity(entity).execute(runnable, null, delay); + } else { + return Bukkit.getScheduler().runTaskLater(Hyperion.plugin, runnable, delay); } } - public static void runGlobalLater(Runnable runnable, long delayTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - SCHEDULER.global().runDelayed(task -> { - runnable.run(); - return null; - }, delayTicks); + /** + * Runs a task on the same thread as an entity after a delay and repeats it until cancelled. + * On Spigot, this is the main thread. On Folia, this is the thread that the entity is on. + * @param entity The entity to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static Object ensureEntityTimer(@NotNull Entity entity, @NotNull Runnable runnable, long delay, long repeat) { + if (entity instanceof Player && !((Player)entity).isOnline()) return null; + delay = Math.max(1, delay); + repeat = Math.max(1, repeat); + if (Hyperion.isFolia()) { + return scheduler.entity(entity).runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in ensureEntityTimer task")) { + task.cancel(); + } + }, null, delay, repeat); } else { - Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); + return Bukkit.getScheduler().runTaskTimer(Hyperion.plugin, runnable, delay, repeat); } } - public static void runLocationLater(Location location, Runnable runnable, long delayTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - if (location != null && location.getWorld() != null) { - SCHEDULER.region(location).runDelayed(task -> { - runnable.run(); - return null; - }, delayTicks); - } else { - Bukkit.getLogger().warning("[Hyperion] Cannot schedule region task: location or world is null. Falling back to global scheduler."); - SCHEDULER.global().runDelayed(task -> { - runnable.run(); - return null; - }, delayTicks); + /** + * Runs a task on the same thread as a location. On Spigot, this is the main + * thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + */ + public static void ensureLocation(@NotNull Location location, @NotNull Runnable runnable) { + if (Hyperion.isFolia()) { + if (scheduler.isOwnedByCurrentRegion(location) || SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in ensureLocation task on shutdown"); + return; } + + scheduler.region(location).execute(runnable); } else { - Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); + if (Bukkit.isPrimaryThread()) { + runCatch(runnable, "Error in ensureLocation task on shutdown"); + return; + } + Bukkit.getScheduler().runTask(Hyperion.plugin, runnable); } } - public static void runEntityLater(Location loc, Runnable runnable, long delayTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - SCHEDULER.region(loc).runDelayed(task -> { - runnable.run(); - return null; - }, delayTicks); + /** + * Runs a task on the same thread as a location after a delay. On Spigot, this is the main + * thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object ensureLocationLater(@NotNull Location location, @NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.region(location).runDelayed((task) -> { + if (!runCatch(runnable, "Error in ensureLocationLater")) { + task.cancel(); + } + }, delay); } else { - Bukkit.getScheduler().runTaskLater(PLUGIN, runnable, delayTicks); + return Bukkit.getScheduler().runTaskLater(Hyperion.plugin, runnable, delay); } } - public static BukkitTask runGlobalTimer(Runnable runnable, long delayTicks, long periodTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - throw new UnsupportedOperationException("Global repeating tasks must be managed differently in Folia."); + /** + * Runs a task on the same thread as a location after a delay and repeats it until cancelled. + * On Spigot, this is the main thread. On Folia, this is the thread that the location is in. + * @param location The location to run the task on. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object ensureLocationTimer(@NotNull Location location, @NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + repeat = Math.max(1, repeat); + if (Hyperion.isFolia()) { + + return scheduler.region(location).runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in ensureLocationTimer task")) + task.cancel(); + }, delay, repeat); + } else { + return Bukkit.getScheduler().runTaskTimer(Hyperion.plugin, runnable, delay, repeat); } - return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } - public static BukkitTask runLocationTimer(Location location, Runnable runnable, long delayTicks, long periodTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - throw new UnsupportedOperationException("Region-based repeating tasks must use Folia task management."); + /** + * Runs a task asynchronously. + * @param runnable The task to run. + */ + public static void runAsync(@NotNull Runnable runnable) { + if (Hyperion.isFolia()) { + if (SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in runAsync task on shutdown"); + return; + } + + scheduler.async().runNow((task) -> { + if (!runCatch(runnable, "Error in runAsync task")) { + task.cancel(); + } + }); + } else { + Bukkit.getScheduler().runTaskAsynchronously(Hyperion.plugin, runnable); } - return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } - public static BukkitTask runEntityTimer(Entity entity, Runnable runnable, long delayTicks, long periodTicks) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - throw new UnsupportedOperationException("Entity-based repeating tasks must use Folia task management."); + /** + * Runs a task asynchronously after a delay. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runAsyncLater(@NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.async().runDelayed((task) -> { + if (!runCatch(runnable, "Error in runAsyncLater task")) { + task.cancel(); + } + }, delay * 50, TimeUnit.MILLISECONDS); + } else { + return Bukkit.getScheduler().runTaskLater(Hyperion.plugin, runnable, delay); } - return Bukkit.getScheduler().runTaskTimer(PLUGIN, runnable, delayTicks, periodTicks); } - public static void runAsync(Runnable runnable) { - Bukkit.getScheduler().runTaskAsynchronously(PLUGIN, runnable); + /** + * Runs a task asynchronously after a delay and repeats it until cancelled. + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runAsyncTimer(@NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.async().runAtFixedRate((Consumer>) (task) -> runnable.run(), delay * 50, repeat * 50, TimeUnit.MILLISECONDS); + } else { + return Bukkit.getScheduler().runTaskTimerAsynchronously(Hyperion.plugin, runnable, delay, repeat); + } } - public static BukkitTask runAsyncTimer(Runnable runnable, long delayTicks, long periodTicks) { - return Bukkit.getScheduler().runTaskTimerAsynchronously(PLUGIN, runnable, delayTicks, periodTicks); + /** + * Runs a task synchronously. On Spigot, this is on the main thread. On Folia, + * this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using {@link #ensureEntity(Entity, Runnable)} + * or {@link #ensureLocation(Location, Runnable)}. + * + * @param runnable The task to run. + */ + public static void runGlobal(@NotNull Runnable runnable) { + if (Hyperion.isFolia()) { + if (SHUTTING_DOWN.get()) { + runCatch(runnable, "Error in runGlobal task on shutdown"); + return; + } + scheduler.global().run((task) -> { + if (!runCatch(runnable, "Error in runGlobal task")) { + task.cancel(); + } + }); + } else { + Bukkit.getScheduler().runTask(Hyperion.plugin, runnable); + } } - public static void cancelTimerTask(Object task) { - if (task instanceof BukkitTask bukkitTask) { - bukkitTask.cancel(); + /** + * Runs a task synchronously after a delay. On Spigot, this is on the main thread. + * On Folia, this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using {@link #ensureEntityLater(Entity, Runnable, long)} + * or {@link #ensureLocationLater(Location, Runnable, long)}. + * + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runGlobalLater(@NotNull Runnable runnable, long delay) { + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.global().runDelayed((task) -> { + if (!runCatch(runnable, "Error in runGlobalLater task")) { + task.cancel(); + } + }, delay); + } else { + return Bukkit.getScheduler().runTaskLater(Hyperion.plugin, runnable, delay); } } - public static void ensureEntity(Entity entity, Runnable runnable) { - if (Hyperion.isFolia() || Hyperion.isLuminol()) { - if (entity.getLocation() == null) { - runnable.run(); - return; + /** + * Runs a task synchronously after a delay and repeats it until cancelled. + * On Spigot, this is on the main thread. On Folia, this is on the global region thread.

+ * + * Warning: This should only be used for tasks that affect the world itself! Such as + * modifying gamerules, the weather, world time, etc. It should not be used for tasks + * that modify entities or the world, as those should be run using + * {@link #ensureEntityTimer(Entity, Runnable, long, long)} + * or {@link #ensureLocationTimer(Location, Runnable, long, long)} + * + * @param runnable The task to run. + * @param delay The delay in ticks before running the task. + * @param repeat The delay in ticks between each repeat of the task. + * @return The task object that can be used to cancel the task. Is a + * {@link com.cjcrafter.foliascheduler.folia.FoliaTask} on Folia and a + * {@link org.bukkit.scheduler.BukkitTask} on Spigot. + */ + public static @NotNull Object runGlobalTimer(@NotNull Runnable runnable, long delay, long repeat) { + delay = Math.max(1, delay); + if (Hyperion.isFolia()) { + return scheduler.global().runAtFixedRate((task) -> { + if (!runCatch(runnable, "Error in runGlobalTimer task")) { + task.cancel(); + } + }, delay, repeat); + } else { + return Bukkit.getScheduler().runTaskTimer(Hyperion.plugin, runnable, delay, repeat); + } + } + + /** + * Cancels a task that was created with either timers or delayed tasks. + * @param task The task to cancel. This is the object returned from + * {@link #ensureLocationTimer(Location, Runnable, long, long)} or + * {@link #ensureEntityTimer(Entity, Runnable, long, long)}. + * @return True if the task was cancelled successfully, false otherwise. + */ + public static boolean cancelTask(Object task) { + if (task == null) return false; + if (Hyperion.isFolia()) { + if (task instanceof FoliaTask) { + ((FoliaTask) task).cancel(); + return true; + } + } else { + if (task instanceof org.bukkit.scheduler.BukkitTask) { + ((org.bukkit.scheduler.BukkitTask) task).cancel(); + return true; + } + } + return false; + } + + /** + * Checks if a task is cancelled. + * @return True if the task is cancelled, false otherwise. + */ + public static boolean isTaskCancelled(Object task) { + if (task == null) return true; + if (Hyperion.isFolia()) { + if (task instanceof FoliaTask) { + return ((FoliaTask) task).isCancelled(); } - ensureLocation(entity.getLocation(), runnable); } else { + if (task instanceof org.bukkit.scheduler.BukkitTask) { + return ((org.bukkit.scheduler.BukkitTask) task).isCancelled(); + } + } + return false; + } + + private static boolean runCatch(Runnable runnable, String error) { + try { runnable.run(); + return true; + } catch (Exception e) { + Hyperion.log.log(Level.WARNING, error, e); + return false; } } - public static boolean isThreadUtilAvailable() { - return THREAD_UTIL_AVAILABLE; + public static void shutdown() { + SHUTTING_DOWN.set(true); } -} +} \ No newline at end of file From 08e7589222e532860b9d07fac745dbd549758b5c Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Tue, 25 Nov 2025 15:20:14 -0800 Subject: [PATCH 24/34] Use PaperLib for abilities that teleport entities. --- build.gradle.kts | 5 +- src/main/java/me/moros/hyperion/Elements.java | 2 +- src/main/java/me/moros/hyperion/Hyperion.java | 14 +- .../abilities/Elements/FireAbility.java | 3 +- .../Elements/RainbowFireAbility.java | 21 ++- .../abilities/earthbending/EarthGlove.java | 5 +- .../abilities/earthbending/MetalCable.java | 3 +- .../abilities/firebending/RainbowWave.java | 9 +- .../hyperion/commands/HyperionCommand.java | 2 +- .../hyperion/listeners/AbilityListener.java | 6 +- .../hyperion/util/BendingFallingBlock.java | 10 +- .../java/me/moros/hyperion/util/PaperLib.java | 4 +- .../util/PotionEffectAdapter_1_20_5.java | 14 +- .../hyperion/util/RainbowParticleEffect.java | 176 ++++++++++++------ .../moros/hyperion/util/TempArmorStand.java | 1 + .../me/moros/hyperion/util/UpdateChecker.java | 2 - 16 files changed, 182 insertions(+), 95 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e0b2cb1..030c5d9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.moros" -version = "1.7.5-PRE-RELEASE-2" +version = "1.7.5" java { toolchain { @@ -23,11 +23,12 @@ dependencies { // Provided by server compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") compileOnly("org.jetbrains:annotations:26.0.2") - compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") + compileOnly("com.projectkorra:projectkorra:1.12.0") // Included in plugin jar implementation("org.bstats:bstats-bukkit:3.1.0") implementation("com.cjcrafter:foliascheduler:0.7.2") + implementation("com.github.Hihelloy-main:JedCore:2.15.1-prerelease-3") } tasks { diff --git a/src/main/java/me/moros/hyperion/Elements.java b/src/main/java/me/moros/hyperion/Elements.java index 49fcab3..c59b43c 100644 --- a/src/main/java/me/moros/hyperion/Elements.java +++ b/src/main/java/me/moros/hyperion/Elements.java @@ -17,7 +17,7 @@ public Elements() { } static { - RAINBOWFIRE = new SubElement("RainbowFire", Element.FIRE, ElementType.BENDING, ProjectKorra.plugin){ + RAINBOWFIRE = new SubElement("RainbowFire", Element.FIRE, ElementType.BENDING, ProjectKorra.plugin) { @Override public ChatColor getColor() { return HexColor.ORANGE; diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index e597e50..4366291 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -25,7 +25,11 @@ import com.cjcrafter.foliascheduler.ServerImplementation; import com.cjcrafter.foliascheduler.TaskImplementation; import com.cjcrafter.foliascheduler.util.ReflectionUtil; +import com.jedk1.jedcore.JedCore; +import com.jedk1.jedcore.ability.waterbending.combo.WaterGimbal; import com.projectkorra.projectkorra.BendingPlayer; +import com.projectkorra.projectkorra.util.TempBlock; +import com.projectkorra.projectkorra.util.TempFallingBlock; import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.commands.HyperionCommand; import me.moros.hyperion.configuration.ConfigManager; @@ -37,8 +41,10 @@ import org.bstats.bukkit.Metrics;; import org.bukkit.Bukkit; import org.bukkit.block.Block; +import org.bukkit.entity.FallingBlock; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; import java.util.logging.Logger; @@ -101,6 +107,7 @@ public void onEnable() { new HyperionCommand(); new Elements(); updateChecker = new UpdateChecker(this, "Hihelloy-main/Hyperion"); + if (isFolia) { scheduler.global().execute(() -> updateChecker.checkForUpdate()); } else { @@ -174,6 +181,8 @@ public void run() { @Override public void onDisable() { + TempFallingBlock.removeAllFallingBlocks(); + TempBlock.removeAll(); BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); @@ -182,7 +191,7 @@ public void onDisable() { } if (isFolia || luminol) { - scheduler.async().cancelTasks(); + scheduler.global().cancelTasks(); } } @@ -259,10 +268,11 @@ public static ServerImplementation getScheduler() { } public static UpdateChecker getUpdateChecker() { - return getPlugin(Hyperion.class).updateChecker; + return updateChecker; } public static void ThreadUtil_test() { Bukkit.getLogger().info("ThreadUtil works"); } + } diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java index 8f53d8f..a366bc8 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java @@ -1,5 +1,6 @@ package me.moros.hyperion.abilities.Elements; +import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; @@ -196,7 +197,7 @@ public void emitFirebendingLight(Location location) { public void playFirebendingParticles(Location loc, int amount, double xOffset, double yOffset, double zOffset) { if (this.getBendingPlayer().canUseSubElement(Elements.RAINBOWFIRE)) { // Instantiate and start the swirling rainbow fire particles task - RainbowFireAbility.playRainbowFireParticles(loc, player); + RainbowFireAbility.playRainbowFireParticles(loc, amount, xOffset, yOffset, zOffset); } else if (this.getBendingPlayer().canUseSubElement(SubElement.BLUE_FIRE)) { ParticleEffect.SOUL_FIRE_FLAME.display(loc, amount, xOffset, yOffset, zOffset); } else { diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java index 42fe601..e5079e1 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/RainbowFireAbility.java @@ -16,13 +16,18 @@ public RainbowFireAbility(Player player) { super(player); } - public static void playRainbowFireParticles(Location loc, Player player) { - // You can make radius/height configurable in the future if needed - int amount = 100; // Number of particles to spawn - - if (loc != null && player != null && player.isOnline()) { - RainbowParticleEffect.spawnRainbowParticleEffect(loc, amount); - } + /** + * Always plays rainbow fire particles (no fallback). + * + * @param loc Location to play particles at + * @param amount Number of particles + * @param xOffset X offset for particle spread + * @param yOffset Y offset for particle spread + * @param zOffset Z offset for particle spread + */ + public static void playRainbowFireParticles(Location loc, int amount, double xOffset, double yOffset, double zOffset) { + + RainbowParticleEffect.spawnRainbowParticleEffect(loc, amount, xOffset, yOffset, zOffset); } @Override @@ -37,7 +42,7 @@ public Element getElement() { public static double getDamageFactor() { FileConfiguration config = Hyperion.getPlugin().getConfig(); - return config.getDouble("Properties.Fire.RainbowFire.DamageFactor", 1.0); // default fallback + return config.getDouble("Properties.Fire.RainbowFire.DamageFactor", 1.0); } public static double getCooldownFactor() { diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGlove.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGlove.java index c0d9421..58be6cc 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGlove.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGlove.java @@ -29,6 +29,7 @@ import com.projectkorra.projectkorra.util.ParticleEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; +import me.moros.hyperion.util.PaperLib; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.ArmorStand; @@ -114,7 +115,7 @@ public void progress() { return; } grabbedTarget.setVelocity(GeneralMethods.getDirection(grabbedTarget.getLocation(), returnLocation).normalize().multiply(GLOVE_GRABBED_SPEED)); - glove.teleport(grabbedTarget.getEyeLocation().subtract(0, grabbedTarget.getHeight() / 2, 0)); + PaperLib.teleportAsync(glove, grabbedTarget.getEyeLocation().subtract(0, grabbedTarget.getHeight() / 2, 0)); return; } else { setGloveVelocity(GeneralMethods.getDirection(glove.getLocation(), returnLocation).normalize().multiply(GLOVE_SPEED)); @@ -179,7 +180,7 @@ public void grabTarget(final LivingEntity entity) { returning = true; grabbed = true; grabbedTarget = entity; - glove.teleport(grabbedTarget.getEyeLocation().subtract(0, grabbedTarget.getHeight() / 2, 0)); + PaperLib.teleportAsync(glove, grabbedTarget.getEyeLocation().subtract(0, grabbedTarget.getHeight() / 2, 0)); } public void checkDamage() { diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/MetalCable.java b/src/main/java/me/moros/hyperion/abilities/earthbending/MetalCable.java index a62ec68..8cb7e0b 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/MetalCable.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/MetalCable.java @@ -32,6 +32,7 @@ import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; import me.moros.hyperion.util.MaterialCheck; +import me.moros.hyperion.util.PaperLib; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -123,7 +124,7 @@ public void progress() { Entity entityToMove = player; Location targetLocation = location; if (target.getType() == CableTarget.Type.ENTITY) { - cable.teleport(target.getEntity().getLocation()); + PaperLib.teleportAsync(cable, target.getEntity().getLocation()); if (player.isSneaking()) { entityToMove = target.getEntity(); Vector dir = player.getEyeLocation().getDirection().multiply(distance / 2); diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java index 99b7852..0cd3482 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/RainbowWave.java @@ -2,6 +2,7 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AddonAbility; +import com.projectkorra.projectkorra.attribute.Attribute; import com.projectkorra.projectkorra.util.DamageHandler; import me.moros.hyperion.Hyperion; import me.moros.hyperion.abilities.Elements.FireAbility; @@ -20,7 +21,7 @@ import static me.moros.hyperion.Elements.RAINBOWFIRE; import static me.moros.hyperion.abilities.Elements.RainbowFireAbility.playRainbowFireParticles; -public class RainbowWave extends RainbowFireAbility implements AddonAbility { +public class RainbowWave extends FireAbility implements AddonAbility { private static final String path = "Abilities.Fire.RainbowWave."; @@ -38,6 +39,7 @@ public class RainbowWave extends RainbowFireAbility implements AddonAbility { private Vector direction; private final Set hitEntities = new HashSet<>(); + public RainbowWave(Player player) { super(player); @@ -82,13 +84,16 @@ public void progress() { currentLocation.add(direction); currentLocation.add(0, fallSpeed, 0); - playRainbowFireParticles(currentLocation, player); + playFirebendingParticles(currentLocation, 10, hitRadius, hitRadius, hitRadius); List nearby = GeneralMethods.getEntitiesAroundPoint(currentLocation, hitRadius); for (Entity entity : nearby) { if (entity instanceof LivingEntity living && !entity.equals(player) && !hitEntities.contains(living)) { DamageHandler.damageEntity(living, damage, this); hitEntities.add(living); + Vector knockback = living.getLocation().toVector().subtract(player.getLocation().toVector()).normalize().multiply(0.5); + knockback.setY(0.2); + living.setVelocity(living.getVelocity().add(knockback)); } } diff --git a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java index 82e05f5..601d33d 100755 --- a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java +++ b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java @@ -68,7 +68,7 @@ else if (sub.equals("checkupdate") && hasPermission(sender, "checkupdate")) { return; } - if (!checker.hasChecked()) { + if (!checker.hasChecked()) { sender.sendMessage(ChatColor.GRAY + "Still checking for updates, please try again shortly."); return; } diff --git a/src/main/java/me/moros/hyperion/listeners/AbilityListener.java b/src/main/java/me/moros/hyperion/listeners/AbilityListener.java index 218bd7f..286737e 100755 --- a/src/main/java/me/moros/hyperion/listeners/AbilityListener.java +++ b/src/main/java/me/moros/hyperion/listeners/AbilityListener.java @@ -29,6 +29,7 @@ import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.event.PlayerSwingEvent; import me.moros.hyperion.Elements; import me.moros.hyperion.abilities.airbending.Evade; import me.moros.hyperion.abilities.chiblocking.Smokescreen; @@ -40,10 +41,7 @@ import me.moros.hyperion.abilities.earthbending.LavaDisk; import me.moros.hyperion.abilities.earthbending.MetalCable; import me.moros.hyperion.abilities.earthbending.passive.Locksmithing; -import me.moros.hyperion.abilities.firebending.Bolt; -import me.moros.hyperion.abilities.firebending.Combustion; -import me.moros.hyperion.abilities.firebending.FlameRush; -import me.moros.hyperion.abilities.firebending.RainbowWave; +import me.moros.hyperion.abilities.firebending.*; import me.moros.hyperion.abilities.waterbending.IceBreath; import me.moros.hyperion.abilities.waterbending.IceCrawl; import me.moros.hyperion.abilities.waterbending.combo.IceDrill; diff --git a/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java b/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java index 007e999..d6a3c66 100755 --- a/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java +++ b/src/main/java/me/moros/hyperion/util/BendingFallingBlock.java @@ -5,14 +5,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Firework; import org.bukkit.util.Vector; -import java.util.Comparator; -import java.util.Iterator; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -28,7 +24,7 @@ public BendingFallingBlock(Location location, BlockData data, Vector velocity, C } public BendingFallingBlock(Location location, BlockData data, Vector velocity, CoreAbility abilityInstance, boolean gravity, long delay) { - fallingBlock = location.getWorld().spawnFallingBlock(location, data); + fallingBlock = Objects.requireNonNull(location.getWorld()).spawnFallingBlock(location, data); fallingBlock.setVelocity(velocity); fallingBlock.setGravity(gravity); fallingBlock.setDropItem(false); diff --git a/src/main/java/me/moros/hyperion/util/PaperLib.java b/src/main/java/me/moros/hyperion/util/PaperLib.java index d98c1de..dd08236 100644 --- a/src/main/java/me/moros/hyperion/util/PaperLib.java +++ b/src/main/java/me/moros/hyperion/util/PaperLib.java @@ -32,8 +32,8 @@ public static CompletableFuture getChunkAtAsync(Block block) { return ENVIRONMENT.getChunkAtAsync(block); } - public static CompletableFuture teleportAsync(Entity entity, Location location) { - return ENVIRONMENT.teleportAsync(entity, location); + public static void teleportAsync(Entity entity, Location location) { + ENVIRONMENT.teleportAsync(entity, location); } public static CompletableFuture teleportAsync(Entity entity, Location location, TeleportCause cause) { diff --git a/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java index 2c165b0..4738fb0 100644 --- a/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java +++ b/src/main/java/me/moros/hyperion/util/PotionEffectAdapter_1_20_5.java @@ -9,6 +9,8 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; +import java.util.Objects; + public class PotionEffectAdapter_1_20_5 implements PotionEffectAdapter { @Override @@ -18,25 +20,25 @@ public PotionType getHarmingPotionType() { @Override public PotionEffect getSlownessEffect(int duration, int strength) { - return new PotionEffect(PotionEffectType.getByName("SLOWNESS"), duration / 50, strength - 1); + return new PotionEffect(Objects.requireNonNull(PotionEffectType.getByName("SLOWNESS")), duration / 50, strength - 1); } @Override public PotionEffect getResistanceEffect(int duration, int strength) { - return new PotionEffect(PotionEffectType.getByName("RESISTANCE"), duration / 50, strength - 1); + return new PotionEffect(Objects.requireNonNull(PotionEffectType.getByName("RESISTANCE")), duration / 50, strength - 1); } @Override public PotionEffect getNauseaEffect(int duration) { - return new PotionEffect(PotionEffectType.getByName("NAUSEA"), duration / 50, 1); + return new PotionEffect(Objects.requireNonNull(PotionEffectType.getByName("NAUSEA")), duration / 50, 1); } @Override public void applyJumpBoost(Player player, int duration, int strength) { - if (player.hasPotionEffect(PotionEffectType.getByName("JUMP_BOOST"))) { - player.removePotionEffect(PotionEffectType.getByName("JUMP_BOOST")); + if (player.hasPotionEffect(Objects.requireNonNull(PotionEffectType.getByName("JUMP_BOOST")))) { + player.removePotionEffect(Objects.requireNonNull(PotionEffectType.getByName("JUMP_BOOST"))); } - player.addPotionEffect(new PotionEffect(PotionEffectType.getByName("JUMP_BOOST"), duration / 50, strength - 1)); + player.addPotionEffect(new PotionEffect(Objects.requireNonNull(PotionEffectType.getByName("JUMP_BOOST")), duration / 50, strength - 1)); } @Override diff --git a/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java index d2fad6e..e07081e 100644 --- a/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java +++ b/src/main/java/me/moros/hyperion/util/RainbowParticleEffect.java @@ -5,74 +5,142 @@ import org.bukkit.Particle; import org.bukkit.Particle.DustOptions; import org.bukkit.World; +import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; -import java.util.Arrays; -import java.util.List; import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; public class RainbowParticleEffect { private static final Random random = new Random(); - // Red and blue handled with these flame particles - private static final List SPECIAL_PARTICLES = Arrays.asList( - Particle.FLAME, // Red - Particle.SOUL_FIRE_FLAME // Blue - ); - - // Rainbow colors except red and blue — all using REDSTONE with DustOptions - private static final List RAINBOW_COLORS = Arrays.asList( - Color.fromRGB(255, 165, 0), // Orange - Color.fromRGB(255, 255, 0), // Yellow - Color.fromRGB(0, 255, 0), // Green - Color.fromRGB(75, 0, 130), // Indigo - Color.fromRGB(138, 43, 226) // Violet - ); - - public static void spawnRainbowParticleEffect(Location center, int amount) { + /** + * Spawns a fixed number of rainbow particles gradually over time. + * + * @param center The center location + * @param amount Total number of particles to spawn + * @param xOffset Horizontal spread + * @param yOffset Vertical spread + * @param zOffset Depth spread + */ + public static void spawnRainbowParticleEffect(Location center, int amount, double xOffset, double yOffset, double zOffset) { World world = center.getWorld(); if (world == null) return; - for (int i = 0; i < amount; i++) { + AtomicInteger spawned = new AtomicInteger(0); + AtomicReference hue = new AtomicReference<>(0f); - Particle particle; - Object data = null; + Runnable task = () -> { + if (!center.isWorldLoaded()) { + ThreadUtil.cancelTask(center); + return; + } + + int remaining = amount - spawned.get(); + if (remaining <= 0) { + ThreadUtil.cancelTask(center); + return; + } + + int particlesThisTick = Math.min(5, remaining); // spawn up to 5 per tick + for (int i = 0; i < particlesThisTick; i++) { + spawnSingleRainbowParticle(world, center, hue.get(), xOffset, yOffset, zOffset); + spawned.incrementAndGet(); + } + + float newHue = hue.get() + 3f; + if (newHue >= 360f) newHue -= 360f; + hue.set(newHue); + }; + + ThreadUtil.ensureLocationTimer(center, task, 1L, 1L); + } + + /** + * Animated rainbow effect — spawns exactly `amount` particles total over time, or until duration is reached. + * + * @param center Center location + * @param amount Total number of particles to spawn + * @param plugin Your plugin instance (for scheduler) + * @param duration Maximum duration in ticks + */ + public static void spawnAnimatedRainbow(Location center, int amount, Plugin plugin, int duration) { + World world = center.getWorld(); + if (world == null) return; + + AtomicInteger ticks = new AtomicInteger(0); + AtomicInteger spawned = new AtomicInteger(0); + AtomicReference hue = new AtomicReference<>(0f); + + Runnable task = () -> { + if (ticks.incrementAndGet() >= duration || !center.isWorldLoaded()) { + ThreadUtil.cancelTask(center); + return; + } + + int remaining = amount - spawned.get(); + if (remaining <= 0) { + ThreadUtil.cancelTask(center); + return; + } - if (random.nextDouble() < 0.4) { - // 40% chance to use flame-style particles (red/blue) - particle = SPECIAL_PARTICLES.get(random.nextInt(SPECIAL_PARTICLES.size())); - } else { - // 60% chance to use REDSTONE color particles - particle = Particle.REDSTONE; - Color color = RAINBOW_COLORS.get(random.nextInt(RAINBOW_COLORS.size())); - data = new DustOptions(color, 1.5f); + int particlesThisTick = Math.min(5, remaining); // spawn up to 5 per tick + for (int i = 0; i < particlesThisTick; i++) { + spawnSingleRainbowParticle(world, center, hue.get(), 0.3, 0.4, 0.3); + spawned.incrementAndGet(); } - // Random offset around center - double offsetX = (random.nextDouble() - 0.5) * 2.0; - double offsetY = random.nextDouble() * 1.5; - double offsetZ = (random.nextDouble() - 0.5) * 2.0; - Location loc = center.clone().add(offsetX, offsetY, offsetZ); - - // Velocity vector (Spigot does not directly support velocity in spawnParticle) - Vector velocity = new Vector( - (random.nextDouble() - 0.5) * 0.2, - random.nextDouble() * 0.2, - (random.nextDouble() - 0.5) * 0.2 - ); - - // Spawn the particle - world.spawnParticle( - particle, - loc, - 0, // count (0 for manual velocity) - velocity.getX(), - velocity.getY(), - velocity.getZ(), - 0, // extra (speed) - data - ); - } + float newHue = hue.get() + 3f; + if (newHue >= 360f) newHue -= 360f; + hue.set(newHue); + }; + + ThreadUtil.ensureLocationTimer(center, task, 1L, 1L); + } + + /** + * Spawns a single rainbow particle (smooth hue-based). + */ + private static void spawnSingleRainbowParticle(World world, Location center, float baseHue, + double xOffset, double yOffset, double zOffset) { + Particle particle = Particle.REDSTONE; + + float hue = (baseHue + random.nextFloat() * 20f) % 360f; + Color color = hsvToColor(hue, 1f, 1f); + + float size = 1.2f + random.nextFloat() * 0.8f; + DustOptions data = new DustOptions(color, size); + + double offsetX = (random.nextDouble() - 0.5) * 2 * xOffset; + double offsetY = random.nextDouble() * yOffset; + double offsetZ = (random.nextDouble() - 0.5) * 2 * zOffset; + Location loc = center.clone().add(offsetX, offsetY, offsetZ); + + Vector velocity = new Vector( + (random.nextDouble() - 0.5) * 0.08, + random.nextDouble() * 0.12, + (random.nextDouble() - 0.5) * 0.08 + ); + + world.spawnParticle( + particle, + loc, + 0, + velocity.getX(), + velocity.getY(), + velocity.getZ(), + 0, + data + ); + } + + /** + * Converts HSV to Bukkit Color. + */ + private static Color hsvToColor(float hue, float saturation, float value) { + int rgb = java.awt.Color.HSBtoRGB(hue / 360f, saturation, value); + return Color.fromRGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF); } } diff --git a/src/main/java/me/moros/hyperion/util/TempArmorStand.java b/src/main/java/me/moros/hyperion/util/TempArmorStand.java index 2396b9f..5e0cc5e 100755 --- a/src/main/java/me/moros/hyperion/util/TempArmorStand.java +++ b/src/main/java/me/moros/hyperion/util/TempArmorStand.java @@ -3,6 +3,7 @@ import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; diff --git a/src/main/java/me/moros/hyperion/util/UpdateChecker.java b/src/main/java/me/moros/hyperion/util/UpdateChecker.java index 34472b8..2aa544a 100644 --- a/src/main/java/me/moros/hyperion/util/UpdateChecker.java +++ b/src/main/java/me/moros/hyperion/util/UpdateChecker.java @@ -13,7 +13,6 @@ public class UpdateChecker { private final JavaPlugin plugin; - private final BukkitScheduler scheduler; private final String apiUrl; private boolean updateAvailable = false; @@ -24,7 +23,6 @@ public class UpdateChecker { public UpdateChecker(JavaPlugin plugin, String repo) { this.plugin = plugin; - this.scheduler = plugin.getServer().getScheduler(); this.apiUrl = "https://api.github.com/repos/" + repo + "/releases/latest"; } From 8bcb203853917cefcb22173b20c1829b9390cd4b Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 2 Jan 2026 08:52:10 -0800 Subject: [PATCH 25/34] Finally use ThreadUtil for every scheduling task. Remove any deprecated ProjectKorra API. Use the Adventure API instead of the Bungee API. Bump Adventure --- build.gradle.kts | 8 +- src/main/java/me/moros/hyperion/Elements.java | 2 +- src/main/java/me/moros/hyperion/Hyperion.java | 106 +++++++----------- .../abilities/Elements/FireAbility.java | 7 +- .../abilities/earthbending/EarthGuard.java | 15 ++- .../earthbending/passive/Locksmithing.java | 34 ++---- .../hyperion/commands/HyperionCommand.java | 37 +++--- .../hyperion/configuration/ConfigManager.java | 1 + .../hyperion/listeners/CoreListener.java | 44 +++++--- .../listeners/PlayerJoinListener.java | 71 ++++++++++-- .../moros/hyperion/methods/CoreMethods.java | 8 ++ .../java/me/moros/hyperion/util/HexColor.java | 31 ++--- .../moros/hyperion/util/TempArmorStand.java | 2 +- .../me/moros/hyperion/util/UpdateChecker.java | 2 +- 14 files changed, 205 insertions(+), 163 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 030c5d9..0c89aa8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,18 +17,20 @@ repositories { maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://jitpack.io") maven("https://repo.papermc.io/repository/maven-public/") + mavenLocal() } dependencies { // Provided by server compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") compileOnly("org.jetbrains:annotations:26.0.2") - compileOnly("com.projectkorra:projectkorra:1.12.0") + compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") // Included in plugin jar implementation("org.bstats:bstats-bukkit:3.1.0") implementation("com.cjcrafter:foliascheduler:0.7.2") - implementation("com.github.Hihelloy-main:JedCore:2.15.1-prerelease-3") + implementation("net.kyori:adventure-api:4.26.1") + implementation("net.kyori:adventure-platform-bukkit:4.4.1") } tasks { @@ -41,6 +43,8 @@ tasks { // Relocate FoliaScheduler to avoid classpath issues relocate("com.cjcrafter.foliascheduler", "me.moros.hyperion.foliascheduler") + //relocate("io.papermc.paperlib", "me.moros.hyperion.paperlib") + } build { diff --git a/src/main/java/me/moros/hyperion/Elements.java b/src/main/java/me/moros/hyperion/Elements.java index c59b43c..d0b274f 100644 --- a/src/main/java/me/moros/hyperion/Elements.java +++ b/src/main/java/me/moros/hyperion/Elements.java @@ -20,7 +20,7 @@ public Elements() { RAINBOWFIRE = new SubElement("RainbowFire", Element.FIRE, ElementType.BENDING, ProjectKorra.plugin) { @Override public ChatColor getColor() { - return HexColor.ORANGE; + return ChatColor.of("#FF7F00"); } }; } diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 4366291..07cc7d9 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -20,13 +20,8 @@ package me.moros.hyperion; -import com.cjcrafter.foliascheduler.AsyncSchedulerImplementation; import com.cjcrafter.foliascheduler.FoliaCompatibility; import com.cjcrafter.foliascheduler.ServerImplementation; -import com.cjcrafter.foliascheduler.TaskImplementation; -import com.cjcrafter.foliascheduler.util.ReflectionUtil; -import com.jedk1.jedcore.JedCore; -import com.jedk1.jedcore.ability.waterbending.combo.WaterGimbal; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.util.TempBlock; import com.projectkorra.projectkorra.util.TempFallingBlock; @@ -38,6 +33,7 @@ import me.moros.hyperion.listeners.PlayerJoinListener; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.*; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bstats.bukkit.Metrics;; import org.bukkit.Bukkit; import org.bukkit.block.Block; @@ -65,6 +61,7 @@ public class Hyperion extends JavaPlugin { private PotionEffectAdapter potionEffectAdapter; public static ServerImplementation scheduler; private static UpdateChecker updateChecker; + private BukkitAudiences adventure; @Override @@ -74,6 +71,7 @@ public void onEnable() { log = getLogger(); version = getDescription().getVersion(); author = getDescription().getAuthors().get(0); + this.adventure = BukkitAudiences.create(this); try { Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); isFolia = true; @@ -108,11 +106,7 @@ public void onEnable() { new Elements(); updateChecker = new UpdateChecker(this, "Hihelloy-main/Hyperion"); - if (isFolia) { - scheduler.global().execute(() -> updateChecker.checkForUpdate()); - } else { - Bukkit.getScheduler().runTaskAsynchronously(this, () -> updateChecker.checkForUpdate()); - } + ThreadUtil.runAsync(() -> updateChecker.checkForUpdate()); getLogger().info("Initialized Hyperion Elements/Configs/Commands/Metrics/UpdateChecker"); getLogger().info("Attempting to load PaperLib"); new PaperLib(); @@ -123,51 +117,23 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new AbilityListener(), this); getServer().getPluginManager().registerEvents(new CoreListener(), this); getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); - ThreadUtil.runGlobalLater(Hyperion::ThreadUtil_test, 0L); - // Use appropriate scheduler depending on platform - if (isFolia || luminol) { - scheduler.global().runAtFixedRate(task -> { - manage(); - return null; - }, 1L, 5L); - - scheduler.global().runAtFixedRate(task -> { - TempArmorStand.manage(); - return null; - }, 1L, 1L); - - scheduler.global().runAtFixedRate(task -> { - BendingFallingBlock.manage(); - return null; - }, 1L, 5L); - - scheduler.global().runAtFixedRate(task -> { - FireAbility.getAbilities(); - return null; - }, 1L, 5L); - } else { - new BukkitRunnable() { - @Override - public void run() { - manage(); - } - }.runTaskTimer(this, 0L, 5L); - - new BukkitRunnable() { - @Override - public void run() { - TempArmorStand.manage(); - } - }.runTaskTimer(this, 0L, 1L); - - new BukkitRunnable() { - @Override - public void run() { - BendingFallingBlock.manage(); - } - }.runTaskTimer(this, 0L, 5L); - } + ThreadUtil.runGlobalTimer(() -> { + manage(); + }, 1L, 5L); + + ThreadUtil.runGlobalTimer(() -> { + TempArmorStand.manage(); + }, 1L, 1L); + + ThreadUtil.runGlobalTimer(() -> { + BendingFallingBlock.manage(); + }, 1L, 5L); + + ThreadUtil.runGlobalTimer(() -> { + FireAbility.getAbilities(); + }, 1L, 5L); + PotionEffectAdapterFactory potionEffectAdapterFactory = new PotionEffectAdapterFactory(); potionEffectAdapter = potionEffectAdapterFactory.getAdapter(); @@ -192,18 +158,14 @@ public void onDisable() { if (isFolia || luminol) { scheduler.global().cancelTasks(); + scheduler.async().cancelTasks(); + scheduler.cancelTasks(); } - } - public static void reload1() { - Hyperion.getPlugin().reloadConfig(); - ConfigManager.modifiersConfig.reloadConfig(); - BendingFallingBlock.removeAll(); - TempArmorStand.removeAll(); - CoreMethods.loadAbilities(); - new HyperionCommand(); - getLog().info("Trying to initialize commands once more"); - getLog().info("Hyperion BUKKIT Reloaded."); + if (this.adventure != null) { + this.adventure.close(); + this.adventure = null; + } } public static void reload() { @@ -212,9 +174,13 @@ public static void reload() { BendingFallingBlock.removeAll(); TempArmorStand.removeAll(); CoreMethods.loadAbilities(); - new HyperionCommand(); getLog().info("Trying to initialize commands once more"); - getLog().info("Hyperion FOLIA Reloaded."); + try { + new HyperionCommand(); + } catch (Exception e) { + e.printStackTrace(); + } + getLog().info("Hyperion Reloaded."); } public static void checkMaintainer() { @@ -271,8 +237,12 @@ public static UpdateChecker getUpdateChecker() { return updateChecker; } - public static void ThreadUtil_test() { - Bukkit.getLogger().info("ThreadUtil works"); + @NotNull + public BukkitAudiences adventure() { + if (this.adventure == null) { + throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!"); + } + return this.adventure; } } diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java index a366bc8..994e784 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java @@ -25,12 +25,7 @@ import me.moros.hyperion.Elements; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.Sound; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index 9ca4788..b3b6318 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -31,7 +31,9 @@ import com.projectkorra.projectkorra.util.TempPotionEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.BendingFallingBlock; -import org.bukkit.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Color; import org.bukkit.GameMode; import org.bukkit.Location; @@ -189,8 +191,10 @@ private void formArmor(Material material, Object entity) { if (generalMeta instanceof LeatherArmorMeta meta) { meta.setColor(color); } - generalMeta.setDisplayName(ChatColor.GREEN + "Earth Guard Armor"); - generalMeta.setLore(Collections.singletonList(ChatColor.DARK_GREEN + "Temporary")); + generalMeta.setDisplayName(toLegacy( + Component.text("Earth Guard Armor", NamedTextColor.GREEN) + )); + generalMeta.setLore(Collections.singletonList(toLegacy(Component.text("Temporary", NamedTextColor.DARK_GREEN)))); Hyperion.getLayer().addEarthGuardKey(generalMeta); item.setItemMeta(generalMeta); } @@ -343,4 +347,9 @@ public void remove() { @Override public void stop() { } + + public static String toLegacy(Component component) { + return LegacyComponentSerializer.legacySection().serialize(component); + } + } \ No newline at end of file diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java b/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java index 4866d14..8b8390a 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java @@ -1,22 +1,3 @@ -/* - * Copyright 2016-2024 Moros - * - * This file is part of Hyperion. - * - * Hyperion 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. - * - * Hyperion 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 Hyperion. If not, see . - */ - package me.moros.hyperion.abilities.earthbending.passive; import com.projectkorra.projectkorra.BendingPlayer; @@ -26,9 +7,11 @@ import com.projectkorra.projectkorra.ability.MetalAbility; import com.projectkorra.projectkorra.ability.PassiveAbility; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.ActionBar; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.MaterialCheck; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -99,12 +82,18 @@ public static void act(BendingPlayer bPlayer, Block block) { container.setLock(keyName); state.update(); block.getWorld().playSound(loc, Sound.BLOCK_CHEST_LOCKED, 1, 1); - ActionBar.sendActionBar(Element.METAL.getColor() + "Locked", player); + Hyperion.plugin.adventure().player(player).sendMessage( + Component.text("Locked", TextColor.color(Element.METAL.getColor().getColor().getRGB())) + .decorate(TextDecoration.BOLD) + ); } else if (player.isSneaking() && (player.hasPermission(OVERRIDE) || validKey(container, meta))) { container.setLock(null); state.update(); block.getWorld().playSound(loc, Sound.BLOCK_CHEST_LOCKED, 1, 2); - ActionBar.sendActionBar(Element.METAL.getColor() + "Unlocked", player); + Hyperion.plugin.adventure().player(player).sendMessage( + Component.text("Unlocked", TextColor.color(Element.METAL.getColor().getColor().getRGB())) + .decorate(TextDecoration.BOLD) + ); } } } @@ -125,7 +114,6 @@ private static boolean validKey(Lockable container, ItemMeta meta) { return container.getLock().equals(meta.getDisplayName()); } - @Override public boolean isInstantiable() { return false; diff --git a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java index 601d33d..71d53ca 100755 --- a/src/main/java/me/moros/hyperion/commands/HyperionCommand.java +++ b/src/main/java/me/moros/hyperion/commands/HyperionCommand.java @@ -23,17 +23,22 @@ import me.moros.hyperion.Hyperion; import me.moros.hyperion.configuration.ConfigManager; import me.moros.hyperion.util.HexColor; +import me.moros.hyperion.util.ThreadUtil; import me.moros.hyperion.util.UpdateChecker; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Entity; +import org.checkerframework.checker.units.qual.C; import org.jetbrains.annotations.NotNull; import java.util.List; -import static me.moros.hyperion.Hyperion.isFolia; -import static me.moros.hyperion.Hyperion.scheduler; + public class HyperionCommand extends PKCommand { public HyperionCommand() { @@ -44,19 +49,15 @@ public HyperionCommand() { public void execute(CommandSender sender, List args) { if (!hasPermission(sender) || !correctLength(sender, args.size(), 0, 1)) return; - if (args.size() == 0) { - sender.sendMessage(ChatColor.GREEN + "Hyperion Version: " + ChatColor.RED + Hyperion.getVersion()); - sender.sendMessage(ChatColor.GREEN + "Developed by: " + ChatColor.RED + Hyperion.getAuthor()); + if (args.isEmpty()) { + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Hyperion Version: ", HexColor.GREEN).append(Component.text(Hyperion.getVersion(), NamedTextColor.RED))); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Developed by: ", NamedTextColor.GREEN).append(Component.text(Hyperion.getAuthor(), NamedTextColor.RED))); } else if (args.size() == 1) { String sub = args.get(0).toLowerCase(); if (sub.equals("reload") && hasPermission(sender, "reload")) { - if (isFolia) { - scheduler.global().run(Hyperion::reload); - } else { - Bukkit.getScheduler().runTask(Hyperion.plugin, Hyperion::reload1); - } - sender.sendMessage(ChatColor.GREEN + "Hyperion config has been reloaded."); + ThreadUtil.runGlobal(Hyperion::reload); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Hyperion config has been reloaded.", NamedTextColor.GREEN)); } @@ -64,12 +65,12 @@ else if (sub.equals("checkupdate") && hasPermission(sender, "checkupdate")) { UpdateChecker checker = Hyperion.getUpdateChecker(); if (checker == null) { - sender.sendMessage(ChatColor.RED + "Update checker not initialized."); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Update checker not initialized.", NamedTextColor.RED)); return; } if (!checker.hasChecked()) { - sender.sendMessage(ChatColor.GRAY + "Still checking for updates, please try again shortly."); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Still checking for updates, please try again shortly.", NamedTextColor.GRAY)); return; } @@ -77,12 +78,12 @@ else if (sub.equals("checkupdate") && hasPermission(sender, "checkupdate")) { String current = checker.getCurrentVersion() != null ? checker.getCurrentVersion() : "unknown"; String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; - sender.sendMessage(HexColor.ORANGE + "[Hyperion] " + "A new version is available!"); - sender.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); - sender.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); - sender.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("[Hyperion] " + " A new version is available!", HexColor.ORANGE)); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("You're running: " + current, HexColor.RED)); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Latest version: ", NamedTextColor.GRAY).append(Component.text(latest, HexColor.GREEN))); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("Download: ", NamedTextColor.GRAY).decorate(TextDecoration.UNDERLINED).append(Component.text("https://github.com/Hihelloy-main/Hyperion", NamedTextColor.BLUE).decorate(TextDecoration.UNDERLINED).clickEvent(ClickEvent.openUrl("https://github.com/Hihelloy-main/Hyperion")))); } else { - sender.sendMessage(ChatColor.GREEN + "You're running the latest version of Hyperion."); + Hyperion.plugin.adventure().sender(sender).sendMessage(Component.text("You're running the latest version of Hyperion.", HexColor.GREEN)); } } } diff --git a/src/main/java/me/moros/hyperion/configuration/ConfigManager.java b/src/main/java/me/moros/hyperion/configuration/ConfigManager.java index 9b74534..630965f 100755 --- a/src/main/java/me/moros/hyperion/configuration/ConfigManager.java +++ b/src/main/java/me/moros/hyperion/configuration/ConfigManager.java @@ -19,6 +19,7 @@ package me.moros.hyperion.configuration; +import com.cjcrafter.foliascheduler.folia.FoliaTask; import me.moros.hyperion.Hyperion; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 982f6df..6be938b 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -19,9 +19,12 @@ package me.moros.hyperion.listeners; -import com.cjcrafter.foliascheduler.folia.FoliaTask; + import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.attribute.AttributeModification; +import com.projectkorra.projectkorra.attribute.AttributeModifier; +import com.projectkorra.projectkorra.event.AbilityRecalculateAttributeEvent; import com.projectkorra.projectkorra.event.AbilityStartEvent; import com.projectkorra.projectkorra.event.BendingReloadEvent; import me.moros.hyperion.Hyperion; @@ -34,6 +37,12 @@ import me.moros.hyperion.configuration.ConfigManager; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; +import me.moros.hyperion.util.ThreadUtil; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.*; @@ -205,19 +214,15 @@ public void onPlayerLogout(final PlayerQuitEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPKReload(final BendingReloadEvent event) { final CommandSender sender = event.getSender(); - if (!isFolia) { - Bukkit.getScheduler().runTaskLater(getPlugin(), Hyperion::reload1, 1); - sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Bukkit" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); - } - - if (isFolia || luminol) { - scheduler.global().runDelayed(task -> { - Hyperion.reload(); - return null; - }, 1L); - sender.sendMessage(ChatColor.GRAY + "[Hyperion]" + ChatColor.RED + ChatColor.ITALIC + " Folia" + ChatColor.RESET + ChatColor.RED + " Config reloaded"); - } - + ThreadUtil.runGlobalLater(Hyperion::reload, 1); + plugin.adventure().sender(sender).sendMessage( + Component.text("[Hyperion]", NamedTextColor.GRAY) + .append(Component.space()) + .append( + Component.text("Config reloaded", NamedTextColor.RED) + .decorate(TextDecoration.ITALIC) + ) + ); } @@ -236,6 +241,15 @@ public void onAbilityStart(final AbilityStartEvent event) { } } + @EventHandler(priority = EventPriority.LOW) + public void onAbilityRecalculateAttribute(AbilityRecalculateAttributeEvent event) { + if (CoreMethods.HassetAttributesbeencalled) { + NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); + event.addModification(AttributeModification.of(AttributeModifier.SET, CoreMethods.value1, key)); + log.info("Recalculated Ability Attribute"); + } + } + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { Player player = event.getPlayer(); @@ -245,7 +259,7 @@ public void onBlockBreak(BlockBreakEvent event) { if (name == null) { name = "Container"; } - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TranslatableComponent("container.isLocked", name)); + plugin.adventure().player(player).sendActionBar(Component.translatable("container.isLocked", Component.text(name))); Location loc = block.getLocation().add(0.5, 0.5, 0.5); block.getWorld().playSound(loc, Sound.BLOCK_CHEST_LOCKED, 1, 1); event.setCancelled(true); diff --git a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java index d4c622a..cac7ffb 100644 --- a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java +++ b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java @@ -1,14 +1,19 @@ package me.moros.hyperion.listeners; import me.moros.hyperion.Hyperion; -import me.moros.hyperion.util.HexColor; import me.moros.hyperion.util.UpdateChecker; -import org.bukkit.ChatColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; +import static me.moros.hyperion.Hyperion.plugin; + public class PlayerJoinListener implements Listener { @EventHandler @@ -19,29 +24,75 @@ public void onPlayerJoin(PlayerJoinEvent event) { UpdateChecker checker = Hyperion.getUpdateChecker(); if (checker == null) { - player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RED + "Update checker not initialized."); + plugin.adventure().player(player).sendMessage( + Component.text("[Hyperion] ", TextColor.color(0xFFA500)) + .append(Component.text("Update checker not initialized.", NamedTextColor.RED)) + ); return; } if (!checker.hasChecked()) { - player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.GRAY + "Checking for updates..."); + plugin.adventure().player(player).sendMessage( + Component.text("[Hyperion] ", TextColor.color(0xFFA500)) + .append( + Component.text("Checking for updates...", NamedTextColor.GRAY) + ) + ); return; } if (checker.isUpdateAvailable()) { String current = checker.getCurrentVersion() != null ? checker.getCurrentVersion() : "unknown"; String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; + var audience = Hyperion.plugin.adventure().player(player); + + audience.sendMessage( + Component.text("[Hyperion] ", TextColor.fromHexString("#FFA500")) + .append( + Component.text("A new version is available!", + TextColor.fromHexString("#FFFF00")) + .decorate(TextDecoration.UNDERLINED) + ) + ); + + audience.sendMessage( + Component.text("You're running: ", NamedTextColor.GRAY) + .append(Component.text(current, NamedTextColor.RED)) + ); - player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RESET + HexColor.YELLOW + ChatColor.UNDERLINE + "A new version is available!"); - player.sendMessage(ChatColor.GRAY + "You're running: " + ChatColor.RED + current); - player.sendMessage(ChatColor.GRAY + "Latest version: " + ChatColor.GREEN + latest); - player.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.UNDERLINE + ChatColor.BLUE + "https://github.com/Hihelloy-main/Hyperion"); + audience.sendMessage( + Component.text("Latest version: ", NamedTextColor.GRAY) + .append(Component.text(latest, NamedTextColor.GREEN)) + ); + + audience.sendMessage( + Component.text("Download: ", NamedTextColor.GRAY) + .append( + Component.text("https://github.com/Hihelloy-main/Hyperion", + NamedTextColor.BLUE) + .decorate(TextDecoration.UNDERLINED) + .clickEvent(ClickEvent.openUrl("https://github.com/Hihelloy-main/Hyperion")) + ) + ); } else { String latest = checker.getLatestVersion() != null ? checker.getLatestVersion() : "unknown"; + var audience = Hyperion.plugin.adventure().player(player); + + audience.sendMessage( + Component.text("[Hyperion] ", TextColor.fromHexString("#FFA500")) + .append( + Component.text( + "No updates available. You're on the latest version.", + NamedTextColor.GREEN + ) + ) + ); - player.sendMessage(HexColor.ORANGE + "[Hyperion] " + ChatColor.RESET + ChatColor.GREEN + "No updates available. You're on the latest version."); - player.sendMessage(ChatColor.GRAY + "Latest GitHub version: " + ChatColor.GREEN + latest); + audience.sendMessage( + Component.text("Latest GitHub version: ", NamedTextColor.GRAY) + .append(Component.text(latest, NamedTextColor.GREEN)) + ); } } diff --git a/src/main/java/me/moros/hyperion/methods/CoreMethods.java b/src/main/java/me/moros/hyperion/methods/CoreMethods.java index 4f21dbc..d733f38 100755 --- a/src/main/java/me/moros/hyperion/methods/CoreMethods.java +++ b/src/main/java/me/moros/hyperion/methods/CoreMethods.java @@ -69,6 +69,9 @@ public class CoreMethods { public static final String GLOVE_KEY = "BENDING_HYPERION_EARTH_GLOVE"; public static final String CABLE_KEY = "BENDING_HYPERION_METAL_CABLE_KEY"; public static final String SMOKESCREEN_KEY = "BENDING_HYPERION_SMOKESCREEN_KEY"; + public static Number value1; + public static String key1; + public static boolean HassetAttributesbeencalled; public static List getCirclePoints(Location location, int points, double size) { List locations = new ArrayList<>(); @@ -239,6 +242,7 @@ public static void setupCollisions() { public static void setAttributes(ConfigurationSection section, CoreAbility ability) { for (String key : section.getKeys(false)) { + HassetAttributesbeencalled = true; Number value; if (section.isInt(key)) { value = section.getInt(key); @@ -249,7 +253,11 @@ public static void setAttributes(ConfigurationSection section, CoreAbility abili } else { continue; } + value1 = value; + key1 = key; + // Deprecated - PK 1.12.0 ability.setAttribute(key, value); + ability.recalculateAttributes(); } } } diff --git a/src/main/java/me/moros/hyperion/util/HexColor.java b/src/main/java/me/moros/hyperion/util/HexColor.java index 428c991..1bf5df5 100644 --- a/src/main/java/me/moros/hyperion/util/HexColor.java +++ b/src/main/java/me/moros/hyperion/util/HexColor.java @@ -1,36 +1,36 @@ package me.moros.hyperion.util; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.TextColor; public class HexColor { /** - * Returns a ChatColor from a hex string like "#FF0000". + * Returns a TextColor from a hex string like "#FF0000". * * @param hex the hex color string - * @return ChatColor instance + * @return TextColor instance */ - public static ChatColor of(String hex) { + public static TextColor of(String hex) { if (hex == null || !hex.matches("^#([A-Fa-f0-9]{6})$")) { throw new IllegalArgumentException("Invalid hex color format: " + hex); } - return ChatColor.of(hex); + return TextColor.fromHexString(hex); } // Classic rainbow color constants - public static final ChatColor RED = of("#FF0000"); - public static final ChatColor ORANGE = of("#FF7F00"); - public static final ChatColor YELLOW = of("#FFFF00"); - public static final ChatColor GREEN = of("#00FF00"); - public static final ChatColor BLUE = of("#0000FF"); - public static final ChatColor INDIGO = of("#4B0082"); - public static final ChatColor VIOLET = of("#8F00FF"); + public static final TextColor RED = of("#FF0000"); + public static final TextColor ORANGE = of("#FF7F00"); + public static final TextColor YELLOW = of("#FFFF00"); + public static final TextColor GREEN = of("#00FF00"); + public static final TextColor BLUE = of("#0000FF"); + public static final TextColor INDIGO = of("#4B0082"); + public static final TextColor VIOLET = of("#8F00FF"); /** * Special rainbow color (can be used as a placeholder). - * Since ChatColor doesn't support multi-color, this is just a bright yellow to represent rainbow. + * Since TextColor doesn't support multi-color, this is just a bright yellow to represent rainbow. */ - public static final ChatColor RAINBOW = YELLOW; + public static final TextColor RAINBOW = YELLOW; /** * Builds a rainbow-colored string by coloring each character with a different rainbow hex. @@ -49,11 +49,12 @@ public static String rainbowify(String text) { "#8F00FF" // violet }; + StringBuilder result = new StringBuilder(); int colorIndex = 0; for (char c : text.toCharArray()) { - result.append(ChatColor.of(rainbow[colorIndex % rainbow.length])).append(c); + result.append(TextColor.fromHexString(rainbow[colorIndex % rainbow.length])).append(c); colorIndex++; } diff --git a/src/main/java/me/moros/hyperion/util/TempArmorStand.java b/src/main/java/me/moros/hyperion/util/TempArmorStand.java index 5e0cc5e..4defcc4 100755 --- a/src/main/java/me/moros/hyperion/util/TempArmorStand.java +++ b/src/main/java/me/moros/hyperion/util/TempArmorStand.java @@ -115,7 +115,7 @@ public static void manage() { continue; } - // ✅ USE ThreadUtil to handle Folia, Paper, and Bukkit cases + Location loc = tas.armorStand.getLocation(); ThreadUtil.ensureLocation(loc, tas::remove); } diff --git a/src/main/java/me/moros/hyperion/util/UpdateChecker.java b/src/main/java/me/moros/hyperion/util/UpdateChecker.java index 2aa544a..2c6412a 100644 --- a/src/main/java/me/moros/hyperion/util/UpdateChecker.java +++ b/src/main/java/me/moros/hyperion/util/UpdateChecker.java @@ -90,7 +90,7 @@ private int compareVersions(String v1, String v2) { return 0; } - // Naive JSON parser for one-level field (for simplicity, you might want to use a proper JSON lib) + private String parseJsonField(String json, String field) { String search = "\"" + field + "\":\""; int index = json.indexOf(search); From 51925984d3d20a68ac7ff01314619f4d78366900 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 2 Jan 2026 09:06:42 -0800 Subject: [PATCH 26/34] Remove "pl" variable in Evade.java because it is null --- .../java/me/moros/hyperion/abilities/airbending/Evade.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java index f10e76a..671ed67 100644 --- a/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java +++ b/src/main/java/me/moros/hyperion/abilities/airbending/Evade.java @@ -31,7 +31,6 @@ public class Evade extends AirAbility implements AddonAbility { private Vector direction; private long cooldown; - private Hyperion pl; private double angleStep; @@ -42,7 +41,7 @@ public Evade(Player player) { super(player); if (!player.isOnGround() || player.getEyeLocation().getBlock().isLiquid() || hasAbility(player, Evade.class) || !bPlayer.canBend(this)) { - pl.getServer().getLogger().info("Player Can't bend ability Evade because they are either not on the ground or they can't bend"); + Hyperion.plugin.getServer().getLogger().info("Player Can't bend ability Evade because they are either not on the ground or they can't bend"); return; } From a6c68f434822344da339df4f8eb6975a5d330540 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 2 Jan 2026 10:10:29 -0800 Subject: [PATCH 27/34] Make UpdateChecker.compareVersions more accurate. --- .../me/moros/hyperion/util/UpdateChecker.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/moros/hyperion/util/UpdateChecker.java b/src/main/java/me/moros/hyperion/util/UpdateChecker.java index 2c6412a..525dc5f 100644 --- a/src/main/java/me/moros/hyperion/util/UpdateChecker.java +++ b/src/main/java/me/moros/hyperion/util/UpdateChecker.java @@ -62,7 +62,6 @@ public void checkForUpdate() { } } - // Simple version comparison: returns <0 if v1 < v2, 0 if equal, >0 if v1 > v2 private int compareVersions(String v1, String v2) { String[] parts1 = v1.split("[.-]"); String[] parts2 = v2.split("[.-]"); @@ -73,18 +72,29 @@ private int compareVersions(String v1, String v2) { String p2 = i < parts2.length ? parts2[i] : "0"; int cmp; - // Try numeric comparison + try { + // Compare numeric parts int n1 = Integer.parseInt(p1); int n2 = Integer.parseInt(p2); cmp = Integer.compare(n1, n2); } catch (NumberFormatException e) { - cmp = p1.compareTo(p2); + // Handle pre-release comparison + boolean isPre1 = p1.toUpperCase().startsWith("PRE"); + boolean isPre2 = p2.toUpperCase().startsWith("PRE"); + + if (isPre1 && !isPre2) { + cmp = -1; // pre-release is older than stable + } else if (!isPre1 && isPre2) { + cmp = 1; // stable is newer than pre-release + } else if (isPre1 && isPre2) { + cmp = p1.compareTo(p2); // compare pre-releases lexically + } else { + cmp = p1.compareTo(p2); // fallback string compare + } } - if (cmp != 0) { - return cmp; - } + if (cmp != 0) return cmp; } return 0; From ae9a72685c6faf89fee1ee193a6590e6ad52c7bf Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 2 Jan 2026 10:23:33 -0800 Subject: [PATCH 28/34] Remove any BukkitScheduler calls I missed and replace with ThreadUtil --- .../moros/hyperion/abilities/firebending/FlameRush.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java index 37ec569..99c71a5 100644 --- a/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/FlameRush.java @@ -33,6 +33,7 @@ import me.moros.hyperion.abilities.Elements.FireAbility; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; +import me.moros.hyperion.util.ThreadUtil; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; @@ -292,12 +293,12 @@ public void handleCollision(Collision collision) { .distinct().toList(); smash.remove(); if (!smashBlocks.isEmpty()) { - ProjectKorra.plugin.getServer().getScheduler().runTaskLater(ProjectKorra.plugin, () -> { - for (Location loc : smashBlocks) { + for (Location loc : smashBlocks) { + ThreadUtil.ensureLocationLater(loc, () -> { Vector vel = CoreMethods.gaussianVector(0.2, 0.1, 0.2); new BendingFallingBlock(loc, Material.MAGMA_BLOCK.createBlockData(), vel, this, true, 5000); - } - }, 1); + }, 1); + } } } else { collision.setRemovingSecond(false); From ee5ad194ce657fe9d9161a81499d65e51b64be03 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Fri, 2 Jan 2026 10:35:52 -0800 Subject: [PATCH 29/34] Use PotionEffectAdapter for compatibility between versions. --- .../me/moros/hyperion/abilities/chiblocking/Smokescreen.java | 2 ++ .../me/moros/hyperion/abilities/earthbending/EarthGuard.java | 3 ++- .../me/moros/hyperion/abilities/waterbending/IceBreath.java | 2 +- .../me/moros/hyperion/abilities/waterbending/IceCrawl.java | 4 +--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/moros/hyperion/abilities/chiblocking/Smokescreen.java b/src/main/java/me/moros/hyperion/abilities/chiblocking/Smokescreen.java index 8aacfbc..cfbe928 100644 --- a/src/main/java/me/moros/hyperion/abilities/chiblocking/Smokescreen.java +++ b/src/main/java/me/moros/hyperion/abilities/chiblocking/Smokescreen.java @@ -24,6 +24,8 @@ import com.projectkorra.projectkorra.attribute.Attribute; import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; +import me.moros.hyperion.util.PotionEffectAdapter; +import me.moros.hyperion.util.PotionMetaUtil; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.entity.AreaEffectCloud; diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index b3b6318..a9a152b 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -31,6 +31,7 @@ import com.projectkorra.projectkorra.util.TempPotionEffect; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.BendingFallingBlock; +import me.moros.hyperion.util.PotionEffectAdapter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @@ -212,7 +213,7 @@ private void formArmor(Material material, Object entity) { originalMode = player.getGameMode(); player.getInventory().setArmorContents(newArmor.toArray(new ItemStack[4])); - new TempPotionEffect(player, new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, NumberConversions.round(duration / 50F), resistance)); + new TempPotionEffect(player, Hyperion.plugin.getPotionEffectAdapter().getResistanceEffect(NumberConversions.round(duration / 50F), resistance)); time = System.currentTimeMillis(); formed = true; } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java index 2462144..c9bb01b 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java @@ -203,7 +203,7 @@ private void checkArea(double radius) { final MovementHandler mh = new MovementHandler((LivingEntity) entity, CoreAbility.getAbility(IceCrawl.class)); mh.stopWithDuration(frostDuration / 50, Element.ICE.getColor() + "* Frozen *"); new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, frostDuration); - new TempPotionEffect((LivingEntity) entity, new PotionEffect(PotionEffectType.SLOW, (int) (frostDuration / 50), 3)); + new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect((int) (frostDuration / 50), 3)); } } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java index f53a79b..0583d21 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java @@ -212,9 +212,7 @@ private void checkDamage() { new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, duration); - new TempPotionEffect((LivingEntity) entity, - new PotionEffect(PotionEffectType.SLOW, - NumberConversions.round(duration / 50F), 5)); + new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect(NumberConversions.round(duration / 50F), 5)); } hit = true; From 546877e5f8c1786610525a402c5476d1a974a4f7 Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sat, 3 Jan 2026 08:29:03 -0800 Subject: [PATCH 30/34] Fix CoreMethods.setAttributes to work with ProjectKorra 1.12.0+ and 1.12.0-. Don't divide the duration of a potion effect by 50 as that is already done in the PotionEffectAdapter implmentations. --- src/main/java/me/moros/hyperion/Hyperion.java | 1 - .../me/moros/hyperion/abilities/earthbending/EarthGuard.java | 2 +- .../me/moros/hyperion/abilities/earthbending/EarthLine.java | 2 +- .../me/moros/hyperion/abilities/waterbending/IceBreath.java | 2 +- .../java/me/moros/hyperion/abilities/waterbending/IceCrawl.java | 2 +- src/main/java/me/moros/hyperion/listeners/CoreListener.java | 2 +- src/main/java/me/moros/hyperion/methods/CoreMethods.java | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index 07cc7d9..b27f9a0 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -39,7 +39,6 @@ import org.bukkit.block.Block; import org.bukkit.entity.FallingBlock; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java index a9a152b..fe7333b 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthGuard.java @@ -213,7 +213,7 @@ private void formArmor(Material material, Object entity) { originalMode = player.getGameMode(); player.getInventory().setArmorContents(newArmor.toArray(new ItemStack[4])); - new TempPotionEffect(player, Hyperion.plugin.getPotionEffectAdapter().getResistanceEffect(NumberConversions.round(duration / 50F), resistance)); + new TempPotionEffect(player, Hyperion.plugin.getPotionEffectAdapter().getResistanceEffect(NumberConversions.round(duration), resistance)); time = System.currentTimeMillis(); formed = true; } diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java index 14c2ce4..d471c9a 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java @@ -264,7 +264,7 @@ private void imprisonTarget() { new TempArmorStand(this, loc.add(0, -0.6, 0), material, prisonDuration, true); } final MovementHandler mh = new MovementHandler(target, CoreAbility.getAbility(EarthLine.class)); - mh.stopWithDuration(prisonDuration / 50, Element.EARTH.getColor() + "* Imprisoned *"); + mh.stopWithDuration(prisonDuration, Element.EARTH.getColor() + "* Imprisoned *"); remove(); } } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java index c9bb01b..81336ee 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceBreath.java @@ -203,7 +203,7 @@ private void checkArea(double radius) { final MovementHandler mh = new MovementHandler((LivingEntity) entity, CoreAbility.getAbility(IceCrawl.class)); mh.stopWithDuration(frostDuration / 50, Element.ICE.getColor() + "* Frozen *"); new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, frostDuration); - new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect((int) (frostDuration / 50), 3)); + new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect((int) (frostDuration), 3)); } } diff --git a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java index 0583d21..8bb50eb 100755 --- a/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java +++ b/src/main/java/me/moros/hyperion/abilities/waterbending/IceCrawl.java @@ -212,7 +212,7 @@ private void checkDamage() { new BendingFallingBlock(entity.getLocation().clone().add(0, -0.2, 0), Material.PACKED_ICE.createBlockData(), new Vector(), this, false, duration); - new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect(NumberConversions.round(duration / 50F), 5)); + new TempPotionEffect((LivingEntity) entity, Hyperion.plugin.getPotionEffectAdapter().getSlownessEffect(NumberConversions.round(duration), 5)); } hit = true; diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 6be938b..b480c21 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -241,7 +241,7 @@ public void onAbilityStart(final AbilityStartEvent event) { } } - @EventHandler(priority = EventPriority.LOW) + @EventHandler(priority = EventPriority.HIGHEST) public void onAbilityRecalculateAttribute(AbilityRecalculateAttributeEvent event) { if (CoreMethods.HassetAttributesbeencalled) { NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); diff --git a/src/main/java/me/moros/hyperion/methods/CoreMethods.java b/src/main/java/me/moros/hyperion/methods/CoreMethods.java index d733f38..c4cb3c0 100755 --- a/src/main/java/me/moros/hyperion/methods/CoreMethods.java +++ b/src/main/java/me/moros/hyperion/methods/CoreMethods.java @@ -242,7 +242,6 @@ public static void setupCollisions() { public static void setAttributes(ConfigurationSection section, CoreAbility ability) { for (String key : section.getKeys(false)) { - HassetAttributesbeencalled = true; Number value; if (section.isInt(key)) { value = section.getInt(key); @@ -253,6 +252,7 @@ public static void setAttributes(ConfigurationSection section, CoreAbility abili } else { continue; } + HassetAttributesbeencalled = true; value1 = value; key1 = key; // Deprecated - PK 1.12.0 From 8647a6b7c9b2e804708990c80dc3a4c8099ffcfa Mon Sep 17 00:00:00 2001 From: Hihelloy-main Date: Sat, 3 Jan 2026 08:31:03 -0800 Subject: [PATCH 31/34] Shade jetbrains annotations --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0c89aa8..1640c48 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,7 +23,6 @@ repositories { dependencies { // Provided by server compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") - compileOnly("org.jetbrains:annotations:26.0.2") compileOnly("com.projectkorra:projectkorra:1.12.1-PRE-RELEASE-1") // Included in plugin jar @@ -31,6 +30,7 @@ dependencies { implementation("com.cjcrafter:foliascheduler:0.7.2") implementation("net.kyori:adventure-api:4.26.1") implementation("net.kyori:adventure-platform-bukkit:4.4.1") + implementation("org.jetbrains:annotations:26.0.2") } tasks { From fb97e0650b989f46cc9862ee78edc8ecdc931ab5 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 3 Jan 2026 12:09:01 -0800 Subject: [PATCH 32/34] Fix event priority --- src/main/java/me/moros/hyperion/listeners/CoreListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index b480c21..6be938b 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -241,7 +241,7 @@ public void onAbilityStart(final AbilityStartEvent event) { } } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOW) public void onAbilityRecalculateAttribute(AbilityRecalculateAttributeEvent event) { if (CoreMethods.HassetAttributesbeencalled) { NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); From 6007a3bcf5bedb0508bdabf9b690c11a6f1a4a76 Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 3 Jan 2026 12:18:08 -0800 Subject: [PATCH 33/34] Fix Hyperion crashing moves when editing attributes --- .../java/me/moros/hyperion/listeners/CoreListener.java | 8 +++++--- src/main/java/me/moros/hyperion/methods/CoreMethods.java | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 6be938b..7e2c4f2 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -244,9 +244,11 @@ public void onAbilityStart(final AbilityStartEvent event) { @EventHandler(priority = EventPriority.LOW) public void onAbilityRecalculateAttribute(AbilityRecalculateAttributeEvent event) { if (CoreMethods.HassetAttributesbeencalled) { - NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); - event.addModification(AttributeModification.of(AttributeModifier.SET, CoreMethods.value1, key)); - log.info("Recalculated Ability Attribute"); + if ((CoreMethods.attributedabil.equals(event.getAbility()))) { + NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); + event.addModification(AttributeModification.of(AttributeModifier.SET, CoreMethods.value1, key)); + log.info("Recalculated Ability Attribute"); + } } } diff --git a/src/main/java/me/moros/hyperion/methods/CoreMethods.java b/src/main/java/me/moros/hyperion/methods/CoreMethods.java index c4cb3c0..3ed9c1d 100755 --- a/src/main/java/me/moros/hyperion/methods/CoreMethods.java +++ b/src/main/java/me/moros/hyperion/methods/CoreMethods.java @@ -72,6 +72,7 @@ public class CoreMethods { public static Number value1; public static String key1; public static boolean HassetAttributesbeencalled; + public static CoreAbility attributedabil; public static List getCirclePoints(Location location, int points, double size) { List locations = new ArrayList<>(); @@ -252,6 +253,7 @@ public static void setAttributes(ConfigurationSection section, CoreAbility abili } else { continue; } + attributedabil = ability; HassetAttributesbeencalled = true; value1 = value; key1 = key; From 7877f0e0bbbd1fed0aa99ad3ffb36ea1b176d30d Mon Sep 17 00:00:00 2001 From: Hihelloy Date: Sat, 10 Jan 2026 01:20:13 -0800 Subject: [PATCH 34/34] Adventure commit 2 --- src/main/java/me/moros/hyperion/Hyperion.java | 1 + .../me/moros/hyperion/abilities/Elements/FireAbility.java | 4 +++- .../me/moros/hyperion/abilities/earthbending/EarthLine.java | 5 +++-- .../abilities/earthbending/passive/Locksmithing.java | 3 ++- .../java/me/moros/hyperion/abilities/firebending/Bolt.java | 3 ++- .../me/moros/hyperion/abilities/firebending/Combustion.java | 5 +++-- src/main/java/me/moros/hyperion/listeners/CoreListener.java | 3 ++- .../java/me/moros/hyperion/listeners/PlayerJoinListener.java | 3 +++ 8 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/moros/hyperion/Hyperion.java b/src/main/java/me/moros/hyperion/Hyperion.java index b27f9a0..993405f 100755 --- a/src/main/java/me/moros/hyperion/Hyperion.java +++ b/src/main/java/me/moros/hyperion/Hyperion.java @@ -146,6 +146,7 @@ public void onEnable() { @Override public void onDisable() { + ThreadUtil.shutdown(); TempFallingBlock.removeAllFallingBlocks(); TempBlock.removeAll(); BendingFallingBlock.removeAll(); diff --git a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java index 994e784..c8cc5cc 100644 --- a/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java +++ b/src/main/java/me/moros/hyperion/abilities/Elements/FireAbility.java @@ -25,6 +25,8 @@ import me.moros.hyperion.Elements; +import me.moros.hyperion.Hyperion; +import net.kyori.adventure.key.Key; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -135,7 +137,7 @@ public static void dryWetBlocks(Block block, CoreAbility ability, boolean playSo if (block.getType() == Material.WET_SPONGE) { block.setType(Material.SPONGE); if (playSound) { - block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.5F, 1.0F); + plugin.adventure().world(Key.key(block.getWorld().getName())).playSound(net.kyori.adventure.sound.Sound.sound(Key.key("block.fire.extinguish"), net.kyori.adventure.sound.Sound.Source.PLAYER, 0.5F, 1.0F), block.getLocation().getX(), block.getLocation().getY(), block.getLocation().getZ()); } } else if (isSnow(block)) { block.getWorld().spawnParticle(Particle.BLOCK_DUST, block.getLocation().add(0.5F, 0.5F, 0.5F), 2, 0.5F, 0.5F, 0.5F, 0.1, Material.SNOW_BLOCK.createBlockData()); diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java index d471c9a..3c985ae 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/EarthLine.java @@ -30,7 +30,6 @@ import com.projectkorra.projectkorra.earthbending.passive.DensityShift; import com.projectkorra.projectkorra.firebending.util.FireDamageTimer; import com.projectkorra.projectkorra.region.RegionProtection; -import com.projectkorra.projectkorra.util.ActionBar; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.MovementHandler; import com.projectkorra.projectkorra.util.ParticleEffect; @@ -39,6 +38,8 @@ import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.BendingFallingBlock; import me.moros.hyperion.util.TempArmorStand; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; @@ -233,7 +234,7 @@ public void setPrisonMode() { if (mode != EarthLineMode.NORMAL) return; ticks = 0; mode = EarthLineMode.PRISON; - ActionBar.sendActionBar(getElement().getColor() + "* Prison Mode *", player); + Hyperion.plugin.adventure().player(player).sendActionBar(Component.text("* Prison Mode *", TextColor.color(getElement().getColor().getColor().getRGB()))); } private void imprisonTarget() { diff --git a/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java b/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java index 8b8390a..3aa8b9a 100755 --- a/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java +++ b/src/main/java/me/moros/hyperion/abilities/earthbending/passive/Locksmithing.java @@ -9,6 +9,7 @@ import com.projectkorra.projectkorra.region.RegionProtection; import me.moros.hyperion.Hyperion; import me.moros.hyperion.util.MaterialCheck; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -81,7 +82,7 @@ public static void act(BendingPlayer bPlayer, Block block) { String keyName = getOrCreateKey(key, meta); container.setLock(keyName); state.update(); - block.getWorld().playSound(loc, Sound.BLOCK_CHEST_LOCKED, 1, 1); + Hyperion.plugin.adventure().world(Key.key(block.getWorld().getName())).playSound(net.kyori.adventure.sound.Sound.sound(Key.key("block.chest.locked"), net.kyori.adventure.sound.Sound.Source.PLAYER, 1, 1), block.getX(), block.getY(), block.getZ()); Hyperion.plugin.adventure().player(player).sendMessage( Component.text("Locked", TextColor.color(Element.METAL.getColor().getColor().getRGB())) .decorate(TextDecoration.BOLD) diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/Bolt.java b/src/main/java/me/moros/hyperion/abilities/firebending/Bolt.java index fc41387..c04819e 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/Bolt.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/Bolt.java @@ -30,6 +30,7 @@ import me.moros.hyperion.Hyperion; import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.MaterialCheck; +import net.kyori.adventure.key.Key; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.ArmorStand; @@ -169,7 +170,7 @@ private void strike() { } location = targetLocation; player.getWorld().strikeLightningEffect(location); - player.getWorld().playSound(location, Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 5, 1.2F); + Hyperion.plugin.adventure().world(Key.key(player.getWorld().getName())).playSound(net.kyori.adventure.sound.Sound.sound(Key.key("entity.lightning_bolt.thunder"), net.kyori.adventure.sound.Sound.Source.PLAYER, 5, 1.2F), location.getX(), location.getY(), location.getZ()); bPlayer.addCooldown(this); if (!Bolt.isNearbyChannel(location, player)) { dealDamage(location); diff --git a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java index 386123d..9aa9c9f 100755 --- a/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java +++ b/src/main/java/me/moros/hyperion/abilities/firebending/Combustion.java @@ -34,6 +34,7 @@ import me.moros.hyperion.methods.CoreMethods; import me.moros.hyperion.util.FastMath; import me.moros.hyperion.util.MaterialCheck; +import net.kyori.adventure.key.Key; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; @@ -161,7 +162,7 @@ private void advanceLocation() { final Vector direction = player.getEyeLocation().getDirection(); ThreadLocalRandom rand = ThreadLocalRandom.current(); if (distanceTravelled >= randomBeamDistance) { - player.getWorld().playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1.5f, 0.01F); + Hyperion.plugin.adventure().player(player).playSound(net.kyori.adventure.sound.Sound.sound(Key.key("entity.firework_rocket.blast"), net.kyori.adventure.sound.Sound.Source.PLAYER, 1.5f, 0.01f), location.getX(), location.getY(), location.getZ()); randomBeamDistance = distanceTravelled + 7 + 3 * rand.nextGaussian(); double radius = rand.nextDouble(0.6, 1.6); for (int angle = 0; angle <= 360; angle += 12) { @@ -185,7 +186,7 @@ private void advanceLocation() { return; } if (rand.nextInt(3) == 0) { - location.getWorld().playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1, 0.01F); + Hyperion.plugin.adventure().world(Key.key(location.getWorld().getName())).playSound(net.kyori.adventure.sound.Sound.sound(Key.key("entity.firework_rocket.blast"), net.kyori.adventure.sound.Sound.Source.PLAYER, 1, 0.01F), location.getX(), location.getY(), location.getZ()); } if (location.getBlock().isLiquid() || !isTransparent(location.getBlock())) { createExplosion(location, power, damage); diff --git a/src/main/java/me/moros/hyperion/listeners/CoreListener.java b/src/main/java/me/moros/hyperion/listeners/CoreListener.java index 7e2c4f2..5e4086a 100755 --- a/src/main/java/me/moros/hyperion/listeners/CoreListener.java +++ b/src/main/java/me/moros/hyperion/listeners/CoreListener.java @@ -43,6 +43,7 @@ import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.title.Title; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.*; @@ -75,6 +76,7 @@ import static me.moros.hyperion.Hyperion.*; public class CoreListener implements Listener { + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void EntityChangeBlockEvent(final EntityChangeBlockEvent event) { if (event.getEntityType().equals(EntityType.FALLING_BLOCK)) { @@ -247,7 +249,6 @@ public void onAbilityRecalculateAttribute(AbilityRecalculateAttributeEvent event if ((CoreMethods.attributedabil.equals(event.getAbility()))) { NamespacedKey key = new NamespacedKey(Hyperion.getPlugin(), CoreMethods.key1); event.addModification(AttributeModification.of(AttributeModifier.SET, CoreMethods.value1, key)); - log.info("Recalculated Ability Attribute"); } } } diff --git a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java index cac7ffb..a63f510 100644 --- a/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java +++ b/src/main/java/me/moros/hyperion/listeners/PlayerJoinListener.java @@ -1,12 +1,15 @@ package me.moros.hyperion.listeners; import me.moros.hyperion.Hyperion; +import me.moros.hyperion.util.ThreadUtil; import me.moros.hyperion.util.UpdateChecker; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener;