diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 6e1d51452..e899169c2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -3,13 +3,17 @@ package net.momirealms.craftengine.bukkit.entity.projectile; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask; +import net.momirealms.craftengine.bukkit.util.ParticleUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; +import org.bukkit.Particle; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.Projectile; @@ -92,7 +96,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { if (!delay) { task.run(); } else if (VersionHelper.isFolia()) { - projectile.getScheduler().run(plugin.bootstrap(), (t) -> task.run(), () -> {}); + } else { plugin.scheduler().sync().runDelayed(task); } @@ -102,29 +106,52 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { public class ProjectileInjectTask implements Runnable { private final Projectile projectile; + private final SchedulerTask task; + private boolean injected; public ProjectileInjectTask(Projectile projectile) { this.projectile = projectile; + if (VersionHelper.isFolia()) { + this.task = new FoliaTask(projectile.getScheduler().runAtFixedRate(plugin.bootstrap(), (t) -> this.run(), () -> {}, 1, 1)); + } else { + this.task = plugin.scheduler().sync().runRepeating(this, 1, 1); + } } @Override public void run() { + if (!this.projectile.isValid()) { + this.task.cancel(); + return; + } Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile); - Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); - if (trackedEntity == null) { - plugin.logger().warn("Failed to update server entity tracking interval due to missing tracked entity"); - return; + if (!this.injected) { + Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); + if (trackedEntity == null) { + return; + } + Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); + if (serverEntity == null) { + return; + } + try { + Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1); + this.injected = true; + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to update server entity tracking interval", e); + } } - Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); - if (serverEntity == null) { - plugin.logger().warn("Failed to update server entity tracking interval due to missing server entity"); - return; + if (canSpawnParticle(nmsEntity)) { + this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0); } - try { - Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to update server entity tracking interval", e); + } + + private static boolean canSpawnParticle(Object nmsEntity) { + if (!FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) return false; + if (Reflections.clazz$AbstractArrow.isInstance(nmsEntity)) { + return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); } + return true; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 4e5515cd3..64f6096c4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6645,4 +6645,11 @@ public class Reflections { clazz$ServerEntity, int.class, 0 ) ); + + public static final Class clazz$AbstractArrow = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.EntityArrow", + "world.entity.projectile.AbstractArrow" + ) + ); } diff --git a/gradle.properties b/gradle.properties index 9acb04c0c..d4e994cdc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.17 +nms_helper_version=0.65.18 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23