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.
++ *
++ * - A yaw of 0 or 360 represents the positive z direction.
++ *
- A yaw of 180 represents the negative z direction.
++ *
- A yaw of 90 represents the negative x direction.
++ *
- A yaw of 270 represents the positive x direction.
++ *
++ * 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.
++ *
++ * - A pitch of 0 represents level forward facing.
++ *
- A pitch of 90 represents downward facing, or negative y
++ * direction.
++ *
- A pitch of -90 represents upward facing, or positive y direction.
++ *
++ * 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);