diff --git a/divinemc-api/paper-patches/features/0004-Expanded-Adventure-support.patch b/divinemc-api/paper-patches/features/0004-Expanded-Adventure-support.patch new file mode 100644 index 0000000..bd8e7c9 --- /dev/null +++ b/divinemc-api/paper-patches/features/0004-Expanded-Adventure-support.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 3 Mar 2025 01:14:19 +0300 +Subject: [PATCH] Expanded Adventure support + + +diff --git a/src/main/java/org/bukkit/Color.java b/src/main/java/org/bukkit/Color.java +index f8edb964c4af597b03a2de06c464cc06a96b791c..596e2e09c6a64fa5861221789185d2fd7b004248 100644 +--- a/src/main/java/org/bukkit/Color.java ++++ b/src/main/java/org/bukkit/Color.java +@@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; + * but subject to change. + */ + @SerializableAs("Color") +-public final class Color implements ConfigurationSerializable { ++public final class Color implements ConfigurationSerializable, net.kyori.adventure.text.format.TextColor { // DivineMC - Expanded Adventure support + private static final int BIT_MASK = 0xff; + private static final int DEFAULT_ALPHA = 255; + +@@ -310,6 +310,13 @@ public final class Color implements ConfigurationSerializable { + return getAlpha() << 24 | getRed() << 16 | getGreen() << 8 | getBlue(); + } + ++ // DivineMC start - Expanded Adventure support ++ @Override ++ public int value() { ++ return asRGB(); ++ } ++ // DivineMC end - Expanded Adventure support ++ + /** + * Gets the color as an BGR integer. + * +diff --git a/src/main/java/org/bukkit/DyeColor.java b/src/main/java/org/bukkit/DyeColor.java +index 2f038f233afd4210687586800070d5f61e40562a..24068f23f45a0d3b837b04565d143a5cd8cd8869 100644 +--- a/src/main/java/org/bukkit/DyeColor.java ++++ b/src/main/java/org/bukkit/DyeColor.java +@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; + /** + * All supported color values for dyes and cloth + */ +-public enum DyeColor { ++public enum DyeColor implements net.kyori.adventure.util.RGBLike, net.kyori.adventure.text.format.StyleBuilderApplicable { // DivineMC - Expanded Adventure support + + /** + * Represents white dye. +@@ -135,6 +135,28 @@ public enum DyeColor { + return firework; + } + ++ // DivineMC start - Expanded Adventure support ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int red() { ++ return color.getRed(); ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int green() { ++ return color.getGreen(); ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int blue() { ++ return color.getBlue(); ++ } ++ ++ @Override ++ public void styleApply(net.kyori.adventure.text.format.Style.@org.jetbrains.annotations.NotNull Builder style) { ++ style.color(net.kyori.adventure.text.format.TextColor.color(color)); ++ } ++ // DivineMC end - Expanded Adventure support ++ + /** + * Gets the DyeColor with the given wool data value. + * diff --git a/divinemc-api/paper-patches/features/0005-Extend-Location-API.patch b/divinemc-api/paper-patches/features/0005-Extend-Location-API.patch new file mode 100644 index 0000000..ec77c57 --- /dev/null +++ b/divinemc-api/paper-patches/features/0005-Extend-Location-API.patch @@ -0,0 +1,181 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 3 Mar 2025 01:15:10 +0300 +Subject: [PATCH] Extend Location API + + +diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java +index 20e30fa5a33c68a4dec12e51a6b81f4afbda35b5..8b71277d3cab283eeab43df3e4dc4fb4fbad2388 100644 +--- a/src/main/java/org/bukkit/Location.java ++++ b/src/main/java/org/bukkit/Location.java +@@ -1253,4 +1253,170 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm + public @NotNull Location toLocation(@NotNull World world) { + return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch()); + } ++ ++ // DivineMC start - Extend Location API ++ /** ++ * Sets the x-coordinate of this location. ++ * ++ * @param x The x-coordinate ++ * @return this location ++ */ ++ public @NotNull Location x(double x) { ++ this.x = x; ++ return this; ++ } ++ ++ /** ++ * Sets the y-coordinate of this location. ++ * ++ * @param y The y-coordinate ++ * @return this location ++ */ ++ public @NotNull Location y(double y) { ++ this.y = y; ++ return this; ++ } ++ ++ /** ++ * Sets the z-coordinate of this location. ++ * ++ * @param z The z-coordinate ++ * @return this location ++ */ ++ public @NotNull Location z(double z) { ++ this.z = z; ++ return this; ++ } ++ ++ /** ++ * Sets the yaw of this location, measured in degrees. ++ * ++ * Increasing yaw values are the equivalent of turning to your ++ * right-facing, increasing the scale of the next respective axis, and ++ * decreasing the scale of the previous axis. ++ * ++ * @param yaw new rotation's yaw ++ * @return this location ++ */ ++ public @NotNull Location yaw(float yaw) { ++ this.yaw = yaw; ++ return this; ++ } ++ ++ /** ++ * Sets the pitch of this location, measured in degrees. ++ * ++ * Increasing pitch values the equivalent of looking down. ++ * ++ * @param pitch new incline's pitch ++ * @return this location ++ */ ++ public @NotNull Location pitch(float pitch) { ++ this.pitch = pitch; ++ return this; ++ } ++ ++ /** ++ * Sets the world that this location resides in ++ * ++ * @param world New world that this location resides in ++ * @return this location ++ */ ++ public @NotNull Location world(@Nullable World world) { ++ this.world = (world == null) ? null : new WeakReference<>(world); ++ return this; ++ } ++ ++ /** ++ * Increments the x-coordinate by the given value. ++ * ++ * @param x Amount to increment the x-coordinate by ++ * @return this location ++ */ ++ public @NotNull Location addX(double x) { ++ this.x += x; ++ return this; ++ } ++ ++ /** ++ * Increments the y-coordinate by the given value. ++ * ++ * @param y Amount to increment the y-coordinate by ++ * @return this location ++ */ ++ public @NotNull Location addY(double y) { ++ this.y += y; ++ return this; ++ } ++ ++ /** ++ * Increments the z-coordinate by the given value. ++ * ++ * @param z Amount to increment the z-coordinate by ++ * @return this location ++ */ ++ public @NotNull Location addZ(double z) { ++ this.z += z; ++ return this; ++ } ++ ++ /** ++ * Returns location with centered X, Y and Z values. ++ * ++ * @return this location ++ */ ++ public @NotNull Location center() { ++ return center(0.5); ++ } ++ ++ /** ++ * Returns location with centered X and Z values. ++ * Y will be set to provided. ++ * ++ * @param y Y adding value ++ * @return this location ++ */ ++ public @NotNull Location center(double y) { ++ return set(getBlockX() + 0.5, getBlockY() + y, getBlockZ() + 0.5); ++ } ++ ++ /** ++ * Checks if locations have the same X, Y and Z values. ++ * ++ * @param loc Location to check ++ * @return true if locations have same coordinates ++ * @apiNote Ignores world ++ */ ++ public boolean isSame(@NotNull Location loc) { ++ return getY() == loc.getY() && getX() == loc.getX() && getZ() == loc.getZ(); ++ } ++ ++ /** ++ * Shifts this location by one block up ++ * ++ * @return this location ++ */ ++ public @NotNull Location above() { ++ return addY(1); ++ } ++ ++ /** ++ * Shifts this location by one block down ++ * ++ * @return this location ++ */ ++ public @NotNull Location below() { ++ return addY(-1); ++ } ++ // DivineMC end - Extend Location API + } diff --git a/divinemc-api/paper-patches/features/0006-Extend-Sound-API.patch b/divinemc-api/paper-patches/features/0006-Extend-Sound-API.patch new file mode 100644 index 0000000..e367f42 --- /dev/null +++ b/divinemc-api/paper-patches/features/0006-Extend-Sound-API.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 3 Mar 2025 01:16:29 +0300 +Subject: [PATCH] Extend Sound API + + +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index b703ad820ff873097dadff9e55b53fcc6b1b8698..b35c3852a3b8e62c7d2f67fc3ff651c8e0a4d5f2 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -817,4 +817,29 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr + return this.getBlockData().getDestroySpeed(itemStack, considerEnchants); + } + // Paper end - destroy speed API ++ ++ // DivineMC start - Extend Sound API ++ /** ++ * Plays a sound at the location of the block ++ * ++ * @param sound sound to play ++ * @param volume volume of the sound ++ * @param pitch pitch of the sound ++ */ ++ default void emitSound(@NotNull org.bukkit.Sound sound, float volume, float pitch) { ++ emitSound(sound, org.bukkit.SoundCategory.BLOCKS, volume, pitch); ++ } ++ ++ /** ++ * Plays a sound at the location of the block ++ * ++ * @param sound sound to play ++ * @param category category of the sound ++ * @param volume volume of the sound ++ * @param pitch pitch of the sound ++ */ ++ default void emitSound(@NotNull org.bukkit.Sound sound, @NotNull org.bukkit.SoundCategory category, float volume, float pitch) { ++ getWorld().playSound(getLocation().toCenterLocation(), sound, category, volume, pitch); ++ } ++ // DivineMC end - Extend Sound API + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index be56f0f42d4ec23397f9974e158b49fcc7ed44f3..82117a1b258d43f68ff803c4c1af0a33c99065a8 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1251,4 +1251,35 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + void setImmuneToFire(@Nullable Boolean fireImmune); + // Purpur end - Fire Immunity API ++ ++ // DivineMC start - Extend Sound API ++ /** ++ * Plays a sound at the location of the entity ++ * ++ * @param sound sound to play ++ * @param volume volume of the sound ++ * @param pitch pitch of the sound ++ */ ++ default void emitSound(@NotNull org.bukkit.Sound sound, float volume, float pitch) { ++ org.bukkit.SoundCategory soundGroup = switch (this) { ++ case HumanEntity humanEntity -> org.bukkit.SoundCategory.PLAYERS; ++ case Ambient ambient -> org.bukkit.SoundCategory.AMBIENT; ++ case Monster monster -> org.bukkit.SoundCategory.HOSTILE; ++ default -> org.bukkit.SoundCategory.NEUTRAL; ++ }; ++ emitSound(sound, soundGroup, volume, pitch); ++ } ++ ++ /** ++ * Plays a sound at the location of the block ++ * ++ * @param sound sound to play ++ * @param category category of the sound ++ * @param volume volume of the sound ++ * @param pitch pitch of the sound ++ */ ++ default void emitSound(@NotNull org.bukkit.Sound sound, @NotNull org.bukkit.SoundCategory category, float volume, float pitch) { ++ getWorld().playSound(this, sound, category, volume, pitch); ++ } ++ // DivineMC end - Extend Sound API + } diff --git a/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityLoadsProjectileEvent.java b/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityLoadsProjectileEvent.java new file mode 100644 index 0000000..9aab3cd --- /dev/null +++ b/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityLoadsProjectileEvent.java @@ -0,0 +1,87 @@ +package org.bxteam.divinemc.event.entity; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.inventory.ItemStack; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import java.util.function.Predicate; + +/** + * Called when some item needs a projectile for further actions + */ +@NullMarked +public class EntityLoadsProjectileEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + private final ItemStack weapon; + private final Predicate projectileValidator; + private ItemStack projectile; + + public EntityLoadsProjectileEvent(LivingEntity entity, ItemStack weapon, @Nullable ItemStack projectile, Predicate projectileValidator) { + super(entity); + this.weapon = weapon; + this.projectile = projectile == null ? ItemStack.empty() : projectile; + this.projectileValidator = projectileValidator; + } + + /** + * Returns the entity firing the weapon + * + * @return the entity firing the weapon + */ + @Override + public LivingEntity getEntity() { + return (LivingEntity) this.entity; + } + + /** + * Returns the weapon requesting the projectile + * + * @return weapon + */ + public ItemStack getWeapon() { + return weapon; + } + + /** + * Returns the projectile that will be submitted to the weapon. + * {@link ItemStack#isEmpty()} items mean no projectile. + * + * @return projectile + */ + public ItemStack getProjectile() { + return projectile; + } + + /** + * Sets the projectile that will be used by the weapon + * + * @param projectile projectile + */ + public void setProjectile(@Nullable ItemStack projectile) { + this.projectile = projectile == null ? ItemStack.empty() : projectile; + } + + /** + * Checks whether the provided item can be fired from the weapon. + *
+ * You may still provide a non-fireable projectile to it. + * + * @param item projectile item + * @return whether the provided item can be fired from the weapon + */ + public boolean canBeFired(@Nullable ItemStack item) { + return item != null && this.projectileValidator.test(item); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityStartUsingItemEvent.java b/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityStartUsingItemEvent.java new file mode 100644 index 0000000..670033c --- /dev/null +++ b/divinemc-api/src/main/java/org/bxteam/divinemc/event/entity/EntityStartUsingItemEvent.java @@ -0,0 +1,84 @@ +package org.bxteam.divinemc.event.entity; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.inventory.ItemStack; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class EntityStartUsingItemEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private final ItemStack item; + private int useDuration; + private boolean cancelled; + + public EntityStartUsingItemEvent(LivingEntity entity, ItemStack item, int useDuration) { + super(entity); + this.item = item; + this.useDuration = useDuration; + } + + @Override + public LivingEntity getEntity() { + return (LivingEntity) this.entity; + } + + /** + * Gets the item that's being used + * + * @return the item that's being used + */ + public ItemStack getItem() { + return this.item; + } + + /** + * Gets for how long in ticks the item should be used until it's ready + * + * @return item use duration + */ + public int getUseDuration() { + return this.useDuration; + } + + /** + * Sets for how long in ticks the item should be used until it's ready + * + * @param useDuration item use duration in ticks + */ + public void setUseDuration(int useDuration) { + this.useDuration = useDuration; + } + + /** + * {@inheritDoc} + * + * @return if cancelled, the item will stop being in use + */ + @Override + public boolean isCancelled() { + return this.cancelled; + } + + /** + * Set whether to cancel item use. If canceled, + * the item will stop being in use. + * + * @param cancel whether you wish to cancel this event + */ + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/divinemc-server/minecraft-patches/features/0008-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0008-Parallel-world-ticking.patch index db39fc2..484e7ad 100644 --- a/divinemc-server/minecraft-patches/features/0008-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0008-Parallel-world-ticking.patch @@ -510,7 +510,7 @@ index f9987beae080f37456bbd195a0b0cd3be40e622a..8c7c18be474fb54e860ef554bbe820a3 LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7)); } diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index e8ff6e79ce7ba0ec8b2a90bcb81283f52106c535..c269b951fd65459609ef6e66d4e039adcbd035b4 100644 +index 04fdd32394e473995648842027b88bf7ed0136ba..9f73125b4604aa5db4eeaa924a9d24976ec1c3a1 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -150,6 +150,7 @@ public abstract class PlayerList { @@ -531,10 +531,10 @@ index e8ff6e79ce7ba0ec8b2a90bcb81283f52106c535..c269b951fd65459609ef6e66d4e039ad + else + ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, respawning in world " + player.serverLevel().getWorld().getName()); + // DivineMC end - parallel world ticking (additional concurrency issues logs) - player.stopRiding(); // CraftBukkit this.players.remove(player); this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -@@ -726,6 +733,7 @@ public abstract class PlayerList { + player.serverLevel().removePlayerImmediately(player, reason); +@@ -725,6 +732,7 @@ public abstract class PlayerList { ServerPlayer serverPlayer = player; Level fromWorld = player.level(); player.wonGame = false; diff --git a/divinemc-server/minecraft-patches/features/0028-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0028-Implement-NoChatReports.patch index fcf7709..af5f455 100644 --- a/divinemc-server/minecraft-patches/features/0028-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0028-Implement-NoChatReports.patch @@ -287,7 +287,7 @@ index 398c1733824b689520170de0be94006731afa5cd..072e9b8810a6ccc292f1eb5ffe02355a if (packet == null || this.processedDisconnect) { // Spigot return; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index c269b951fd65459609ef6e66d4e039adcbd035b4..e361910a26d1ee5d19e9eb9ad71a0aa6f34c926b 100644 +index 9f73125b4604aa5db4eeaa924a9d24976ec1c3a1..5d312dd133c89b51bdb6f7c519e16b718c1dfb79 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -274,7 +274,7 @@ public abstract class PlayerList { @@ -299,7 +299,7 @@ index c269b951fd65459609ef6e66d4e039adcbd035b4..e361910a26d1ee5d19e9eb9ad71a0aa6 ) ); player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit -@@ -1327,6 +1327,7 @@ public abstract class PlayerList { +@@ -1326,6 +1326,7 @@ public abstract class PlayerList { } public boolean verifyChatTrusted(PlayerChatMessage message) { // Paper - private -> public diff --git a/divinemc-server/minecraft-patches/features/0038-Add-EntityLoadsProjectileEvent.patch b/divinemc-server/minecraft-patches/features/0038-Add-EntityLoadsProjectileEvent.patch new file mode 100644 index 0000000..e2e4744 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0038-Add-EntityLoadsProjectileEvent.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 3 Mar 2025 01:27:13 +0300 +Subject: [PATCH] Add EntityLoadsProjectileEvent + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index e44c871e86711b343cf8016241e9c8a997c85fe2..03e8147e8315da36914cbbe477a556b72c97fd26 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -4498,6 +4498,22 @@ public abstract class LivingEntity extends Entity implements Attackable { + return ItemStack.EMPTY; + } + ++ // DivineMC start - Add EntityLoadsProjectileEvent ++ public ItemStack getProjectile(ItemStack weapon, ItemStack projectile, Predicate projectileValidator) { ++ var event = new org.bxteam.divinemc.event.entity.EntityLoadsProjectileEvent( ++ getBukkitLivingEntity(), ++ weapon.asBukkitMirror(), ++ projectile.asBukkitMirror(), ++ bukkitItem -> projectileValidator.test(CraftItemStack.asNMSCopy(bukkitItem)) ++ ); ++ event.callEvent(); ++ var item = event.getProjectile(); ++ if (item.isEmpty()) return ItemStack.EMPTY; ++ ++ return item instanceof CraftItemStack craftItem && craftItem.handle != null ? craftItem.handle : CraftItemStack.asNMSCopy(item); ++ } ++ // DivineMC end - Add EntityLoadsProjectileEvent ++ + public static byte entityEventForEquipmentBreak(EquipmentSlot slot) { + return switch (slot) { + case MAINHAND -> 47; +diff --git a/net/minecraft/world/entity/monster/Monster.java b/net/minecraft/world/entity/monster/Monster.java +index c1ebb74b0d4a8e2eb8880ccaf20f0f9bc1940094..8d08fca5d0e234dfc10abb8538483d89789ac617 100644 +--- a/net/minecraft/world/entity/monster/Monster.java ++++ b/net/minecraft/world/entity/monster/Monster.java +@@ -147,7 +147,7 @@ public abstract class Monster extends PathfinderMob implements Enemy { + if (shootable.getItem() instanceof ProjectileWeaponItem) { + Predicate supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles(); + ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles); +- return heldProjectile.isEmpty() ? new ItemStack(Items.ARROW) : heldProjectile; ++ return getProjectile(shootable, heldProjectile.isEmpty() ? new ItemStack(Items.ARROW) : heldProjectile, supportedHeldProjectiles); // DivineMC - Add EntityLoadsProjectileEvent + } else { + return ItemStack.EMPTY; + } +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 3572874d755bd0ceff8811634adf99b8c9fabfb1..27eae556fb3f83a729a7f7859347bedd7cfe7257 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -2311,19 +2311,19 @@ public abstract class Player extends LivingEntity { + Predicate supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent + ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles); + if (!heldProjectile.isEmpty()) { +- return heldProjectile; ++ return getProjectile(shootable, heldProjectile, supportedHeldProjectiles); // DivineMC - Add EntityLoadsProjectileEvent + } else { + supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent + + for (int i = 0; i < this.inventory.getContainerSize(); i++) { + ItemStack item = this.inventory.getItem(i); + if (supportedHeldProjectiles.test(item)) { +- return item; ++ return getProjectile(shootable, item, supportedHeldProjectiles); // DivineMC - Add EntityLoadsProjectileEvent + } + } + + if (anyEventCancelled.booleanValue() && !this.abilities.instabuild && this instanceof final ServerPlayer player) this.resyncUsingItem(player); // Paper - resync if no item matched the Predicate +- return this.abilities.instabuild ? new ItemStack(Items.ARROW) : ItemStack.EMPTY; ++ return getProjectile(shootable, this.abilities.instabuild ? new ItemStack(Items.ARROW) : ItemStack.EMPTY, supportedHeldProjectiles); // DivineMC - Add EntityLoadsProjectileEvent + } + } + } diff --git a/divinemc-server/minecraft-patches/features/0039-Add-EntityStartUsingItemEvent.patch b/divinemc-server/minecraft-patches/features/0039-Add-EntityStartUsingItemEvent.patch new file mode 100644 index 0000000..8c46cb8 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0039-Add-EntityStartUsingItemEvent.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 3 Mar 2025 01:28:34 +0300 +Subject: [PATCH] Add EntityStartUsingItemEvent + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 03e8147e8315da36914cbbe477a556b72c97fd26..7d6be5ad0c1209429860f2c1edf996d120ed6536 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -4049,8 +4049,16 @@ public abstract class LivingEntity extends Entity implements Attackable { + ItemStack itemInHand = this.getItemInHand(hand); + if (!itemInHand.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack + this.useItem = itemInHand; ++ // DivineMC start - Add EntityStartUsingItemEvent ++ var event = new org.bxteam.divinemc.event.entity.EntityStartUsingItemEvent(getBukkitLivingEntity(), itemInHand.asBukkitMirror(), itemInHand.getUseDuration(this)); ++ if (!event.callEvent()) { ++ stopUsingItem(); ++ return; ++ } ++ int useDuration = event.getUseDuration(); ++ // DivineMC end - Add EntityStartUsingItemEvent + // Paper start - lag compensate eating +- this.useItemRemaining = this.totalEatTimeTicks = itemInHand.getUseDuration(this); ++ this.useItemRemaining = this.totalEatTimeTicks = useDuration; // DivineMC - Add EntityStartUsingItemEvent + this.eatStartTime = System.nanoTime(); + // Paper end - lag compensate eating + if (!this.level().isClientSide) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch new file mode 100644 index 0000000..2ad186a --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch @@ -0,0 +1,60 @@ +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -85,7 +_,7 @@ + private static final ProtocolInfo INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND; + private final PacketFlow receiving; + private volatile boolean sendLoginDisconnect = true; +- private final Queue pendingActions = Queues.newConcurrentLinkedQueue(); // Paper - Optimize network ++ private final Queue pendingActions = new java.util.ArrayDeque<>(); // Paper - Optimize network // DivineMC - Optimize Connection.flushQueue + public Channel channel; + public SocketAddress address; + // Spigot start +@@ -541,10 +_,10 @@ + if (io.papermc.paper.util.MCUtil.isMainThread()) { + return this.processQueue(); + } else if (this.isPending) { +- // Should only happen during login/status stages +- synchronized (this.pendingActions) { +- return this.processQueue(); +- } ++ // DivineMC start - Optimize Connection.flushQueue ++ this.channel.eventLoop().execute(this::processQueue); ++ return false; ++ // DivineMC end - Optimize Connection.flushQueue + } + return false; + } +@@ -554,29 +_,16 @@ + return true; + } + +- // If we are on main, we are safe here in that nothing else should be processing queue off main anymore +- // But if we are not on main due to login/status, the parent is synchronized on packetQueue +- final java.util.Iterator iterator = this.pendingActions.iterator(); +- while (iterator.hasNext()) { +- final WrappedConsumer queued = iterator.next(); // poll -> peek +- +- // Fix NPE (Spigot bug caused by handleDisconnection()) +- if (queued == null) { +- return true; +- } +- +- if (queued.isConsumed()) { +- continue; +- } +- ++ // DivineMC start - Optimize Connection.flushQueue ++ WrappedConsumer queued; ++ while ((queued = this.pendingActions.poll()) != null) { + if (queued instanceof PacketSendAction packetSendAction) { + final Packet packet = packetSendAction.packet; + if (!packet.isReady()) { + return false; + } + } +- +- iterator.remove(); ++ // DivineMC end - Optimize Connection.flushQueue + if (queued.tryMarkConsumed()) { + queued.accept(this); + } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch new file mode 100644 index 0000000..f7172a5 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -716,7 +_,6 @@ + return this.respawn(player, keepInventory, reason, eventReason, null); + } + public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) { +- player.stopRiding(); // CraftBukkit + this.players.remove(player); + this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot + player.serverLevel().removePlayerImmediately(player, reason);