diff --git a/build.gradle.kts b/build.gradle.kts index 36e62bf5..d26c43a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { implementation(project(":eco-core:core-nms:v1_20_R2")) implementation(project(":eco-core:core-nms:v1_20_R3", configuration = "reobf")) implementation(project(":eco-core:core-nms:v1_20_6", configuration = "reobf")) + implementation(project(":eco-core:core-nms:v1_21", configuration = "reobf")) } allprojects { @@ -41,14 +42,17 @@ allprojects { maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.auxilor.io/repository/maven-public/") - maven("https://jitpack.io") maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://repo.codemc.org/repository/nms/") maven("https://repo.essentialsx.net/releases/") + + maven("https://jitpack.io") { + content { includeGroupByRegex("com\\.github\\..*") } + } } dependencies { - compileOnly("com.willfp:eco:6.70.0") + compileOnly("com.willfp:eco:6.71.0") compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20") compileOnly("com.github.ben-manes.caffeine:caffeine:3.1.5") @@ -65,12 +69,6 @@ allprojects { } } - java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - withSourcesJar() - } - compileJava { options.isDeprecation = true options.encoding = "UTF-8" @@ -91,6 +89,17 @@ allprojects { build { dependsOn(shadowJar) } + + withType().configureEach { + options.release = 17 + } + } + + java { + withSourcesJar() + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } } diff --git a/eco-core/core-nms/build.gradle.kts b/eco-core/core-nms/build.gradle.kts index d15ed517..ca1a5d6c 100644 --- a/eco-core/core-nms/build.gradle.kts +++ b/eco-core/core-nms/build.gradle.kts @@ -1,8 +1,7 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.6.2" apply false + id("io.papermc.paperweight.userdev") version "1.7.1" apply false } - group = "com.willfp" version = rootProject.version diff --git a/eco-core/core-nms/v1_20_6/build.gradle.kts b/eco-core/core-nms/v1_20_6/build.gradle.kts index 517a56f6..afa6679c 100644 --- a/eco-core/core-nms/v1_20_6/build.gradle.kts +++ b/eco-core/core-nms/v1_20_6/build.gradle.kts @@ -14,10 +14,8 @@ tasks { dependsOn(reobfJar) } - java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - withSourcesJar() + compileJava { + options.release = 21 } compileKotlin { diff --git a/eco-core/core-nms/v1_20_R3/build.gradle.kts b/eco-core/core-nms/v1_20_R3/build.gradle.kts index dc278e4a..73670127 100644 --- a/eco-core/core-nms/v1_20_R3/build.gradle.kts +++ b/eco-core/core-nms/v1_20_R3/build.gradle.kts @@ -7,6 +7,7 @@ version = rootProject.version dependencies { paperweight.paperDevBundle("1.20.3-R0.1-SNAPSHOT") + pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat") } tasks { diff --git a/eco-core/core-nms/v1_21/build.gradle.kts b/eco-core/core-nms/v1_21/build.gradle.kts new file mode 100644 index 00000000..118e82d2 --- /dev/null +++ b/eco-core/core-nms/v1_21/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group = "com.willfp" +version = rootProject.version + +dependencies { + paperweight.paperDevBundle("1.21-R0.1-SNAPSHOT") +} + +tasks { + build { + dependsOn(reobfJar) + } + + compileJava { + options.release = 21 + } + + compileKotlin { + kotlinOptions { + jvmTarget = "21" + } + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/HideStoredEnchants.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/HideStoredEnchants.kt new file mode 100644 index 00000000..6b951c48 --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/HideStoredEnchants.kt @@ -0,0 +1,19 @@ +package com.willfp.ecoenchants.proxy.v1_21 + +import com.willfp.eco.core.fast.FastItemStack +import com.willfp.ecoenchants.display.HideStoredEnchantsProxy +import org.bukkit.inventory.ItemFlag + +class HideStoredEnchants: HideStoredEnchantsProxy { + override fun hideStoredEnchants(fis: FastItemStack) { + fis.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS) + } + + override fun areStoredEnchantsHidden(fis: FastItemStack): Boolean { + return fis.hasItemFlag(ItemFlag.HIDE_STORED_ENCHANTS) + } + + override fun showStoredEnchants(fis: FastItemStack) { + fis.removeItemFlags(ItemFlag.HIDE_STORED_ENCHANTS) + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/ModernEnchantmentRegisterer.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/ModernEnchantmentRegisterer.kt new file mode 100644 index 00000000..628390c0 --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/ModernEnchantmentRegisterer.kt @@ -0,0 +1,140 @@ +package com.willfp.ecoenchants.proxy.v1_21 + +import com.willfp.ecoenchants.enchant.EcoEnchant +import com.willfp.ecoenchants.enchant.EcoEnchants +import com.willfp.ecoenchants.enchant.impl.EcoEnchantBase +import com.willfp.ecoenchants.enchant.registration.modern.ModernEnchantmentRegistererProxy +import com.willfp.ecoenchants.proxy.v1_21.registration.EcoEnchantsCraftEnchantment +import com.willfp.ecoenchants.proxy.v1_21.registration.ModifiedVanillaCraftEnchantment +import com.willfp.ecoenchants.proxy.v1_21.registration.vanillaEcoEnchantsEnchantment +import com.willfp.ecoenchants.setStaticFinal +import io.papermc.paper.registry.PaperRegistryAccess +import io.papermc.paper.registry.RegistryAccess +import io.papermc.paper.registry.RegistryKey +import io.papermc.paper.registry.WritableCraftRegistry +import net.minecraft.core.Holder +import net.minecraft.core.MappedRegistry +import net.minecraft.core.Registry +import net.minecraft.core.RegistrySynchronization +import net.minecraft.core.registries.Registries +import net.minecraft.resources.ResourceKey +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.enchantment.Enchantments +import org.bukkit.Bukkit +import org.bukkit.NamespacedKey +import org.bukkit.craftbukkit.CraftRegistry +import org.bukkit.craftbukkit.CraftServer +import org.bukkit.craftbukkit.util.CraftNamespacedKey +import org.bukkit.enchantments.Enchantment +import java.util.HashMap +import java.util.IdentityHashMap +import java.util.function.BiFunction + +private val enchantmentRegistry = + (Bukkit.getServer() as CraftServer).server.registryAccess().registryOrThrow(Registries.ENCHANTMENT) + +@Suppress("DEPRECATION") +private val bukkitRegistry = + org.bukkit.Registry.ENCHANTMENT + +class ModernEnchantmentRegisterer : ModernEnchantmentRegistererProxy { + private val frozenField = MappedRegistry::class.java + .declaredFields + .filter { it.type.isPrimitive }[0] + .apply { isAccessible = true } + + private val unregisteredIntrusiveHoldersField = MappedRegistry::class.java + .declaredFields + .last { it.type == Map::class.java } + .apply { isAccessible = true } + + private val minecraftToBukkit = bukkitRegistry::class.java + .getDeclaredField("minecraftToBukkit") + .apply { isAccessible = true } + + // Paper has two minecraftToBukkit fields, one in CraftRegistry and one in WritableCraftRegistry + private val minecraftToBukkitAlt = CraftRegistry::class.java + .getDeclaredField("minecraftToBukkit") + .apply { isAccessible = true } + + private val cache = CraftRegistry::class.java + .getDeclaredField("cache") + .apply { isAccessible = true } + + @Suppress("UNCHECKED_CAST") + private val vanillaEnchantments = Enchantments::class.java + .declaredFields + .asSequence() + .filter { it.type == ResourceKey::class.java } + .map { it.get(null) as ResourceKey } + .map { it.location() } + .map { CraftNamespacedKey.fromMinecraft(it) } + .toSet() + + override fun replaceRegistry() { + val newRegistryMTB = + BiFunction { key, registry -> + val isVanilla = vanillaEnchantments.contains(key) + val eco = EcoEnchants.getByID(key.key) + + if (isVanilla) { + ModifiedVanillaCraftEnchantment(key, registry) + } else if (eco != null) { + eco as Enchantment + } else { + null + } + } + + // Update bukkit registry + minecraftToBukkit.set(bukkitRegistry, newRegistryMTB) + minecraftToBukkitAlt.set(bukkitRegistry, newRegistryMTB) + + // Clear the enchantment cache + cache.set(bukkitRegistry, mutableMapOf()) + + // Unfreeze NMS registry + frozenField.set(enchantmentRegistry, false) + unregisteredIntrusiveHoldersField.set( + enchantmentRegistry, + IdentityHashMap>() + ) + } + + override fun register(enchant: EcoEnchantBase): Enchantment { + // Clear the enchantment cache + cache.set(bukkitRegistry, mutableMapOf()) + + if (enchantmentRegistry.containsKey(CraftNamespacedKey.toMinecraft(enchant.enchantmentKey))) { + val nms = enchantmentRegistry[CraftNamespacedKey.toMinecraft(enchant.enchantmentKey)] + + if (nms != null) { + return EcoEnchantsCraftEnchantment(enchant, nms) + } else { + throw IllegalStateException("Enchantment ${enchant.id} wasn't registered") + } + } + + val vanillaEnchantment = vanillaEcoEnchantsEnchantment(enchant) + + enchantmentRegistry.createIntrusiveHolder(vanillaEnchantment) + + Registry.register( + enchantmentRegistry, + ResourceLocation.withDefaultNamespace(enchant.id), + vanillaEnchantment + ) + + return register(enchant) + } + + override fun unregister(enchant: EcoEnchant) { + /* + + You can't unregister from a minecraft registry, so we simply leave the stale reference there. + This shouldn't cause many issues in production as the bukkit registry is replaced on each reload. + + */ + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/OpenInventory.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/OpenInventory.kt new file mode 100644 index 00000000..716becd3 --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/OpenInventory.kt @@ -0,0 +1,11 @@ +package com.willfp.ecoenchants.proxy.v1_21 + +import com.willfp.ecoenchants.mechanics.OpenInventoryProxy +import org.bukkit.craftbukkit.entity.CraftPlayer +import org.bukkit.entity.Player + +class OpenInventory : OpenInventoryProxy { + override fun getOpenInventory(player: Player): Any { + return (player as CraftPlayer).handle.containerMenu + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/EcoEnchantsCraftEnchantment.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/EcoEnchantsCraftEnchantment.kt new file mode 100644 index 00000000..5db774db --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/EcoEnchantsCraftEnchantment.kt @@ -0,0 +1,109 @@ +package com.willfp.ecoenchants.proxy.v1_21.registration + +import com.willfp.eco.util.toComponent +import com.willfp.ecoenchants.display.getFormattedName +import com.willfp.ecoenchants.enchant.EcoEnchant +import com.willfp.ecoenchants.enchant.impl.EcoEnchantBase +import net.kyori.adventure.text.Component +import net.minecraft.world.item.enchantment.Enchantment +import org.bukkit.craftbukkit.enchantments.CraftEnchantment +import org.bukkit.enchantments.EnchantmentTarget +import org.bukkit.inventory.ItemStack + +class EcoEnchantsCraftEnchantment( + private val enchant: EcoEnchantBase, + nmsEnchantment: Enchantment +) : CraftEnchantment(enchant.enchantmentKey, nmsEnchantment), EcoEnchant by enchant { + init { + enchant.enchantment = this + } + + override fun onRegister() { + // Fix for hardcoded enchantments + if (plugin.isLoaded) { + enchant.onRegister() + } + } + + override fun onRemove() { + enchant.onRemove() + } + + override fun canEnchantItem(item: ItemStack): Boolean { + return enchant.canEnchantItem(item) + } + + override fun conflictsWith(other: org.bukkit.enchantments.Enchantment): Boolean { + return enchant.conflictsWith(other) + } + + @Deprecated( + message = "getName is a paper Spigot API", + replaceWith = ReplaceWith("this.displayName(level)") + ) + override fun translationKey(): String { + return "ecoenchants:enchantment.$id" + } + + @Deprecated( + message = "getName is a legacy Spigot API", + replaceWith = ReplaceWith("this.displayName(level)") + ) + override fun getName(): String = this.id.uppercase() + override fun getMaxLevel(): Int = enchant.maximumLevel + + override fun getStartLevel(): Int = 1 + + @Deprecated( + message = "getItemTargets is an incompatible Spigot API", + replaceWith = ReplaceWith("this.targets") + ) + @Suppress("DEPRECATION") + override fun getItemTarget(): EnchantmentTarget = EnchantmentTarget.ALL + + @Deprecated( + message = "Treasure enchantments do not exist in EcoEnchants", + replaceWith = ReplaceWith("this.isEnchantable") + ) + override fun isTreasure(): Boolean = !enchant.isObtainableThroughEnchanting + + @Deprecated( + message = "Use EnchantmentType instead", + replaceWith = ReplaceWith("type.id") + ) + override fun isCursed(): Boolean { + return false + } + + override fun displayName(level: Int): Component { + return enchant.getFormattedName(level).toComponent() + } + + override fun isTradeable(): Boolean { + return enchant.isObtainableThroughTrading + } + + override fun isDiscoverable(): Boolean { + return enchant.isObtainableThroughDiscovery + } + + override fun getMinModifiedCost(level: Int): Int { + return Int.MAX_VALUE + } + + override fun getMaxModifiedCost(level: Int): Int { + return Int.MAX_VALUE + } + + override fun equals(other: Any?): Boolean { + return other is EcoEnchant && this.enchantmentKey == other.enchantmentKey + } + + override fun hashCode(): Int { + return this.enchantmentKey.hashCode() + } + + override fun toString(): String { + return "EcoEnchantsCraftEnchantment(key=$key)" + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/ModifiedVanillaCraftEnchantment.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/ModifiedVanillaCraftEnchantment.kt new file mode 100644 index 00000000..f54cefc5 --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/ModifiedVanillaCraftEnchantment.kt @@ -0,0 +1,23 @@ +package com.willfp.ecoenchants.proxy.v1_21.registration + +import com.willfp.ecoenchants.enchant.vanillaEnchantmentData +import net.minecraft.world.item.enchantment.Enchantment +import org.bukkit.NamespacedKey +import org.bukkit.craftbukkit.enchantments.CraftEnchantment + +class ModifiedVanillaCraftEnchantment( + key: NamespacedKey, + target: Enchantment +) : CraftEnchantment(key, target) { + override fun getMaxLevel(): Int = this.vanillaEnchantmentData?.maxLevel ?: super.getMaxLevel() + + override fun conflictsWith(other: org.bukkit.enchantments.Enchantment): Boolean { + val otherConflicts = when (other) { + is ModifiedVanillaCraftEnchantment -> other.vanillaEnchantmentData?.conflicts?.contains(this.key) == true + else -> other.conflictsWith(this) + } + + return this.vanillaEnchantmentData?.conflicts?.contains(other.key) ?: super.conflictsWith(other) + || otherConflicts + } +} diff --git a/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/VanillaEcoEnchantsEnchantment.kt b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/VanillaEcoEnchantsEnchantment.kt new file mode 100644 index 00000000..a3bcb530 --- /dev/null +++ b/eco-core/core-nms/v1_21/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21/registration/VanillaEcoEnchantsEnchantment.kt @@ -0,0 +1,21 @@ +package com.willfp.ecoenchants.proxy.v1_21.registration + +import com.willfp.ecoenchants.enchant.EcoEnchant +import net.minecraft.core.HolderSet +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.enchantment.Enchantment + +fun vanillaEcoEnchantsEnchantment(enchant: EcoEnchant): Enchantment { + val enchantment = Enchantment.enchantment( + Enchantment.definition( + HolderSet.empty(), + 1, // 1.21 hardcodes a minimum weight of 1 + enchant.maximumLevel, + Enchantment.constantCost(1), + Enchantment.constantCost(1), + 0 + ) + ) + + return enchantment.build(ResourceLocation.withDefaultNamespace(enchant.id)) +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/EcoEnchantsPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/EcoEnchantsPlugin.kt index a02c9d46..1d19b64b 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/EcoEnchantsPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/EcoEnchantsPlugin.kt @@ -88,7 +88,7 @@ class EcoEnchantsPlugin : LibreforgePlugin() { ) } - if (Prerequisite.HAS_1_20_5.isMet) { + if (Prerequisite.HAS_1_20_5.isMet && !Prerequisite.HAS_1_21.isMet) { getProxy(CodecReplacerProxy::class.java).replaceItemCodec() } } @@ -96,8 +96,12 @@ class EcoEnchantsPlugin : LibreforgePlugin() { override fun handleAfterLoad() { isLoaded = true + if (Prerequisite.HAS_1_21.isMet) { + plugin.getProxy(ModernEnchantmentRegistererProxy::class.java).replaceRegistry() + } + // Run in afterLoad to prevent items from having their enchantments deleted - if (Prerequisite.HAS_1_20_5.isMet) { + if (Prerequisite.HAS_1_20_5.isMet && !Prerequisite.HAS_1_21.isMet) { if (!this.configYml.getBool("enable-1-20-6")) { Bukkit.getPluginManager().disablePlugin(this) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/enchant/EcoEnchants.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/enchant/EcoEnchants.kt index ee49ccac..d1e57fac 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/enchant/EcoEnchants.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoenchants/enchant/EcoEnchants.kt @@ -19,6 +19,8 @@ import com.willfp.ecoenchants.type.EnchantmentTypes import com.willfp.libreforge.loader.LibreforgePlugin import com.willfp.libreforge.loader.configs.RegistrableCategory import org.bukkit.ChatColor +import org.bukkit.NamespacedKey +import org.bukkit.enchantments.Enchantment @Suppress("UNUSED") object EcoEnchants : RegistrableCategory("enchant", "enchants") { diff --git a/gradle.properties b/gradle.properties index 333cec99..db9e4de6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ #Fri May 31 20:38:06 BST 2024 kotlin.code.style=official libreforge-version=4.59.1 -version=12.6.1 +version=12.7.0 diff --git a/settings.gradle.kts b/settings.gradle.kts index 6685935d..b33ee708 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,6 +7,10 @@ pluginManagement { } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} + rootProject.name = "EcoEnchants" // Core @@ -23,3 +27,4 @@ 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-nms:v1_20_6") +include(":eco-core:core-nms:v1_21")