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..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 @@ -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 cf7abd95b..a8a39911e 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 @@ -3368,11 +3368,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); } @@ -6669,7 +6681,7 @@ public class Reflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundCustomPayloadPacket) + ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) ); // 1.20.2+ @@ -6684,4 +6696,100 @@ public class Reflections { public static final Field field$PaperPluginClassLoader$libraryLoader = Optional.ofNullable(clazz$PaperPluginClassLoader) .map(it -> ReflectionUtils.getDeclaredField(it, URLClassLoader.class, 0)) .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 dc3c0846c..7886f0e0f 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) { @@ -231,6 +233,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