diff --git a/patches/api/0002-Create-interfaces-for-getting-UUIDs-and-Players.patch b/patches/api/0002-Create-interfaces-for-getting-UUIDs-and-Players.patch
new file mode 100644
index 0000000..7c1f82e
--- /dev/null
+++ b/patches/api/0002-Create-interfaces-for-getting-UUIDs-and-Players.patch
@@ -0,0 +1,1128 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: lexikiq
WARNING: TAMPERING WITH THIS EVENT CAN BE DANGEROUS
+ */ +-public class PlayerHandshakeEvent extends Event implements Cancellable { ++public class PlayerHandshakeEvent extends Event implements Cancellable, OptionalUniqueId { + + private static final HandlerList HANDLERS = new HandlerList(); + @NotNull private final String originalHandshake; +diff --git a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java +index 4dcf6242c9acc62d030a94f67b78729ed29f8c85..5218d184b9ea12a6cac3643d897dad1eafea2cb9 100644 +--- a/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/profile/PreLookupProfileEvent.java +@@ -3,6 +3,7 @@ package com.destroystokyo.paper.event.profile; + import com.destroystokyo.paper.profile.PlayerProfile; + import com.destroystokyo.paper.profile.ProfileProperty; + import com.google.common.collect.ArrayListMultimap; ++import me.lexikiq.OptionalUniqueId; + import org.bukkit.Bukkit; + import org.bukkit.event.Event; + import org.bukkit.event.HandlerList; +@@ -23,7 +24,7 @@ import org.jetbrains.annotations.Nullable; + * No guarantees are made about thread execution context for this event. If you need to know, check + * event.isAsync() + */ +-public class PreLookupProfileEvent extends Event { ++public class PreLookupProfileEvent extends Event implements OptionalUniqueId { // Parchment + + private static final HandlerList handlers = new HandlerList(); + @NotNull private final String name; +@@ -49,12 +50,21 @@ public class PreLookupProfileEvent extends Event { + * {@link LookupProfileEvent} + * + * @return The UUID of the profile if it has already been provided by a plugin ++ * @deprecated alias of {@link #getUniqueId()} (Parchment) + */ + @Nullable ++ @Deprecated // Parchment + public UUID getUUID() { + return uuid; + } + ++ // Parchment start ++ @Override ++ public @Nullable UUID getUniqueId() { ++ return uuid; ++ } ++ // Parchment end ++ + /** + * Sets the UUID for this player name. This will skip the initial API call to find the players UUID. + * +diff --git a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java +index 89e132525cfae0ce979e37b3e2793df781e47227..8b8b529fc3ee8dc370937e7125a665905fd45806 100644 +--- a/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java ++++ b/src/main/java/com/destroystokyo/paper/exception/ServerPluginMessageException.java +@@ -1,14 +1,16 @@ + package com.destroystokyo.paper.exception; + ++import me.lexikiq.HasPlayer; + import org.bukkit.entity.Player; + import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; + + import static com.google.common.base.Preconditions.*; + + /** + * Thrown when an incoming plugin message channel throws an exception + */ +-public class ServerPluginMessageException extends ServerPluginException { ++public class ServerPluginMessageException extends ServerPluginException implements HasPlayer { // Parchment + + private final Player player; + private final String channel; +@@ -40,7 +42,7 @@ public class ServerPluginMessageException extends ServerPluginException { + * + * @return exception channel + */ +- public String getChannel() { ++ public @NotNull String getChannel() { // Parchment + return channel; + } + +@@ -58,7 +60,7 @@ public class ServerPluginMessageException extends ServerPluginException { + * + * @return exception player + */ +- public Player getPlayer() { ++ public @NotNull Player getPlayer() { // Parchment + return player; + } + } +diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java +index 2c1cda1126e577a88f19071e958eddb5a38785af..56976277476d3ebb6627269d35a92800fed1169d 100644 +--- a/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkLoadEvent.java +@@ -1,5 +1,6 @@ + package io.papermc.paper.event.packet; + ++import me.lexikiq.HasPlayer; + import org.bukkit.Chunk; + import org.bukkit.entity.Player; + import org.bukkit.event.HandlerList; +@@ -14,7 +15,7 @@ import org.jetbrains.annotations.NotNull; + * Should only be used for packet/clientside related stuff. + * Not intended for modifying server side state. + */ +-public class PlayerChunkLoadEvent extends ChunkEvent { ++public class PlayerChunkLoadEvent extends ChunkEvent implements HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private final Player player; +diff --git a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java +index 12163a7b0591a7d022dc7eb9ee6608a1b6c39d9b..139ce51c98d68d2a1a493ae92825d9375d7b1950 100644 +--- a/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java ++++ b/src/main/java/io/papermc/paper/event/packet/PlayerChunkUnloadEvent.java +@@ -1,5 +1,6 @@ + package io.papermc.paper.event.packet; + ++import me.lexikiq.HasPlayer; + import org.bukkit.Chunk; + import org.bukkit.entity.Player; + import org.bukkit.event.HandlerList; +@@ -12,7 +13,7 @@ import org.jetbrains.annotations.NotNull; + * Should only be used for packet/clientside related stuff. + * Not intended for modifying server side. + */ +-public class PlayerChunkUnloadEvent extends ChunkEvent { ++public class PlayerChunkUnloadEvent extends ChunkEvent implements HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private final Player player; +diff --git a/src/main/java/me/lexikiq/HasHumanEntity.java b/src/main/java/me/lexikiq/HasHumanEntity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d2fbd2a415584e71f5c88ad7e42a13bebabe16d7 +--- /dev/null ++++ b/src/main/java/me/lexikiq/HasHumanEntity.java +@@ -0,0 +1,17 @@ ++package me.lexikiq; ++ ++import org.bukkit.entity.HumanEntity; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents an object that has a {@link HumanEntity} ++ */ ++public interface HasHumanEntity extends OptionalHumanEntity { ++ /** ++ * Gets a {@link HumanEntity} object that this represents ++ * ++ * @return human entity ++ */ ++ @Override ++ @NotNull HumanEntity getPlayer(); ++} +diff --git a/src/main/java/me/lexikiq/HasOfflinePlayer.java b/src/main/java/me/lexikiq/HasOfflinePlayer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..184055b7468911550bf86b4a6ad95a9399e5e669 +--- /dev/null ++++ b/src/main/java/me/lexikiq/HasOfflinePlayer.java +@@ -0,0 +1,17 @@ ++package me.lexikiq; ++ ++import org.bukkit.OfflinePlayer; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents an object that has a {@link OfflinePlayer} ++ */ ++public interface HasOfflinePlayer extends OptionalOfflinePlayer { ++ /** ++ * Gets an {@link OfflinePlayer} object that this represents ++ * ++ * @return offline player ++ */ ++ @Override ++ @NotNull OfflinePlayer getOfflinePlayer(); ++} +diff --git a/src/main/java/me/lexikiq/HasPlayer.java b/src/main/java/me/lexikiq/HasPlayer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df10bd66eb531f51b519815a67566195a9432f96 +--- /dev/null ++++ b/src/main/java/me/lexikiq/HasPlayer.java +@@ -0,0 +1,17 @@ ++package me.lexikiq; ++ ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents an object that has a {@link Player} ++ */ ++public interface HasPlayer extends OptionalPlayer, HasHumanEntity { ++ /** ++ * Gets a {@link Player} object that this represents ++ * ++ * @return player ++ */ ++ @Override ++ @NotNull Player getPlayer(); ++} +diff --git a/src/main/java/me/lexikiq/HasUniqueId.java b/src/main/java/me/lexikiq/HasUniqueId.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4fe1da41b9417d82f52432c3bd5b4e8b4c73f09b +--- /dev/null ++++ b/src/main/java/me/lexikiq/HasUniqueId.java +@@ -0,0 +1,17 @@ ++package me.lexikiq; ++ ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.UUID; ++ ++/** ++ * Represents an object that has a {@link UUID} ++ */ ++public interface HasUniqueId extends OptionalUniqueId { ++ /** ++ * Returns a unique and persistent id for this object ++ * ++ * @return unique id ++ */ ++ @NotNull UUID getUniqueId(); ++} +diff --git a/src/main/java/me/lexikiq/OptionalHumanEntity.java b/src/main/java/me/lexikiq/OptionalHumanEntity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fc5a565e9b654eaa3604f9be5f0fa86bbaab6f2f +--- /dev/null ++++ b/src/main/java/me/lexikiq/OptionalHumanEntity.java +@@ -0,0 +1,16 @@ ++package me.lexikiq; ++ ++import org.bukkit.entity.HumanEntity; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Represents an object that may have a {@link HumanEntity} ++ */ ++public interface OptionalHumanEntity { ++ /** ++ * Gets a {@link HumanEntity} object that this represents, if there is one ++ * ++ * @return human entity or null ++ */ ++ @Nullable HumanEntity getPlayer(); ++} +diff --git a/src/main/java/me/lexikiq/OptionalOfflinePlayer.java b/src/main/java/me/lexikiq/OptionalOfflinePlayer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1622ec23d985337c61da4b977c98a9b8cbd051f8 +--- /dev/null ++++ b/src/main/java/me/lexikiq/OptionalOfflinePlayer.java +@@ -0,0 +1,16 @@ ++package me.lexikiq; ++ ++import org.bukkit.OfflinePlayer; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Represents an object that may have an {@link OfflinePlayer} ++ */ ++public interface OptionalOfflinePlayer { ++ /** ++ * Gets an {@link OfflinePlayer} object that this represents, if there is one ++ * ++ * @return offline player or null ++ */ ++ @Nullable OfflinePlayer getOfflinePlayer(); ++} +diff --git a/src/main/java/me/lexikiq/OptionalPlayer.java b/src/main/java/me/lexikiq/OptionalPlayer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..70fcce84e8b42f3a2c3543b8365b25cc90addc8d +--- /dev/null ++++ b/src/main/java/me/lexikiq/OptionalPlayer.java +@@ -0,0 +1,16 @@ ++package me.lexikiq; ++ ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Represents an object that may have a {@link Player} ++ */ ++public interface OptionalPlayer extends OptionalHumanEntity { ++ /** ++ * Gets a {@link Player} object that this represents, if there is one ++ * ++ * @return player or null ++ */ ++ @Nullable Player getPlayer(); ++} +diff --git a/src/main/java/me/lexikiq/OptionalUniqueId.java b/src/main/java/me/lexikiq/OptionalUniqueId.java +new file mode 100644 +index 0000000000000000000000000000000000000000..da4a0422dd4f072dc15750a9e133262a344ef78a +--- /dev/null ++++ b/src/main/java/me/lexikiq/OptionalUniqueId.java +@@ -0,0 +1,17 @@ ++package me.lexikiq; ++ ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.UUID; ++ ++/** ++ * Represents an object that may have a {@link UUID} ++ */ ++public interface OptionalUniqueId { ++ /** ++ * Returns a unique and persistent id for this object which may be null ++ * ++ * @return unique id or null ++ */ ++ @Nullable UUID getUniqueId(); ++} +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 3afd5f5c0208a4ee93b5dbfc2aab2b9d2e8a7544..e2b4f86fc3825a77a5a0c1c29b428308eee54b16 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -1,6 +1,10 @@ + package org.bukkit; + + import java.util.UUID; ++ ++import me.lexikiq.HasOfflinePlayer; ++import me.lexikiq.HasUniqueId; ++import me.lexikiq.OptionalPlayer; + import org.bukkit.configuration.serialization.ConfigurationSerializable; + import org.bukkit.entity.AnimalTamer; + import org.bukkit.entity.EntityType; +@@ -9,7 +13,13 @@ import org.bukkit.permissions.ServerOperator; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +-public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable { ++public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable, OptionalPlayer, HasUniqueId, HasOfflinePlayer { // Parchment ++ // Parchment start ++ @Override ++ @NotNull default OfflinePlayer getOfflinePlayer() { ++ return this; ++ } ++ // Parchment end + + /** + * Checks if this player is currently online +diff --git a/src/main/java/org/bukkit/attribute/AttributeModifier.java b/src/main/java/org/bukkit/attribute/AttributeModifier.java +index ff8f1231f3e2e71740fd24fa8d4dac5d0e550ae7..b2f6e641125fb4c3389cbda8a62d6198bbcacc0f 100644 +--- a/src/main/java/org/bukkit/attribute/AttributeModifier.java ++++ b/src/main/java/org/bukkit/attribute/AttributeModifier.java +@@ -4,6 +4,8 @@ import java.util.HashMap; + import java.util.Map; + import java.util.Objects; + import java.util.UUID; ++ ++import me.lexikiq.HasUniqueId; + import org.apache.commons.lang.Validate; + import org.bukkit.configuration.serialization.ConfigurationSerializable; + import org.bukkit.inventory.EquipmentSlot; +@@ -14,7 +16,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Concrete implementation of an attribute modifier. + */ +-public class AttributeModifier implements ConfigurationSerializable { ++public class AttributeModifier implements ConfigurationSerializable, HasUniqueId { // Parchment + + private final UUID uuid; + private final String name; +diff --git a/src/main/java/org/bukkit/entity/AnimalTamer.java b/src/main/java/org/bukkit/entity/AnimalTamer.java +index 2e17b2d4f759531fbe9ee8e9b00c839186af09ca..b412cca0cdcb7ffa295a77cb96546d3c51c683d1 100644 +--- a/src/main/java/org/bukkit/entity/AnimalTamer.java ++++ b/src/main/java/org/bukkit/entity/AnimalTamer.java +@@ -1,10 +1,9 @@ + package org.bukkit.entity; + +-import java.util.UUID; +-import org.jetbrains.annotations.NotNull; ++import me.lexikiq.HasUniqueId; + import org.jetbrains.annotations.Nullable; + +-public interface AnimalTamer { ++public interface AnimalTamer extends HasUniqueId { // Parchment + + /** + * This is the name of the specified AnimalTamer. +@@ -14,11 +13,5 @@ public interface AnimalTamer { + @Nullable + public String getName(); + +- /** +- * This is the UUID of the specified AnimalTamer. +- * +- * @return The UUID to reference on tamed animals +- */ +- @NotNull +- public UUID getUniqueId(); ++ // Parchment: now inherits getUniqueId from interface HasUniqueId + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 46985eaea3d3b00d1dd88c2dd5a2bc53d518c64f..b33b9bb12e16f1e491912a3fdae6db552a4f8bfa 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -2,7 +2,8 @@ package org.bukkit.entity; + + import java.util.List; + import java.util.Set; +-import java.util.UUID; ++ ++import me.lexikiq.HasUniqueId; + import org.bukkit.Chunk; // Paper + import org.bukkit.EntityEffect; + import org.bukkit.Location; +@@ -26,7 +27,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a base entity in the world + */ +-public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource+ * If a Block Damage event is cancelled, the block will not be damaged. + */ +-public class BlockDamageEvent extends BlockEvent implements Cancellable { ++public class BlockDamageEvent extends BlockEvent implements Cancellable, HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private boolean instaBreak; +diff --git a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +index 3dd4bd38e72c04e74e5787fb38ca9abd10bad06b..bfb0672f25581db817a4fed1bec3489af98ec809 100644 +--- a/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockDropItemEvent.java +@@ -1,6 +1,8 @@ + package org.bukkit.event.block; + + import java.util.List; ++ ++import me.lexikiq.HasPlayer; + import org.bukkit.block.Block; + import org.bukkit.block.BlockState; + import org.bukkit.entity.Item; +@@ -24,7 +26,7 @@ import org.jetbrains.annotations.NotNull; + * AIR in most cases. Use #getBlockState() for more Information about the broken + * block. + */ +-public class BlockDropItemEvent extends BlockEvent implements Cancellable { ++public class BlockDropItemEvent extends BlockEvent implements Cancellable, HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private final Player player; +diff --git a/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java b/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java +index 695309b4b7ef269ba2496408a5f874f61cd6c445..0351d70dc5faefb80a373317e2145a958d0e485e 100644 +--- a/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockFertilizeEvent.java +@@ -1,6 +1,8 @@ + package org.bukkit.event.block; + + import java.util.List; ++ ++import me.lexikiq.HasPlayer; + import org.bukkit.block.Block; + import org.bukkit.block.BlockState; + import org.bukkit.entity.Player; +@@ -15,7 +17,7 @@ import org.jetbrains.annotations.Nullable; + * block with bonemeal. Will be called after the applicable + * {@link StructureGrowEvent}. + */ +-public class BlockFertilizeEvent extends BlockEvent implements Cancellable { ++public class BlockFertilizeEvent extends BlockEvent implements Cancellable, HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; +diff --git a/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java b/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java +index 6dcd9f828c6c40e48593b0bad5a44a656eb01645..42b5ddf3e89842fc0e2eb5319e5318d976638761 100644 +--- a/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockIgniteEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.block; + ++import me.lexikiq.OptionalPlayer; + import org.bukkit.block.Block; + import org.bukkit.entity.Entity; + import org.bukkit.entity.Player; +@@ -14,7 +15,7 @@ import org.jetbrains.annotations.Nullable; + *
+ * If a Block Ignite event is cancelled, the block will not be ignited. + */ +-public class BlockIgniteEvent extends BlockEvent implements Cancellable { ++public class BlockIgniteEvent extends BlockEvent implements Cancellable, OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private final IgniteCause cause; + private final Entity ignitingEntity; +diff --git a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +index be0a2d1f234d8265d98e54e518a994957b1f3ab7..8999f8ce6b82d7a8ad7c977037d7939b0a43f609 100644 +--- a/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java ++++ b/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.block; + ++import me.lexikiq.HasPlayer; + import org.bukkit.block.Block; + import org.bukkit.block.BlockState; + import org.bukkit.entity.Player; +@@ -14,7 +15,7 @@ import org.jetbrains.annotations.NotNull; + *
+ * If a Block Place event is cancelled, the block will not be placed. + */ +-public class BlockPlaceEvent extends BlockEvent implements Cancellable { ++public class BlockPlaceEvent extends BlockEvent implements Cancellable, HasPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + protected boolean cancel; + protected boolean canBuild; +diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +index 1f79f704abf339150df08900b8ea7da4cefef258..08c8f7578b0c9a48b25fe161b506cc4772ff96f5 100644 +--- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java ++++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.block; + ++import me.lexikiq.HasPlayer; + import org.bukkit.block.Block; + import org.bukkit.entity.Player; + import org.bukkit.event.Cancellable; +@@ -12,7 +13,7 @@ import org.jetbrains.annotations.Nullable; + *
+ * If a Sign Change event is cancelled, the sign will not be changed.
+ */
+-public class SignChangeEvent extends BlockEvent implements Cancellable {
++public class SignChangeEvent extends BlockEvent implements Cancellable, HasPlayer { // Parchment
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancel = false;
+ private final Player player;
+diff --git a/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java b/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java
+index 59aab10c2d27247eb77bd71d75b5f9126aa0fb12..1d4abde60166d63cbd0344419052b1f946e483a8 100644
+--- a/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java
++++ b/src/main/java/org/bukkit/event/entity/EntityEnterLoveModeEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.entity;
+
++import me.lexikiq.OptionalHumanEntity;
+ import org.bukkit.entity.Animals;
+ import org.bukkit.entity.HumanEntity;
+ import org.bukkit.event.Cancellable;
+@@ -7,13 +8,15 @@ import org.bukkit.event.HandlerList;
+ import org.jetbrains.annotations.NotNull;
+ import org.jetbrains.annotations.Nullable;
+
++import java.util.UUID;
++
+ /**
+ * Called when an entity enters love mode.
+ *
+ * This can be cancelled but the item will still be consumed that was used to
+ * make the entity enter into love mode.
+ */
+-public class EntityEnterLoveModeEvent extends EntityEvent implements Cancellable {
++public class EntityEnterLoveModeEvent extends EntityEvent implements Cancellable, OptionalHumanEntity { // Parchment
+
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancel;
+@@ -42,12 +45,27 @@ public class EntityEnterLoveModeEvent extends EntityEvent implements Cancellable
+ *
+ * @return The Human entity that caused the animal to enter love mode, or
+ * null if there wasn't one.
++ * @deprecated alias of {@link #getPlayer()}
+ */
+ @Nullable
++ @Deprecated // Parchment - inconsistent naming, other events use getPlayer even when returned type is HumanEntity
+ public HumanEntity getHumanEntity() {
+ return humanEntity;
+ }
+
++ // Parchment start
++ /**
++ * Gets the Human Entity that caused the animal to enter love mode.
++ *
++ * @return The Human entity that caused the animal to enter love mode, or
++ * null if there wasn't one.
++ */
++ @Nullable
++ public HumanEntity getPlayer() {
++ return humanEntity;
++ }
++ // Parchment end
++
+ /**
+ * Gets the amount of ticks that the animal will fall in love for.
+ *
+diff --git a/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java b/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java
+index ea8f9ed43d8e4158e6c9c345252a94a5000c5561..a56d5f0518bcbf5c07646e449659055bd08a0ff3 100644
+--- a/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java
++++ b/src/main/java/org/bukkit/event/entity/EntityPlaceEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.entity;
+
++import me.lexikiq.OptionalPlayer;
+ import org.bukkit.block.Block;
+ import org.bukkit.block.BlockFace;
+ import org.bukkit.entity.Entity;
+@@ -16,7 +17,7 @@ import org.jetbrains.annotations.Nullable;
+ * Note that this event is currently only fired for four specific placements:
+ * armor stands, boats, minecarts, and end crystals.
+ */
+-public class EntityPlaceEvent extends EntityEvent implements Cancellable {
++public class EntityPlaceEvent extends EntityEvent implements Cancellable, OptionalPlayer { // Parchment
+
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancelled;
+diff --git a/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java b/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java
+index 5eb3fb72a13881b8bf0e40037b0002cb0a6eb883..0f1d9a271ceb3a62026211301771b38176dab077 100644
+--- a/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java
++++ b/src/main/java/org/bukkit/event/entity/PlayerLeashEntityEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.entity;
+
++import me.lexikiq.HasPlayer;
+ import org.bukkit.entity.Entity;
+ import org.bukkit.entity.Player;
+ import org.bukkit.event.Cancellable;
+@@ -10,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
+ /**
+ * Called immediately prior to a creature being leashed by a player.
+ */
+-public class PlayerLeashEntityEvent extends Event implements Cancellable {
++public class PlayerLeashEntityEvent extends Event implements Cancellable, HasPlayer { // Parchment
+ private static final HandlerList handlers = new HandlerList();
+ private final Entity leashHolder;
+ private final Entity entity;
+diff --git a/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java b/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java
+index 959b9f3fb41f8de6c8fb9a3b2df13212e29cf0e7..6a77a4dedcd15e0a1549be330774c22b213fff4e 100644
+--- a/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java
++++ b/src/main/java/org/bukkit/event/hanging/HangingPlaceEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.hanging;
+
++import me.lexikiq.OptionalPlayer;
+ import org.bukkit.block.Block;
+ import org.bukkit.block.BlockFace;
+ import org.bukkit.entity.Hanging;
+@@ -12,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
+ /**
+ * Triggered when a hanging entity is created in the world
+ */
+-public class HangingPlaceEvent extends HangingEvent implements Cancellable {
++public class HangingPlaceEvent extends HangingEvent implements Cancellable, OptionalPlayer { // Parchment
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancelled;
+ private final Player player;
+diff --git a/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java b/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java
+index 020739697a0b535cad0b15b574f77cdabbdfa3eb..8d83f406a07fa20fee0a63237e31f141919199fb 100644
+--- a/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java
++++ b/src/main/java/org/bukkit/event/inventory/FurnaceExtractEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.inventory;
+
++import me.lexikiq.HasPlayer;
+ import org.bukkit.Material;
+ import org.bukkit.block.Block;
+ import org.bukkit.entity.Player;
+@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
+ /**
+ * This event is called when a player takes items out of the furnace
+ */
+-public class FurnaceExtractEvent extends BlockExpEvent {
++public class FurnaceExtractEvent extends BlockExpEvent implements HasPlayer { // Parchment
+ private final Player player;
+ private final Material itemType;
+ private final int itemAmount;
+diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
+index 21ad8888c0e403bfc63518502577d651c02dda05..fcf0424fa7dbbca8c8358069971304dfc8153e49 100644
+--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java
+@@ -1,6 +1,7 @@
+
+ package org.bukkit.event.inventory;
+
++import me.lexikiq.HasHumanEntity;
+ import org.bukkit.entity.HumanEntity;
+ import org.bukkit.event.HandlerList;
+ import org.bukkit.inventory.InventoryView;
+@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
+ /**
+ * Represents a player related inventory event
+ */
+-public class InventoryCloseEvent extends InventoryEvent {
++public class InventoryCloseEvent extends InventoryEvent implements HasHumanEntity { // Parchment
+ private static final HandlerList handlers = new HandlerList();
+ // Paper start
+ private final Reason reason;
+diff --git a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java
+index 9013d043503d175004ad276799e5935b7fa59dc4..9a6e1ebd46d580addf532786842ea64f6559ba37 100644
+--- a/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java
++++ b/src/main/java/org/bukkit/event/inventory/InventoryOpenEvent.java
+@@ -1,5 +1,6 @@
+ package org.bukkit.event.inventory;
+
++import me.lexikiq.HasHumanEntity;
+ import org.bukkit.entity.HumanEntity;
+ import org.bukkit.event.Cancellable;
+ import org.bukkit.event.HandlerList;
+@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
+ /**
+ * Represents a player related inventory event
+ */
+-public class InventoryOpenEvent extends InventoryEvent implements Cancellable {
++public class InventoryOpenEvent extends InventoryEvent implements Cancellable, HasHumanEntity { // Parchment
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancelled;
+
+diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
+index c9af02b0f62b3d18da1e91d1ea02ce0864fc60b9..35e8c680309f0a67e941b749240f902be07c22e6 100644
+--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
+@@ -4,6 +4,7 @@ import java.net.InetAddress;
+ import java.util.UUID;
+
+ import com.destroystokyo.paper.profile.PlayerProfile;
++import me.lexikiq.HasUniqueId;
+ import org.bukkit.Bukkit;
+ import org.bukkit.event.Event;
+ import org.bukkit.event.HandlerList;
+@@ -14,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
+ *
+ * This event is asynchronous, and not run using main thread. + */ +-public class AsyncPlayerPreLoginEvent extends Event { ++public class AsyncPlayerPreLoginEvent extends Event implements HasUniqueId { // Parchment + private static final HandlerList handlers = new HandlerList(); + private Result result; + private net.kyori.adventure.text.Component message; // Paper +diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java +index f6d3b817de3001f04ea4554c7c39a1290af3fd6d..85a7a49d59902cd292f5a0d14af472c458f9b674 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.player; + ++import me.lexikiq.HasPlayer; + import org.bukkit.entity.Player; + import org.bukkit.event.Event; + import org.jetbrains.annotations.NotNull; +@@ -7,7 +8,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Represents a player related event + */ +-public abstract class PlayerEvent extends Event { ++public abstract class PlayerEvent extends Event implements HasPlayer { // Parchment + protected Player player; + + public PlayerEvent(@NotNull final Player who) { +diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +index 123979ed64939d615b061f91c19c630e1e1db8c7..90cbfe9c3bd1c6fb8da85e0fb6b24d3ad23282ce 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +@@ -2,6 +2,8 @@ package org.bukkit.event.player; + + import java.net.InetAddress; + import java.util.UUID; ++ ++import me.lexikiq.HasUniqueId; + import org.bukkit.Warning; + import org.bukkit.event.Event; + import org.bukkit.event.HandlerList; +@@ -16,7 +18,7 @@ import org.jetbrains.annotations.NotNull; + */ + @Deprecated + @Warning(reason = "This event causes a login thread to synchronize with the main thread") +-public class PlayerPreLoginEvent extends Event { ++public class PlayerPreLoginEvent extends Event implements HasUniqueId { // Parchment + private static final HandlerList handlers = new HandlerList(); + private Result result; + private net.kyori.adventure.text.Component message; // Paper +diff --git a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java +index 68eab1563caba1ee4f52b308f390e4e172667fc5..9e4ed3642e60a49a29c0bbfa3c46043d645bde4d 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerUnleashEntityEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.player; + ++import me.lexikiq.HasPlayer; + import org.bukkit.entity.Entity; + import org.bukkit.entity.Player; + import org.bukkit.event.Cancellable; +@@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull; + /** + * Called prior to an entity being unleashed due to a player's action. + */ +-public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Cancellable { ++public class PlayerUnleashEntityEvent extends EntityUnleashEvent implements Cancellable, HasPlayer { // Parchment + private final Player player; + private boolean cancelled = false; + +diff --git a/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java b/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java +index 128e43cf12205f82f2b119a773208502cdccfdd4..d18daf2d8625e27bfd02c8191b57d8eae96b8d2c 100644 +--- a/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java ++++ b/src/main/java/org/bukkit/event/raid/RaidTriggerEvent.java +@@ -1,5 +1,6 @@ + package org.bukkit.event.raid; + ++import me.lexikiq.HasPlayer; + import org.bukkit.Raid; + import org.bukkit.World; + import org.bukkit.entity.Player; +@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull; + * Called when a {@link Raid} is triggered (e.g: a player with Bad Omen effect + * enters a village). + */ +-public class RaidTriggerEvent extends RaidEvent implements Cancellable { ++public class RaidTriggerEvent extends RaidEvent implements Cancellable, HasPlayer { // Parchment + + private static final HandlerList handlers = new HandlerList(); + // +diff --git a/src/main/java/org/bukkit/event/world/StructureGrowEvent.java b/src/main/java/org/bukkit/event/world/StructureGrowEvent.java +index 7af8d6e51c824cf0592b722b834f1d4986e3cc08..5e869c53255d3fa5876c7a6bb0e7104a24b33388 100644 +--- a/src/main/java/org/bukkit/event/world/StructureGrowEvent.java ++++ b/src/main/java/org/bukkit/event/world/StructureGrowEvent.java +@@ -1,6 +1,8 @@ + package org.bukkit.event.world; + + import java.util.List; ++ ++import me.lexikiq.OptionalPlayer; + import org.bukkit.Location; + import org.bukkit.TreeType; + import org.bukkit.block.BlockState; +@@ -14,7 +16,7 @@ import org.jetbrains.annotations.Nullable; + * Event that is called when an organic structure attempts to grow (Sapling {@literal ->} + * Tree), (Mushroom {@literal ->} Huge Mushroom), naturally or using bonemeal. + */ +-public class StructureGrowEvent extends WorldEvent implements Cancellable { ++public class StructureGrowEvent extends WorldEvent implements Cancellable, OptionalPlayer { // Parchment + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled = false; + private final Location location; +diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java +index b06995aa57aa9cba0bb59f1d26d81015619a08e6..c16b7174139d9e437ce6c16f48e40e8b639f9ec7 100644 +--- a/src/main/java/org/bukkit/inventory/InventoryView.java ++++ b/src/main/java/org/bukkit/inventory/InventoryView.java +@@ -1,6 +1,7 @@ + package org.bukkit.inventory; + + import com.google.common.base.Preconditions; ++import me.lexikiq.HasHumanEntity; + import org.bukkit.entity.HumanEntity; + import org.bukkit.event.inventory.InventoryType; + import org.jetbrains.annotations.NotNull; +@@ -14,7 +15,7 @@ import org.jetbrains.annotations.Nullable; + * contracts of certain methods, there's no guarantee that the game will work + * as it should. + */ +-public abstract class InventoryView { ++public abstract class InventoryView implements HasHumanEntity { // Parchment + public static final int OUTSIDE = -999; + /** + * Represents various extra properties of certain inventory windows. +diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java +index f4e626f92857f2d091b1c2370aa0ce928b088c9e..d4de2902c5ba6e03a68fea4b2c4c6828f767f920 100644 +--- a/src/main/java/org/bukkit/scoreboard/Score.java ++++ b/src/main/java/org/bukkit/scoreboard/Score.java +@@ -1,5 +1,6 @@ + package org.bukkit.scoreboard; + ++import me.lexikiq.HasOfflinePlayer; + import org.bukkit.OfflinePlayer; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; +@@ -9,7 +10,7 @@ import org.jetbrains.annotations.Nullable; + * #getObjective() objective}. Changing this will not affect any other + * objective or scoreboard. + */ +-public interface Score { ++public interface Score extends HasOfflinePlayer { // Parchment + + /** + * Gets the OfflinePlayer being tracked by this Score +@@ -22,6 +23,22 @@ public interface Score { + @NotNull + OfflinePlayer getPlayer(); + ++ // Parchment start ++ /** ++ * Gets the OfflinePlayer being tracked by this Score ++ *
++ * Alias for {@link #getPlayer()}
++ *
++ * @return this Score's tracked player
++ * @deprecated Scoreboards can contain entries that aren't players
++ * @see #getEntry()
++ */
++ @Override
++ @NotNull default OfflinePlayer getOfflinePlayer() {
++ return getPlayer();
++ }
++ // Parchment end
++
+ /**
+ * Gets the entry being tracked by this Score
+ *
diff --git a/patches/api/0003-Use-eden-api-and-ComponentLike-interfaces.patch b/patches/api/0003-Use-eden-api-and-ComponentLike-interfaces.patch
new file mode 100644
index 0000000..8ae9a12
--- /dev/null
+++ b/patches/api/0003-Use-eden-api-and-ComponentLike-interfaces.patch
@@ -0,0 +1,78 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: lexikiq