diff --git a/dough-api/pom.xml b/dough-api/pom.xml
index d9aa5f75..4bb28d00 100644
--- a/dough-api/pom.xml
+++ b/dough-api/pom.xml
@@ -167,10 +167,6 @@
enginehub-repo
https://maven.enginehub.org/repo/
-
- IntellectualSites
- https://mvn.intellectualsites.com/content/repositories/snapshots/
-
funnyguilds-repo
https://repo.panda-lang.org/releases
@@ -415,6 +411,13 @@
plugin
4.12.0
provided
+
+
+
+ com.github.PikaMug
+ LocaleLib
+
+
diff --git a/dough-items/src/main/java/io/github/bakedlibs/dough/items/ItemUtils.java b/dough-items/src/main/java/io/github/bakedlibs/dough/items/ItemUtils.java
index c5f1ae61..c3d3b1a9 100644
--- a/dough-items/src/main/java/io/github/bakedlibs/dough/items/ItemUtils.java
+++ b/dough-items/src/main/java/io/github/bakedlibs/dough/items/ItemUtils.java
@@ -6,6 +6,8 @@
import javax.annotation.Nullable;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Registry;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
@@ -174,8 +176,8 @@ public static void damageItem(@Nonnull ItemStack item, int damage, boolean ignor
if (item.getType() != Material.AIR && item.getAmount() > 0) {
int remove = damage;
- if (!ignoreEnchantments && item.getEnchantments().containsKey(Enchantment.DURABILITY)) {
- int level = item.getEnchantmentLevel(Enchantment.DURABILITY);
+ if (!ignoreEnchantments && item.getEnchantments().containsKey(Registry.ENCHANTMENT.get(NamespacedKey.minecraft("unbreaking")))) {
+ int level = item.getEnchantmentLevel(Registry.ENCHANTMENT.get(NamespacedKey.minecraft("unbreaking")));
for (int i = 0; i < damage; i++) {
if (Math.random() * 100 <= (60 + Math.floorDiv(40, (level + 1)))) {
diff --git a/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter.java b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter.java
index a541f203..a596f0b2 100644
--- a/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter.java
+++ b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter.java
@@ -7,6 +7,7 @@
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
+import io.papermc.lib.PaperLib;
import org.bukkit.inventory.ItemStack;
import io.github.bakedlibs.dough.common.DoughLogger;
@@ -20,11 +21,19 @@ public interface ItemNameAdapter {
public static @Nullable ItemNameAdapter get() {
try {
- MinecraftVersion version = MinecraftVersion.get();
-
if (MinecraftVersion.isMocked()) {
// Special case for MockBukkit
return new ItemNameAdapterMockBukkit();
+ }
+
+ MinecraftVersion version = MinecraftVersion.get();
+
+ if (version.isAtLeast(1, 20, 4) && PaperLib.isPaper()) {
+ return new ItemNameAdapterPaper();
+ }
+
+ if (version.isAtLeast(1, 20, 5)) {
+ return new ItemNameAdapter20v5();
} else if (version.isAtLeast(1, 20)) {
return new ItemNameAdapter20();
} else if (version.isAtLeast(1, 19)) {
diff --git a/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter20v5.java b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter20v5.java
new file mode 100644
index 00000000..c2acd256
--- /dev/null
+++ b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapter20v5.java
@@ -0,0 +1,32 @@
+package io.github.bakedlibs.dough.items.nms;
+
+import io.github.bakedlibs.dough.reflection.ReflectionUtils;
+import io.github.bakedlibs.dough.versions.UnknownServerVersionException;
+import org.bukkit.inventory.ItemStack;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class ItemNameAdapter20v5 implements ItemNameAdapter {
+
+ private final Method getCopy;
+ private final Method getName;
+ private final Method toString;
+
+ ItemNameAdapter20v5() throws NoSuchMethodException, SecurityException, ClassNotFoundException, UnknownServerVersionException {
+ super();
+
+ getCopy = ReflectionUtils.getOBCClass("inventory.CraftItemStack").getMethod("asNMSCopy", ItemStack.class);
+ getName = ReflectionUtils.getMethodOrAlternative(ReflectionUtils.getNetMinecraftClass("world.item.ItemStack"), "getDisplayName", "G");
+ toString = ReflectionUtils.getMethod(ReflectionUtils.getNetMinecraftClass("network.chat.IChatBaseComponent"), "getString");
+ }
+
+ @Override
+ @ParametersAreNonnullByDefault
+ public String getName(ItemStack item) throws IllegalAccessException, InvocationTargetException {
+ Object instance = getCopy.invoke(null, item);
+ return (String) toString.invoke(getName.invoke(instance));
+ }
+
+}
diff --git a/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapterPaper.java b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapterPaper.java
new file mode 100644
index 00000000..bc0a90ba
--- /dev/null
+++ b/dough-items/src/main/java/io/github/bakedlibs/dough/items/nms/ItemNameAdapterPaper.java
@@ -0,0 +1,16 @@
+package io.github.bakedlibs.dough.items.nms;
+
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
+import org.bukkit.Bukkit;
+import org.bukkit.inventory.ItemStack;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.lang.reflect.InvocationTargetException;
+
+public class ItemNameAdapterPaper implements ItemNameAdapter {
+ @Override
+ @ParametersAreNonnullByDefault
+ public String getName(ItemStack item) throws IllegalAccessException, InvocationTargetException {
+ return PlainTextComponentSerializer.plainText().serialize(Bukkit.getItemFactory().displayName(item));
+ }
+}
diff --git a/dough-protection/pom.xml b/dough-protection/pom.xml
index fa2e72ee..d12c8315 100644
--- a/dough-protection/pom.xml
+++ b/dough-protection/pom.xml
@@ -79,18 +79,36 @@
worldedit-core
7.2.17
provided
+
+
+ bukkit
+ *
+
+
com.sk89q.worldedit
worldedit-bukkit
7.2.17
provided
+
+
+ bukkit
+ *
+
+
com.sk89q.worldguard
worldguard-bukkit
7.0.9
provided
+
+
+ bukkit
+ *
+
+
@@ -99,6 +117,12 @@
PreciousStones
1.17.2
provided
+
+
+ bukkit
+ *
+
+
@@ -107,6 +131,12 @@
coreprotect
21.3
provided
+
+
+ bukkit
+ *
+
+
@@ -115,6 +145,12 @@
logblock
1.17.0.0-SNAPSHOT
provided
+
+
+ bukkit
+ *
+
+
@@ -123,6 +159,12 @@
SimpleClans
7c3db52796
provided
+
+
+ bukkit
+ *
+
+
@@ -131,6 +173,12 @@
GriefPrevention
16.18.2
provided
+
+
+ bukkit
+ *
+
+
@@ -139,6 +187,12 @@
lwc
master-4.5.1-g2100b5e-18
provided
+
+
+ bukkit
+ *
+
+
@@ -147,12 +201,24 @@
helper
5.6.14
provided
+
+
+ bukkit
+ *
+
+
com.massivecraft
Factions
1.6.9.5-4.1.4-STABLE
provided
+
+
+ bukkit
+ *
+
+
@@ -161,6 +227,12 @@
Towny
1b86d017c5
provided
+
+
+ bukkit
+ *
+
+
@@ -169,6 +241,12 @@
Lockette
9dac96e8f8
provided
+
+
+ bukkit
+ *
+
+
@@ -182,6 +260,10 @@
org.projectlombok
lombok
+
+ bukkit
+ *
+
@@ -194,6 +276,10 @@
plotsquared-core
*
+
+ bukkit
+ *
+
@@ -203,12 +289,24 @@
RedProtect-Core
7.7.3
provided
+
+
+ bukkit
+ *
+
+
br.net.fabiozumbi12.RedProtect
RedProtect-Spigot
7.7.3
provided
+
+
+ bukkit
+ *
+
+
@@ -217,6 +315,12 @@
bentobox
1.20.1
provided
+
+
+ bukkit
+ *
+
+
@@ -225,6 +329,12 @@
blocklocker
1.10.4
provided
+
+
+ bukkit
+ *
+
+
@@ -233,6 +343,12 @@
LandsAPI
6.29.12
provided
+
+
+ bukkit
+ *
+
+
@@ -241,6 +357,12 @@
ChestProtectAPI
3.9.1
provided
+
+
+ bukkit
+ *
+
+
@@ -249,6 +371,17 @@
plugin
4.12.0
provided
+
+
+ bukkit
+ *
+
+
+
+ com.github.PikaMug
+ LocaleLib
+
+
@@ -257,6 +390,12 @@
husktowns-bukkit
3.0-988161b
provided
+
+
+ bukkit
+ *
+
+
@@ -265,14 +404,26 @@
huskclaims-bukkit
1.0.2-e60150d
provided
+
+
+ bukkit
+ *
+
+
-
+
de.epiceric
ShopChest
1.13-SNAPSHOT
provided
+
+
+ bukkit
+ *
+
+
@@ -281,6 +432,12 @@
bolt-bukkit
1.0.580
provided
+
+
+ bukkit
+ *
+
+
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/PlayerHead.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/PlayerHead.java
index a8973261..97d1ee07 100644
--- a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/PlayerHead.java
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/PlayerHead.java
@@ -80,16 +80,7 @@ public static void setSkin(Block block, PlayerSkin skin, boolean sendBlockUpdate
try {
GameProfile profile = skin.getProfile();
- Object tileEntity = adapter.getTileEntity(block);
-
- if (tileEntity != null) {
- adapter.setGameProfile(tileEntity, profile);
-
- if (sendBlockUpdate) {
- block.getState().update(true, false);
- }
- }
-
+ adapter.setGameProfile(block, profile, sendBlockUpdate);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter.java
index 957571d9..c66ac871 100644
--- a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter.java
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter.java
@@ -6,6 +6,7 @@
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
+import io.papermc.lib.PaperLib;
import org.bukkit.block.Block;
import com.mojang.authlib.GameProfile;
@@ -16,17 +17,16 @@
public interface PlayerHeadAdapter {
@ParametersAreNonnullByDefault
- @Nullable
- Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException;
-
- @ParametersAreNonnullByDefault
- void setGameProfile(Object tileEntity, GameProfile profile) throws IllegalAccessException, InvocationTargetException;
+ void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws IllegalAccessException, InvocationTargetException, InstantiationException;
public static @Nullable PlayerHeadAdapter get() {
try {
MinecraftVersion version = MinecraftVersion.get();
- if (version.isAtLeast(1, 18)) {
+ if (version.isAtLeast(1, 20, 5)) {
+ // 1.20.5 mappings
+ return new PlayerHeadAdapter20v5();
+ } else if (version.isAtLeast(1, 18)) {
// 1.18 mappings
return new PlayerHeadAdapter18();
} else if (version.isAtLeast(1, 17)) {
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter17.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter17.java
index de3f8b7a..136593f6 100644
--- a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter17.java
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter17.java
@@ -31,9 +31,8 @@ class PlayerHeadAdapter17 implements PlayerHeadAdapter {
getTileEntity = ReflectionUtils.getNMSClass("level.WorldServer").getMethod("getTileEntity", blockPosition);
}
- @Override
@ParametersAreNonnullByDefault
- public @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ private @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
Object world = getHandle.invoke(block.getWorld());
Object position = newPosition.newInstance(block.getX(), block.getY(), block.getZ());
@@ -42,8 +41,15 @@ class PlayerHeadAdapter17 implements PlayerHeadAdapter {
@Override
@ParametersAreNonnullByDefault
- public void setGameProfile(Object tileEntity, GameProfile profile) throws IllegalAccessException, InvocationTargetException {
+ public void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object tileEntity = getTileEntity(block);
+ if (tileEntity == null) return;
+
setGameProfile.invoke(tileEntity, profile);
+
+ if (sendBlockUpdate) {
+ block.getState().update(true, false);
+ }
}
}
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter18.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter18.java
index c0762fc7..f369987a 100644
--- a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter18.java
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter18.java
@@ -27,9 +27,8 @@ class PlayerHeadAdapter18 implements PlayerHeadAdapter {
getTileEntity = ReflectionUtils.getNMSClass("level.WorldServer").getMethod("getBlockEntity", blockPosition, boolean.class);
}
- @Override
@ParametersAreNonnullByDefault
- public @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ private @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
Object world = getHandle.invoke(block.getWorld());
Object position = newPosition.newInstance(block.getX(), block.getY(), block.getZ());
@@ -38,8 +37,15 @@ class PlayerHeadAdapter18 implements PlayerHeadAdapter {
@Override
@ParametersAreNonnullByDefault
- public void setGameProfile(Object tileEntity, GameProfile profile) throws IllegalAccessException, InvocationTargetException {
+ public void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object tileEntity = getTileEntity(block);
+ if (tileEntity == null) return;
+
setGameProfile.invoke(tileEntity, profile);
+
+ if (sendBlockUpdate) {
+ block.getState().update(true, false);
+ }
}
}
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter20v5.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter20v5.java
new file mode 100644
index 00000000..abc86dfa
--- /dev/null
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapter20v5.java
@@ -0,0 +1,58 @@
+package io.github.bakedlibs.dough.skins.nms;
+
+import com.mojang.authlib.GameProfile;
+import io.github.bakedlibs.dough.reflection.ReflectionUtils;
+import io.github.bakedlibs.dough.versions.UnknownServerVersionException;
+import org.bukkit.block.Block;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class PlayerHeadAdapter20v5 implements PlayerHeadAdapter {
+
+ private final Constructor> newPosition;
+ private final Constructor> newResolvableProfile;
+
+ private final Method getHandle;
+ private final Method getTileEntity;
+ private final Method setOwner;
+
+ PlayerHeadAdapter20v5() throws NoSuchMethodException, SecurityException, ClassNotFoundException, UnknownServerVersionException {
+ Class> resolvableProfile = ReflectionUtils.getNetMinecraftClass("world.item.component.ResolvableProfile");
+ newResolvableProfile = ReflectionUtils.getConstructor(resolvableProfile, GameProfile.class);
+
+ setOwner = ReflectionUtils.getNetMinecraftClass("world.level.block.entity.TileEntitySkull").getMethod("a", resolvableProfile);
+ getHandle = ReflectionUtils.getOBCClass("CraftWorld").getMethod("getHandle");
+
+ Class> blockPosition = ReflectionUtils.getNetMinecraftClass("core.BlockPosition");
+ newPosition = ReflectionUtils.getConstructor(blockPosition, int.class, int.class, int.class);
+
+ getTileEntity = ReflectionUtils.getNMSClass("level.WorldServer").getMethod("getBlockEntity", blockPosition, boolean.class);
+ }
+
+ @ParametersAreNonnullByDefault
+ private @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object world = getHandle.invoke(block.getWorld());
+
+ Object position = newPosition.newInstance(block.getX(), block.getY(), block.getZ());
+ return getTileEntity.invoke(world, position, true);
+ }
+
+ @Override
+ @ParametersAreNonnullByDefault
+ public void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object tileEntity = getTileEntity(block);
+ if (tileEntity == null) return;
+
+ Object resolvableProfile = newResolvableProfile.newInstance(profile);
+ setOwner.invoke(tileEntity, resolvableProfile);
+
+ if (sendBlockUpdate) {
+ block.getState().update(true, false);
+ }
+ }
+
+}
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterBefore17.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterBefore17.java
index 40dae6c0..39924465 100644
--- a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterBefore17.java
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterBefore17.java
@@ -31,9 +31,8 @@ class PlayerHeadAdapterBefore17 implements PlayerHeadAdapter {
getTileEntity = ReflectionUtils.getNMSClass("WorldServer").getMethod("getTileEntity", blockPosition);
}
- @Override
@ParametersAreNonnullByDefault
- public @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ private @Nullable Object getTileEntity(Block block) throws IllegalAccessException, InvocationTargetException, InstantiationException {
Object world = getHandle.invoke(block.getWorld());
Object position = newPosition.newInstance(block.getX(), block.getY(), block.getZ());
@@ -42,8 +41,15 @@ class PlayerHeadAdapterBefore17 implements PlayerHeadAdapter {
@Override
@ParametersAreNonnullByDefault
- public void setGameProfile(Object tileEntity, GameProfile profile) throws IllegalAccessException, InvocationTargetException {
+ public void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object tileEntity = getTileEntity(block);
+ if (tileEntity == null) return;
+
setGameProfile.invoke(tileEntity, profile);
+
+ if (sendBlockUpdate) {
+ block.getState().update(true, false);
+ }
}
}
diff --git a/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterPaper.java b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterPaper.java
new file mode 100644
index 00000000..4660e1b9
--- /dev/null
+++ b/dough-skins/src/main/java/io/github/bakedlibs/dough/skins/nms/PlayerHeadAdapterPaper.java
@@ -0,0 +1,50 @@
+package io.github.bakedlibs.dough.skins.nms;
+
+import com.destroystokyo.paper.profile.PlayerProfile;
+import com.destroystokyo.paper.profile.ProfileProperty;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import io.github.bakedlibs.dough.reflection.ReflectionUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Skull;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+// Not currently in use.
+// This does not correctly update heads on updates currently.
+public class PlayerHeadAdapterPaper implements PlayerHeadAdapter {
+
+ @Override
+ @ParametersAreNonnullByDefault
+ public void setGameProfile(Block block, GameProfile profile, boolean sendBlockUpdate) throws InvocationTargetException, IllegalAccessException {
+ BlockState state = block.getState();
+ if (!(state instanceof Skull)) return;
+
+ Skull skull = (Skull) state;
+
+ Property property = profile.getProperties().get("textures").iterator().next();
+
+ PlayerProfile paperPlayerProfile = Bukkit.createProfile(profile.getId(), profile.getName());
+
+ Method getName = ReflectionUtils.getMethod(Property.class, "getName");
+ Method getValue = ReflectionUtils.getMethod(Property.class, "getValue");
+ Method getSignature = ReflectionUtils.getMethod(Property.class, "getSignature");
+
+ // Old authlib check
+ if (getName != null && getValue != null && getSignature != null) {
+ paperPlayerProfile.setProperty(new ProfileProperty((String) getName.invoke(property), (String) getValue.invoke(property), (String) getSignature.invoke(property)));
+ } else {
+ paperPlayerProfile.setProperty(new ProfileProperty(property.name(), property.value(), property.signature()));
+ }
+
+ skull.setPlayerProfile(paperPlayerProfile);
+
+ if (sendBlockUpdate) {
+ skull.update(true, false);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 908d3814..3aa0152d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -278,15 +278,15 @@
- spigot-repo
- https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+ paper
+ https://repo.papermc.io/repository/maven-public/
- org.spigotmc
- spigot-api
+ io.papermc.paper
+ paper-api
1.18.1-R0.1-SNAPSHOT
provided