diff --git a/build.gradle.kts b/build.gradle.kts index 07ddee34..30ab7e8c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java - id("io.izzel.taboolib") version "2.0.23" apply false + id("io.izzel.taboolib") version "2.0.22" apply false id("org.jetbrains.kotlin.jvm") version "1.8.22" apply false } @@ -21,7 +21,7 @@ subprojects { install(BukkitNMSDataSerializer) } - version { taboolib = "6.2.3-8cc2f66" } + version { taboolib = "6.2.3-20d868d" } } repositories { mavenLocal() diff --git a/gradle.properties b/gradle.properties index c1ddf75c..65d7370a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=ink.ptms.adyeshach -version=2.1.1 +version=2.1.0 kotlin.incremental=true kotlin.incremental.java=true kotlin.incremental.useClasspathSnapshot=true diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftBlockAccess.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftBlockAccess.kt index eca72f95..9d547566 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftBlockAccess.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftBlockAccess.kt @@ -2,7 +2,7 @@ package ink.ptms.adyeshach.impl.nms import ink.ptms.adyeshach.core.MinecraftWorldAccess import ink.ptms.adyeshach.impl.DefaultAdyeshachMinecraftAPI -import net.minecraft.world.level.chunk.Chunk +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import net.minecraft.world.level.chunk.ChunkStatus import org.bukkit.Material import org.bukkit.World @@ -33,7 +33,9 @@ class DefaultMinecraftBlockAccess(val world: World?, override val x: Int, overri (obcChunk as org.bukkit.craftbukkit.v1_19_R2.CraftChunk?)?.handle as Any? } catch (_: NoSuchMethodError) { // 1.19.4 (最新版改动) - obcChunk?.getHandle(ChunkStatus.FULL) as Any? + if (MinecraftVersion.versionId >= 12101) { + NMS21.instance.getChunk(world?.getChunkAt(x, z)) + } else obcChunk?.getHandle(ChunkStatus.FULL) as Any? } override fun getBlockType(x: Int, y: Int, z: Int): Material { @@ -46,7 +48,7 @@ class DefaultMinecraftBlockAccess(val world: World?, override val x: Int, overri // 这个版本的命名与 1.16 相同,但是类型不同 9 -> ((nmsChunk as NMS16IBlockAccess).getType(NMS16BlockPosition(x, y, z)) as NMSBlockData).block // 1.18, 1.19, 1.20 - 10, 11, 12 -> ((nmsChunk as NMSIBlockAccess).getBlockState(NMSBlockPosition(x, y, z)) as NMSBlockData).block + 10, 11, 12, 13 -> ((nmsChunk as NMSIBlockAccess).getBlockState(NMSBlockPosition(x, y, z)) as NMSBlockData).block // 不支持 else -> error("Unsupported version: $major") } @@ -83,7 +85,7 @@ class DefaultMinecraftBlockAccess(val world: World?, override val x: Int, overri // 1.9, 1.10, 1.11, 1.12 1, 2, 3, 4 -> getBlockHeightLegacy(obcChunk!!.getBlock(x, y, z)) // 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20 - 5, 6, 7, 8, 9, 10, 11, 12 -> { + 5, 6, 7, 8, 9, 10, 11, 12, 13 -> { val slab = world!!.getBlockAt(x, y, z).blockData as Slab if (slab.type == Slab.Type.TOP || slab.type == Slab.Type.DOUBLE) 1.0 else 0.5 } diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityMetadataHandler.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityMetadataHandler.kt index f63bc5be..ec5b29bd 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityMetadataHandler.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityMetadataHandler.kt @@ -1,6 +1,5 @@ package ink.ptms.adyeshach.impl.nms -import taboolib.module.nms.createDataSerializer import ink.ptms.adyeshach.core.* import ink.ptms.adyeshach.core.bukkit.BukkitParticles import ink.ptms.adyeshach.core.bukkit.BukkitPose @@ -11,6 +10,7 @@ import ink.ptms.adyeshach.core.entity.type.AdySniffer import ink.ptms.adyeshach.impl.entity.DefaultEntityInstance import ink.ptms.adyeshach.impl.nms.parser.* import ink.ptms.adyeshach.impl.nms.specific.NMS19 +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import org.bukkit.Art import org.bukkit.entity.Cat import org.bukkit.inventory.ItemStack @@ -21,6 +21,7 @@ import taboolib.common.platform.function.warning import taboolib.common5.Quat import taboolib.module.nms.MinecraftVersion import taboolib.module.nms.MinecraftVersion.isUniversal +import taboolib.module.nms.createDataSerializer import java.util.* import java.util.function.Consumer @@ -100,8 +101,11 @@ class DefaultMinecraftEntityMetadataHandler : MinecraftEntityMetadataHandler { } override fun createMetadataPacket(entityId: Int, metaList: List): Any { - // 1.19.3 变更为 record 类型,因此无法兼容之前的写法 - return if (majorLegacy >= 11903) { + // 1.21取消了DataSerializer,改用构造函数实例化 + return if (MinecraftVersion.versionId >= 12101) { + NMS21.instance.createPacketPlayOutEntityMetadata(entityId, metaList) + } else if (majorLegacy >= 11903) { + // 1.19.3 变更为 record 类型,因此无法兼容之前的写法 NMS19.instance.createPacketPlayOutEntityMetadata(entityId, metaList) } else if (isUniversal) { NMSPacketPlayOutEntityMetadata(createDataSerializer { diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityOperator.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityOperator.kt index 96d11034..5fea7f20 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityOperator.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntityOperator.kt @@ -1,16 +1,18 @@ package ink.ptms.adyeshach.impl.nms import com.mojang.datafixers.util.Pair -import taboolib.module.nms.createDataSerializer import ink.ptms.adyeshach.core.* import ink.ptms.adyeshach.core.bukkit.BukkitAnimation import ink.ptms.adyeshach.core.util.ifloor +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import org.bukkit.Location import org.bukkit.entity.Player import org.bukkit.inventory.EquipmentSlot import org.bukkit.inventory.ItemStack import org.bukkit.util.Vector +import taboolib.library.reflex.Reflex.Companion.invokeConstructor import taboolib.module.nms.MinecraftVersion +import taboolib.module.nms.createDataSerializer /** * Adyeshach @@ -68,7 +70,21 @@ class DefaultMinecraftEntityOperator : MinecraftEntityOperator { writeBoolean(onGround) }.build() as NMSPacketDataSerializer) // 1.21 - 13 -> error("还不支持") + 13 -> { + if (MinecraftVersion.versionId == 12101) { + NMSPacketPlayOutEntityTeleport::class.java.invokeConstructor(createDataSerializer { + writeVarInt(entityId) + writeDouble(location.x) + writeDouble(location.y) + writeDouble(location.z) + writeByte(yaw) + writeByte(pitch) + writeBoolean(onGround) + }.build() as NMSPacketDataSerializer) + } else { + NMS21.instance.createTeleport(entityId, location, yaw, pitch, onGround) + } + } // 不支持 else -> error("Unsupported version.") } @@ -135,7 +151,9 @@ class DefaultMinecraftEntityOperator : MinecraftEntityOperator { override fun updateHeadRotation(player: List, entityId: Int, yaw: Float) { // 修复视角 val yf = Adyeshach.api().getEntityFinder().getEntityFromClientEntityId(entityId, player.firstOrNull() ?: return)?.entityType.fixYaw(yaw) - if (isUniversal) { + if (MinecraftVersion.versionId >= 12101) { + packetHandler.sendPacket(player, NMS21.instance.createEntityHead(entityId, ifloor(yf * 256.0 / 360.0).toByte())) + } else if (isUniversal) { packetHandler.sendPacket(player, NMSPacketPlayOutEntityHeadRotation(createDataSerializer { writeVarInt(entityId) writeByte(ifloor(yf * 256.0 / 360.0).toByte()) @@ -156,6 +174,9 @@ class DefaultMinecraftEntityOperator : MinecraftEntityOperator { override fun updateEquipment(player: List, entityId: Int, equipment: Map) { when { + majorLegacy >= 12100 -> { + packetHandler.sendPacket(player, NMS21.instance.createEntityEquipment(entityId, equipment)) + } // 从 1.16 开始每个包支持多个物品 majorLegacy >= 11600 -> { val items = equipment.map { Pair(it.key.toNMSEnumItemSlot(), CraftItemStack19.asNMSCopy(it.value)) } @@ -171,7 +192,9 @@ class DefaultMinecraftEntityOperator : MinecraftEntityOperator { } override fun updatePassengers(player: List, entityId: Int, vararg passengers: Int) { - if (isUniversal) { + if (MinecraftVersion.versionId >= 12101) { + packetHandler.sendPacket(player, NMS21.instance.createPassengers(entityId, *passengers)) + } else if (isUniversal) { packetHandler.sendPacket(player, NMSPacketPlayOutMount(createDataSerializer { writeVarInt(entityId) writeVarIntArray(passengers) diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntitySpawner.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntitySpawner.kt index 2d963f77..5681f624 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntitySpawner.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftEntitySpawner.kt @@ -1,20 +1,22 @@ package ink.ptms.adyeshach.impl.nms -import taboolib.module.nms.createDataSerializer import ink.ptms.adyeshach.core.* import ink.ptms.adyeshach.core.bukkit.BukkitDirection import ink.ptms.adyeshach.core.bukkit.BukkitPaintings import ink.ptms.adyeshach.core.entity.EntityTypes import ink.ptms.adyeshach.impl.nms.specific.NMS19 +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import org.bukkit.Location import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.material.MaterialData import taboolib.common.util.unsafeLazy import taboolib.library.reflex.Reflex.Companion.getProperty +import taboolib.library.reflex.Reflex.Companion.invokeConstructor import taboolib.library.reflex.Reflex.Companion.invokeMethod import taboolib.library.reflex.UnsafeAccess import taboolib.module.nms.MinecraftVersion +import taboolib.module.nms.createDataSerializer import java.lang.invoke.MethodHandle import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -117,7 +119,7 @@ class DefaultMinecraftEntitySpawner : MinecraftEntitySpawner { }.build() as NMS16PacketDataSerializer) } // 1.17, 1.18, 1.19, 1.12 - 9, 10, 11, 12 -> NMSPacketPlayOutSpawnEntity(createDataSerializer { + 9, 10, 11, 12 -> NMSPacketPlayOutSpawnEntity::class.java.invokeConstructor(createDataSerializer { writeVarInt(entityId) writeUUID(uuid) // 类型 @@ -125,7 +127,9 @@ class DefaultMinecraftEntitySpawner : MinecraftEntitySpawner { // 1.17, 1.18 写法相同 // 1.17 -> this.type = (EntityTypes)IRegistry.ENTITY_TYPE.fromId(var0.j()); // 1.18 -> this.type = (EntityTypes)IRegistry.ENTITY_TYPE.byId(var0.readVarInt()); - 9, 10 -> writeVarInt(NMSIRegistry.ENTITY_TYPE.getId(helper.adapt(entityType) as NMSEntityTypes<*>)) + 9, 10 -> writeVarInt( + NMSIRegistry.ENTITY_TYPE.getId(helper.adapt(entityType) as NMSEntityTypes<*>) + ) // 1.19 写法不同 11 -> { when (minor) { @@ -160,6 +164,19 @@ class DefaultMinecraftEntitySpawner : MinecraftEntitySpawner { writeShort(0) writeShort(0) }.build() as NMSPacketDataSerializer) + + 13 -> { + NMS21.instance.createSpawnEntity( + entityId, + uuid, + location, + yaw.toFloat(), + pitch.toFloat(), + data, + NMS19.instance.entityTypeGetId(helper.adapt(entityType)), + yaw.toDouble() + ) + } // 不支持 else -> error("Unsupported version.") } diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftHelper.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftHelper.kt index 4bf4c876..2afd4f26 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftHelper.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftHelper.kt @@ -9,6 +9,7 @@ import ink.ptms.adyeshach.core.entity.EntityTypes import ink.ptms.adyeshach.core.util.errorBy import ink.ptms.adyeshach.impl.nms.specific.NMS19p import ink.ptms.adyeshach.impl.nms.specific.NMS20p +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import ink.ptms.adyeshach.minecraft.ChunkPos import org.bukkit.Location import org.bukkit.World @@ -137,10 +138,18 @@ class DefaultMinecraftHelper : MinecraftHelper { } override fun craftChatSerializerToJson(compound: Any): String { - return if (MinecraftVersion.isUniversal) { - NMSChatSerializer.toJson(compound as NMSIChatBaseComponent) - } else { - NMS16ChatSerializer.a(compound as NMS16IChatBaseComponent) + return when { + MinecraftVersion.versionId >= 12100 -> { + NMS21.instance.toJson(compound) + } + + MinecraftVersion.isUniversal -> { + NMSChatSerializer.toJson(compound as NMSIChatBaseComponent) + } + + else -> { + NMS16ChatSerializer.a(compound as NMS16IChatBaseComponent) + } } } @@ -164,9 +173,12 @@ class DefaultMinecraftHelper : MinecraftHelper { } catch (_: Throwable) { } return try { + if (MinecraftVersion.versionId >= 12101) { + (player.world as CraftWorld19).isChunkLoaded(chunkX, chunkZ) + } // 从 1.18 开始 getVisibleChunk -> getVisibleChunkIfPresent // getChunkProvider -> getChunkSource - if (MinecraftVersion.isHigherOrEqual(MinecraftVersion.V1_18)) { + else if (MinecraftVersion.isHigherOrEqual(MinecraftVersion.V1_18)) { val craftWorld = player.world as CraftWorld19 craftWorld.handle.chunkSource.chunkMap.visibleChunkMap.get(ChunkPos.asLong(chunkX, chunkZ)) != null } diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftScoreboardOperator.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftScoreboardOperator.kt index 083ebccc..eb2d0867 100644 --- a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftScoreboardOperator.kt +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/DefaultMinecraftScoreboardOperator.kt @@ -5,7 +5,7 @@ import ink.ptms.adyeshach.core.Adyeshach import ink.ptms.adyeshach.core.MinecraftPacketHandler import ink.ptms.adyeshach.core.MinecraftScoreboardOperator import org.bukkit.entity.Player -import taboolib.common.platform.function.info +import ink.ptms.adyeshach.impl.nms.specific.NMS21 import taboolib.module.nms.MinecraftVersion /** @@ -93,6 +93,10 @@ class DefaultMinecraftScoreboardOperator : MinecraftScoreboardOperator { team.members.forEach { name -> writeUtf(name) } } }.build() as NMSPacketDataSerializer) + + 13 -> { + NMS21.instance.createTeam(team, method) + } // 不支持 else -> error("Unsupported version.") } diff --git a/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21.kt b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21.kt new file mode 100644 index 00000000..7482dc2f --- /dev/null +++ b/project/common-impl-nms/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21.kt @@ -0,0 +1,35 @@ +package ink.ptms.adyeshach.impl.nms.specific + +import ink.ptms.adyeshach.core.MinecraftMeta +import ink.ptms.adyeshach.core.MinecraftScoreboardOperator +import org.bukkit.Location +import org.bukkit.inventory.EquipmentSlot +import org.bukkit.inventory.ItemStack +import taboolib.common.util.unsafeLazy +import taboolib.module.nms.nmsProxy +import java.util.* + +abstract class NMS21 { + + abstract fun createEntityHead(entityId: Int, yHeadRot: Byte): Any + + abstract fun toJson(compound: Any): String + + abstract fun createSpawnEntity(entityId: Int, uuid: UUID, location: Location, yaw: Float, pitch: Float, data: Int, entityType: Int, yhead: Double): Any + + abstract fun createPacketPlayOutEntityMetadata(entityId: Int, packedItems: List): Any + + abstract fun createPassengers(entityId: Int, vararg passengers: Int): Any + + abstract fun getChunk(chunk: Any?): Any? + + abstract fun createTeleport(entityId: Int, location: Location, yaw: Byte, pitch: Byte, onGround: Boolean): Any + + abstract fun createEntityEquipment(entityId: Int, equipment: Map): Any + + abstract fun createTeam(team: MinecraftScoreboardOperator.Team, method: MinecraftScoreboardOperator.TeamMethod): Any + + companion object { + val instance by unsafeLazy { nmsProxy() } + } +} \ No newline at end of file diff --git a/project/common-impl-nms19/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS19Impl.kt b/project/common-impl-nms19/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS19Impl.kt index a702f565..ac368ee0 100644 --- a/project/common-impl-nms19/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS19Impl.kt +++ b/project/common-impl-nms19/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS19Impl.kt @@ -7,6 +7,7 @@ import ink.ptms.adyeshach.core.bukkit.data.GameProfileAction import ink.ptms.adyeshach.core.entity.type.AdySniffer import ink.ptms.adyeshach.impl.nms.NMSDataWatcherItem import ink.ptms.adyeshach.impl.nms.NMSDataWatcherObject +import net.minecraft.core.Holder import net.minecraft.core.IRegistry import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.network.chat.IChatBaseComponent @@ -88,7 +89,11 @@ class NMS19Impl : NMS19() { val ir = BuiltInRegistries.CAT_VARIANT as IRegistry val texture = "textures/entity/cat/${type.name.lowercase()}.png" val variant = ir.first { it.texture.path == texture } - return DataWatcher.Item(DataWatcherObject(index, DataWatcherRegistry.CAT_VARIANT), variant) + return kotlin.runCatching { + DataWatcher.Item(DataWatcherObject(index, DataWatcherRegistry.CAT_VARIANT), variant) + }.getOrElse { + DataWatcher.Item::class.java.invokeConstructor(DataWatcherObject(index, DataWatcherRegistry.CAT_VARIANT), Holder.direct(variant)) + } } override fun createSnifferStateMeta(index: Int, type: AdySniffer.State): Any { @@ -158,6 +163,7 @@ class NMS19Impl : NMS19() { // } } } + else -> error("Unsupported action: $action") } } @@ -185,13 +191,7 @@ class NMS19Impl : NMS19() { val gameMode = if (gameProfile.spectator) EnumGamemode.SPECTATOR else EnumGamemode.CREATIVE val displayName = Adyeshach.api().getMinecraftAPI().getHelper().literalChatBaseComponent(gameProfile.name) as IChatBaseComponent return ClientboundPlayerInfoUpdatePacket.b( - uuid, - gameProfile.toMojang(uuid), - listed, - latency, - gameMode, - displayName, - null + uuid, gameProfile.toMojang(uuid), listed, latency, gameMode, displayName, null ) } } diff --git a/project/common-impl-nms21/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21Impl.kt b/project/common-impl-nms21/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21Impl.kt new file mode 100644 index 00000000..0e37853e --- /dev/null +++ b/project/common-impl-nms21/src/main/kotlin/ink/ptms/adyeshach/impl/nms/specific/NMS21Impl.kt @@ -0,0 +1,114 @@ +package ink.ptms.adyeshach.impl.nms.specific + +import com.mojang.datafixers.util.Pair +import ink.ptms.adyeshach.core.MinecraftMeta +import ink.ptms.adyeshach.core.MinecraftScoreboardOperator +import ink.ptms.adyeshach.impl.nms.NMSIChatBaseComponent +import ink.ptms.adyeshach.impl.nms.NMSPacketDataSerializer +import net.minecraft.EnumChatFormat +import net.minecraft.core.IRegistryCustom +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.network.chat.IChatBaseComponent +import net.minecraft.network.protocol.game.* +import net.minecraft.network.syncher.DataWatcher +import net.minecraft.world.entity.EnumItemSlot +import net.minecraft.world.entity.PositionMoveRotation +import net.minecraft.world.entity.Relative +import net.minecraft.world.phys.Vec3D +import org.bukkit.Location +import org.bukkit.craftbukkit.v1_21_R3.CraftChunk +import org.bukkit.craftbukkit.v1_21_R3.inventory.CraftItemStack +import org.bukkit.inventory.EquipmentSlot +import org.bukkit.inventory.ItemStack +import taboolib.library.reflex.Reflex.Companion.invokeConstructor +import taboolib.module.nms.MinecraftVersion +import taboolib.module.nms.createDataSerializer +import java.util.* + +class NMS21Impl : NMS21() { + override fun createEntityHead(entityId: Int, yHeadRot: Byte): Any { + return PacketPlayOutEntityHeadRotation::class.java.invokeConstructor(createDataSerializer { + writeVarInt(entityId) + writeByte(yHeadRot) + }.build() as NMSPacketDataSerializer) + } + + override fun toJson(compound: Any): String { + return IChatBaseComponent.ChatSerializer.toJson(compound as NMSIChatBaseComponent, IRegistryCustom.EMPTY) + } + + override fun createSpawnEntity( + entityId: Int, + uuid: UUID, + location: Location, + yaw: Float, + pitch: Float, + data: Int, + entityType: Int, + yhead: Double + ): Any { + val type = if (MinecraftVersion.versionId == 12101) { + BuiltInRegistries.ENTITY_TYPE.byId(entityType) + } else { + BuiltInRegistries.ENTITY_TYPE.get(entityType).get().value() + } + return PacketPlayOutSpawnEntity(entityId, uuid, location.x, location.y, location.z, pitch, yaw, type, data, Vec3D.ZERO, yhead) + } + + override fun createPacketPlayOutEntityMetadata(entityId: Int, packedItems: List): Any { + return PacketPlayOutEntityMetadata(entityId, packedItems.map { (it.source() as DataWatcher.Item<*>).value() }) + } + + override fun createPassengers(entityId: Int, vararg passengers: Int): Any { + return PacketPlayOutMount::class.java.invokeConstructor(createDataSerializer { + writeVarInt(entityId) + writeVarIntArray(passengers) + }.build() as NMSPacketDataSerializer) + } + + override fun getChunk(chunk: Any?): Any? { + return (chunk as? CraftChunk)?.getHandle(net.minecraft.world.level.chunk.status.ChunkStatus.FULL) + } + + override fun createTeleport(entityId: Int, location: Location, yaw: Byte, pitch: Byte, onGround: Boolean): Any { + return PacketPlayOutEntityTeleport( + entityId, + PositionMoveRotation(Vec3D(location.x, location.y, location.z), Vec3D(location.x, location.y, location.z), yaw.toFloat(), pitch.toFloat()), + setOf(Relative.X, Relative.Y, Relative.Z), + onGround + ) + } + + override fun createEntityEquipment(entityId: Int, equipment: Map): Any { + fun EquipmentSlot.toNMS(): EnumItemSlot { + return when (this) { + EquipmentSlot.HAND -> EnumItemSlot.MAINHAND + EquipmentSlot.OFF_HAND -> EnumItemSlot.OFFHAND + else -> EnumItemSlot.valueOf(name) + } + } + return PacketPlayOutEntityEquipment(entityId, equipment.map { Pair(it.key.toNMS(), CraftItemStack.asNMSCopy(it.value)) }) + } + + override fun createTeam(team: MinecraftScoreboardOperator.Team, method: MinecraftScoreboardOperator.TeamMethod): Any { + return PacketPlayOutScoreboardTeam::class.java.invokeConstructor(createDataSerializer { + writeUtf(team.name, 16) + writeByte(method.ordinal.toByte()) + // ADD or CHANGE + if (method.ordinal == 0 || method.ordinal == 2) { + writeComponent("{\"text\":\"\"}") + writeByte(2) // 设置 + writeUtf(if (team.nameTagVisible) "always" else "never", 40) + writeUtf(if (team.collision) "always" else "never", 40) + writeEnumSet(EnumSet.copyOf(EnumChatFormat.values().toList()), EnumChatFormat::class.java) + writeComponent("{\"text\":\"\"}") + writeComponent("{\"text\":\"\"}") + } + // ADD or JOIN or LEAVE + if (method.ordinal == 0 || method.ordinal == 3 || method.ordinal == 4) { + writeVarInt(team.members.size) + team.members.forEach { name -> writeUtf(name) } + } + }.build()) + } +} \ No newline at end of file diff --git a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityMetadataRegistry.kt b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityMetadataRegistry.kt index 4412f8c8..2de9cc78 100644 --- a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityMetadataRegistry.kt +++ b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityMetadataRegistry.kt @@ -12,7 +12,6 @@ import ink.ptms.adyeshach.impl.entity.DefaultMetaNatural import taboolib.common.LifeCycle import taboolib.common.platform.Awake import taboolib.common.platform.PlatformFactory -import taboolib.common.platform.function.registerLifeCycleTask import taboolib.common.platform.function.releaseResourceFile import taboolib.common.util.unsafeLazy import taboolib.platform.bukkit.parallel diff --git a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityTypeRegistry.kt b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityTypeRegistry.kt index eb234434..1260c5eb 100644 --- a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityTypeRegistry.kt +++ b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/DefaultAdyeshachEntityTypeRegistry.kt @@ -59,6 +59,12 @@ class DefaultAdyeshachEntityTypeRegistry : AdyeshachEntityTypeRegistry { /** 所有实体对象的原件,用于克隆实体 */ val originEntityBaseMap = HashMap() + get() { + if (field.isEmpty()) { + field += generateEntityBase() + } + return field + } init { // 生成实体类 @@ -150,7 +156,11 @@ class DefaultAdyeshachEntityTypeRegistry : AdyeshachEntityTypeRegistry { // 执行回调函数 callback.forEach { interfaces += it(k, interfaces) } // 生成类 - val newClass = AsmClassLoader.createNewClass(name, generator.generate(name, v.instance.replace('.', '/'), interfaces.map { it.replace('.', '/') })) + val newClass = kotlin.runCatching { + AsmClassLoader.createNewClass(name, generator.generate(name, v.instance.replace('.', '/'), interfaces.map { it.replace('.', '/') })) + }.getOrElse { + AsmClassLoader.loadClass(name) + } // 生成实例 map[k] = newClass.invokeConstructor(k) as EntityBase } diff --git a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/manager/DefaultPlayerEvents.kt b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/manager/DefaultPlayerEvents.kt index 2722b500..6a55b46a 100644 --- a/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/manager/DefaultPlayerEvents.kt +++ b/project/common-impl/src/main/kotlin/ink/ptms/adyeshach/impl/manager/DefaultPlayerEvents.kt @@ -19,6 +19,7 @@ import taboolib.common.platform.event.EventPriority import taboolib.common.platform.event.SubscribeEvent import taboolib.common.platform.function.submit import taboolib.library.reflex.Reflex.Companion.getProperty +import taboolib.library.reflex.Reflex.Companion.invokeMethod import taboolib.module.nms.MinecraftVersion import taboolib.module.nms.PacketReceiveEvent import taboolib.platform.util.bukkitPlugin @@ -107,25 +108,32 @@ internal object DefaultPlayerEvents { onlinePlayerSet += e.player.name AdyeshachPlayerJoinEvent(e.player).call() } - if (e.packet.name == "PacketPlayInUseEntity") { - val entity = Adyeshach.api().getEntityFinder().getEntityFromEntityId(e.packet.read("a")!!, e.player) ?: return + if (e.packet.name in listOf("PacketPlayInUseEntity", "ServerboundInteractPacket")) { + val id = (if (MinecraftVersion.versionId < 12101) e.packet.read("a") else e.packet.read("entityId")) ?: return + val entity = Adyeshach.api().getEntityFinder().getEntityFromEntityId(id, e.player) ?: return // 判定观察者并检测作弊 if (entity.isViewer(e.player) && entity.getLocation().safeDistance(e.player.location) < 10) { if (MinecraftVersion.isUniversal) { - val action = e.packet.source.getProperty("b", remap = false)!! - // 高版本 EnumEntityUseAction 不再是枚举类型 - // 通过类名判断点击方式 - val name = action.javaClass.name - when { + // 1.21+的字段变为c了,太操蛋了 + // nm的缓存傻逼玩意,换了就必须清缓存 + val action = if (MinecraftVersion.versionId >= 12101) { + e.packet.source.getProperty("action", remap = true) + } else { + e.packet.source.getProperty("b", remap = true) + }!! + + val actionOrdinal = (action.invokeMethod("getType", remap = true) as Enum<*>).ordinal + + when(actionOrdinal) { // 左键 - name.endsWith("PacketPlayInUseEntity\$1") -> { + 1 -> { submit { AdyeshachEntityDamageEvent(entity, e.player).call() } } // 右键 - name.endsWith("PacketPlayInUseEntity\$e") -> { - val location = action.getProperty("b", remap = false) + 0, 2 -> { + val location = kotlin.runCatching { action.getProperty("location", remap = true) }.getOrNull() val vector = location?.let { Adyeshach.api().getMinecraftAPI().getHelper().vec3dToVector(it) } ?: Vector(0, 0, 0) - val hand = action.getProperty("a", remap = false).toString() == "MAIN_HAND" + val hand = action.getProperty("hand", remap = true).toString() == "MAIN_HAND" submit { AdyeshachEntityInteractEvent(entity, e.player, hand, vector).call() } } } @@ -136,6 +144,7 @@ internal object DefaultPlayerEvents { "ATTACK" -> { submit { AdyeshachEntityDamageEvent(entity, e.player).call() } } + "INTERACT_AT" -> { val location = e.packet.read("c") val vector = location?.let { Adyeshach.api().getMinecraftAPI().getHelper().vec3dToVector(it) } ?: Vector(0, 0, 0) diff --git a/project/compat-model-engine-v4/build.gradle.kts b/project/compat-model-engine-v4/build.gradle.kts index 02b1b7ea..e947908a 100644 --- a/project/compat-model-engine-v4/build.gradle.kts +++ b/project/compat-model-engine-v4/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { - compileOnly("com.ticxo:modelengine:4.0.8@jar") + compileOnly(fileTree("libs")) compileOnly(project(":project:common")) compileOnly(project(":project:common-impl")) } diff --git a/project/compat-model-engine-v4/libs/ModelEngine-4.0.4.min.jar b/project/compat-model-engine-v4/libs/ModelEngine-4.0.4.min.jar new file mode 100644 index 00000000..961555e5 Binary files /dev/null and b/project/compat-model-engine-v4/libs/ModelEngine-4.0.4.min.jar differ diff --git a/project/compat-model-engine-v4/src/main/kotlin/ink/ptms/adyeshach/compat/modelengine4/ActiveModelExtension.kt b/project/compat-model-engine-v4/src/main/kotlin/ink/ptms/adyeshach/compat/modelengine4/ActiveModelExtension.kt index 7dcd2f20..582d7b42 100644 --- a/project/compat-model-engine-v4/src/main/kotlin/ink/ptms/adyeshach/compat/modelengine4/ActiveModelExtension.kt +++ b/project/compat-model-engine-v4/src/main/kotlin/ink/ptms/adyeshach/compat/modelengine4/ActiveModelExtension.kt @@ -3,7 +3,6 @@ package ink.ptms.adyeshach.compat.modelengine4 import com.ticxo.modelengine.api.ModelEngineAPI import com.ticxo.modelengine.api.animation.BlueprintAnimation import com.ticxo.modelengine.api.animation.handler.IStateMachineHandler -import com.ticxo.modelengine.api.events.AnimationEndEvent import com.ticxo.modelengine.api.model.ActiveModel import com.ticxo.modelengine.api.model.ModeledEntity import com.ticxo.modelengine.api.nms.entity.HitboxEntity @@ -14,7 +13,6 @@ import ink.ptms.adyeshach.core.entity.EntityInstance import ink.ptms.adyeshach.core.entity.ModelEngine import ink.ptms.adyeshach.core.entity.ModelEngineOptions import org.bukkit.entity.Entity -import taboolib.common.platform.event.SubscribeEvent import taboolib.common.platform.function.warning import taboolib.common.util.orNull @@ -63,13 +61,6 @@ fun ModelEngine.getActiveModel(modelId: String): ActiveModel? { return modeledEntity.getModel(modelId.lowercase()).orNull() } -/** - * 尝试从 ActiveModel 中获取绑定的 EntityInstance 对象 - */ -fun ActiveModel.getBaseEntityInstance(): EntityInstance? { - return modeledEntity.base.original as? EntityInstance -} - /** * 播放模型动画 * @@ -140,70 +131,6 @@ fun ModelEngine.stopAnimation( } } -/** - * 更改模型部件 - * - * @param fromModelId 源模型 ID - * @param fromPartId 源部件 ID - * @param toModelId 目标模型 ID - * @param toPartId 目标部件 ID - */ -fun ModelEngine.changePart( - fromModelId: String, - fromPartId: String, - toModelId: String, - toPartId: String, -): Boolean { - val activeModel = getActiveModel(fromModelId) ?: return false - val fromBone = activeModel.getBone(fromPartId).orNull() ?: return false - if (fromBone.isRenderer) { - val toBlueprint = ModelEngineAPI.getBlueprint(toModelId) ?: return false - val toBone = toBlueprint.flatMap[toPartId] ?: return false - if (toBone.isRenderer) { - fromBone.setModelScale(toBone.scale) - fromBone.setModel(toBone) - return true - } - } - return false -} - -/** - * 更改模型部件的可见性 - * - * @param modelId 模型 ID - * @param partId 部件 ID - * @param visible 可见性 - */ -fun ModelEngine.changePartVisible( - modelId: String, - partId: String, - visible: Boolean, -): Boolean { - val activeModel = getActiveModel(modelId) ?: return false - val fromBone = activeModel.getBone(partId).orNull() ?: return false - if (fromBone.isRenderer) { - fromBone.isVisible = visible - return true - } - return false -} - -/** - * 当模型动画播放完成时 - */ -fun ModelEngine.whenAnimationEnd(callback: Runnable) { - this as EntityInstance - setTag("animation_end_callback", callback) -} - -@SubscribeEvent -internal fun onEnd(e: AnimationEndEvent) { - val entity = e.model.getBaseEntityInstance() ?: return - val callback = entity.getTag("animation_end_callback") as? Runnable ?: return - callback.run() -} - internal fun ModelEngine.createModel() { // 获取配置 val options = modelEngineOptions ?: ModelEngineOptions()