diff --git a/.gitignore b/.gitignore index d8eddf64..b53a9b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ bin/ gradle-app.setting # Mac OSX -.DS_Store \ No newline at end of file +.DS_Store + +.kotlin \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index a03fa2d9..cc617d7d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { java `java-library` `maven-publish` - kotlin("jvm") version "1.9.20" + kotlin("jvm") version "2.1.0" id("com.gradleup.shadow") version "8.3.5" id("com.willfp.libreforge-gradle-plugin") version "1.0.0" } @@ -28,6 +30,7 @@ dependencies { implementation(project(":eco-core:core-nms:v1_20_R3", configuration = "reobf")) implementation(project(":eco-core:core-nms:v1_21", configuration = "reobf")) implementation(project(":eco-core:core-nms:v1_21_3", configuration = "reobf")) + implementation(project(":eco-core:core-nms:v1_21_4", configuration = "reobf")) } allprojects { @@ -54,7 +57,7 @@ allprojects { dependencies { compileOnly("com.willfp:eco:6.74.3") compileOnly("org.jetbrains:annotations:23.0.0") - compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20") + compileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0") compileOnly("com.github.ben-manes.caffeine:caffeine:3.1.5") } @@ -64,8 +67,8 @@ allprojects { } compileKotlin { - kotlinOptions { - jvmTarget = "17" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) } } diff --git a/eco-core/core-nms/v1_21/build.gradle.kts b/eco-core/core-nms/v1_21/build.gradle.kts index 118e82d2..1cdaf5a4 100644 --- a/eco-core/core-nms/v1_21/build.gradle.kts +++ b/eco-core/core-nms/v1_21/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("io.papermc.paperweight.userdev") } @@ -19,8 +21,8 @@ tasks { } compileKotlin { - kotlinOptions { - jvmTarget = "21" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) } } } 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 index 914a6b12..aa7d56d7 100644 --- 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 @@ -63,7 +63,7 @@ class ModernEnchantmentRegisterer : ModernEnchantmentRegistererProxy { override fun replaceRegistry() { val newRegistryMTB = - BiFunction { key, registry -> + BiFunction { key, registry -> val eco = EcoEnchants.getByID(key.key) val registered = enchantmentRegistry.containsKey(CraftNamespacedKey.toMinecraft(key)) diff --git a/eco-core/core-nms/v1_21_3/build.gradle.kts b/eco-core/core-nms/v1_21_3/build.gradle.kts index 2d3a76d2..a3e6c53f 100644 --- a/eco-core/core-nms/v1_21_3/build.gradle.kts +++ b/eco-core/core-nms/v1_21_3/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("io.papermc.paperweight.userdev") } @@ -19,8 +21,8 @@ tasks { } compileKotlin { - kotlinOptions { - jvmTarget = "21" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) } } } diff --git a/eco-core/core-nms/v1_21_3/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_3/ModernEnchantmentRegisterer.kt b/eco-core/core-nms/v1_21_3/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_3/ModernEnchantmentRegisterer.kt index 73d3ea5a..53aa340e 100644 --- a/eco-core/core-nms/v1_21_3/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_3/ModernEnchantmentRegisterer.kt +++ b/eco-core/core-nms/v1_21_3/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_3/ModernEnchantmentRegisterer.kt @@ -60,7 +60,7 @@ class ModernEnchantmentRegisterer : ModernEnchantmentRegistererProxy { override fun replaceRegistry() { val newRegistryMTB = - BiFunction { key, registry -> + BiFunction { key, registry -> val eco = EcoEnchants.getByID(key.key) val registered = enchantmentRegistry.containsKey(CraftNamespacedKey.toMinecraft(key)) diff --git a/eco-core/core-nms/v1_21_4/build.gradle.kts b/eco-core/core-nms/v1_21_4/build.gradle.kts new file mode 100644 index 00000000..26f42504 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/build.gradle.kts @@ -0,0 +1,28 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + id("io.papermc.paperweight.userdev") +} + +group = "com.willfp" +version = rootProject.version + +dependencies { + paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT") +} + +tasks { + build { + dependsOn(reobfJar) + } + + compileJava { + options.release = 21 + } + + compileKotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } + } +} diff --git a/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/HideStoredEnchants.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/HideStoredEnchants.kt new file mode 100644 index 00000000..d3e67589 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/HideStoredEnchants.kt @@ -0,0 +1,33 @@ +package com.willfp.ecoenchants.proxy.v1_21_4 + +import com.willfp.eco.core.Prerequisite +import com.willfp.eco.core.fast.FastItemStack +import com.willfp.ecoenchants.display.HideStoredEnchantsProxy +import org.bukkit.inventory.ItemFlag +import javax.print.attribute.PrintRequestAttribute + +class HideStoredEnchants: HideStoredEnchantsProxy { + override fun hideStoredEnchants(fis: FastItemStack) { + if (Prerequisite.HAS_PAPER.isMet) { + fis.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS) + } else { + fis.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP) + } + } + + override fun areStoredEnchantsHidden(fis: FastItemStack): Boolean { + return if (Prerequisite.HAS_PAPER.isMet) { + fis.hasItemFlag(ItemFlag.HIDE_STORED_ENCHANTS) + } else { + fis.hasItemFlag(ItemFlag.HIDE_ADDITIONAL_TOOLTIP) + } + } + + override fun showStoredEnchants(fis: FastItemStack) { + if (Prerequisite.HAS_PAPER.isMet) { + fis.removeItemFlags(ItemFlag.HIDE_STORED_ENCHANTS) + } else { + fis.removeItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP) + } + } +} diff --git a/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/ModernEnchantmentRegisterer.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/ModernEnchantmentRegisterer.kt new file mode 100644 index 00000000..e978f03d --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/ModernEnchantmentRegisterer.kt @@ -0,0 +1,142 @@ +package com.willfp.ecoenchants.proxy.v1_21_4 + +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_4.registration.EcoEnchantsCraftEnchantment +import com.willfp.ecoenchants.proxy.v1_21_4.registration.ModifiedVanillaCraftEnchantment +import com.willfp.ecoenchants.proxy.v1_21_4.registration.vanillaEcoEnchantsEnchantment +import net.minecraft.core.Holder +import net.minecraft.core.MappedRegistry +import net.minecraft.core.Registry +import net.minecraft.core.registries.Registries +import net.minecraft.resources.ResourceLocation +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.lang.reflect.Modifier +import java.util.IdentityHashMap +import java.util.function.BiFunction + +private val enchantmentRegistry = + (Bukkit.getServer() as CraftServer).server.registryAccess().lookupOrThrow(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 allTags = MappedRegistry::class.java + .declaredFields + .filter { it.type.name.contains("TagSet") }[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 } + + override fun replaceRegistry() { + val newRegistryMTB = + BiFunction { key, registry -> + val eco = EcoEnchants.getByID(key.key) + val registered = enchantmentRegistry.containsKey(CraftNamespacedKey.toMinecraft(key)) + + if (eco != null) { + eco as Enchantment + } else if (registered) { + ModifiedVanillaCraftEnchantment(key, registry) + } 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>() + ) + + /* + Creating an unbound tag set requires using reflection because the inner class is + package-private, so we just find the method manually. + */ + + val unboundTagSet = MappedRegistry::class.java + .declaredClasses[0] + .declaredMethods + .filter { Modifier.isStatic(it.modifiers) } + .filter { it.parameterCount == 0 }[0] + .apply { isAccessible = true } + .invoke(null) + + allTags.set(enchantmentRegistry, unboundTagSet) + } + + 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.isPresent) { + return EcoEnchantsCraftEnchantment(enchant, nms.get().value()) + } 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_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/OpenInventory.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/OpenInventory.kt new file mode 100644 index 00000000..bee14bc7 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/OpenInventory.kt @@ -0,0 +1,11 @@ +package com.willfp.ecoenchants.proxy.v1_21_4 + +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_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/EcoEnchantsCraftEnchantment.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/EcoEnchantsCraftEnchantment.kt new file mode 100644 index 00000000..55362a55 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/EcoEnchantsCraftEnchantment.kt @@ -0,0 +1,109 @@ +package com.willfp.ecoenchants.proxy.v1_21_4.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 = "EcoEnchants enchantments are not translatable", + 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_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/ModifiedVanillaCraftEnchantment.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/ModifiedVanillaCraftEnchantment.kt new file mode 100644 index 00000000..77c86a15 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/ModifiedVanillaCraftEnchantment.kt @@ -0,0 +1,23 @@ +package com.willfp.ecoenchants.proxy.v1_21_4.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_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/VanillaEcoEnchantsEnchantment.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/VanillaEcoEnchantsEnchantment.kt new file mode 100644 index 00000000..21452706 --- /dev/null +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/ecoenchants/proxy/v1_21_4/registration/VanillaEcoEnchantsEnchantment.kt @@ -0,0 +1,21 @@ +package com.willfp.ecoenchants.proxy.v1_21_4.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/gradle.properties b/gradle.properties index f92b9320..bd66194e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,7 @@ #libreforge-updater #Wed Nov 06 18:33:45 GMT 2024 -kotlin.code.style=official libreforge-version=4.72.2 version=12.19.3 +org.gradle.parallel=true +kotlin.daemon.jvmargs=-Xmx2g -XX:+UseG1GC -XX:MaxMetaspaceSize=512m +kotlin.code.style=official diff --git a/settings.gradle.kts b/settings.gradle.kts index 6818e10e..6055bed1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,3 +28,4 @@ include(":eco-core:core-nms:v1_20_R2") include(":eco-core:core-nms:v1_20_R3") include(":eco-core:core-nms:v1_21") include(":eco-core:core-nms:v1_21_3") +include(":eco-core:core-nms:v1_21_4")