summaryrefslogtreecommitdiffhomepage
path: root/patches/server/0674-More-Projectile-API.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0674-More-Projectile-API.patch')
-rw-r--r--patches/server/0674-More-Projectile-API.patch201
1 files changed, 195 insertions, 6 deletions
diff --git a/patches/server/0674-More-Projectile-API.patch b/patches/server/0674-More-Projectile-API.patch
index 97f7eb71ab..b526158a7f 100644
--- a/patches/server/0674-More-Projectile-API.patch
+++ b/patches/server/0674-More-Projectile-API.patch
@@ -20,9 +20,12 @@ public net.minecraft.world.entity.projectile.Projectile leftOwner
public net.minecraft.world.entity.projectile.Projectile preOnHit(Lnet/minecraft/world/phys/HitResult;)V
public net.minecraft.world.entity.projectile.Projectile canHitEntity(Lnet/minecraft/world/entity/Entity;)Z
public net.minecraft.world.entity.projectile.FireworkRocketEntity getDefaultItem()Lnet/minecraft/world/item/ItemStack;
+public net.minecraft.world.item.CrossbowItem FIREWORK_POWER
Co-authored-by: Nassim Jahnke <[email protected]>
Co-authored-by: SoSeDiK <[email protected]>
+Co-authored-by: MelnCat <[email protected]>
+Co-authored-by: Lulu13022002 <[email protected]>
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 5b7734020b496ade3740d92908ad2d399bfd55e6..e70ca1b2e6fbbc1f20e65429298d01b4ebd2dd29 100644
@@ -515,10 +518,27 @@ index 6e2f91423371ead9890095cf4b1e2299c4dcba28..9d8f4b7176e60180565e3134a14ecf19
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
-index 097f03c83a90f476b74834407d2dcd0e98fe010a..741cc56304005c48b26966f617d282bae7a87ee6 100644
+index 097f03c83a90f476b74834407d2dcd0e98fe010a..877e3d20edba3fe2ea6b51d0b54ec8893bd112ed 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
-@@ -596,7 +596,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+@@ -569,8 +569,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+ }
+
+ @Override
+- @SuppressWarnings("unchecked")
+ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) {
++ // Paper start - launchProjectile consumer
++ return this.launchProjectile(projectile, velocity, null);
++ }
++
++ @Override
++ @SuppressWarnings("unchecked")
++ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity, java.util.function.Consumer<? super T> function) {
++ // Paper end - launchProjectile consumer
+ Preconditions.checkState(!this.getHandle().generation, "Cannot launch projectile during world generation");
+
+ net.minecraft.world.level.Level world = ((CraftWorld) this.getWorld()).getHandle();
+@@ -596,7 +603,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
} else {
launch = new net.minecraft.world.entity.projectile.Arrow(world, this.getHandle(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null);
}
@@ -527,7 +547,7 @@ index 097f03c83a90f476b74834407d2dcd0e98fe010a..741cc56304005c48b26966f617d282ba
} else if (ThrownPotion.class.isAssignableFrom(projectile)) {
if (LingeringPotion.class.isAssignableFrom(projectile)) {
launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, this.getHandle());
-@@ -622,10 +622,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+@@ -622,10 +629,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
launch = new net.minecraft.world.entity.projectile.WitherSkull(world, this.getHandle(), vec);
} else if (DragonFireball.class.isAssignableFrom(projectile)) {
launch = new net.minecraft.world.entity.projectile.DragonFireball(world, this.getHandle(), vec);
@@ -548,15 +568,47 @@ index 097f03c83a90f476b74834407d2dcd0e98fe010a..741cc56304005c48b26966f617d282ba
} else {
launch = new LargeFireball(world, this.getHandle(), vec, 1);
}
-@@ -650,7 +656,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+@@ -650,8 +663,26 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
} else if (Firework.class.isAssignableFrom(projectile)) {
Location location = this.getEyeLocation();
- launch = new FireworkRocketEntity(world, net.minecraft.world.item.ItemStack.EMPTY, this.getHandle());
-+ launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle()); // Paper - pass correct default to rocket for data storage
- launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+- launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
++ // Paper start - see CrossbowItem
++ launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle(), location.getX(), location.getY() - 0.15F, location.getZ(), true); // Paper - pass correct default to rocket for data storage & see CrossbowItem for regular launch without elytra boost
++
++ // Lifted from net.minecraft.world.item.ProjectileWeaponItem.shoot
++ float f2 = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack
++ int projectileSize = 1;
++ int i = 0;
++
++ float f3 = projectileSize == 1 ? 0.0F : 2.0F * f2 / (float) (projectileSize - 1);
++ float f4 = (float) ((projectileSize - 1) % 2) * f3 / 2.0F;
++ float f5 = 1.0F;
++ float yaw = f4 + f5 * (float) ((i + 1) / 2) * f3;
++
++ // Lifted from net.minecraft.world.item.CrossbowItem.shootProjectile
++ Vec3 vec3 = this.getHandle().getUpVector(1.0F);
++ org.joml.Quaternionf quaternionf = new org.joml.Quaternionf().setAngleAxis((double)(yaw * (float) (Math.PI / 180.0)), vec3.x, vec3.y, vec3.z);
++ Vec3 vec32 = this.getHandle().getViewVector(1.0F);
++ org.joml.Vector3f vector3f = vec32.toVector3f().rotate(quaternionf);
++ ((FireworkRocketEntity) launch).shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F);
++ // Paper end
+ }
+
+ Preconditions.checkArgument(launch != null, "Projectile (%s) not supported", projectile.getName());
+@@ -659,6 +690,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
+ if (velocity != null) {
+ ((T) launch.getBukkitEntity()).setVelocity(velocity);
}
++ // Paper start - launchProjectile consumer
++ if (function != null) {
++ function.accept((T) launch.getBukkitEntity());
++ }
++ // Paper end - launchProjectile consumer
+ world.addFreshEntity(launch);
+ return (T) launch.getBukkitEntity();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java
index 70cbc6c668c60e9d608ca7013b72f9b916c05c2d..47633f05b4fab1dcabc2117e7645fe6d6949622a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java
@@ -812,3 +864,140 @@ index e8a455eb5e17bcfcae3f03664f2b47773fbdf37e..08178a88ba7d0881a6c2843eef24a846
return ((CraftItemType<?>) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item);
}
+diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
+index 8b57044518fbb0fd507da6ae3ff12b99eff70b37..e3312df146b942568ccee6595ae609c7d6a4f68f 100644
+--- a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
++++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
+@@ -56,90 +56,68 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
+
+ @Override
+ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) {
++ // Paper start - launchProjectile consumer
++ return this.launchProjectile(projectile, velocity, null);
++ }
++
++ @Override
++ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity, java.util.function.Consumer<? super T> function) {
++ // Paper end - launchProjectile consumer
+ Preconditions.checkArgument(this.getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser");
+- // Copied from BlockDispenser.dispense()
+- BlockSource sourceblock = new BlockSource((ServerLevel) this.dispenserBlock.getLevel(), this.dispenserBlock.getBlockPos(), this.dispenserBlock.getBlockState(), this.dispenserBlock);
+- // Copied from DispenseBehaviorProjectile
+- Position iposition = DispenserBlock.getDispensePosition(sourceblock);
+- Direction enumdirection = (Direction) sourceblock.state().getValue(DispenserBlock.FACING);
+- net.minecraft.world.level.Level world = this.dispenserBlock.getLevel();
+- net.minecraft.world.entity.Entity launch = null;
+
++ // Paper start - rewrite whole method to match ProjectileDispenseBehavior
++ net.minecraft.world.item.Item item = null;
+ if (Snowball.class.isAssignableFrom(projectile)) {
+- launch = new net.minecraft.world.entity.projectile.Snowball(world, iposition.x(), iposition.y(), iposition.z());
++ item = net.minecraft.world.item.Items.SNOWBALL;
+ } else if (Egg.class.isAssignableFrom(projectile)) {
+- launch = new ThrownEgg(world, iposition.x(), iposition.y(), iposition.z());
+- } else if (EnderPearl.class.isAssignableFrom(projectile)) {
+- launch = new ThrownEnderpearl(world, null);
+- launch.setPos(iposition.x(), iposition.y(), iposition.z());
++ item = net.minecraft.world.item.Items.EGG;
+ } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) {
+- launch = new ThrownExperienceBottle(world, iposition.x(), iposition.y(), iposition.z());
++ item = net.minecraft.world.item.Items.EXPERIENCE_BOTTLE;
+ } else if (ThrownPotion.class.isAssignableFrom(projectile)) {
+ if (LingeringPotion.class.isAssignableFrom(projectile)) {
+- launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, iposition.x(), iposition.y(), iposition.z());
+- ((net.minecraft.world.entity.projectile.ThrownPotion) launch).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1)));
++ item = net.minecraft.world.item.Items.LINGERING_POTION;
+ } else {
+- launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, iposition.x(), iposition.y(), iposition.z());
+- ((net.minecraft.world.entity.projectile.ThrownPotion) launch).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1)));
++ item = net.minecraft.world.item.Items.SPLASH_POTION;
+ }
+ } else if (AbstractArrow.class.isAssignableFrom(projectile)) {
+- if (TippedArrow.class.isAssignableFrom(projectile)) {
+- launch = new net.minecraft.world.entity.projectile.Arrow(world, iposition.x(), iposition.y(), iposition.z(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null);
+- ((Arrow) launch.getBukkitEntity()).setBasePotionType(PotionType.WATER);
+- } else if (SpectralArrow.class.isAssignableFrom(projectile)) {
+- launch = new net.minecraft.world.entity.projectile.SpectralArrow(world, iposition.x(), iposition.y(), iposition.z(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.SPECTRAL_ARROW), null);
++ if (SpectralArrow.class.isAssignableFrom(projectile)) {
++ item = net.minecraft.world.item.Items.SPECTRAL_ARROW;
+ } else {
+- launch = new net.minecraft.world.entity.projectile.Arrow(world, iposition.x(), iposition.y(), iposition.z(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null);
+- }
+- ((net.minecraft.world.entity.projectile.AbstractArrow) launch).pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.ALLOWED;
+- ((net.minecraft.world.entity.projectile.AbstractArrow) launch).projectileSource = this;
+- } else if (Fireball.class.isAssignableFrom(projectile)) {
+- double d0 = iposition.x() + (double) ((float) enumdirection.getStepX() * 0.3F);
+- double d1 = iposition.y() + (double) ((float) enumdirection.getStepY() * 0.3F);
+- double d2 = iposition.z() + (double) ((float) enumdirection.getStepZ() * 0.3F);
+- RandomSource random = world.random;
+- double d3 = random.nextGaussian() * 0.05D + (double) enumdirection.getStepX();
+- double d4 = random.nextGaussian() * 0.05D + (double) enumdirection.getStepY();
+- double d5 = random.nextGaussian() * 0.05D + (double) enumdirection.getStepZ();
+-
+- if (SmallFireball.class.isAssignableFrom(projectile)) {
+- launch = new net.minecraft.world.entity.projectile.SmallFireball(world, null, new Vec3(d0, d1, d2));
+- } else if (WitherSkull.class.isAssignableFrom(projectile)) {
+- launch = EntityType.WITHER_SKULL.create(world);
+- launch.setPos(d0, d1, d2);
+-
+- ((AbstractHurtingProjectile) launch).assignDirectionalMovement(new Vec3(d3, d4, d5), 0.1D);
+- } else {
+- launch = EntityType.FIREBALL.create(world);
+- launch.setPos(d0, d1, d2);
+-
+- ((AbstractHurtingProjectile) launch).assignDirectionalMovement(new Vec3(d3, d4, d5), 0.1D);
++ item = net.minecraft.world.item.Items.ARROW;
+ }
++ } else if (org.bukkit.entity.WindCharge.class.isAssignableFrom(projectile)) {
++ item = net.minecraft.world.item.Items.WIND_CHARGE;
++ } else if (org.bukkit.entity.Firework.class.isAssignableFrom(projectile)) {
++ item = net.minecraft.world.item.Items.FIREWORK_ROCKET;
++ } else if (SmallFireball.class.isAssignableFrom(projectile)) {
++ item = net.minecraft.world.item.Items.FIRE_CHARGE;
++ }
+
+- ((AbstractHurtingProjectile) launch).projectileSource = this;
++ if (!(item instanceof net.minecraft.world.item.ProjectileItem projectileItem)) {
++ throw new IllegalArgumentException("Projectile '%s' is not supported".formatted(projectile.getSimpleName()));
+ }
+
+- Preconditions.checkArgument(launch != null, "Projectile not supported");
++ net.minecraft.world.item.ProjectileItem.DispenseConfig config = projectileItem.createDispenseConfig();
++ net.minecraft.world.level.block.state.BlockState state = this.dispenserBlock.getBlockState();
++ net.minecraft.world.level.Level world = this.dispenserBlock.getLevel();
++ BlockSource pointer = new BlockSource((ServerLevel) world, this.dispenserBlock.getBlockPos(), state, this.dispenserBlock); // copied from DispenseBlock#dispenseFrom
++ Direction facing = state.getValue(DispenserBlock.FACING);
++ Position pos = config.positionFunction().getDispensePosition(pointer, facing);
+
+- if (launch instanceof net.minecraft.world.entity.projectile.Projectile) {
+- if (launch instanceof ThrowableProjectile) {
+- ((ThrowableProjectile) launch).projectileSource = this;
+- }
+- // Values from DispenseBehaviorProjectile
+- float a = 6.0F;
+- float b = 1.1F;
+- if (launch instanceof net.minecraft.world.entity.projectile.ThrownPotion || launch instanceof ThrownExpBottle) {
+- // Values from respective DispenseBehavior classes
+- a *= 0.5F;
+- b *= 1.25F;
+- }
+- // Copied from DispenseBehaviorProjectile
+- ((net.minecraft.world.entity.projectile.Projectile) launch).shoot((double) enumdirection.getStepX(), (double) ((float) enumdirection.getStepY() + 0.1F), (double) enumdirection.getStepZ(), b, a);
+- }
++ net.minecraft.world.entity.projectile.Projectile launch = projectileItem.asProjectile(world, pos, new net.minecraft.world.item.ItemStack(item), facing);
++ // some projectile are not shoot and doesn't rely on the config for power/uncertainty
++ projectileItem.shoot(launch, facing.getStepX(), facing.getStepY(), facing.getStepZ(), config.power(), config.uncertainty());
++ launch.projectileSource = this;
++ // Paper end
+
+ if (velocity != null) {
+ ((T) launch.getBukkitEntity()).setVelocity(velocity);
+ }
++ // Paper start
++ if (function != null) {
++ function.accept((T) launch.getBukkitEntity());
++ }
++ // Paper end
+
+ world.addFreshEntity(launch);
+ return (T) launch.getBukkitEntity();