mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 18:05:51 -04:00
PacketChunkData support, outsource chunk parsing into ChunkUtil.java
This commit is contained in:
parent
d1b0eb3b2c
commit
699b12e036
@ -13,18 +13,15 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.protocol.packets.clientbound.play;
|
package de.bixilon.minosoft.protocol.packets.clientbound.play;
|
||||||
|
|
||||||
import de.bixilon.minosoft.game.datatypes.blocks.Block;
|
|
||||||
import de.bixilon.minosoft.game.datatypes.world.Chunk;
|
import de.bixilon.minosoft.game.datatypes.world.Chunk;
|
||||||
import de.bixilon.minosoft.game.datatypes.world.ChunkLocation;
|
import de.bixilon.minosoft.game.datatypes.world.ChunkLocation;
|
||||||
import de.bixilon.minosoft.game.datatypes.world.ChunkNibble;
|
|
||||||
import de.bixilon.minosoft.game.datatypes.world.ChunkNibbleLocation;
|
|
||||||
import de.bixilon.minosoft.logging.Log;
|
import de.bixilon.minosoft.logging.Log;
|
||||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||||
import de.bixilon.minosoft.protocol.protocol.InPacketBuffer;
|
import de.bixilon.minosoft.protocol.protocol.InPacketBuffer;
|
||||||
import de.bixilon.minosoft.protocol.protocol.PacketHandler;
|
import de.bixilon.minosoft.protocol.protocol.PacketHandler;
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
|
||||||
import de.bixilon.minosoft.util.BitByte;
|
import de.bixilon.minosoft.util.ChunkUtil;
|
||||||
import de.bixilon.minosoft.util.Util;
|
import de.bixilon.minosoft.util.Util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -37,8 +34,7 @@ public class PacketChunkBulk implements ClientboundPacket {
|
|||||||
public void read(InPacketBuffer buffer, ProtocolVersion v) {
|
public void read(InPacketBuffer buffer, ProtocolVersion v) {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case VERSION_1_7_10:
|
case VERSION_1_7_10:
|
||||||
// ToDo only implement once, not twice (chunk data and chunk bulk)
|
short chunkCount = buffer.readShort();
|
||||||
short chunkColumnCount = buffer.readShort();
|
|
||||||
int dataLen = buffer.readInteger();
|
int dataLen = buffer.readInteger();
|
||||||
boolean containsSkyLight = buffer.readBoolean();
|
boolean containsSkyLight = buffer.readBoolean();
|
||||||
|
|
||||||
@ -46,77 +42,13 @@ public class PacketChunkBulk implements ClientboundPacket {
|
|||||||
InByteBuffer decompressed = Util.decompress(buffer.readBytes(dataLen));
|
InByteBuffer decompressed = Util.decompress(buffer.readBytes(dataLen));
|
||||||
|
|
||||||
// chunk meta data
|
// chunk meta data
|
||||||
int read = 0;
|
for (int i = 0; i < chunkCount; i++) {
|
||||||
for (int i = 0; i < chunkColumnCount; i++) {
|
|
||||||
int x = buffer.readInteger();
|
int x = buffer.readInteger();
|
||||||
int z = buffer.readInteger();
|
int z = buffer.readInteger();
|
||||||
short sectionBitMask = buffer.readShort();
|
short sectionBitMask = buffer.readShort();
|
||||||
short addBitMask = buffer.readShort();
|
short addBitMask = buffer.readShort();
|
||||||
|
|
||||||
|
chunkMap.put(new ChunkLocation(x, z), ChunkUtil.readChunkPacket(v, decompressed, sectionBitMask, addBitMask, true, containsSkyLight));
|
||||||
//chunk
|
|
||||||
byte sections = BitByte.getBitCount(sectionBitMask);
|
|
||||||
int totalBytes = 4096 * sections; // 16 * 16 * 16 * sections; Section Width * Section Height * Section Width * sections
|
|
||||||
int halfBytes = totalBytes / 2; // half bytes
|
|
||||||
|
|
||||||
byte[] blockTypes = decompressed.readBytes(totalBytes);
|
|
||||||
byte[] meta = decompressed.readBytes(halfBytes);
|
|
||||||
byte[] light = decompressed.readBytes(halfBytes);
|
|
||||||
byte[] skyLight = null;
|
|
||||||
if (containsSkyLight) {
|
|
||||||
skyLight = decompressed.readBytes(halfBytes);
|
|
||||||
}
|
|
||||||
byte[] addBlockTypes = decompressed.readBytes(Integer.bitCount(addBitMask) * 2048); // 16 * 16 * 16 * addBlocks / 2
|
|
||||||
//ToDo test add Block Types
|
|
||||||
byte[] biomes = decompressed.readBytes(256);
|
|
||||||
|
|
||||||
//parse data
|
|
||||||
int arrayPos = 0;
|
|
||||||
HashMap<Byte, ChunkNibble> nibbleMap = new HashMap<>();
|
|
||||||
for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column
|
|
||||||
if (BitByte.isBitSet(sectionBitMask, c)) {
|
|
||||||
|
|
||||||
HashMap<ChunkNibbleLocation, Block> blockMap = new HashMap<>();
|
|
||||||
|
|
||||||
for (int nibbleY = 0; nibbleY < 16; nibbleY++) {
|
|
||||||
for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) {
|
|
||||||
for (int nibbleX = 0; nibbleX < 16; nibbleX++) {
|
|
||||||
|
|
||||||
short singeBlockId = blockTypes[arrayPos];
|
|
||||||
byte singleMeta;
|
|
||||||
// get block meta and shift and add (merge) id if needed
|
|
||||||
if (arrayPos % 2 == 0) {
|
|
||||||
// high bits
|
|
||||||
singleMeta = BitByte.getLow4Bits(meta[arrayPos / 2]);
|
|
||||||
if (BitByte.isBitSet(addBitMask, c)) {
|
|
||||||
singeBlockId = (short) ((singeBlockId << 4) | BitByte.getHigh4Bits(addBlockTypes[arrayPos / 2]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// low 4 bits
|
|
||||||
singleMeta = BitByte.getHigh4Bits(meta[arrayPos / 2]);
|
|
||||||
|
|
||||||
if (BitByte.isBitSet(addBitMask, c)) {
|
|
||||||
singeBlockId = (short) ((singeBlockId << 4) | BitByte.getLow4Bits(addBlockTypes[arrayPos / 2]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ToDo light, biome
|
|
||||||
Block block = Block.byLegacy(singeBlockId, singleMeta);
|
|
||||||
if (block == Block.AIR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block);
|
|
||||||
arrayPos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nibbleMap.put(c, new ChunkNibble(blockMap));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
chunkMap.put(new ChunkLocation(x, z), new Chunk(nibbleMap));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Codename Minosoft
|
||||||
|
* Copyright (C) 2020 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.protocol.packets.clientbound.play;
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.game.datatypes.world.Chunk;
|
||||||
|
import de.bixilon.minosoft.game.datatypes.world.ChunkLocation;
|
||||||
|
import de.bixilon.minosoft.logging.Log;
|
||||||
|
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.InPacketBuffer;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.PacketHandler;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
|
||||||
|
import de.bixilon.minosoft.util.ChunkUtil;
|
||||||
|
import de.bixilon.minosoft.util.Util;
|
||||||
|
|
||||||
|
public class PacketChunkData implements ClientboundPacket {
|
||||||
|
ChunkLocation location;
|
||||||
|
Chunk chunk;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(InPacketBuffer buffer, ProtocolVersion v) {
|
||||||
|
switch (v) {
|
||||||
|
case VERSION_1_7_10:
|
||||||
|
this.location = new ChunkLocation(buffer.readInteger(), buffer.readInteger());
|
||||||
|
boolean groundUpContinuous = buffer.readBoolean();
|
||||||
|
short sectionBitMask = buffer.readShort();
|
||||||
|
short addBitMask = buffer.readShort();
|
||||||
|
|
||||||
|
// decompress chunk data
|
||||||
|
InByteBuffer decompressed = Util.decompress(buffer.readBytes(buffer.readInteger()));
|
||||||
|
|
||||||
|
chunk = ChunkUtil.readChunkPacket(v, decompressed, sectionBitMask, addBitMask, groundUpContinuous, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log() {
|
||||||
|
Log.protocol(String.format("Chunk packet received (chunk: %s)", location.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkLocation getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk getChunk() {
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(PacketHandler h) {
|
||||||
|
h.handle(this);
|
||||||
|
}
|
||||||
|
}
|
@ -239,4 +239,8 @@ public class PacketHandler {
|
|||||||
public void handle(PacketSpawnWeatherEntity pkg) {
|
public void handle(PacketSpawnWeatherEntity pkg) {
|
||||||
//ToDo
|
//ToDo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handle(PacketChunkData pkg) {
|
||||||
|
connection.getPlayer().getWorld().setChunk(pkg.getLocation(), pkg.getChunk());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,5 +81,6 @@ public interface Protocol {
|
|||||||
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_OBJECT, PacketSpawnObject.class);
|
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_OBJECT, PacketSpawnObject.class);
|
||||||
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_EXPERIENCE_ORB, PacketSpawnExperienceOrb.class);
|
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_EXPERIENCE_ORB, PacketSpawnExperienceOrb.class);
|
||||||
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_WEATHER_ENTITY, PacketSpawnWeatherEntity.class);
|
packetClassMapping.put(Packets.Clientbound.PLAY_SPAWN_WEATHER_ENTITY, PacketSpawnWeatherEntity.class);
|
||||||
|
packetClassMapping.put(Packets.Clientbound.PLAY_CHUNK_DATA, PacketChunkData.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
99
src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
Normal file
99
src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Codename Minosoft
|
||||||
|
* Copyright (C) 2020 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.util;
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.game.datatypes.blocks.Block;
|
||||||
|
import de.bixilon.minosoft.game.datatypes.world.Chunk;
|
||||||
|
import de.bixilon.minosoft.game.datatypes.world.ChunkNibble;
|
||||||
|
import de.bixilon.minosoft.game.datatypes.world.ChunkNibbleLocation;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ChunkUtil {
|
||||||
|
public static Chunk readChunkPacket(ProtocolVersion v, InByteBuffer buffer, short sectionBitMask, short addBitMask, boolean groundUpContinuous, boolean containsSkyLight) {
|
||||||
|
|
||||||
|
switch (v) {
|
||||||
|
case VERSION_1_7_10:
|
||||||
|
//chunk
|
||||||
|
byte sections = BitByte.getBitCount(sectionBitMask);
|
||||||
|
int totalBytes = 4096 * sections; // 16 * 16 * 16 * sections; Section Width * Section Height * Section Width * sections
|
||||||
|
int halfBytes = totalBytes / 2; // half bytes
|
||||||
|
|
||||||
|
byte[] blockTypes = buffer.readBytes(totalBytes);
|
||||||
|
byte[] meta = buffer.readBytes(halfBytes);
|
||||||
|
byte[] light = buffer.readBytes(halfBytes);
|
||||||
|
byte[] skyLight = null;
|
||||||
|
if (containsSkyLight) {
|
||||||
|
skyLight = buffer.readBytes(halfBytes);
|
||||||
|
}
|
||||||
|
byte[] addBlockTypes = buffer.readBytes(Integer.bitCount(addBitMask) * 2048); // 16 * 16 * 16 * addBlocks / 2
|
||||||
|
if (groundUpContinuous) {
|
||||||
|
byte[] biomes = buffer.readBytes(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
//parse data
|
||||||
|
int arrayPos = 0;
|
||||||
|
HashMap<Byte, ChunkNibble> nibbleMap = new HashMap<>();
|
||||||
|
for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column
|
||||||
|
if (BitByte.isBitSet(sectionBitMask, c)) {
|
||||||
|
|
||||||
|
HashMap<ChunkNibbleLocation, Block> blockMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (int nibbleY = 0; nibbleY < 16; nibbleY++) {
|
||||||
|
for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) {
|
||||||
|
for (int nibbleX = 0; nibbleX < 16; nibbleX++) {
|
||||||
|
|
||||||
|
short singeBlockId = blockTypes[arrayPos];
|
||||||
|
byte singleMeta;
|
||||||
|
// get block meta and shift and add (merge) id if needed
|
||||||
|
if (arrayPos % 2 == 0) {
|
||||||
|
// high bits
|
||||||
|
singleMeta = BitByte.getLow4Bits(meta[arrayPos / 2]);
|
||||||
|
if (BitByte.isBitSet(addBitMask, c)) {
|
||||||
|
singeBlockId = (short) ((singeBlockId << 4) | BitByte.getHigh4Bits(addBlockTypes[arrayPos / 2]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// low 4 bits
|
||||||
|
singleMeta = BitByte.getHigh4Bits(meta[arrayPos / 2]);
|
||||||
|
|
||||||
|
if (BitByte.isBitSet(addBitMask, c)) {
|
||||||
|
singeBlockId = (short) ((singeBlockId << 4) | BitByte.getLow4Bits(addBlockTypes[arrayPos / 2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ToDo light, biome
|
||||||
|
Block block = Block.byLegacy(singeBlockId, singleMeta);
|
||||||
|
if (block == Block.AIR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block);
|
||||||
|
arrayPos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nibbleMap.put(c, new ChunkNibble(blockMap));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return new Chunk(nibbleMap);
|
||||||
|
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Could not parse chunk!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user