Skip to content

Commit

Permalink
Added 1.21.4 support
Browse files Browse the repository at this point in the history
  • Loading branch information
WillFP committed Dec 6, 2024
1 parent 6467290 commit f45b510
Show file tree
Hide file tree
Showing 20 changed files with 791 additions and 3 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation(project(path = ":eco-core:core-nms:v1_20_R3", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21_3", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21_4", configuration = "reobf"))
}

allprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public final class ProxyConstants {
"v1_20_R2",
"v1_20_R3",
"v1_21",
"v1_21_3"
"v1_21_3",
"v1_21_4"
);

private ProxyConstants() {
Expand Down
6 changes: 4 additions & 2 deletions eco-core/core-nms/v1_21_3/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("io.papermc.paperweight.userdev")
}
Expand Down Expand Up @@ -43,8 +45,8 @@ tasks {
}

compileKotlin {
kotlinOptions {
jvmTarget = "21"
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
}
52 changes: 52 additions & 0 deletions eco-core/core-nms/v1_21_4/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("io.papermc.paperweight.userdev")
}

group = "com.willfp"
version = rootProject.version

dependencies {
implementation(project(":eco-core:core-nms:modern"))
implementation(project(":eco-core:core-nms:common"))
paperweight.paperDevBundle("1.21.4-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_21_4.common"
)
relocate(
"net.kyori.adventure.text.minimessage",
"com.willfp.eco.internal.spigot.proxy.v1_21_4.minimessage"
)
}

compileJava {
options.release.set(21)
}

compileKotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.willfp.eco.internal.spigot.proxy.v1_21_4

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.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<String, Command>
get() = knownCommandsField.get(getCommandMap()) as MutableMap<String, Command>

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}")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package com.willfp.eco.internal.spigot.proxy.v1_21_4

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.component.DataComponents
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.CraftServer
import org.bukkit.craftbukkit.entity.CraftEntity
import org.bukkit.craftbukkit.entity.CraftMob
import org.bukkit.craftbukkit.entity.CraftPlayer
import org.bukkit.craftbukkit.inventory.CraftItemStack
import org.bukkit.craftbukkit.inventory.CraftMetaArmor
import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.util.CraftMagicNumbers
import org.bukkit.craftbukkit.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 = CraftMetaArmor::class.java
.superclass // Access 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<String, Tag> = 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.remove(DataComponents.CUSTOM_DATA)
}
} 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)
val holderLookupProvider = (Bukkit.getServer() as CraftServer).server.registryAccess()

return net.minecraft.network.chat.Component.Serializer.fromJson(json, holderLookupProvider)!!
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.willfp.eco.internal.spigot.proxy.v1_21_4

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 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.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<Optional<net.minecraft.network.chat.Component>>

private val customNameVisibleAccessor = Entity::class.java
.declaredFields
.filter { it.type == EntityDataAccessor::class.java }
.toList()[3]
.apply { isAccessible = true }
.get(null) as EntityDataAccessor<Boolean>

override fun setClientsideDisplayName(
entity: LivingEntity,
player: Player,
displayName: Component,
visible: Boolean
) {
if (entity !is CraftLivingEntity) {
return
}

val nmsComponent = displayName.toNMS()

val nmsEntity = entity.handle

val packet = ClientboundSetEntityDataPacket(
nmsEntity.id,
listOf(
SynchedEntityData.DataValue.create(displayNameAccessor, Optional.of(nmsComponent)),
SynchedEntityData.DataValue.create(customNameVisibleAccessor, visible)
)
)

player.sendPacket(Packet(packet))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_21_4

import com.willfp.eco.internal.entities.EcoDummyEntity
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
import org.bukkit.Location
import org.bukkit.craftbukkit.CraftWorld
import org.bukkit.entity.Entity
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))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.v1_21_4

import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.v1_21_4.entity.EcoEntityController
import org.bukkit.entity.Mob

class EntityControllerFactory : EntityControllerFactoryProxy {
override fun <T : Mob> createEntityController(entity: T): EntityController<T> {
return EcoEntityController(entity)
}
}
Loading

0 comments on commit f45b510

Please sign in to comment.