From 9cde66537c4ca3a5cf16ceb079d684cc1d98b7a0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 13 May 2025 19:25:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(config):=20=E5=88=AB=E6=A0=B7=E7=9A=84?= =?UTF-8?q?=E6=8A=95=E5=B0=84=E4=B8=89=E5=8F=89=E6=88=9F=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectile/BukkitProjectileManager.java | 52 +- .../entity/projectile/TridentRelease.java | 515 ++++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 114 +++- .../entity/projectile/ProjectileMeta.java | 2 +- .../craftengine/core/item/ItemSettings.java | 3 +- .../craftengine/core/util/MCUtils.java | 10 + gradle.properties | 2 +- 7 files changed, 688 insertions(+), 10 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java 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 164055f18..c82cc6c17 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.entity.projectile; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; +import io.papermc.paper.event.player.PlayerStopUsingItemEvent; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask; @@ -9,22 +11,22 @@ 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.CustomItem; 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.entity.Arrow; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.ThrowableProjectile; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.inventory.ItemStack; +import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -95,6 +97,48 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { }); } + @EventHandler + public void onPlayerInteract(PlayerItemConsumeEvent event) { + ItemStack item = event.getItem(); + String type = getType(item); + if (type == null) return; + if (type.equals("bow") || type.equals("spear")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onPlayerStopUsingItem(PlayerStopUsingItemEvent event) { + ItemStack item = event.getItem(); + String type = getType(item); + if (type == null) return; + int ticksHeldFor = event.getTicksHeldFor(); + Player player = event.getPlayer(); + if (type.equals("bow")) { + if (ticksHeldFor < 3) return; + // player.sendMessage("可以投出自定义弓: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); + } else if (type.equals("trident")) { + if (ticksHeldFor < 10) return; + // player.sendMessage("可以投出自定义三叉戟: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); + Object nmsItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(item); + Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); + Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player); + boolean success = TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); + player.sendMessage("释放成功: " + success); + } + } + + @Nullable + private String getType(ItemStack item) { + Item wrapped = BukkitItemManager.instance().wrap(item); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) return null; + CustomItem customItem = optionalCustomItem.get(); + ProjectileMeta meta = customItem.settings().projectileMeta(); + if (meta == null) return null; + return meta.type(); + } + public class ProjectileInjectTask implements Runnable { private final Projectile projectile; private final SchedulerTask task; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java new file mode 100644 index 000000000..549b3f8f8 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java @@ -0,0 +1,515 @@ +package net.momirealms.craftengine.bukkit.entity.projectile; + +import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; + +public class TridentRelease { + + private TridentRelease() {} + + public static boolean releaseUsing(Object stack, Object level, Object entity) { + if (VersionHelper.isOrAbove1_21_2()) { + return releaseUsing_1_21_2(stack, level, entity); + } else if (VersionHelper.isOrAbove1_21()) { + return releaseUsing_1_21(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20_5()) { + return releaseUsing_1_20_5(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20_3()) { + return releaseUsing_1_20_3(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20()) { + return releaseUsing_1_20(stack, level, entity); + } + return false; + } + + private static boolean releaseUsing_1_21_2(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + Object copyStack1 = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack1)) return false; + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack1, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack); + + if (spinStrength == 0.0F) { + Object projectile = FastNMS.INSTANCE.method$Projectile$ThrownTrident$spawnProjectileFromRotationDelayed( + level, + copyStack, + entity, + 0.0F, + 2.5F, + 1.0F + ); + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile)) + ); + + if (!event.callEvent() || !FastNMS.INSTANCE.method$Projectile$Delayed$attemptSpawn(projectile)) { + FastNMS.INSTANCE.method$AbstractContainerMenu$sendAllDataToRemote(FastNMS.INSTANCE.field$Player$containerMenu(entity)); + return false; + } + + Object trident = FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile); + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtWithoutBreaking(stack, 1, entity); + FastNMS.INSTANCE.method$ItemStack$consume(stack, 1, entity); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(trident, copyStack1); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(trident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + trident, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_21(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20_5(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20_3(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + (player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + (player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$ThrownTrident$tridentItem(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + 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 679a26279..345e6a05c 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 @@ -3367,11 +3367,23 @@ public class Reflections { ); public static final Object instance$SoundEvent$EMPTY; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_1; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_2; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_3; + public static final Object instance$SoundEvent$TRIDENT_THROW; static { try { - Object key = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "intentionally_empty"); - instance$SoundEvent$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, key); + Object intentionallyEmpty = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "intentionally_empty"); + instance$SoundEvent$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, intentionallyEmpty); + Object tridentRiptide1 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident_riptide_1"); + instance$SoundEvent$TRIDENT_RIPTIDE_1 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide1); + Object tridentRiptide2 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident_riptide_2"); + instance$SoundEvent$TRIDENT_RIPTIDE_2 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide2); + Object tridentRiptide3 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident.riptide_3"); + instance$SoundEvent$TRIDENT_RIPTIDE_3 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide3); + Object tridentThrow = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident.throw"); + instance$SoundEvent$TRIDENT_THROW = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentThrow); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6668,11 +6680,107 @@ public class Reflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundCustomPayloadPacket) + ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) ); // 1.20.2+ public static final Constructor constructor$DiscardedPayload = Optional.ofNullable(clazz$DiscardedPayload) .map(clazz -> ReflectionUtils.getTheOnlyConstructor(clazz)) .orElse(null); + + public static final Method method$SoundSource$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$SoundSource, clazz$SoundSource.arrayType() + ) + ); + + public static final Object instance$SoundSource$MASTER; + public static final Object instance$SoundSource$MUSIC; + public static final Object instance$SoundSource$RECORDS; + public static final Object instance$SoundSource$WEATHER; + public static final Object instance$SoundSource$BLOCKS; + public static final Object instance$SoundSource$HOSTILE; + public static final Object instance$SoundSource$NEUTRAL; + public static final Object instance$SoundSource$PLAYERS; + public static final Object instance$SoundSource$AMBIENT; + public static final Object instance$SoundSource$VOICE; + + static { + try { + Object[] values = (Object[]) method$SoundSource$values.invoke(null); + instance$SoundSource$MASTER = values[0]; + instance$SoundSource$MUSIC = values[1]; + instance$SoundSource$RECORDS = values[2]; + instance$SoundSource$WEATHER = values[3]; + instance$SoundSource$BLOCKS = values[4]; + instance$SoundSource$HOSTILE = values[5]; + instance$SoundSource$NEUTRAL = values[6]; + instance$SoundSource$PLAYERS = values[7]; + instance$SoundSource$AMBIENT = values[8]; + instance$SoundSource$VOICE = values[9]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + public static final Class clazz$MoverType = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.EnumMoveType", + "world.entity.MoverType" + ) + ); + + public static final Method method$MoverType$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$MoverType, clazz$MoverType.arrayType() + ) + ); + + public static final Object instance$MoverType$SELF; + public static final Object instance$MoverType$PLAYER; + public static final Object instance$MoverType$PISTON; + public static final Object instance$MoverType$SHULKER_BOX; + public static final Object instance$MoverType$SHULKER; + + static { + try { + Object[] values = (Object[]) method$MoverType$values.invoke(null); + instance$MoverType$SELF = values[0]; + instance$MoverType$PLAYER = values[1]; + instance$MoverType$PISTON = values[2]; + instance$MoverType$SHULKER_BOX = values[3]; + instance$MoverType$SHULKER = values[4]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + public static final Class clazz$AbstractArrow$Pickup = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.EntityArrow$PickupStatus", + "world.entity.projectile.AbstractArrow$Pickup" + ) + ); + + public static final Method method$AbstractArrow$Pickup$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$AbstractArrow$Pickup, clazz$AbstractArrow$Pickup.arrayType() + ) + ); + + public static final Object instance$AbstractArrow$Pickup$DISALLOWED; + public static final Object instance$AbstractArrow$Pickup$ALLOWED; + public static final Object instance$AbstractArrow$Pickup$CREATIVE_ONLY; + + static { + try { + Object[] values = (Object[]) method$AbstractArrow$Pickup$values.invoke(null); + instance$AbstractArrow$Pickup$DISALLOWED = values[0]; + instance$AbstractArrow$Pickup$ALLOWED = values[1]; + instance$AbstractArrow$Pickup$CREATIVE_ONLY = values[2]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java index a7fde9ad4..9f0337be0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java @@ -5,5 +5,5 @@ import net.momirealms.craftengine.core.util.Key; import org.joml.Quaternionf; import org.joml.Vector3f; -public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation) { +public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation, String type) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index bc8f9960f..c2f41b13c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -226,7 +226,8 @@ public class ItemSettings { Vector3f translation = MiscUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation"); Vector3f scale = MiscUtils.getAsVector3f(args.getOrDefault("scale", "1"), "scale"); Quaternionf rotation = MiscUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation-left", "rotation"), "rotation-left"); - return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation)); + String type = args.getOrDefault("type", "none").toString(); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation, type)); })); registerFactory("dyeable", (value -> { boolean bool = (boolean) value; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 869229f26..5ead78a3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -12,6 +12,8 @@ public class MCUtils { private MCUtils() {} + public static final float DEG_TO_RAD = ((float)Math.PI / 180F); + private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; private static final float[] SIN = make(new float[65536], (sineTable) -> { for(int i = 0; i < sineTable.length; ++i) { @@ -168,6 +170,14 @@ public class MCUtils { return SIN[(int) (value * 10430.378F) & '\uffff']; } + public static float cos(float value) { + return SIN[(int)(value * 10430.378F + 16384.0F) & '\uffff']; + } + + public static float sqrt(float value) { + return (float)Math.sqrt(value); + } + public static T findNextInIterable(Iterable iterable, @Nullable T object) { Iterator iterator = iterable.iterator(); T next = iterator.next(); diff --git a/gradle.properties b/gradle.properties index ec72047d6..31dd432b9 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.21 +nms_helper_version=0.65.23 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 5eb0b5c2851d385dbb01a87d9f0fd653e0813fcd Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 13 May 2025 19:30:46 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(bukkit):=20=E5=8E=BB=E6=8E=89=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E8=B0=83=E8=AF=95=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/entity/projectile/BukkitProjectileManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c82cc6c17..3d3ad8f87 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 @@ -124,7 +124,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player); boolean success = TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); - player.sendMessage("释放成功: " + success); + // player.sendMessage("释放成功: " + success); } }