VIAaaS/src/main/kotlin/com/viaversion/aas/protocol/id47toid5/packets/PlayerPackets.kt

500 lines
23 KiB
Kotlin

package com.viaversion.aas.protocol.id47toid5.packets
import com.google.common.base.Charsets
import com.viaversion.aas.generateOfflinePlayerUuid
import com.viaversion.aas.protocol.id47toid5.Protocol1_8To1_7_6
import com.viaversion.aas.protocol.id47toid5.metadata.MetadataRewriter
import com.viaversion.aas.protocol.id47toid5.storage.EntityTracker
import com.viaversion.aas.protocol.id47toid5.storage.Scoreboard
import com.viaversion.aas.protocol.id47toid5.storage.Tablist
import com.viaversion.aas.protocol.xyzToPosition
import com.viaversion.aas.protocol.xyzUBytePos
import com.viaversion.viaversion.api.Via
import com.viaversion.viaversion.api.minecraft.entities.Entity1_10Types
import com.viaversion.viaversion.api.minecraft.item.Item
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper
import com.viaversion.viaversion.api.protocol.packet.State
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper
import com.viaversion.viaversion.api.protocol.remapper.TypeRemapper
import com.viaversion.viaversion.api.type.Type
import com.viaversion.viaversion.api.type.types.CustomByteType
import com.viaversion.viaversion.api.type.types.version.Types1_8
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag
import com.viaversion.viaversion.util.ChatColorUtil
import de.gerrygames.viarewind.protocol.protocol1_7_6_10to1_8.types.CustomStringType
import de.gerrygames.viarewind.protocol.protocol1_7_6_10to1_8.types.Types1_7_6_10
import de.gerrygames.viarewind.utils.ChatUtil
import io.netty.buffer.Unpooled
import java.nio.charset.StandardCharsets
import java.util.*
import kotlin.experimental.and
fun Protocol1_8To1_7_6.registerPlayerPackets() {
//Keep Alive
this.registerClientbound(State.PLAY, 0x00, 0x00, object : PacketRemapper() {
override fun registerMap() {
map(Type.INT, Type.VAR_INT)
}
})
//Join Game
this.registerClientbound(State.PLAY, 0x01, 0x01, object : PacketRemapper() {
override fun registerMap() {
map(Type.INT) //Entiy Id
map(Type.UNSIGNED_BYTE) //Gamemode
map(Type.BYTE) //Dimension
map(Type.UNSIGNED_BYTE) //Difficulty
map(Type.UNSIGNED_BYTE) //Max players
map(Type.STRING) //Level Type
create { packetWrapper ->
packetWrapper.write(Type.BOOLEAN, false) //Reduced Debug Info
}
}
})
//Chat Message
this.registerClientbound(State.PLAY, 0x02, 0x02, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING) //Chat Message
create { packetWrapper ->
packetWrapper.write(Type.BYTE, 0.toByte()) //Position (chat box)
}
}
})
//Spawn Position
this.registerClientbound(State.PLAY, 0x05, 0x05, object : PacketRemapper() {
override fun registerMap() {
map(xyzToPosition, TypeRemapper(Type.POSITION)) //Position
}
})
//Update Health
this.registerClientbound(State.PLAY, 0x06, 0x06, object : PacketRemapper() {
override fun registerMap() {
map(Type.FLOAT) //Health
map(Type.SHORT, Type.VAR_INT) //Food
map(Type.FLOAT) //Food Saturation
}
})
//Player Position And Look
this.registerClientbound(State.PLAY, 0x08, 0x08, object : PacketRemapper() {
override fun registerMap() {
map(Type.DOUBLE) //x
handler { packetWrapper ->
val y = packetWrapper.read(Type.DOUBLE)
packetWrapper.write(Type.DOUBLE, y - 1.62) //y - fixed value
}
map(Type.DOUBLE) //z
map(Type.FLOAT) //pitch
map(Type.FLOAT) //yaw
handler { packetWrapper ->
packetWrapper.read(Type.BOOLEAN) //OnGround
packetWrapper.write(Type.BYTE, 0.toByte()) //BitMask
}
}
})
//Use Bed
this.registerClientbound(State.PLAY, 0x0A, 0x0A, object : PacketRemapper() {
override fun registerMap() {
map(Type.INT, Type.VAR_INT) //Entity Id
map(xyzUBytePos, TypeRemapper(Type.POSITION))
}
})
//Spawn Player
this.registerClientbound(State.PLAY, 0x0C, 0x0C, object : PacketRemapper() {
override fun registerMap() {
handler { packetWrapper ->
val entityId = packetWrapper.passthrough(Type.VAR_INT) //Entity Id
val uuid = UUID.fromString(packetWrapper.read(Type.STRING)) //UUID
packetWrapper.write(Type.UUID, uuid)
val name = ChatColorUtil.stripColor(packetWrapper.read(Type.STRING)) //Name
val dataCount = packetWrapper.read(Type.VAR_INT) //DataCunt
val properties = ArrayList<Tablist.Property>()
for (i in 0 until dataCount) {
val key: String = packetWrapper.read(Type.STRING) //Name
val value: String = packetWrapper.read(Type.STRING) //Value
val signature: String = packetWrapper.read(Type.STRING) //Signature
properties.add(Tablist.Property(key, value, signature))
}
val x = packetWrapper.passthrough(Type.INT) //x
val y = packetWrapper.passthrough(Type.INT) //y
val z = packetWrapper.passthrough(Type.INT) //z
val yaw = packetWrapper.passthrough(Type.BYTE) //yaw
val pitch = packetWrapper.passthrough(Type.BYTE) //pitch
val item = packetWrapper.passthrough(Type.SHORT) //Item in hand
val metadata = packetWrapper.read(Types1_7_6_10.METADATA_LIST) //Metadata
MetadataRewriter.transform(Entity1_10Types.EntityType.PLAYER, metadata)
packetWrapper.write(Types1_8.METADATA_LIST, metadata)
val tablist = packetWrapper.user().get(Tablist::class.java)!!
var entryByName = tablist.getTabListEntry(name)
if (entryByName == null && name.length > 14) entryByName =
tablist.getTabListEntry(name.substring(0, 14))
val entryByUUID = tablist.getTabListEntry(uuid)
if (entryByName == null || entryByUUID == null) {
if (entryByName != null || entryByUUID != null) {
val remove = PacketWrapper.create(0x38, null, packetWrapper.user())
remove.write(Type.VAR_INT, 4)
remove.write(Type.VAR_INT, 1)
remove.write(Type.UUID, entryByName?.uuid ?: entryByUUID!!.uuid)
tablist.remove(entryByName ?: entryByUUID!!)
remove.send(Protocol1_8To1_7_6::class.java)
}
val packetPlayerListItem = PacketWrapper.create(0x38, null, packetWrapper.user())
val newentry = Tablist.TabListEntry(name, uuid)
if (entryByName != null || entryByUUID != null) {
newentry.displayName =
if (entryByUUID != null) entryByUUID.displayName else entryByName!!.displayName
}
newentry.properties = properties
tablist.add(newentry)
packetPlayerListItem.write(Type.VAR_INT, 0)
packetPlayerListItem.write(Type.VAR_INT, 1)
packetPlayerListItem.write(Type.UUID, newentry.uuid)
packetPlayerListItem.write(Type.STRING, newentry.name)
packetPlayerListItem.write(Type.VAR_INT, dataCount)
for (property in newentry.properties) {
packetPlayerListItem.write(Type.STRING, property.name)
packetPlayerListItem.write(Type.STRING, property.value)
packetPlayerListItem.write(Type.BOOLEAN, property.signature != null)
if (property.signature != null) packetPlayerListItem.write(Type.STRING, property.signature)
}
packetPlayerListItem.write(Type.VAR_INT, 0)
packetPlayerListItem.write(Type.VAR_INT, 0)
packetPlayerListItem.write(Type.BOOLEAN, newentry.displayName != null)
if (newentry.displayName != null) {
packetPlayerListItem.write(Type.STRING, newentry.displayName)
}
packetPlayerListItem.send(Protocol1_8To1_7_6::class.java)
packetWrapper.cancel()
val delayedPacket = PacketWrapper.create(0x0C, null, packetWrapper.user())
delayedPacket.write(Type.VAR_INT, entityId)
delayedPacket.write(Type.UUID, uuid)
delayedPacket.write(Type.INT, x)
delayedPacket.write(Type.INT, y)
delayedPacket.write(Type.INT, z)
delayedPacket.write(Type.BYTE, yaw)
delayedPacket.write(Type.BYTE, pitch)
delayedPacket.write(Type.SHORT, item)
delayedPacket.write(Types1_8.METADATA_LIST, metadata)
Via.getPlatform().runSync({
try {
delayedPacket.send(Protocol1_8To1_7_6::class.java)
} catch (ex: Exception) {
ex.printStackTrace()
}
}, 1L)
} else {
entryByUUID.properties = properties
}
}
handler { packetWrapper ->
val entityID: Int = packetWrapper.get(Type.VAR_INT, 0)
val tracker: EntityTracker = packetWrapper.user().get(EntityTracker::class.java)!!
tracker.clientEntityTypes[entityID] = Entity1_10Types.EntityType.PLAYER
tracker.sendMetadataBuffer(entityID)
}
}
})
//Set Experience
this.registerClientbound(State.PLAY, 0x1F, 0x1F, object : PacketRemapper() {
override fun registerMap() {
map(Type.FLOAT) //Experience bar
map(Type.SHORT, Type.VAR_INT) //Level
map(Type.SHORT, Type.VAR_INT) //Total Experience
}
})
//Player List Item
this.registerClientbound(State.PLAY, 0x38, 0x38, object : PacketRemapper() {
override fun registerMap() {
handler { packetWrapper ->
val name = packetWrapper.read(Type.STRING)
val displayName: String? = null
val online = packetWrapper.read(Type.BOOLEAN)
val ping = packetWrapper.read(Type.SHORT)
val tablist = packetWrapper.user().get(Tablist::class.java)!!
var entry = tablist.getTabListEntry(name)
if (!online && entry != null) {
packetWrapper.write(Type.VAR_INT, 4)
packetWrapper.write(Type.VAR_INT, 1)
packetWrapper.write(Type.UUID, entry.uuid)
tablist.remove(entry)
} else if (online && entry == null) {
val uuid = if (name == packetWrapper.user().protocolInfo?.username) {
packetWrapper.user().protocolInfo!!.uuid!!
} else {
generateOfflinePlayerUuid(name)
}
entry = Tablist.TabListEntry(name, uuid)
entry.displayName = displayName
tablist.add(entry)
packetWrapper.write(Type.VAR_INT, 0) // Add
packetWrapper.write(Type.VAR_INT, 1) // Entries
packetWrapper.write(Type.UUID, entry.uuid)
packetWrapper.write(Type.STRING, entry.name)
packetWrapper.write(Type.VAR_INT, entry.properties.size)
for (property in entry.properties) {
packetWrapper.write(Type.STRING, property.name)
packetWrapper.write(Type.STRING, property.value)
packetWrapper.write(Type.BOOLEAN, property.signature != null)
if (property.signature != null) packetWrapper.write(Type.STRING, property.signature)
}
packetWrapper.write(Type.VAR_INT, 0)
packetWrapper.write(Type.VAR_INT, ping.toInt())
packetWrapper.write(Type.BOOLEAN, entry.displayName != null)
if (entry.displayName != null) {
packetWrapper.write(Type.STRING, entry.displayName)
}
} else if (online && Tablist.shouldUpdateDisplayName(entry!!.displayName, displayName)) {
entry.displayName = displayName
packetWrapper.write(Type.VAR_INT, 3)
packetWrapper.write(Type.VAR_INT, 1)
packetWrapper.write(Type.UUID, entry.uuid)
packetWrapper.write(Type.BOOLEAN, entry.displayName != null)
if (entry.displayName != null) {
packetWrapper.write(Type.STRING, entry.displayName)
}
} else if (online) {
entry!!.ping = ping.toInt()
packetWrapper.write(Type.VAR_INT, 2) // Update ping
packetWrapper.write(Type.VAR_INT, 1) // Entries
packetWrapper.write(Type.UUID, entry.uuid)
packetWrapper.write(Type.VAR_INT, ping.toInt())
} else {
packetWrapper.write(Type.VAR_INT, 0)
packetWrapper.write(Type.VAR_INT, 0)
}
}
}
})
//Scoreboard Objective
this.registerClientbound(State.PLAY, 0x3B, 0x3B, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING) // name
handler { packetWrapper ->
val value = packetWrapper.read(Type.STRING)
val mode = packetWrapper.read(Type.BYTE)
packetWrapper.write(Type.BYTE, mode)
if (mode.toInt() == 0 || mode.toInt() == 2) {
packetWrapper.write(Type.STRING, value)
packetWrapper.write(Type.STRING, "integer")
}
}
}
})
//Update Score
this.registerClientbound(State.PLAY, 0x3C, 0x3C, object : PacketRemapper() {
override fun registerMap() {
handler { packetWrapper ->
val name = packetWrapper.passthrough(Type.STRING)
val mode = packetWrapper.passthrough(Type.BYTE)
if (mode.toInt() != 1) {
val objective = packetWrapper.passthrough(Type.STRING)
packetWrapper.user().get(Scoreboard::class.java)!!.put(name, objective)
packetWrapper.write(Type.VAR_INT, packetWrapper.read(Type.INT))
} else {
val objective = packetWrapper.user().get(Scoreboard::class.java)!!.get(name)
packetWrapper.write(Type.STRING, objective)
}
}
}
})
//Scoreboard Teams
this.registerClientbound(State.PLAY, 0x3E, 0x3E, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING)
handler { packetWrapper ->
val mode: Byte = packetWrapper.read(Type.BYTE)
packetWrapper.write(Type.BYTE, mode)
if (mode.toInt() == 0 || mode.toInt() == 2) {
packetWrapper.passthrough(Type.STRING)
packetWrapper.passthrough(Type.STRING)
packetWrapper.passthrough(Type.STRING)
packetWrapper.passthrough(Type.BYTE)
packetWrapper.write(Type.STRING, "always")
packetWrapper.write(Type.BYTE, 0.toByte())
}
if (mode.toInt() == 0 || mode.toInt() == 3 || mode.toInt() == 4) {
val count = packetWrapper.read(Type.SHORT).toInt()
val type = CustomStringType(count)
val entries = packetWrapper.read(type)
packetWrapper.write(Type.STRING_ARRAY, entries)
}
}
}
})
//Custom Payload
this.registerClientbound(State.PLAY, 0x3F, 0x3F, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING)
handler { packetWrapper ->
val channel: String = packetWrapper.get(Type.STRING, 0)
val length: Short = packetWrapper.read(Type.SHORT)
if (channel == "MC|Brand") {
val data: ByteArray = packetWrapper.read(CustomByteType(length.toInt()))
val brand = String(data, StandardCharsets.UTF_8)
packetWrapper.write(Type.STRING, brand)
} else if (channel == "MC|AdvCdm") {
val type: Byte = packetWrapper.passthrough(Type.BYTE)
if (type.toInt() == 0) {
packetWrapper.passthrough(Type.INT)
packetWrapper.passthrough(Type.INT)
packetWrapper.passthrough(Type.INT)
packetWrapper.passthrough(Type.STRING)
packetWrapper.passthrough(Type.BOOLEAN)
} else if (type.toInt() == 1) {
packetWrapper.passthrough(Type.INT)
packetWrapper.passthrough(Type.STRING)
packetWrapper.passthrough(Type.BOOLEAN)
}
packetWrapper.write(Type.BYTE, 1.toByte())
}
if (channel.equals("MC|TrList", ignoreCase = true)) {
packetWrapper.passthrough(Type.INT) //Window Id
val size: Int = packetWrapper.passthrough(Type.UNSIGNED_BYTE).toInt() //Size
for (i in 0 until size) {
var item: Item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM)
packetWrapper.write(Type.ITEM, item) //Buy Item 1
item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM)
packetWrapper.write(Type.ITEM, item) //Buy Item 3
val has3Items: Boolean = packetWrapper.passthrough(Type.BOOLEAN)
if (has3Items) {
item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM)
packetWrapper.write(Type.ITEM, item) //Buy Item 2
}
packetWrapper.passthrough(Type.BOOLEAN) //Unavailable
packetWrapper.write(Type.INT, 0) //Uses
packetWrapper.write(Type.INT, 0) //Max Uses
}
}
}
}
})
//Keep Alive
this.registerServerbound(State.PLAY, 0x00, 0x00, object : PacketRemapper() {
override fun registerMap() {
map(Type.VAR_INT, Type.INT)
}
})
//Custom Payload
this.registerServerbound(State.PLAY, 0x17, 0x17, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING)
handler { packetWrapper ->
val channel = packetWrapper.get(Type.STRING, 0)
if (channel.equals("MC|ItemName", ignoreCase = true)) {
val name: ByteArray = packetWrapper.read(Type.STRING).toByteArray(Charsets.UTF_8)
packetWrapper.write(Type.REMAINING_BYTES, name)
} else if (channel.equals("MC|BEdit", ignoreCase = true) || channel.equals(
"MC|BSign",
ignoreCase = true
)
) {
packetWrapper.read(Type.SHORT) //length
val book: Item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM)
val tag = book.tag
if (tag != null && tag.contains("pages")) {
val pages = tag.get<ListTag>("pages")
if (pages != null) {
(0 until pages.size()).forEach { i ->
val page = pages.get<StringTag>(i)
var value: String? = page.value
value = ChatUtil.jsonToLegacy(value)
page.value = value
}
}
}
packetWrapper.write(Type.ITEM, book)
}
packetWrapper.cancel()
packetWrapper.id = -1
val newPacketBuf = Unpooled.buffer()
packetWrapper.writeToBuffer(newPacketBuf)
val newWrapper = PacketWrapper.create(0x17, newPacketBuf, packetWrapper.user())
newWrapper.passthrough(Type.STRING)
newWrapper.write(Type.SHORT, newPacketBuf.readableBytes().toShort())
newWrapper.sendToServer(Protocol1_8To1_7_6::class.java, true, true)
}
}
})
//Player Position
this.registerServerbound(State.PLAY, 0x04, 0x04, object : PacketRemapper() {
override fun registerMap() {
map(Type.DOUBLE) //X
handler { packetWrapper ->
val feetY: Double = packetWrapper.passthrough(Type.DOUBLE)
packetWrapper.write(Type.DOUBLE, feetY + 1.62) //HeadY
}
map(Type.DOUBLE) //Z
map(Type.BOOLEAN) //OnGround
}
})
//Player Position And Look
this.registerServerbound(State.PLAY, 0x06, 0x06, object : PacketRemapper() {
override fun registerMap() {
map(Type.DOUBLE) //X
handler { packetWrapper ->
val feetY: Double = packetWrapper.passthrough(Type.DOUBLE)
packetWrapper.write(Type.DOUBLE, feetY + 1.62) //HeadY
}
map(Type.DOUBLE) //Z
map(Type.FLOAT) //Yaw
map(Type.FLOAT) //Pitch
map(Type.BOOLEAN) //OnGround
}
})
//Animation
this.registerServerbound(State.PLAY, 0x0A, 0x0A, object : PacketRemapper() {
override fun registerMap() {
create { packetWrapper ->
packetWrapper.write(Type.INT, 0) //Entity Id, hopefully 0 is ok
packetWrapper.write(Type.BYTE, 1.toByte()) //Animation
}
}
})
//Client Settings
this.registerServerbound(State.PLAY, 0x15, 0x15, object : PacketRemapper() {
override fun registerMap() {
map(Type.STRING)
map(Type.BYTE)
map(Type.BYTE)
map(Type.BOOLEAN)
create { packetWrapper -> packetWrapper.write(Type.BYTE, 0.toByte()) }
handler { packetWrapper ->
val flags = packetWrapper.read(Type.UNSIGNED_BYTE)
packetWrapper.write(Type.BOOLEAN, flags and 1 == 1.toShort())
}
}
})
//Tab-Complete
this.registerServerbound(State.PLAY, 0x14, 0x14, object : PacketRemapper() {
override fun registerMap() {
handler { packetWrapper ->
val text = packetWrapper.read(Type.STRING)
packetWrapper.clearInputBuffer()
packetWrapper.write(Type.STRING, text)
}
}
})
}