diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/recipes/Ingredient.kt b/src/main/java/de/bixilon/minosoft/data/mappings/recipes/Ingredient.kt index aa44c684e..3530aefc8 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/recipes/Ingredient.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/recipes/Ingredient.kt @@ -14,7 +14,7 @@ package de.bixilon.minosoft.data.mappings.recipes import de.bixilon.minosoft.data.inventory.ItemStack -data class Ingredient(val itemStacks: Array) { +data class Ingredient(val itemStacks: Array) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PacketJoinGame.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PacketJoinGame.kt index 492519a1b..beb8fd288 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PacketJoinGame.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PacketJoinGame.kt @@ -92,7 +92,7 @@ class PacketJoinGame(buffer: PlayInByteBuffer) : PlayS2CPacket() { if (buffer.versionId < ProtocolVersions.V_20W21A) { dimension = buffer.connection.mapping.dimensionRegistry.get(buffer.readInt()) } else { - val dimensionCodec = buffer.readNBT() + val dimensionCodec = buffer.readNBT()!! dimensions = parseDimensionCodec(dimensionCodec, buffer.versionId) if (buffer.versionId < ProtocolVersions.V_1_16_2_PRE3) { dimension = dimensions[buffer.readResourceLocation()]!! diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt index 0b89a754f..0cceab443 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt @@ -70,12 +70,11 @@ open class InByteBuffer { return bytes[pointer++] } - fun readByteArray(length: Int = readVarInt()): ByteArray { + open fun readByteArray(length: Int = readVarInt()): ByteArray { check(length <= bytes.size) { "Trying to allocate to much memory!" } val array = ByteArray(length) - for (i in 0 until length) { - array[i] = readByte() - } + System.arraycopy(bytes, pointer, array, 0, length) + pointer += length return array } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.java deleted file mode 100644 index 7532f3e34..000000000 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2021 Moritz Zwerger - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.protocol.protocol; - -import de.bixilon.minosoft.data.entities.meta.EntityMetaData; -import de.bixilon.minosoft.data.inventory.ItemStack; -import de.bixilon.minosoft.data.mappings.biomes.Biome; -import de.bixilon.minosoft.data.mappings.particle.Particle; -import de.bixilon.minosoft.data.mappings.particle.data.BlockParticleData; -import de.bixilon.minosoft.data.mappings.particle.data.DustParticleData; -import de.bixilon.minosoft.data.mappings.particle.data.ItemParticleData; -import de.bixilon.minosoft.data.mappings.particle.data.ParticleData; -import de.bixilon.minosoft.data.mappings.recipes.Ingredient; -import de.bixilon.minosoft.data.text.ChatComponent; -import de.bixilon.minosoft.protocol.network.connection.PlayConnection; -import de.bixilon.minosoft.util.nbt.tag.CompoundTag; -import de.bixilon.minosoft.util.nbt.tag.NBTTag; -import glm_.vec3.Vec3i; - -import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*; - -public class PlayInByteBuffer extends InByteBuffer { - private final PlayConnection connection; - private final int versionId; - - public PlayInByteBuffer(byte[] bytes, PlayConnection connection) { - super(bytes, connection); - this.connection = connection; - this.versionId = connection.getVersion().getVersionId(); - } - - public PlayInByteBuffer(PlayInByteBuffer buffer) { - super(buffer); - this.connection = buffer.getConnection(); - this.versionId = this.connection.getVersion().getVersionId(); - } - - public byte[] readByteArray() { - int count; - if (this.versionId < V_14W21A) { - count = readUnsignedShort(); - } else { - count = readVarInt(); - } - return readByteArray(count); - } - - - public Vec3i readBlockPosition() { - // ToDo: protocol id 7 - long raw = readLong(); - int x = (int) (raw >> 38); - if (this.versionId < V_18W43A) { - int y = (int) ((raw >> 26) & 0xFFF); - int z = (int) (raw << 38 >> 38); - return new Vec3i(x, y, z); - } - int y = (int) (raw << 52 >> 52); - int z = (int) (raw << 26 >> 38); - return new Vec3i(x, y, z); - } - - @Override - public ChatComponent readChatComponent() { - return ChatComponent.Companion.valueOf(this.connection.getVersion().getLocaleManager(), null, readString()); - } - - public ParticleData readParticle() { - Particle type = this.connection.getMapping().getParticleRegistry().get(readVarInt()); - return readParticleData(type); - } - - public ParticleData readParticleData(Particle type) { - if (this.versionId < V_17W45A) { - // old particle format - return switch (type.getResourceLocation().getFull()) { - case "minecraft:iconcrack" -> new ItemParticleData(new ItemStack(this.connection.getMapping().getItemRegistry().get((readVarInt() << 16) | readVarInt()), this.connection.getVersion()), type); - case "minecraft:blockcrack", "minecraft:blockdust", "minecraft:falling_dust" -> new BlockParticleData(this.connection.getMapping().getBlockState(readVarInt() << 4), type); - default -> new ParticleData(type); - }; - } - return switch (type.getResourceLocation().getFull()) { - case "minecraft:block", "minecraft:falling_dust" -> new BlockParticleData(this.connection.getMapping().getBlockState(readVarInt()), type); - case "minecraft:dust" -> new DustParticleData(readFloat(), readFloat(), readFloat(), readFloat(), type); - case "minecraft:item" -> new ItemParticleData(readItemStack(), type); - default -> new ParticleData(type); - }; - } - - public NBTTag readNBT() { - return readNBT(this.versionId < V_14W28B); - } - - public ItemStack readItemStack() { - if (this.versionId < V_1_13_2_PRE1) { - short id = readShort(); - if (id == -1) { - return null; - } - byte count = readByte(); - short metaData = 0; - - if (this.versionId < ProtocolDefinition.FLATTING_VERSION_ID) { - metaData = readShort(); - } - CompoundTag nbt = (CompoundTag) readNBT(this.versionId < V_14W28B); - return new ItemStack(this.connection.getVersion(), this.connection.getMapping().getItemRegistry().get((id << 16) | metaData), count, metaData, nbt); - } - if (readBoolean()) { - return new ItemStack(this.connection.getVersion(), this.connection.getMapping().getItemRegistry().get(readVarInt()), readByte(), (CompoundTag) readNBT()); - } - return null; - } - - public Biome[] readBiomeArray() { - int length = 0; - if (this.versionId >= V_20W28A) { - length = readVarInt(); - } else if (this.versionId >= V_19W36A) { - length = 1024; - } - if (length > ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE) { - throw new IllegalArgumentException("Trying to allocate to much memory"); - } - - Biome[] ret = new Biome[length]; - for (int i = 0; i < length; i++) { - int biomeId; - - if (this.versionId >= V_20W28A) { - biomeId = readVarInt(); - } else { - biomeId = readInt(); - } - ret[i] = this.connection.getMapping().getBiomeRegistry().get(biomeId); - } - return ret; - } - - public int getVersionId() { - return this.versionId; - } - - public EntityMetaData readMetaData() { - EntityMetaData metaData = new EntityMetaData(this.connection); - EntityMetaData.MetaDataHashMap sets = metaData.getSets(); - - if (this.versionId < V_15W31A) { // ToDo: This version was 48, but this one does not exist! - int item = readUnsignedByte(); - while (item != 0x7F) { - byte index = (byte) (item & 0x1F); - EntityMetaData.EntityMetaDataDataTypes type = this.connection.getMapping().getEntityMetaDataDataDataTypesRegistry().get((item & 0xFF) >> 5); - sets.put((int) index, metaData.getData(type, this)); - item = readByte(); - } - } else { - int index = readUnsignedByte(); - while (index != 0xFF) { - int id; - if (this.versionId < V_1_9_1_PRE1) { - id = readUnsignedByte(); - } else { - id = readVarInt(); - } - EntityMetaData.EntityMetaDataDataTypes type = this.connection.getMapping().getEntityMetaDataDataDataTypesRegistry().get(id); - if (type == null) { - throw new IllegalStateException("Can not get meta data index for id " + id); - } - sets.put(index, metaData.getData(type, this)); - index = readUnsignedByte(); - } - } - return metaData; - } - - public Ingredient readIngredient() { - return new Ingredient(readItemStackArray()); - } - - public Ingredient[] readIngredientArray(int length) { - if (length > ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE) { - throw new IllegalArgumentException("Trying to allocate to much memory"); - } - Ingredient[] ret = new Ingredient[length]; - for (int i = 0; i < length; i++) { - ret[i] = readIngredient(); - } - return ret; - } - - public Ingredient[] readIngredientArray() { - return readIngredientArray(readVarInt()); - } - - public ItemStack[] readItemStackArray(int length) { - if (length > ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE) { - throw new IllegalArgumentException("Trying to allocate to much memory"); - } - ItemStack[] res = new ItemStack[length]; - for (int i = 0; i < length; i++) { - res[i] = readItemStack(); - } - return res; - } - - public ItemStack[] readItemStackArray() { - return readItemStackArray(readVarInt()); - } - - public PlayConnection getConnection() { - return this.connection; - } - - public int readEntityId() { - if (this.versionId < V_14W04A) { - return readInt(); - } - return readVarInt(); - } -} diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt new file mode 100644 index 000000000..02669ff74 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt @@ -0,0 +1,206 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.protocol.protocol + +import de.bixilon.minosoft.data.entities.meta.EntityMetaData +import de.bixilon.minosoft.data.inventory.ItemStack +import de.bixilon.minosoft.data.mappings.biomes.Biome +import de.bixilon.minosoft.data.mappings.particle.Particle +import de.bixilon.minosoft.data.mappings.particle.data.BlockParticleData +import de.bixilon.minosoft.data.mappings.particle.data.DustParticleData +import de.bixilon.minosoft.data.mappings.particle.data.ItemParticleData +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.data.mappings.recipes.Ingredient +import de.bixilon.minosoft.data.text.ChatComponent +import de.bixilon.minosoft.data.text.ChatComponent.Companion.valueOf +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.* +import de.bixilon.minosoft.util.nbt.tag.CompoundTag +import de.bixilon.minosoft.util.nbt.tag.NBTTag +import glm_.vec3.Vec3i + + +class PlayInByteBuffer : InByteBuffer { + val connection: PlayConnection + val versionId: Int + + constructor(bytes: ByteArray, connection: PlayConnection) : super(bytes, connection) { + this.connection = connection + versionId = connection.version.versionId + } + + constructor(buffer: PlayInByteBuffer) : super(buffer) { + connection = buffer.connection + versionId = connection.version.versionId + } + + fun readByteArray(): ByteArray { + val length: Int = if (versionId < V_14W21A) { + readUnsignedShort() + } else { + readVarInt() + } + return super.readByteArray(length) + } + + + fun readBlockPosition(): Vec3i { + // ToDo: protocol id 7 + val raw = readLong() + val x = raw shr 38 + val y: Long + val z: Long + if (versionId < V_18W43A) { + y = raw shr 26 and 0xFFF + z = raw shl 38 shr 38 + } else { + y = raw shl 52 shr 52 + z = raw shl 26 shr 38 + } + return Vec3i(x, y, z) + } + + override fun readChatComponent(): ChatComponent { + return valueOf(connection.version.localeManager, null, readString()) + } + + fun readParticle(): ParticleData { + val type = connection.mapping.particleRegistry.get(readVarInt()) + return readParticleData(type) + } + + fun readParticleData(type: Particle): ParticleData { + // ToDo: Replace with dynamic particle type calling + if (this.versionId < V_17W45A) { + return when (type.resourceLocation.full) { + "minecraft:iconcrack" -> ItemParticleData(ItemStack(item = connection.mapping.itemRegistry.get(readVarInt() shl 16 or readVarInt()), connection.version), type) + "minecraft:blockcrack", "minecraft:blockdust", "minecraft:falling_dust" -> BlockParticleData(connection.mapping.getBlockState(readVarInt() shl 4), type) // ToDo: What about meta data? + else -> ParticleData(type) + } + } + + return when (type.resourceLocation.full) { + "minecraft:block", "minecraft:falling_dust" -> BlockParticleData(connection.mapping.getBlockState(readVarInt()), type) + "minecraft:dust" -> DustParticleData(readFloat(), readFloat(), readFloat(), readFloat(), type) + "minecraft:item" -> ItemParticleData(readItemStack(), type) + else -> ParticleData(type) + } + } + + fun readNBT(): NBTTag? { + return readNBT(versionId < V_14W28B) + } + + fun readItemStack(): ItemStack? { + if (versionId < V_1_13_2_PRE1) { + val id = readShort().toInt() + if (id == -1) { + return null + } + val count = readByte() + var metaData = 0 + if (connection.version.isFlattened()) { + metaData = readUnsignedShort() + } + val nbt = readNBT(versionId < V_14W28B) as CompoundTag? + return ItemStack(connection.version, connection.mapping.itemRegistry.get(id shl 16 or metaData), count, metaData, nbt) + } + + return if (readBoolean()) { + ItemStack(connection.version, connection.mapping.itemRegistry.get(readVarInt()), readByte().toInt(), readNBT() as CompoundTag?) + } else { + null + } + } + + fun readItemStackArray(length: Int = readVarInt()): Array { + return readArray(length) { readItemStack() } + } + + fun readBiomeArray(): Array { + val length = when { + versionId >= V_20W28A -> { + readVarInt() + } + versionId >= V_19W36A -> { + 1024 + } + else -> { + 0 + } + } + + check(length <= ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE) { "Trying to allocate to much memory" } + + val ret: MutableList = mutableListOf() + for (i in 0 until length) { + val biomeId: Int = if (versionId >= V_20W28A) { + readVarInt() + } else { + readInt() + } + ret.add(i, connection.mapping.biomeRegistry.get(biomeId)) + } + return ret.toTypedArray() + } + + fun readMetaData(): EntityMetaData { + val metaData = EntityMetaData(connection) + val sets = metaData.sets + if (versionId < V_15W31A) { // ToDo: This version was 48, but this one does not exist! + var item = readUnsignedByte() + while (item != 0x7F) { + val index = item and 0x1F + val type = connection.mapping.entityMetaDataDataDataTypesRegistry.get(item and 0xFF shr 5)!! + sets[index] = metaData.getData(type, this)!! + item = readUnsignedByte() + } + } else { + var index = readUnsignedByte() + while (index != 0xFF) { + val id: Int = if (versionId < V_1_9_1_PRE1) { + readUnsignedByte() + } else { + readVarInt() + } + val type = connection.mapping.entityMetaDataDataDataTypesRegistry.get(id) ?: error("Can not get meta data index for id $id") + sets[index] = metaData.getData(type, this)!! + index = readUnsignedByte() + } + } + return metaData + } + + fun readIngredient(): Ingredient { + return Ingredient(readItemStackArray()) + } + + @Deprecated(message = "Legacy only", replaceWith = ReplaceWith("readIngredientArray(readVarInt())")) + fun readIngredientArray(): Array { + return readIngredientArray(readVarInt()) + } + + fun readIngredientArray(length: Int = readVarInt()): Array { + return readArray(length) { readIngredient() } + } + + fun readEntityId(): Int { + return if (versionId < V_14W04A) { + readInt() + } else { + readVarInt() + } + } + + +}