environment = new HashMap<>();
/**
- * If the plugin uses reflective reload (via {@link com.willfp.eco.core.config.updating.ConfigUpdater}).
+ * If the plugin uses reflective reload.
*/
private boolean usesReflectiveReload = true;
diff --git a/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java b/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java
index 667d1f9e..a197e99a 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java
@@ -37,6 +37,14 @@ public class Prerequisite {
"Requires server to have ProtocolLib"
);
+ /**
+ * Requires the server to be running 1.20.3.
+ */
+ public static final Prerequisite HAS_1_20_3 = new Prerequisite(
+ () -> ProxyConstants.NMS_VERSION.contains("20_R3"),
+ "Requires server to be running 1.20.3+"
+ );
+
/**
* Requires the server to be running 1.20.
*/
diff --git a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java
index 3f19337a..83c3ae14 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java
@@ -29,6 +29,22 @@ public interface LoadableConfig extends Config {
*/
void save() throws IOException;
+ /**
+ * Save the config asynchronously.
+ */
+ default void saveAsync() {
+ // This default implementation exists purely for backwards compatibility
+ // with legacy Config implementations that don't have saveAsync().
+ // Default eco implementations of Config have saveAsync() implemented.
+ new Thread(() -> {
+ try {
+ this.save();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+
/**
* Get the config file.
*
diff --git a/eco-api/src/main/java/com/willfp/eco/core/config/updating/ConfigUpdater.java b/eco-api/src/main/java/com/willfp/eco/core/config/updating/ConfigUpdater.java
index ac36f37c..ad36d161 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/config/updating/ConfigUpdater.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/config/updating/ConfigUpdater.java
@@ -38,12 +38,16 @@ import java.lang.annotation.Target;
*
* By having a plugin as a parameter, you shouldn't really need getInstance()
* calls in your code.
- *
+ *
* While flexible, this can lead to long initialization times, so this feature
* can be disabled in eco.yml with the uses-reflective-reload option.
+ *
+ * @deprecated This has been deprecated due to the poor control flow and long startup times.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
+@Deprecated(since = "6.67.0", forRemoval = true)
+@SuppressWarnings("DeprecatedIsStillUsed")
public @interface ConfigUpdater {
}
diff --git a/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java b/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java
index 00f0aa8b..13f80cac 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java
@@ -32,7 +32,7 @@ public final class PersistentDataKey {
/**
* If the key uses local storage.
*/
- private final boolean local;
+ private final boolean isLocal;
/**
* Create a new Persistent Data Key.
@@ -40,16 +40,16 @@ public final class PersistentDataKey {
* @param key The key.
* @param type The data type.
* @param defaultValue The default value.
- * @param local If the key uses local storage.
+ * @param isLocal If the key uses local storage.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type,
@NotNull final T defaultValue,
- final boolean local) {
+ final boolean isLocal) {
this.key = key;
this.defaultValue = defaultValue;
this.type = type;
- this.local = local;
+ this.isLocal = isLocal;
Eco.get().registerPersistentKey(this);
}
@@ -67,7 +67,7 @@ public final class PersistentDataKey {
this.key = key;
this.defaultValue = defaultValue;
this.type = type;
- this.local = false;
+ this.isLocal = false;
Eco.get().registerPersistentKey(this);
}
@@ -108,7 +108,14 @@ public final class PersistentDataKey {
return this.type;
}
- public boolean isLocalStorage() { return this.local; }
+ /**
+ * Get if the key uses local storage.
+ *
+ * @return If the key uses local storage.
+ */
+ public boolean isLocal() {
+ return this.isLocal;
+ }
/**
* Get all persistent data keys.
diff --git a/eco-api/src/main/java/com/willfp/eco/core/gui/slot/SlotBuilder.java b/eco-api/src/main/java/com/willfp/eco/core/gui/slot/SlotBuilder.java
index fef7cc10..0e34dd85 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/gui/slot/SlotBuilder.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/gui/slot/SlotBuilder.java
@@ -196,6 +196,7 @@ public interface SlotBuilder {
* @deprecated Use {@link SlotBuilder#setUpdater(SlotUpdater)} instead.
*/
@Deprecated
+ @SuppressWarnings("DeprecatedIsStillUsed")
default SlotBuilder setModifier(@NotNull SlotModifier modifier) {
return setUpdater((player, menu, previous) -> {
modifier.modify(player, menu, previous);
diff --git a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java
index 4266e8e5..51ba6fe7 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java
@@ -150,6 +150,7 @@ public final class PlaceholderManager {
*/
@Deprecated(since = "6.56.0", forRemoval = true)
@NotNull
+ @SuppressWarnings("DeprecatedIsStillUsed")
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player) {
return translatePlaceholders(text, player, EMPTY_INJECTABLE);
@@ -166,6 +167,7 @@ public final class PlaceholderManager {
*/
@Deprecated(since = "6.56.0", forRemoval = true)
@NotNull
+ @SuppressWarnings("DeprecatedIsStillUsed")
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context) {
@@ -192,6 +194,7 @@ public final class PlaceholderManager {
*/
@Deprecated(since = "6.56.0", forRemoval = true)
@NotNull
+ @SuppressWarnings("DeprecatedIsStillUsed")
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context,
diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java b/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java
index d2a2f563..d6f97d60 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java
@@ -120,8 +120,12 @@ public final class ConfiguredPrice implements Price {
*/
public String getDisplay(@NotNull final Player player,
final double multiplier) {
+ double value = this.getPrice().getValue(player, multiplier);
+
return StringUtils.format(
- formatString.replace("%value%", NumberUtils.format(this.getPrice().getValue(player, multiplier))),
+ formatString
+ .replace("%value%", NumberUtils.format(value))
+ .replace("%value_commas%", NumberUtils.formatWithCommas(value)),
player,
StringUtils.FormatOption.WITH_PLACEHOLDERS
);
diff --git a/eco-api/src/main/java/com/willfp/eco/core/proxy/ProxyConstants.java b/eco-api/src/main/java/com/willfp/eco/core/proxy/ProxyConstants.java
index cc55caf8..05079b89 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/proxy/ProxyConstants.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/proxy/ProxyConstants.java
@@ -25,7 +25,8 @@ public final class ProxyConstants {
"v1_19_R2",
"v1_19_R3",
"v1_20_R1",
- "v1_20_R2"
+ "v1_20_R2",
+ "v1_20_R3"
);
private ProxyConstants() {
diff --git a/eco-api/src/main/java/com/willfp/eco/core/web/UpdateChecker.java b/eco-api/src/main/java/com/willfp/eco/core/web/UpdateChecker.java
index 3aeedc32..edb155c0 100644
--- a/eco-api/src/main/java/com/willfp/eco/core/web/UpdateChecker.java
+++ b/eco-api/src/main/java/com/willfp/eco/core/web/UpdateChecker.java
@@ -1,13 +1,13 @@
package com.willfp.eco.core.web;
import com.willfp.eco.core.EcoPlugin;
-import org.bukkit.util.Consumer;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Scanner;
+import java.util.function.Consumer;
/**
* Class to check for updates of a plugin on spigot.
diff --git a/eco-api/src/main/java/com/willfp/eco/util/EntityUtils.java b/eco-api/src/main/java/com/willfp/eco/util/EntityUtils.java
new file mode 100644
index 00000000..955693cc
--- /dev/null
+++ b/eco-api/src/main/java/com/willfp/eco/util/EntityUtils.java
@@ -0,0 +1,31 @@
+package com.willfp.eco.util;
+
+import com.willfp.eco.core.Eco;
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Utilities / API methods for entities.
+ */
+public final class EntityUtils {
+ /**
+ * Set a client-side entity display name.
+ *
+ * @param entity The entity.
+ * @param player The player.
+ * @param name The display name.
+ * @param visible If the display name should be forcibly visible.
+ */
+ public static void setClientsideDisplayName(@NotNull final LivingEntity entity,
+ @NotNull final Player player,
+ @NotNull final Component name,
+ final boolean visible) {
+ Eco.get().setClientsideDisplayName(entity, player, name, visible);
+ }
+
+ private EntityUtils() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+}
diff --git a/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java b/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java
index 61192def..05cc91a9 100644
--- a/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java
+++ b/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java
@@ -203,6 +203,20 @@ public final class NumberUtils {
return formatted.endsWith("00") ? String.valueOf((int) toFormat) : formatted;
}
+ /**
+ * Format double to string with commas.
+ *
+ * @param toFormat The number to format.
+ * @return Formatted.
+ */
+ @NotNull
+ public static String formatWithCommas(final double toFormat) {
+ DecimalFormat df = new DecimalFormat("#,##0.00");
+ String formatted = df.format(toFormat);
+
+ return formatted.endsWith(".00") ? formatted.substring(0, formatted.length() - 3) : formatted;
+ }
+
/**
* Evaluate an expression.
*
diff --git a/eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java b/eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java
index 1eccedba..95531b87 100644
--- a/eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java
+++ b/eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java
@@ -15,7 +15,7 @@ public final class PatternUtils {
* Cache of compiled literal patterns.
*/
private static final Cache LITERAL_PATTERN_CACHE = Caffeine.newBuilder()
- .expireAfterAccess(1, TimeUnit.MINUTES)
+ .expireAfterAccess(15, TimeUnit.MINUTES)
.build();
/**
diff --git a/eco-api/src/main/java/com/willfp/eco/util/PotionUtils.java b/eco-api/src/main/java/com/willfp/eco/util/PotionUtils.java
index 341b2d95..53da6a06 100644
--- a/eco-api/src/main/java/com/willfp/eco/util/PotionUtils.java
+++ b/eco-api/src/main/java/com/willfp/eco/util/PotionUtils.java
@@ -13,6 +13,7 @@ public final class PotionUtils {
* @param data The data.
* @return The duration.
*/
+ @SuppressWarnings("deprecation")
public static int getDuration(@NotNull final PotionData data) {
if (data.isExtended()) {
return switch (data.getType()) {
diff --git a/eco-api/src/main/kotlin/com/willfp/eco/util/EntityUtils.kt b/eco-api/src/main/kotlin/com/willfp/eco/util/EntityUtils.kt
new file mode 100644
index 00000000..6de26938
--- /dev/null
+++ b/eco-api/src/main/kotlin/com/willfp/eco/util/EntityUtils.kt
@@ -0,0 +1,12 @@
+@file:JvmName("EntityUtilsExtensions")
+
+package com.willfp.eco.util
+
+import net.kyori.adventure.text.Component
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+
+/** @see EntityUtils.setClientsideDisplayName */
+fun LivingEntity.setClientsideDisplayName(player: Player, displayName: Component, visible: Boolean) {
+ EntityUtils.setClientsideDisplayName(this, player, displayName, visible)
+}
diff --git a/eco-api/src/main/kotlin/com/willfp/eco/util/NumberUtils.kt b/eco-api/src/main/kotlin/com/willfp/eco/util/NumberUtils.kt
index 281b80a5..29c3a3ec 100644
--- a/eco-api/src/main/kotlin/com/willfp/eco/util/NumberUtils.kt
+++ b/eco-api/src/main/kotlin/com/willfp/eco/util/NumberUtils.kt
@@ -8,6 +8,10 @@ import com.willfp.eco.core.placeholder.context.PlaceholderContext
fun Number.toNumeral(): String =
NumberUtils.toNumeral(this.toInt())
+/** @see NumberUtils.formatWithCommas */
+fun Number.formatWithCommas(): String =
+ NumberUtils.formatWithCommas(this.toDouble())
+
/** @see NumberUtils.fromNumeral */
fun String.parseNumeral(): Int =
NumberUtils.fromNumeral(this)
diff --git a/eco-api/src/main/kotlin/com/willfp/eco/util/PotionUtils.kt b/eco-api/src/main/kotlin/com/willfp/eco/util/PotionUtils.kt
index 7a726022..e5daef53 100644
--- a/eco-api/src/main/kotlin/com/willfp/eco/util/PotionUtils.kt
+++ b/eco-api/src/main/kotlin/com/willfp/eco/util/PotionUtils.kt
@@ -2,8 +2,8 @@
package com.willfp.eco.util
-import org.bukkit.potion.PotionData
-/** @see PotionData.duration */
-val PotionData.duration: Int
+/** @see PotionUtils.getDuration */
+@Suppress("DEPRECATION")
+val org.bukkit.potion.PotionData.duration: Int
get() = PotionUtils.getDuration(this)
diff --git a/eco-core/core-backend/build.gradle.kts b/eco-core/core-backend/build.gradle.kts
index df258648..f951608d 100644
--- a/eco-core/core-backend/build.gradle.kts
+++ b/eco-core/core-backend/build.gradle.kts
@@ -6,8 +6,8 @@ dependencies {
implementation("org.reflections:reflections:0.9.12")
implementation("org.objenesis:objenesis:3.2")
- compileOnly("org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT")
- compileOnly("me.clip:placeholderapi:2.10.10")
+ compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT")
+ compileOnly("me.clip:placeholderapi:2.11.4")
compileOnly("net.kyori:adventure-text-minimessage:4.10.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.1.0")
compileOnly("org.yaml:snakeyaml:1.33")
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/command/HandledCommand.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/command/HandledCommand.kt
index c4dd15e3..0318d946 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/command/HandledCommand.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/command/HandledCommand.kt
@@ -3,7 +3,6 @@ package com.willfp.eco.internal.command
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.CommandBase
import com.willfp.eco.core.command.NotificationException
-import com.willfp.eco.core.config.base.LangYml
import org.bukkit.Bukkit
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoConfigSection.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoConfigSection.kt
index f6c24e19..65dbc5ac 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoConfigSection.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoConfigSection.kt
@@ -2,7 +2,6 @@ package com.willfp.eco.internal.config
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.placeholder.InjectablePlaceholder
-import java.util.concurrent.ConcurrentHashMap
class EcoConfigSection(
type: ConfigType,
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt
index eabe3e61..2faab918 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt
@@ -10,10 +10,11 @@ import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.Reader
+import java.nio.ByteBuffer
+import java.nio.channels.AsynchronousFileChannel
import java.nio.file.Files
import java.nio.file.StandardOpenOption
-@Suppress("UNCHECKED_CAST")
open class EcoLoadableConfig(
type: ConfigType,
configName: String,
@@ -74,6 +75,20 @@ open class EcoLoadableConfig(
}
}
+ override fun saveAsync() {
+ // Save asynchronously using NIO
+ AsynchronousFileChannel.open(
+ configFile.toPath(),
+ StandardOpenOption.WRITE,
+ StandardOpenOption.CREATE
+ ).use { channel ->
+ channel.write(
+ ByteBuffer.wrap(this.toPlaintext().toByteArray()),
+ 0
+ )
+ }
+ }
+
private fun makeHeader(contents: String) {
header.clear()
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/handler/ReflectiveConfigHandler.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/handler/ReflectiveConfigHandler.kt
index 8c663230..5c92ed05 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/handler/ReflectiveConfigHandler.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/handler/ReflectiveConfigHandler.kt
@@ -1,7 +1,6 @@
package com.willfp.eco.internal.config.handler
import com.willfp.eco.core.EcoPlugin
-import com.willfp.eco.core.config.updating.ConfigUpdater
import org.reflections.Reflections
import org.reflections.scanners.MethodAnnotationsScanner
@@ -14,7 +13,8 @@ class ReflectiveConfigHandler(
)
override fun callUpdate() {
- for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) {
+ @Suppress("DEPRECATION", "REMOVAL")
+ for (method in reflections.getMethodsAnnotatedWith(com.willfp.eco.core.config.updating.ConfigUpdater::class.java)) {
runCatching {
when (method.parameterCount) {
0 -> method.invoke(null)
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/drops/EcoDropQueue.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/drops/EcoDropQueue.kt
index 0f6e6d57..5d68219a 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/drops/EcoDropQueue.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/drops/EcoDropQueue.kt
@@ -1,5 +1,6 @@
package com.willfp.eco.internal.drops
+import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.core.events.DropQueuePushEvent
import com.willfp.eco.core.integrations.antigrief.AntigriefManager
@@ -72,10 +73,17 @@ open class EcoDropQueue(val player: Player) : DropQueue() {
world.dropItem(location, drop!!).velocity = Vector()
}
if (xp > 0) {
- val orb =
- world.spawnEntity(player.location.add(0.0, 0.2, 0.0), EntityType.EXPERIENCE_ORB) as ExperienceOrb
- orb.velocity = Vector(0, 0, 0)
- orb.experience = xp
+ if (Prerequisite.HAS_PAPER.isMet) {
+ player.giveExp(xp, true)
+ } else {
+ val orb =
+ world.spawnEntity(
+ player.location.add(0.0, 0.2, 0.0),
+ EntityType.EXPERIENCE_ORB
+ ) as ExperienceOrb
+ orb.velocity = Vector(0, 0, 0)
+ orb.experience = xp
+ }
}
} else {
for (drop in items) {
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/entities/EntityArgParserName.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/entities/EntityArgParserName.kt
index b41bd617..767bc530 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/entities/EntityArgParserName.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/entities/EntityArgParserName.kt
@@ -19,6 +19,7 @@ object EntityArgParserName : EntityArgParser {
val formatted = StringUtils.format(name)
+ @Suppress("DEPRECATION")
return EntityArgParseResult(
{ it.customName == formatted },
{
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/events/EcoEventManager.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/events/EcoEventManager.kt
index 1b207ce1..4aa71c62 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/events/EcoEventManager.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/events/EcoEventManager.kt
@@ -2,12 +2,14 @@ package com.willfp.eco.internal.events
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.events.EventManager
+import com.willfp.eco.core.map.listMap
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.core.packet.PacketPriority
import org.bukkit.Bukkit
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
+import java.lang.Exception
private class RegisteredPacketListener(
@@ -15,19 +17,25 @@ private class RegisteredPacketListener(
val listener: PacketListener
)
-private val listeners = mutableMapOf>()
+private val listeners = listMap()
fun PacketEvent.handleSend() {
for (priority in PacketPriority.values()) {
- for (listener in listeners[priority] ?: continue) {
+ for (listener in listeners[priority]) {
try {
listener.listener.onSend(this)
- } catch (e: Exception) {
+ } catch (e: Throwable) {
listener.plugin.logger.warning(
"Exception in packet listener ${listener.listener.javaClass.name}" +
" for packet ${packet.handle.javaClass.name}!"
)
e.printStackTrace()
+ } catch (e: LinkageError) {
+ listener.plugin.logger.warning(
+ "Error in packet listener ${listener.listener.javaClass.name}" +
+ " for packet ${packet.handle.javaClass.name}!"
+ )
+ e.printStackTrace()
}
}
}
@@ -35,7 +43,7 @@ fun PacketEvent.handleSend() {
fun PacketEvent.handleReceive() {
for (priority in PacketPriority.values()) {
- for (listener in listeners[priority] ?: continue) {
+ for (listener in listeners[priority]) {
try {
listener.listener.onReceive(this)
} catch (e: Exception) {
@@ -44,6 +52,12 @@ fun PacketEvent.handleReceive() {
" for packet ${packet.handle.javaClass.name}!"
)
e.printStackTrace()
+ } catch (e: LinkageError) {
+ listener.plugin.logger.warning(
+ "Error in packet listener ${listener.listener.javaClass.name}" +
+ " for packet ${packet.handle.javaClass.name}!"
+ )
+ e.printStackTrace()
}
}
}
@@ -66,11 +80,9 @@ class EcoEventManager(private val plugin: EcoPlugin) : EventManager {
}
override fun registerPacketListener(listener: PacketListener) {
- listeners.getOrPut(listener.priority) { mutableListOf() }.add(
- RegisteredPacketListener(
- plugin,
- listener
- )
+ listeners[listener.priority] += RegisteredPacketListener(
+ plugin,
+ listener
)
}
}
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/extensions/EcoExtensionLoader.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/extensions/EcoExtensionLoader.kt
index 3fe7b09e..40d4c6a1 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/extensions/EcoExtensionLoader.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/extensions/EcoExtensionLoader.kt
@@ -42,6 +42,7 @@ class EcoExtensionLoader(
}
}
+ @Suppress("DEPRECATION")
@Throws(MalformedExtensionException::class)
private fun loadExtension(extensionJar: File) {
val url = extensionJar.toURI().toURL()
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/factory/EcoNamespacedKeyFactory.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/factory/EcoNamespacedKeyFactory.kt
index 7768362e..c93fd166 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/factory/EcoNamespacedKeyFactory.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/factory/EcoNamespacedKeyFactory.kt
@@ -7,6 +7,6 @@ import org.bukkit.NamespacedKey
class EcoNamespacedKeyFactory(private val plugin: EcoPlugin) : NamespacedKeyFactory {
override fun create(key: String): NamespacedKey {
- return NamespacedKeyUtils.create(plugin.name, key)
+ return NamespacedKeyUtils.create(plugin.id, key)
}
}
\ No newline at end of file
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/fast/InternalNamespacedKeyFactory.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/fast/InternalNamespacedKeyFactory.kt
index a86cb0fb..5459e280 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/fast/InternalNamespacedKeyFactory.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/fast/InternalNamespacedKeyFactory.kt
@@ -25,7 +25,6 @@ class FastInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
class SafeInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
override fun create(namespace: String, key: String): NamespacedKey {
- @Suppress("DEPRECATION")
return NamespacedKey(namespace, key)
}
}
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt
index dbd9221b..3d3b5557 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt
@@ -43,6 +43,7 @@ class EcoMenu(
getPossiblyReactiveSlot(row, column, player)
override fun open(player: Player): Inventory {
+ @Suppress("DEPRECATION")
val inventory = if (columns == 9) {
Bukkit.createInventory(null, rows * columns, title)
} else {
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/RenderedInventory.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/RenderedInventory.kt
index 609f4c1c..dcdd097e 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/RenderedInventory.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/RenderedInventory.kt
@@ -1,7 +1,6 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent
-import com.willfp.eco.core.items.isEmpty
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.util.MenuUtils
import com.willfp.eco.util.openMenu
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/integrations/PAPIExpansion.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/integrations/PAPIExpansion.kt
index 74488672..799c3e9d 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/integrations/PAPIExpansion.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/integrations/PAPIExpansion.kt
@@ -6,6 +6,7 @@ import com.willfp.eco.core.placeholder.context.placeholderContext
import me.clip.placeholderapi.expansion.PlaceholderExpansion
import org.bukkit.entity.Player
+@Suppress("DEPRECATION")
class PAPIExpansion(private val plugin: EcoPlugin) : PlaceholderExpansion() {
init {
register()
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserHead.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserHead.kt
index 1d73f594..fe96be30 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserHead.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserHead.kt
@@ -28,7 +28,6 @@ object ArgParserHead : LookupArgParser {
playerName ?: return null
- @Suppress("DEPRECATION")
val player = Bukkit.getOfflinePlayer(playerName)
meta.owningPlayer = player
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserName.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserName.kt
index 554b23a1..608f0476 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserName.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserName.kt
@@ -22,12 +22,13 @@ object ArgParserName : LookupArgParser {
val formatted = StringUtils.format(name)
// I don't know why it says it's redundant, the compiler yells at me
- @Suppress("UsePropertyAccessSyntax", "RedundantSuppression")
+ @Suppress("UsePropertyAccessSyntax", "RedundantSuppression", "DEPRECATION")
meta.setDisplayName(formatted)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
+ @Suppress("DEPRECATION")
testMeta.displayName == formatted
}
}
@@ -37,6 +38,7 @@ object ArgParserName : LookupArgParser {
return null
}
+ @Suppress("DEPRECATION")
return "name:\"${meta.displayName}\""
}
}
\ No newline at end of file
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserTrim.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserTrim.kt
index 3de5e82b..80d7f40b 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserTrim.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/items/ArgParserTrim.kt
@@ -1,13 +1,11 @@
package com.willfp.eco.internal.items
import com.willfp.eco.core.items.args.LookupArgParser
-import org.bukkit.Color
import org.bukkit.NamespacedKey
import org.bukkit.Registry
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ArmorMeta
import org.bukkit.inventory.meta.ItemMeta
-import org.bukkit.inventory.meta.LeatherArmorMeta
import org.bukkit.inventory.meta.trim.ArmorTrim
import org.bukkit.inventory.meta.trim.TrimMaterial
import org.bukkit.inventory.meta.trim.TrimPattern
diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/placeholder/PlaceholderParser.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/placeholder/PlaceholderParser.kt
index e0774ff5..72b17368 100644
--- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/placeholder/PlaceholderParser.kt
+++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/placeholder/PlaceholderParser.kt
@@ -7,6 +7,8 @@ import com.willfp.eco.core.placeholder.InjectablePlaceholder
import com.willfp.eco.core.placeholder.Placeholder
import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.util.StringUtils
+import com.willfp.eco.util.evaluateExpression
+import com.willfp.eco.util.toNiceString
import java.util.concurrent.TimeUnit
/*
@@ -19,6 +21,8 @@ but it's still best to minimise the memory overhead.
class PlaceholderParser {
private val placeholderRegex = Regex("%([^% ]+)%")
+ private val prettyMathExpressionRegex = Regex("(\\{\\^\\{)(.)+(}})")
+ private val mathExpressionRegex = Regex("(\\{\\{)(.)+(}})")
private val placeholderLookupCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
@@ -34,6 +38,29 @@ class PlaceholderParser {
injections: Collection,
translateEcoPlaceholders: Boolean = true
): String {
+ var processed = text
+
+ // Only evaluate math expressions if there might be any
+ // Checking { as a char is faster than checking a string sequence,
+ // even if it might lead to false positives.
+ if ('{' in processed) {
+ if ('^' in processed) {
+ // Evaluate pretty math expressions
+ processed = prettyMathExpressionRegex.findAll(processed).fold(processed) { acc, matchResult ->
+ val expression = matchResult.value.substring(3, matchResult.value.length - 2)
+ val result = evaluateExpression(expression, context)
+ acc.replace(matchResult.value, result.toNiceString())
+ }
+ }
+
+ // Evaluate math expressions
+ processed = mathExpressionRegex.findAll(processed).fold(processed) { acc, matchResult ->
+ val expression = matchResult.value.substring(2, matchResult.value.length - 2)
+ val result = evaluateExpression(expression, context)
+ acc.replace(matchResult.value, result.toString())
+ }
+ }
+
/*
Why am I doing injections at the start, and again at the end?
@@ -55,7 +82,7 @@ class PlaceholderParser {
*/
// Apply injections first
- var processed = injections.fold(text) { acc, injection ->
+ processed = injections.fold(processed) { acc, injection ->
injection.tryTranslateQuickly(acc, context)
}
diff --git a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt
index 7bf91f5d..6a71e652 100644
--- a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt
+++ b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt
@@ -1,9 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.common
+import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.entities.ai.EntityGoal
import com.willfp.eco.core.entities.ai.TargetGoal
import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory
import com.willfp.eco.internal.spigot.proxy.common.ai.TargetGoalFactory
+import io.papermc.paper.adventure.PaperAdventure
+import net.kyori.adventure.text.Component
import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
@@ -68,6 +71,9 @@ fun CompoundTag.setPdc(pdc: PersistentDataContainer?, item: net.minecraft.world.
fun Player.toNMS(): ServerPlayer =
impl.toNMS(this)
+fun Component.toNMS(): net.minecraft.network.chat.Component =
+ if (Prerequisite.HAS_PAPER.isMet) PaperAdventure.asVanilla(this) else impl.toNMS(this)
+
interface CommonsProvider {
val nbtTagString: Int
@@ -101,6 +107,8 @@ interface CommonsProvider {
fun toNMS(player: Player): ServerPlayer
+ fun toNMS(component: Component): net.minecraft.network.chat.Component
+
companion object {
fun setIfNeeded(provider: CommonsProvider) {
if (::impl.isInitialized) {
diff --git a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/Skull.kt b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/Skull.kt
index 0a78675d..a0fcc473 100644
--- a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/Skull.kt
+++ b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/Skull.kt
@@ -9,18 +9,28 @@ import java.util.UUID
private lateinit var setProfile: Method
private lateinit var profile: Field
+private lateinit var value: Field
var SkullMeta.texture: String?
get() {
+ if (!::value.isInitialized) {
+ // Doing it this way because Property was changed to be a record and this is
+ // a quick hack to get around that
+ value = Property::class.java.getDeclaredField("value")
+ value.isAccessible = true
+ }
+
if (!::profile.isInitialized) {
// Assumes instance of CraftMetaSkull; package-private class so can't do manual type check
profile = this.javaClass.getDeclaredField("profile")
profile.isAccessible = true
}
+
val profile = profile[this] as GameProfile? ?: return null
val properties = profile.properties ?: return null
- val prop = properties["textures"] ?: return null
- return prop.toMutableList().firstOrNull()?.value
+ val props = properties["textures"] ?: return null
+ val prop = props.toMutableList().firstOrNull() ?: return null
+ return value[prop] as String?
}
set(base64) {
if (!::setProfile.isInitialized) {
diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt
index 6b6e7e1c..2a578573 100644
--- a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/DisplayName.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/DisplayName.kt
new file mode 100644
index 00000000..d7a5c000
--- /dev/null
+++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/DisplayName.kt
@@ -0,0 +1,83 @@
+package com.willfp.eco.internal.spigot.proxy.v1_17_R1
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_17_R1.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData,
+ true
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt
index e992315a..d65db856 100644
--- a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/DisplayName.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/DisplayName.kt
new file mode 100644
index 00000000..2383acaf
--- /dev/null
+++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/DisplayName.kt
@@ -0,0 +1,83 @@
+package com.willfp.eco.internal.spigot.proxy.v1_18_R1
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_18_R1.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData,
+ true
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt
index 9b21fd52..4d221237 100644
--- a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/DisplayName.kt b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/DisplayName.kt
new file mode 100644
index 00000000..789606d3
--- /dev/null
+++ b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/DisplayName.kt
@@ -0,0 +1,83 @@
+package com.willfp.eco.internal.spigot.proxy.v1_18_R2
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_18_R2.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData,
+ true
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/CommonsInitializer.kt
index 51538401..1a6f6e7c 100644
--- a/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/DisplayName.kt b/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/DisplayName.kt
new file mode 100644
index 00000000..f7dc50eb
--- /dev/null
+++ b/eco-core/core-nms/v1_19_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R1/DisplayName.kt
@@ -0,0 +1,83 @@
+package com.willfp.eco.internal.spigot.proxy.v1_19_R1
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_19_R1.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData,
+ true
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/CommonsInitializer.kt b/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/CommonsInitializer.kt
index 4d87433c..6a35c524 100644
--- a/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/CommonsInitializer.kt
@@ -6,6 +6,8 @@ import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import io.netty.channel.Channel
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -157,5 +159,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/DisplayName.kt b/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/DisplayName.kt
new file mode 100644
index 00000000..d0689c54
--- /dev/null
+++ b/eco-core/core-nms/v1_19_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R2/DisplayName.kt
@@ -0,0 +1,82 @@
+package com.willfp.eco.internal.spigot.proxy.v1_19_R2
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_19_R2.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData.packDirty() ?: throw IllegalStateException("No packed entity data")
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/CommonsInitializer.kt b/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/CommonsInitializer.kt
index 4459ab91..c56feda8 100644
--- a/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = GsonComponentSerializer.gson().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/DisplayName.kt b/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/DisplayName.kt
new file mode 100644
index 00000000..444645e9
--- /dev/null
+++ b/eco-core/core-nms/v1_19_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_19_R3/DisplayName.kt
@@ -0,0 +1,82 @@
+package com.willfp.eco.internal.spigot.proxy.v1_19_R3
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_19_R3.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ private val itemsByIDMapField = SynchedEntityData::class.java
+ .declaredFields
+ .filter { it.type == Int2ObjectMap::class.java }
+ .toList()[0]
+ .apply { isAccessible = true }
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData.packDirty() ?: throw IllegalStateException("No packed entity data")
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+
+ private fun SynchedEntityData.hasItem(accessor: EntityDataAccessor): Boolean {
+ val itemsByIDMap = itemsByIDMapField.get(this) as Int2ObjectMap
+ return itemsByIDMap.containsKey(accessor.id)
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/CommonsInitializer.kt
index a9d5ac31..03d19b6f 100644
--- a/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = JSONComponentSerializer.json().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/DisplayName.kt b/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/DisplayName.kt
new file mode 100644
index 00000000..8fd8b72c
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R1/DisplayName.kt
@@ -0,0 +1,71 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R1
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import io.papermc.paper.adventure.PaperAdventure
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_20_R1.entity.CraftLivingEntity
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ override fun setClientsideDisplayName(
+ entity: LivingEntity,
+ player: Player,
+ displayName: Component,
+ visible: Boolean
+ ) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData.packDirty() ?: throw IllegalStateException("No packed entity data")
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/CommonsInitializer.kt b/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/CommonsInitializer.kt
index 23df35dd..85d6c674 100644
--- a/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/CommonsInitializer.kt
+++ b/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/CommonsInitializer.kt
@@ -5,6 +5,8 @@ import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
@@ -155,5 +157,10 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = JSONComponentSerializer.json().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
}
}
diff --git a/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/DisplayName.kt b/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/DisplayName.kt
new file mode 100644
index 00000000..7d290497
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R2/DisplayName.kt
@@ -0,0 +1,68 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R2
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import io.papermc.paper.adventure.PaperAdventure
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_20_R2.entity.CraftLivingEntity
+import org.bukkit.craftbukkit.v1_20_R2.entity.CraftMob
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Mob
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ override fun setClientsideDisplayName(entity: LivingEntity, player: Player, displayName: Component, visible: Boolean) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData.packDirty() ?: throw IllegalStateException("No packed entity data")
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/build.gradle.kts b/eco-core/core-nms/v1_20_R3/build.gradle.kts
new file mode 100644
index 00000000..fbc42137
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/build.gradle.kts
@@ -0,0 +1,39 @@
+plugins {
+ id("io.papermc.paperweight.userdev")
+}
+
+group = "com.willfp"
+version = rootProject.version
+
+dependencies {
+ implementation(project(":eco-core:core-nms:nms-common"))
+ paperweight.paperDevBundle("1.20.3-R0.1-SNAPSHOT")
+
+ implementation("net.kyori:adventure-text-minimessage:4.11.0") {
+ version {
+ strictly("4.11.0")
+ }
+ exclude(group = "net.kyori", module = "adventure-api")
+ }
+}
+
+tasks {
+ build {
+ dependsOn(reobfJar)
+ }
+
+ reobfJar {
+ mustRunAfter(shadowJar)
+ }
+
+ shadowJar {
+ relocate(
+ "com.willfp.eco.internal.spigot.proxy.common",
+ "com.willfp.eco.internal.spigot.proxy.v1_20_R3.common"
+ )
+ relocate(
+ "net.kyori.adventure.text.minimessage",
+ "com.willfp.eco.internal.spigot.proxy.v1_20_R3.minimessage"
+ )
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/BukkitCommands.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/BukkitCommands.kt
new file mode 100644
index 00000000..ffdfc68a
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/BukkitCommands.kt
@@ -0,0 +1,35 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.command.PluginCommandBase
+import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
+import org.bukkit.Bukkit
+import org.bukkit.command.Command
+import org.bukkit.command.SimpleCommandMap
+import org.bukkit.craftbukkit.v1_20_R3.CraftServer
+import java.lang.reflect.Field
+
+class BukkitCommands : BukkitCommandsProxy {
+ private val knownCommandsField: Field by lazy {
+ SimpleCommandMap::class.java.getDeclaredField("knownCommands")
+ .apply {
+ isAccessible = true
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private val knownCommands: MutableMap
+ get() = knownCommandsField.get(getCommandMap()) as MutableMap
+
+ override fun getCommandMap(): SimpleCommandMap {
+ return (Bukkit.getServer() as CraftServer).commandMap
+ }
+
+ override fun syncCommands() {
+ (Bukkit.getServer() as CraftServer).syncCommands()
+ }
+
+ override fun unregisterCommand(command: PluginCommandBase) {
+ knownCommands.remove(command.name)
+ knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/CommonsInitializer.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/CommonsInitializer.kt
new file mode 100644
index 00000000..ceb4c3d6
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/CommonsInitializer.kt
@@ -0,0 +1,166 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.EcoPlugin
+import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
+import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
+import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
+import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
+import net.kyori.adventure.text.Component
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer
+import net.minecraft.core.registries.BuiltInRegistries
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.nbt.Tag
+import net.minecraft.resources.ResourceLocation
+import net.minecraft.server.level.ServerPlayer
+import net.minecraft.world.entity.PathfinderMob
+import net.minecraft.world.item.Item
+import org.bukkit.Bukkit
+import org.bukkit.Material
+import org.bukkit.NamespacedKey
+import org.bukkit.craftbukkit.v1_20_R3.CraftServer
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMob
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer
+import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack
+import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataContainer
+import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataTypeRegistry
+import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers
+import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Mob
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+import org.bukkit.persistence.PersistentDataContainer
+import java.lang.reflect.Field
+
+class CommonsInitializer : CommonsInitializerProxy {
+ override fun init(plugin: EcoPlugin) {
+ CommonsProvider.setIfNeeded(CommonsProviderImpl)
+ plugin.onEnable {
+ plugin.eventManager.registerListener(PacketInjectorListener)
+ }
+ }
+
+ object CommonsProviderImpl : CommonsProvider {
+ private val cisHandle: Field = CraftItemStack::class.java.getDeclaredField("handle").apply {
+ isAccessible = true
+ }
+
+ private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_20_R3.inventory.CraftMetaItem")
+ .getDeclaredField("DATA_TYPE_REGISTRY")
+ .apply { isAccessible = true }
+ .get(null) as CraftPersistentDataTypeRegistry
+
+ override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
+
+ override fun toPathfinderMob(mob: Mob): PathfinderMob? {
+ val craft = mob as? CraftMob ?: return null
+ return craft.handle as? PathfinderMob
+ }
+
+ override fun toResourceLocation(namespacedKey: NamespacedKey): ResourceLocation =
+ CraftNamespacedKey.toMinecraft(namespacedKey)
+
+ override fun asNMSStack(itemStack: ItemStack): net.minecraft.world.item.ItemStack {
+ return if (itemStack !is CraftItemStack) {
+ CraftItemStack.asNMSCopy(itemStack)
+ } else {
+ cisHandle[itemStack] as net.minecraft.world.item.ItemStack? ?: CraftItemStack.asNMSCopy(itemStack)
+ }
+ }
+
+ override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
+ return CraftItemStack.asCraftMirror(itemStack)
+ }
+
+ override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
+ if (itemStack !is CraftItemStack) {
+ itemStack.itemMeta = CraftItemStack.asCraftMirror(nmsStack).itemMeta
+ }
+ }
+
+ override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
+ CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
+
+ override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
+ fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
+
+ fun CompoundTag?.toPdc(): PersistentDataContainer {
+ val pdc = emptyPdc()
+ this ?: return pdc
+ val keys = this.allKeys
+ for (key in keys) {
+ pdc.put(key, this[key])
+ }
+
+ return pdc
+ }
+
+ return if (base) {
+ tag.toPdc()
+ } else {
+ if (tag.contains("PublicBukkitValues")) {
+ tag.getCompound("PublicBukkitValues").toPdc()
+ } else {
+ emptyPdc()
+ }
+ }
+ }
+
+ override fun setPdc(
+ tag: CompoundTag,
+ pdc: PersistentDataContainer?,
+ item: net.minecraft.world.item.ItemStack?
+ ) {
+ fun CraftPersistentDataContainer.toTag(): CompoundTag {
+ val compound = CompoundTag()
+ val rawPublicMap: Map = this.raw
+ for ((key, value) in rawPublicMap) {
+ compound.put(key, value)
+ }
+
+ return compound
+ }
+
+ val container = when (pdc) {
+ is CraftPersistentDataContainer? -> pdc
+ else -> null
+ }
+
+ if (item != null) {
+ if (container != null && !container.isEmpty) {
+ for (key in tag.allKeys.toSet()) {
+ tag.remove(key)
+ }
+
+ tag.merge(container.toTag())
+ } else {
+ item.tag = null
+ }
+ } else {
+ if (container != null && !container.isEmpty) {
+ tag.put("PublicBukkitValues", container.toTag())
+ } else {
+ tag.remove("PublicBukkitValues")
+ }
+ }
+ }
+
+ override fun materialToItem(material: Material): Item =
+ BuiltInRegistries.ITEM.getOptional(material.key.toResourceLocation())
+ .orElseThrow { IllegalArgumentException("Material is not item!") }
+
+ override fun itemToMaterial(item: Item) =
+ Material.getMaterial(BuiltInRegistries.ITEM.getKey(item).path.uppercase())
+ ?: throw IllegalArgumentException("Invalid material!")
+
+ override fun toNMS(player: Player): ServerPlayer {
+ return (player as CraftPlayer).handle
+ }
+
+ override fun toNMS(component: Component): net.minecraft.network.chat.Component {
+ val json = JSONComponentSerializer.json().serialize(component)
+ return net.minecraft.network.chat.Component.Serializer.fromJson(json)!!
+ }
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DisplayName.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DisplayName.kt
new file mode 100644
index 00000000..4fcb40f2
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DisplayName.kt
@@ -0,0 +1,68 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.packet.Packet
+import com.willfp.eco.core.packet.sendPacket
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
+import com.willfp.eco.internal.spigot.proxy.common.toNMS
+import io.papermc.paper.adventure.PaperAdventure
+import net.kyori.adventure.text.Component
+import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket
+import net.minecraft.network.syncher.EntityDataAccessor
+import net.minecraft.network.syncher.SynchedEntityData
+import net.minecraft.world.entity.Entity
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftLivingEntity
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMob
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Mob
+import org.bukkit.entity.Player
+import java.util.Optional
+
+@Suppress("UNCHECKED_CAST")
+class DisplayName : DisplayNameProxy {
+ private val displayNameAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[2]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor>
+
+ private val customNameVisibleAccessor = Entity::class.java
+ .declaredFields
+ .filter { it.type == EntityDataAccessor::class.java }
+ .toList()[3]
+ .apply { isAccessible = true }
+ .get(null) as EntityDataAccessor
+
+ override fun setClientsideDisplayName(entity: LivingEntity, player: Player, displayName: Component, visible: Boolean) {
+ if (entity !is CraftLivingEntity) {
+ return
+ }
+
+ val nmsComponent = displayName.toNMS()
+
+ val nmsEntity = entity.handle
+ nmsEntity.isCustomNameVisible
+ val entityData = SynchedEntityData(nmsEntity)
+
+ entityData.forceSet(displayNameAccessor, Optional.of(nmsComponent))
+ entityData.forceSet(customNameVisibleAccessor, visible)
+
+ val packet = ClientboundSetEntityDataPacket(
+ nmsEntity.id,
+ entityData.packDirty() ?: throw IllegalStateException("No packed entity data")
+ )
+
+ player.sendPacket(Packet(packet))
+ }
+
+ private fun SynchedEntityData.forceSet(
+ accessor: EntityDataAccessor,
+ value: T
+ ) {
+ if (!this.hasItem(accessor)) {
+ this.define(accessor, value)
+ }
+ this[accessor] = value
+ this.markDirty(accessor)
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DummyEntityFactory.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DummyEntityFactory.kt
new file mode 100644
index 00000000..ca7af496
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/DummyEntityFactory.kt
@@ -0,0 +1,16 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.internal.entities.EcoDummyEntity
+import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
+import org.bukkit.Location
+import org.bukkit.craftbukkit.v1_20_R3.CraftWorld
+import org.bukkit.entity.Entity
+import org.bukkit.entity.EntityType
+import org.bukkit.entity.Zombie
+
+class DummyEntityFactory : DummyEntityFactoryProxy {
+ override fun createDummyEntity(location: Location): Entity {
+ val world = location.world as CraftWorld
+ return EcoDummyEntity(world.createEntity(location, Zombie::class.java))
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/EntityControllerFactory.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/EntityControllerFactory.kt
new file mode 100644
index 00000000..0986c8c4
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/EntityControllerFactory.kt
@@ -0,0 +1,12 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.entities.ai.EntityController
+import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
+import com.willfp.eco.internal.spigot.proxy.v1_20_R3.entity.EcoEntityController
+import org.bukkit.entity.Mob
+
+class EntityControllerFactory : EntityControllerFactoryProxy {
+ override fun createEntityController(entity: T): EntityController {
+ return EcoEntityController(entity)
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/ExtendedPersistentDataContainerFactory.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/ExtendedPersistentDataContainerFactory.kt
new file mode 100644
index 00000000..fe688996
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/ExtendedPersistentDataContainerFactory.kt
@@ -0,0 +1,82 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.data.ExtendedPersistentDataContainer
+import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
+import net.minecraft.nbt.Tag
+import org.bukkit.Material
+import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack
+import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataContainer
+import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataTypeRegistry
+import org.bukkit.inventory.ItemStack
+import org.bukkit.persistence.PersistentDataContainer
+import org.bukkit.persistence.PersistentDataType
+
+class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFactoryProxy {
+ private val registry: CraftPersistentDataTypeRegistry
+
+ init {
+ /*
+ Can't grab actual instance since it's in CraftMetaItem (which is package-private)
+ And getting it would mean more janky reflection
+ */
+ val item = CraftItemStack.asCraftCopy(ItemStack(Material.STONE))
+ val pdc = item.itemMeta!!.persistentDataContainer
+ this.registry = CraftPersistentDataContainer::class.java.getDeclaredField("registry")
+ .apply { isAccessible = true }.get(pdc) as CraftPersistentDataTypeRegistry
+ }
+
+ override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer {
+ return when (pdc) {
+ is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc)
+ else -> throw IllegalArgumentException("Custom PDC instance ims not supported!")
+ }
+ }
+
+ override fun newPdc(): PersistentDataContainer {
+ return CraftPersistentDataContainer(registry)
+ }
+
+ inner class EcoPersistentDataContainer(
+ private val handle: CraftPersistentDataContainer
+ ) : ExtendedPersistentDataContainer {
+ @Suppress("UNCHECKED_CAST")
+ private val customDataTags: MutableMap =
+ CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags")
+ .apply { isAccessible = true }.get(handle) as MutableMap
+
+ override fun set(key: String, dataType: PersistentDataType, value: Z) {
+ customDataTags[key] =
+ registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, handle.adapterContext))
+ }
+
+ override fun has(key: String, dataType: PersistentDataType): Boolean {
+ val value = customDataTags[key] ?: return false
+ return registry.isInstanceOf(dataType.primitiveType, value)
+ }
+
+ override fun get(key: String, dataType: PersistentDataType): Z? {
+ val value = customDataTags[key] ?: return null
+ return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), handle.adapterContext)
+ }
+
+ override fun getOrDefault(
+ key: String,
+ dataType: PersistentDataType,
+ defaultValue: Z
+ ): Z {
+ return get(key, dataType) ?: defaultValue
+ }
+
+ override fun remove(key: String) {
+ customDataTags.remove(key)
+ }
+
+ override fun getAllKeys(): MutableSet {
+ return customDataTags.keys
+ }
+
+ override fun getBase(): PersistentDataContainer {
+ return handle
+ }
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/FastItemStackFactory.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/FastItemStackFactory.kt
new file mode 100644
index 00000000..89323482
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/FastItemStackFactory.kt
@@ -0,0 +1,12 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.fast.FastItemStack
+import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
+import com.willfp.eco.internal.spigot.proxy.common.item.EcoFastItemStack
+import org.bukkit.inventory.ItemStack
+
+class FastItemStackFactory : FastItemStackFactoryProxy {
+ override fun create(itemStack: ItemStack): FastItemStack {
+ return EcoFastItemStack(itemStack)
+ }
+}
\ No newline at end of file
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/MiniMessageTranslator.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/MiniMessageTranslator.kt
new file mode 100644
index 00000000..a85f90d7
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/MiniMessageTranslator.kt
@@ -0,0 +1,33 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.display.Display
+import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
+import com.willfp.eco.util.toLegacy
+import net.kyori.adventure.text.minimessage.MiniMessage
+
+class MiniMessageTranslator : MiniMessageTranslatorProxy {
+ override fun format(message: String): String {
+ var mut = message
+
+ val startsWithPrefix = mut.startsWith(Display.PREFIX)
+ if (startsWithPrefix) {
+ mut = mut.substring(2)
+ }
+
+ mut = mut.replace('ยง', '&')
+
+ val miniMessage = runCatching {
+ MiniMessage.miniMessage().deserialize(
+ mut
+ ).toLegacy()
+ }.getOrNull() ?: mut
+
+ mut = if (startsWithPrefix) {
+ Display.PREFIX + miniMessage
+ } else {
+ miniMessage
+ }
+
+ return mut
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/PacketHandler.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/PacketHandler.kt
new file mode 100644
index 00000000..0fd417ee
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/PacketHandler.kt
@@ -0,0 +1,46 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.EcoPlugin
+import com.willfp.eco.core.packet.PacketListener
+import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
+import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
+import net.minecraft.network.protocol.Packet
+import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer
+import org.bukkit.entity.Player
+
+class PacketHandler : PacketHandlerProxy {
+ override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
+ if (player !is CraftPlayer) {
+ return
+ }
+
+ val handle = packet.handle
+
+ if (handle !is Packet<*>) {
+ return
+ }
+
+ player.handle.connection.send(handle)
+ }
+
+ override fun clearDisplayFrames() {
+ clearFrames()
+ }
+
+ override fun getPacketListeners(plugin: EcoPlugin): List {
+ return listOf(
+ PacketAutoRecipe(plugin),
+ PacketHeldItemSlot,
+ PacketOpenWindowMerchant,
+ PacketSetCreativeSlot,
+ PacketSetSlot,
+ PacketWindowItems(plugin)
+ )
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/SNBTConverter.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/SNBTConverter.kt
new file mode 100644
index 00000000..d40e7adc
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/SNBTConverter.kt
@@ -0,0 +1,52 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.core.items.TestableItem
+import com.willfp.eco.core.recipe.parts.EmptyTestableItem
+import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.nbt.SnbtPrinterTagVisitor
+import net.minecraft.nbt.TagParser
+import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack
+import org.bukkit.inventory.ItemStack
+
+class SNBTConverter : SNBTConverterProxy {
+ override fun fromSNBT(snbt: String): ItemStack? {
+ val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
+ val nms = net.minecraft.world.item.ItemStack.of(nbt)
+ return CraftItemStack.asBukkitCopy(nms)
+ }
+
+ override fun toSNBT(itemStack: ItemStack): String {
+ val nms = CraftItemStack.asNMSCopy(itemStack)
+ return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
+ }
+
+ override fun makeSNBTTestable(snbt: String): TestableItem {
+ val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
+ val nms = net.minecraft.world.item.ItemStack.of(nbt)
+ if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
+ return EmptyTestableItem()
+ }
+
+ nbt.remove("Count")
+ return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
+ }
+
+ class SNBTTestableItem(
+ private val item: ItemStack,
+ private val tag: CompoundTag
+ ) : TestableItem {
+ override fun matches(itemStack: ItemStack?): Boolean {
+ if (itemStack == null) {
+ return false
+ }
+
+ val nms = CraftItemStack.asNMSCopy(itemStack)
+ val nmsTag = nms.save(CompoundTag())
+ nmsTag.remove("Count")
+ return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
+ }
+
+ override fun getItem(): ItemStack = item
+ }
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/Skull.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/Skull.kt
new file mode 100644
index 00000000..5373f8b3
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/Skull.kt
@@ -0,0 +1,18 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.internal.spigot.proxy.SkullProxy
+import com.willfp.eco.internal.spigot.proxy.common.texture
+import org.bukkit.inventory.meta.SkullMeta
+
+class Skull : SkullProxy {
+ override fun setSkullTexture(
+ meta: SkullMeta,
+ base64: String
+ ) {
+ meta.texture = base64
+ }
+
+ override fun getSkullTexture(
+ meta: SkullMeta
+ ): String? = meta.texture
+}
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/TPS.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/TPS.kt
new file mode 100644
index 00000000..0e6f5c78
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/TPS.kt
@@ -0,0 +1,11 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3
+
+import com.willfp.eco.internal.spigot.proxy.TPSProxy
+import org.bukkit.Bukkit
+import org.bukkit.craftbukkit.v1_20_R3.CraftServer
+
+class TPS : TPSProxy {
+ override fun getTPS(): Double {
+ return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
+ }
+}
\ No newline at end of file
diff --git a/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/entity/EcoEntityController.kt b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/entity/EcoEntityController.kt
new file mode 100644
index 00000000..db84c2e5
--- /dev/null
+++ b/eco-core/core-nms/v1_20_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_20_R3/entity/EcoEntityController.kt
@@ -0,0 +1,95 @@
+package com.willfp.eco.internal.spigot.proxy.v1_20_R3.entity
+
+import com.willfp.eco.core.entities.ai.CustomGoal
+import com.willfp.eco.core.entities.ai.EntityController
+import com.willfp.eco.core.entities.ai.EntityGoal
+import com.willfp.eco.core.entities.ai.TargetGoal
+import com.willfp.eco.internal.spigot.proxy.common.ai.CustomGoalFactory
+import com.willfp.eco.internal.spigot.proxy.common.ai.getGoalFactory
+import com.willfp.eco.internal.spigot.proxy.common.toPathfinderMob
+import net.minecraft.world.entity.PathfinderMob
+import net.minecraft.world.entity.ai.goal.Goal
+import org.bukkit.entity.Mob
+
+class EcoEntityController(
+ private val handle: T
+) : EntityController {
+ override fun addEntityGoal(priority: Int, goal: EntityGoal): EntityController {
+ val nms = getNms() ?: return this
+
+ nms.goalSelector.addGoal(
+ priority,
+ goal.getGoalFactory()?.create(goal, nms) ?: return this
+ )
+
+ return this
+ }
+
+ override fun removeEntityGoal(goal: EntityGoal): EntityController {
+ val nms = getNms() ?: return this
+
+ val predicate: (Goal) -> Boolean = if (goal is CustomGoal<*>) {
+ { CustomGoalFactory.isGoalOfType(it, goal) }
+ } else {
+ { goal.getGoalFactory()?.isGoalOfType(it) == true }
+ }
+
+ for (wrapped in nms.goalSelector.availableGoals.toSet()) {
+ if (predicate(wrapped.goal)) {
+ nms.goalSelector.removeGoal(wrapped.goal)
+ }
+ }
+
+ return this
+ }
+
+ override fun clearEntityGoals(): EntityController {
+ val nms = getNms() ?: return this
+ nms.goalSelector.availableGoals.clear()
+ return this
+ }
+
+ override fun addTargetGoal(priority: Int, goal: TargetGoal): EntityController {
+ val nms = getNms() ?: return this
+
+ nms.targetSelector.addGoal(
+ priority, goal.getGoalFactory()?.create(goal, nms) ?: return this
+ )
+
+ nms.targetSelector
+
+ return this
+ }
+
+ override fun removeTargetGoal(goal: TargetGoal): EntityController {
+ val nms = getNms() ?: return this
+
+ val predicate: (Goal) -> Boolean = if (goal is CustomGoal<*>) {
+ { CustomGoalFactory.isGoalOfType(it, goal) }
+ } else {
+ { goal.getGoalFactory()?.isGoalOfType(it) == true }
+ }
+
+ for (wrapped in nms.targetSelector.availableGoals.toSet()) {
+ if (predicate(wrapped.goal)) {
+ nms.targetSelector.removeGoal(wrapped.goal)
+ }
+ }
+
+ return this
+ }
+
+ override fun clearTargetGoals(): EntityController {
+ val nms = getNms() ?: return this
+ nms.targetSelector.availableGoals.clear()
+ return this
+ }
+
+ private fun getNms(): PathfinderMob? {
+ return handle.toPathfinderMob()
+ }
+
+ override fun getEntity(): T {
+ return handle
+ }
+}
\ No newline at end of file
diff --git a/eco-core/core-plugin/build.gradle.kts b/eco-core/core-plugin/build.gradle.kts
index 47f4a1ce..827c788b 100644
--- a/eco-core/core-plugin/build.gradle.kts
+++ b/eco-core/core-plugin/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.gradle.internal.impldep.org.junit.experimental.categories.Categories.CategoryFilter.exclude
+
group = "com.willfp"
version = rootProject.version
@@ -15,20 +17,21 @@ dependencies {
implementation("net.kyori:adventure-platform-bukkit:4.1.0")
implementation("org.javassist:javassist:3.29.2-GA")
implementation("org.mongodb:mongodb-driver-sync:4.6.0")
- implementation("org.litote.kmongo:kmongo-coroutine:4.6.0")
+ implementation("org.litote.kmongo:kmongo-coroutine:4.10.0")
implementation("com.moandjiezana.toml:toml4j:0.7.2") {
exclude(group = "com.google.code.gson", module = "gson")
}
+ implementation("com.willfp:ModelEngineBridge:1.2.0")
// Included in spigot jar
compileOnly("com.google.code.gson:gson:2.8.8")
- compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
+ compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT")
// Plugin dependencies
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT")
compileOnly("com.github.TechFortress:GriefPrevention:16.17.1")
- compileOnly("com.github.TownyAdvanced:Towny:0.97.2.6") {
+ compileOnly("com.github.TownyAdvanced:Towny:0.99.5.21") {
exclude(group = "com.zaxxer", module = "HikariCP")
}
compileOnly("com.github.angeschossen:LandsAPI:6.26.18")
@@ -36,8 +39,7 @@ dependencies {
compileOnly("fr.neatmonster:nocheatplus:3.16.1-SNAPSHOT")
compileOnly("com.github.jiangdashao:matrix-api-repo:317d4635fd")
compileOnly("com.gmail.nossr50.mcMMO:mcMMO:2.1.202")
- compileOnly("me.clip:placeholderapi:2.10.10")
- compileOnly("com.github.oraxen:oraxen:1.155.0")
+ compileOnly("me.clip:placeholderapi:2.11.4")
compileOnly("com.github.brcdev-minecraft:shopgui-api:3.0.0")
compileOnly("com.github.LoneDev6:API-ItemsAdder:2.4.7")
compileOnly("com.arcaniax:HeadDatabase-API:1.3.1")
@@ -46,11 +48,9 @@ dependencies {
compileOnly("com.bgsoftware:SuperiorSkyblockAPI:1.8.3")
compileOnly("com.github.MilkBowl:VaultAPI:1.7")
compileOnly("com.github.WhipDevelopment:CrashClaim:f9cd7d92eb")
- compileOnly("com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0")
- compileOnly("com.github.decentsoftware-eu:decentholograms:2.1.2")
+ compileOnly("com.github.decentsoftware-eu:decentholograms:2.8.5")
compileOnly("com.github.Gypopo:EconomyShopGUI-API:1.4.6")
compileOnly("com.github.N0RSKA:ScytherAPI:55a")
- compileOnly("com.ticxo.modelengine:api:R3.0.1")
compileOnly("org.black_ixx:playerpoints:3.2.5")
compileOnly("com.github.Ssomar-Developement:SCore:3.4.7")
compileOnly("io.lumine:Mythic:5.3.5")
@@ -61,6 +61,7 @@ dependencies {
compileOnly("com.denizenscript:denizen:1.2.7-SNAPSHOT") {
exclude(group = "*", module = "*")
}
+ compileOnly("com.iridium:IridiumSkyblock:4.0.8")
compileOnly(fileTree("../../lib") {
include("*.jar")
@@ -72,6 +73,7 @@ tasks {
minimize {
exclude(dependency("org.litote.kmongo:kmongo-coroutine:.*"))
exclude(dependency("org.jetbrains.exposed:.*:.*"))
+ exclude(dependency("com.willfp:ModelEngineBridge:.*"))
}
}
diff --git a/eco-core/core-plugin/src/main/kotlin/com/mongodb/diagnostics/logging/Loggers.kt b/eco-core/core-plugin/src/main/kotlin/com/mongodb/internal/diagnostics/logging/Loggers.kt
similarity index 93%
rename from eco-core/core-plugin/src/main/kotlin/com/mongodb/diagnostics/logging/Loggers.kt
rename to eco-core/core-plugin/src/main/kotlin/com/mongodb/internal/diagnostics/logging/Loggers.kt
index 8ff03fd9..9e3f88b7 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/mongodb/diagnostics/logging/Loggers.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/mongodb/internal/diagnostics/logging/Loggers.kt
@@ -1,4 +1,4 @@
-package com.mongodb.diagnostics.logging
+package com.mongodb.internal.diagnostics.logging
/*
This is a terrible fix for mongo logging.
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoImpl.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoImpl.kt
index 6cfa89fc..da412af9 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoImpl.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoImpl.kt
@@ -4,6 +4,7 @@ import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.PluginProps
+import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.command.CommandBase
import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.core.config.ConfigType
@@ -51,6 +52,7 @@ import com.willfp.eco.internal.spigot.math.ImmediatePlaceholderTranslationExpres
import com.willfp.eco.internal.spigot.math.LazyPlaceholderTranslationExpressionHandler
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
+import com.willfp.eco.internal.spigot.proxy.DisplayNameProxy
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
@@ -60,10 +62,12 @@ import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy
+import net.kyori.adventure.text.Component
import org.bukkit.Location
import org.bukkit.NamespacedKey
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.entity.Entity
+import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
@@ -346,4 +350,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
override fun getPlaceholderValue(plugin: EcoPlugin?, args: String, context: PlaceholderContext) =
placeholderParser.getPlaceholderResult(plugin, args, context)
+
+ override fun setClientsideDisplayName(entity: LivingEntity, player: Player, name: Component, visible: Boolean) =
+ this.getProxy(DisplayNameProxy::class.java).setClientsideDisplayName(entity, player, name, visible)
}
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt
index b427a3d9..e5eb6706 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt
@@ -209,6 +209,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
profileHandler.migrateIfNeeded()
}
+ profileHandler.startAutosaving()
+
ProfileSaver(this, profileHandler).startTicking()
this.scheduler.runTimer(
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt
index 72ba1062..f8331604 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt
@@ -29,7 +29,7 @@ abstract class EcoProfile(
return this.data[key] as T
}
- this.data[key] = if (key.isLocal) {
+ this.data[key] = if (key.isSavedLocally) {
localHandler.read(uuid, key)
} else {
handler.read(uuid, key)
@@ -104,6 +104,7 @@ class EcoServerProfile(
}
}
-private val PersistentDataKey<*>.isLocal: Boolean
- get() = this == localServerIDKey || EcoPlugin.getPlugin(this.key.namespace)?.isUsingLocalStorage == true
- || this.isLocalStorage
+private val PersistentDataKey<*>.isSavedLocally: Boolean
+ get() = this == localServerIDKey
+ || EcoPlugin.getPlugin(this.key.namespace)?.isUsingLocalStorage == true
+ || this.isLocal
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt
index 76648060..0809ee12 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt
@@ -169,4 +169,17 @@ class ProfileHandler(
localHandler.initialize()
}
}
+
+ fun startAutosaving() {
+ if (!plugin.configYml.getBool("yaml.autosave")) {
+ return
+ }
+
+ val interval = plugin.configYml.getInt("yaml.autosave-interval") * 20L
+
+ plugin.scheduler.runTimer(20, interval) {
+ handler.saveAsync()
+ localHandler.saveAsync()
+ }
+ }
}
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt
index 1da537d1..0855a066 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt
@@ -27,6 +27,10 @@ abstract class DataHandler(
}
+ open fun saveAsync() {
+
+ }
+
open fun initialize() {
}
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt
index 1174799a..edbf73b6 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt
@@ -18,6 +18,10 @@ class YamlDataHandler(
dataYml.save()
}
+ override fun saveAsync() {
+ dataYml.saveAsync()
+ }
+
override fun read(uuid: UUID, key: PersistentDataKey): T? {
// Separate `as T?` for each branch to prevent compiler warnings.
val value = when (key.type) {
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/antigrief/AntigriefIridiumSkyblock.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/antigrief/AntigriefIridiumSkyblock.kt
index 8aeea0d0..1634ead4 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/antigrief/AntigriefIridiumSkyblock.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/antigrief/AntigriefIridiumSkyblock.kt
@@ -1,7 +1,7 @@
package com.willfp.eco.internal.spigot.integrations.antigrief
-import com.iridium.iridiumskyblock.PermissionType
import com.iridium.iridiumskyblock.api.IridiumSkyblockAPI
+import com.iridium.iridiumteams.PermissionType
import com.willfp.eco.core.integrations.antigrief.AntigriefIntegration
import org.bukkit.Location
import org.bukkit.block.Block
@@ -49,8 +49,13 @@ class AntigriefIridiumSkyblock : AntigriefIntegration {
}
override fun canPickupItem(player: Player, location: Location): Boolean {
+ return true
+ /*
val api = IridiumSkyblockAPI.getInstance()
return api.getIslandPermission(api.getIslandViaLocation(location).orElse(null) ?: return true, api.getUser(player), PermissionType.PICKUP_ITEMS)
+
+ PICKUP_ITEMS was removed in Iridium v4
+ */
}
override fun getPluginName(): String {
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/entitylookup/EntityLookupModelEngine.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/entitylookup/EntityLookupModelEngine.kt
index 8f1185e9..ae9b6708 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/entitylookup/EntityLookupModelEngine.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/entitylookup/EntityLookupModelEngine.kt
@@ -1,10 +1,10 @@
package com.willfp.eco.internal.spigot.integrations.entitylookup
-import com.ticxo.modelengine.api.ModelEngineAPI
import com.willfp.eco.core.entities.Entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import com.willfp.eco.core.integrations.Integration
+import com.willfp.modelenginebridge.ModelEngineBridge
object EntityLookupModelEngine : Integration {
fun register() {
@@ -18,7 +18,6 @@ object EntityLookupModelEngine : Integration {
private object EntityArgParserModelEngine : EntityArgParser {
override fun parseArguments(args: Array): EntityArgParseResult? {
var id: String? = null
- var animation: String? = null
for (arg in args) {
val argSplit = arg.split(":")
@@ -29,10 +28,7 @@ object EntityLookupModelEngine : Integration {
continue
}
- val modelEngineInfo = argSplit[1].split(",")
-
- id = modelEngineInfo.getOrNull(0)
- animation = modelEngineInfo.getOrNull(1)
+ id = argSplit[1]
}
if (id == null) {
@@ -41,24 +37,16 @@ object EntityLookupModelEngine : Integration {
return EntityArgParseResult(
{
- val modelled = ModelEngineAPI.getModeledEntity(it.uniqueId) ?: return@EntityArgParseResult false
+ val modelled =
+ ModelEngineBridge.instance.getModeledEntity(it.uniqueId) ?: return@EntityArgParseResult false
modelled.models.containsKey(id)
},
{
- val model = ModelEngineAPI.createActiveModel(id)
+ val model = ModelEngineBridge.instance.createActiveModel(id) ?: return@EntityArgParseResult
- if (animation != null) {
- val handler = model.animationHandler
- val property = handler.getAnimation(animation)
-
- if (property != null) {
- handler.playAnimation(property, true)
- }
- }
-
- val modelled = ModelEngineAPI.createModeledEntity(it)
- modelled.addModel(model, true)
+ val modelled = ModelEngineBridge.instance.createModeledEntity(it)
+ modelled.addModel(model)
}
)
}
diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/hologram/HologramDecentHolograms.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/hologram/HologramDecentHolograms.kt
index 7a78eb3a..5951d1ad 100644
--- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/hologram/HologramDecentHolograms.kt
+++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/integrations/hologram/HologramDecentHolograms.kt
@@ -7,7 +7,7 @@ import org.bukkit.Location
import java.util.UUID
class HologramDecentHolograms : HologramIntegration {
- override fun createHologram(location: Location, contents: MutableList): Hologram {
+ override fun createHologram(location: Location, contents: List): Hologram {
val id = UUID.randomUUID().toString()
DHAPI.createHologram(id, location, contents)
@@ -26,8 +26,8 @@ class HologramDecentHolograms : HologramIntegration {
DHAPI.getHologram(id)?.destroy()
}
- override fun setContents(contents: MutableList) {
+ override fun setContents(contents: List) {
DHAPI.setHologramLines(DHAPI.getHologram(id), contents)
}
}
-}
\ No newline at end of file
+}
diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml
index ed17ec4b..dc1f4ecb 100644
--- a/eco-core/core-plugin/src/main/resources/config.yml
+++ b/eco-core/core-plugin/src/main/resources/config.yml
@@ -30,6 +30,10 @@ mysql:
user: username
password: passy
+yaml:
+ autosave: true # If data should be saved automatically
+ autosave-interval: 1800 # How often data should be saved (in seconds)
+
# How many ticks to wait between committing data to a database. This doesn't
# affect yaml storage, only MySQL and MongoDB. By default, data is committed
# every tick, but you can increase this to be every x ticks, for example 20
diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml
index 54bd9317..393e0681 100644
--- a/eco-core/core-plugin/src/main/resources/lang.yml
+++ b/eco-core/core-plugin/src/main/resources/lang.yml
@@ -2,6 +2,7 @@ multiple-in-craft: '&l&c! &fThis recipe requires &a%amount%&f of this item.'
# Specify default display names for prices made through ConfiguredPrice#create
# These will override any custom configured price display names.
+# You can use %value% and %value_commas% as placeholders.
price-display:
- type: example_type
display: "&e%value% Price"
diff --git a/eco-core/core-plugin/src/main/resources/paper-plugin.yml b/eco-core/core-plugin/src/main/resources/paper-plugin.yml
deleted file mode 100644
index 1280303e..00000000
--- a/eco-core/core-plugin/src/main/resources/paper-plugin.yml
+++ /dev/null
@@ -1,206 +0,0 @@
-name: eco
-version: ${projectVersion}
-main: com.willfp.eco.internal.spigot.EcoImpl
-api-version: 1.19
-load: STARTUP
-
-dependencies:
- - name: Terra
- required: false
- bootstrap: false
-
- - name: ProtocolLib
- required: false
- bootstrap: false
-
- - name: WorldGuard
- required: false
- bootstrap: false
-
- - name: GriefPrevention
- required: false
- bootstrap: false
-
- - name: Towny
- required: false
- bootstrap: false
-
- - name: FactionsUUID
- required: false
- bootstrap: false
-
- - name: Lands
- required: false
- bootstrap: false
-
- - name: Kingdoms
- required: false
- bootstrap: false
-
- - name: NoCheatPlus
- required: false
- bootstrap: false
-
- - name: AAC
- required: false
- bootstrap: false
-
- - name: Matrix
- required: false
- bootstrap: false
-
- - name: Spartan
- required: false
- bootstrap: false
-
- - name: Vulcan
- required: false
- bootstrap: false
-
- - name: PlaceholderAPI
- required: false
- bootstrap: false
-
- - name: mcMMO
- required: false
- bootstrap: false
-
- - name: CombatLogX
- required: false
- bootstrap: false
-
- - name: ShopGUIPlus
- required: false
- bootstrap: false
-
- - name: ItemsAdder
- required: false
- bootstrap: false
-
- - name: Oraxen
- required: false
- bootstrap: false
-
- - name: HeadDatabase
- required: false
- bootstrap: false
-
- - name: Multiverse-Inventories
- required: false
- bootstrap: false
-
- - name: Alice
- required: false
- bootstrap: false
-
- - name: HolographicDisplays
- required: false
- bootstrap: false
-
- - name: GHolo
- required: false
- bootstrap: false
-
- - name: CMI
- required: false
- bootstrap: false
-
- - name: Essentials
- required: false
- bootstrap: false
-
- - name: Vault
- required: false
- bootstrap: false
-
- - name: BentoBox
- required: false
- bootstrap: false
-
- - name: DeluxeCombat
- required: false
- bootstrap: false
-
- - name: IridiumSkyblock
- required: false
- bootstrap: false
-
- - name: SuperiorSkyblock2
- required: false
- bootstrap: false
-
- - name: FabledSkyBlock
- required: false
- bootstrap: false
-
- - name: CrashClaim
- required: false
- bootstrap: false
-
- - name: DecentHolograms
- required: false
- bootstrap: false
-
- - name: MythicMobs
- required: false
- bootstrap: false
-
- - name: CustomCrafting
- required: false
- bootstrap: false
-
- - name: ExecutableItems
- required: false
- bootstrap: false
-
- - name: RPGHorses
- required: false
- bootstrap: false
-
- - name: EconomyShopGUI
- required: false
- bootstrap: false
-
- - name: EconomyShopGUI-Premium
- required: false
- bootstrap: false
-
- - name: zShop
- required: false
- bootstrap: false
-
- - name: DeluxeSellwands
- required: false
- bootstrap: false
-
- - name: Scyther
- required: false
- bootstrap: false
-
- - name: ModelEngine
- required: false
- bootstrap: false
-
- - name: PvPManager
- required: false
- bootstrap: false
-
- - name: DeluxeMenus
- required: false
- bootstrap: false
-
- - name: UltraEconomy
- required: false
- bootstrap: false
-
- - name: PlayerPoints
- required: false
- bootstrap: false
-
- - name: Denizen
- required: false
- bootstrap: false
-
- - name: RoyaleEconomy
- required: false
- bootstrap: false
\ No newline at end of file
diff --git a/eco-core/core-plugin/src/main/resources/plugin.yml b/eco-core/core-plugin/src/main/resources/plugin.yml
index d81192a2..daf61b6f 100644
--- a/eco-core/core-plugin/src/main/resources/plugin.yml
+++ b/eco-core/core-plugin/src/main/resources/plugin.yml
@@ -5,6 +5,14 @@ api-version: 1.17
authors: [ Auxilor ]
website: willfp.com
load: STARTUP
+
+# Fixes some plugins breaking load order
+loadbefore:
+ - Spartan
+ - CustomCrafting
+ - Lands
+ - EconomyShopGUI
+ - EconomyShopGUI-Premium
softdepend:
- Terra
- ProtocolLib
@@ -12,12 +20,10 @@ softdepend:
- GriefPrevention
- Towny
- FactionsUUID
- - Lands
- Kingdoms
- NoCheatPlus
- AAC
- Matrix
- - Spartan
- Vulcan
- PlaceholderAPI
- mcMMO
@@ -41,11 +47,8 @@ softdepend:
- CrashClaim
- DecentHolograms
- MythicMobs
- - CustomCrafting
- ExecutableItems
- RPGHorses
- - EconomyShopGUI
- - EconomyShopGUI-Premium
- zShop
- DeluxeSellwands
- Scyther
diff --git a/eco-core/core-proxy/build.gradle.kts b/eco-core/core-proxy/build.gradle.kts
index aa3d2617..457a3a36 100644
--- a/eco-core/core-proxy/build.gradle.kts
+++ b/eco-core/core-proxy/build.gradle.kts
@@ -2,5 +2,5 @@ group = "com.willfp"
version = rootProject.version
dependencies {
- compileOnly("org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT")
+ compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")
}
diff --git a/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/DisplayNameProxy.kt b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/DisplayNameProxy.kt
new file mode 100644
index 00000000..a8ebae5b
--- /dev/null
+++ b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/DisplayNameProxy.kt
@@ -0,0 +1,9 @@
+package com.willfp.eco.internal.spigot.proxy
+
+import net.kyori.adventure.text.Component
+import org.bukkit.entity.LivingEntity
+import org.bukkit.entity.Player
+
+interface DisplayNameProxy {
+ fun setClientsideDisplayName(entity: LivingEntity, player: Player, displayName: Component, visible: Boolean)
+}
diff --git a/gradle.properties b/gradle.properties
index a60489b5..244dbe0a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,2 @@
-version = 6.66.1
-plugin-name = eco
-kotlin.code.style = official
\ No newline at end of file
+version = 6.68.3
+kotlin.incremental.useClasspathSnapshot=false
\ No newline at end of file
diff --git a/jitpack.yml b/jitpack.yml
deleted file mode 100644
index caba981a..00000000
--- a/jitpack.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-jdk: openjdk17
-before_install:
- - source "$HOME/.sdkman/bin/sdkman-init.sh"
- - sdk update
- - sdk install java 17.0.1-tem
- - sdk use java 17.0.1-tem
\ No newline at end of file
diff --git a/lib/FabledSkyblock-3.jar b/lib/FabledSkyblock-3.jar
new file mode 100644
index 00000000..56d57f90
Binary files /dev/null and b/lib/FabledSkyblock-3.jar differ
diff --git a/lib/IridiumSkyblock-3.2.8.jar b/lib/IridiumSkyblock-3.2.8.jar
deleted file mode 100644
index c2b71c93..00000000
Binary files a/lib/IridiumSkyblock-3.2.8.jar and /dev/null differ
diff --git a/lib/customcrafting-spigot-3.16.0.0-f.jar b/lib/customcrafting-spigot-3.16.0.0-f.jar
deleted file mode 100644
index d3f0e00d..00000000
Binary files a/lib/customcrafting-spigot-3.16.0.0-f.jar and /dev/null differ
diff --git a/lib/customcrafting-spigot-4.16.8.5.jar b/lib/customcrafting-spigot-4.16.8.5.jar
new file mode 100644
index 00000000..09dee03f
Binary files /dev/null and b/lib/customcrafting-spigot-4.16.8.5.jar differ
diff --git a/lib/oraxen-1.164.1.jar b/lib/oraxen-1.164.1.jar
new file mode 100644
index 00000000..f9c38757
Binary files /dev/null and b/lib/oraxen-1.164.1.jar differ
diff --git a/lib/wolfyutils-spigot-4.16.14.1.jar b/lib/wolfyutils-spigot-4.16.14.1.jar
new file mode 100644
index 00000000..d1b4f873
Binary files /dev/null and b/lib/wolfyutils-spigot-4.16.14.1.jar differ
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 228bf5f8..134968d0 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -20,6 +20,7 @@ include(":eco-core:core-nms:v1_19_R2")
include(":eco-core:core-nms:v1_19_R3")
include(":eco-core:core-nms:v1_20_R1")
include(":eco-core:core-nms:v1_20_R2")
+include(":eco-core:core-nms:v1_20_R3")
include(":eco-core:core-proxy")
include(":eco-core:core-plugin")
include(":eco-core:core-backend")
\ No newline at end of file