diff --git a/README.md b/README.md index 79f194d3..a238868c 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ cd eco ## License -eco is licensed under GNU GPL3. *Click here to read [the entire license](https://github.com/Auxilor/eco/blob/master/LICENSE.md).* +eco is licensed under the MIT license. *Click here to read [the entire license](https://github.com/Auxilor/eco/blob/master/LICENSE.md).*

Check out our partners! diff --git a/build.gradle.kts b/build.gradle.kts index 476b4417..2bd6aca2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21") } } @@ -13,7 +13,7 @@ plugins { id("com.github.johnrengelman.shadow") version "8.1.1" id("maven-publish") id("java") - kotlin("jvm") version "1.7.10" + kotlin("jvm") version "1.9.21" } dependencies { @@ -29,6 +29,7 @@ dependencies { implementation(project(path = ":eco-core:core-nms:v1_19_R3", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_20_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_20_R2", configuration = "reobf")) + implementation(project(path = ":eco-core:core-nms:v1_20_R3", configuration = "reobf")) } allprojects { @@ -41,11 +42,9 @@ allprojects { repositories { mavenCentral() mavenLocal() + maven("https://repo.auxilor.io/repository/maven-public/") maven("https://jitpack.io") - // CustomCrafting - maven("https://maven.wolfyscript.com/repository/public/") - // SuperiorSkyblock2 maven("https://repo.bg-software.com/repository/api/") @@ -87,20 +86,23 @@ allprojects { // Denizen maven("https://maven.citizensnpcs.co/repo") + + // IridiumSkyblock + maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/") } dependencies { // Kotlin - implementation(kotlin("stdlib", version = "1.7.10")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2") + implementation(kotlin("stdlib", version = "1.9.21")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Included in spigot jar, no need to move to implementation compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("com.google.guava:guava:31.1-jre") // Test - testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") // Adventure implementation("net.kyori:adventure-api:4.10.1") @@ -110,8 +112,8 @@ allprojects { implementation("net.kyori:adventure-text-serializer-legacy:4.10.1") // Other - implementation("com.github.ben-manes.caffeine:caffeine:3.1.0") - implementation("org.apache.maven:maven-artifact:3.8.5") + implementation("com.github.ben-manes.caffeine:caffeine:3.1.5") + implementation("org.apache.maven:maven-artifact:3.9.0") } tasks.withType { @@ -169,6 +171,7 @@ allprojects { relocate("org.reactivestreams", "com.willfp.eco.libs.reactivestreams") relocate("reactor.", "com.willfp.eco.libs.reactor.") // Dot in name to be safe relocate("com.moandjiezana.toml", "com.willfp.eco.libs.toml") + relocate("com.willfp.modelenginebridge", "com.willfp.eco.libs.modelenginebridge") /* Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins. diff --git a/eco-api/build.gradle.kts b/eco-api/build.gradle.kts index 2469709d..4d7b406c 100644 --- a/eco-api/build.gradle.kts +++ b/eco-api/build.gradle.kts @@ -3,7 +3,8 @@ dependencies { compileOnly("net.kyori:adventure-platform-bukkit:4.1.0") // Other - compileOnly("org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT") + compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") + compileOnly("commons-lang:commons-lang:2.6") compileOnly("com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT") compileOnly("com.google.code.gson:gson:2.8.8") } diff --git a/eco-api/src/main/java/com/willfp/eco/core/Eco.java b/eco-api/src/main/java/com/willfp/eco/core/Eco.java index 9363842b..e5e919dc 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/Eco.java +++ b/eco-api/src/main/java/com/willfp/eco/core/Eco.java @@ -30,11 +30,13 @@ import com.willfp.eco.core.placeholder.context.PlaceholderContext; import com.willfp.eco.core.proxy.ProxyFactory; import com.willfp.eco.core.scheduling.Scheduler; import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.Component; import org.apache.commons.lang.Validate; 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; @@ -587,6 +589,19 @@ public interface Eco { @NotNull String args, @NotNull PlaceholderContext context); + /** + * 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. + */ + void setClientsideDisplayName(@NotNull LivingEntity entity, + @NotNull Player player, + @NotNull Component name, + boolean visible); + /** * Get the instance of eco; the bridge between the api frontend and the implementation backend. * diff --git a/eco-api/src/main/java/com/willfp/eco/core/PluginProps.java b/eco-api/src/main/java/com/willfp/eco/core/PluginProps.java index 08316bf3..7fd184c7 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/PluginProps.java +++ b/eco-api/src/main/java/com/willfp/eco/core/PluginProps.java @@ -55,7 +55,7 @@ public final class PluginProps { private final Map 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