mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -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;
|
||||
|
||||
import de.bixilon.minosoft.game.datatypes.blocks.Block;
|
||||
import de.bixilon.minosoft.game.datatypes.world.Chunk;
|
||||
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.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.BitByte;
|
||||
import de.bixilon.minosoft.util.ChunkUtil;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -37,8 +34,7 @@ public class PacketChunkBulk implements ClientboundPacket {
|
||||
public void read(InPacketBuffer buffer, ProtocolVersion v) {
|
||||
switch (v) {
|
||||
case VERSION_1_7_10:
|
||||
// ToDo only implement once, not twice (chunk data and chunk bulk)
|
||||
short chunkColumnCount = buffer.readShort();
|
||||
short chunkCount = buffer.readShort();
|
||||
int dataLen = buffer.readInteger();
|
||||
boolean containsSkyLight = buffer.readBoolean();
|
||||
|
||||
@ -46,77 +42,13 @@ public class PacketChunkBulk implements ClientboundPacket {
|
||||
InByteBuffer decompressed = Util.decompress(buffer.readBytes(dataLen));
|
||||
|
||||
// chunk meta data
|
||||
int read = 0;
|
||||
for (int i = 0; i < chunkColumnCount; i++) {
|
||||
for (int i = 0; i < chunkCount; i++) {
|
||||
int x = buffer.readInteger();
|
||||
int z = buffer.readInteger();
|
||||
short sectionBitMask = buffer.readShort();
|
||||
short addBitMask = buffer.readShort();
|
||||
|
||||
|
||||
//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));
|
||||
chunkMap.put(new ChunkLocation(x, z), ChunkUtil.readChunkPacket(v, decompressed, sectionBitMask, addBitMask, true, containsSkyLight));
|
||||
}
|
||||
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) {
|
||||
//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_EXPERIENCE_ORB, PacketSpawnExperienceOrb.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