Open robotman3000 opened 7 years ago
Four hours later and I still couldn't figure out how to handle those chunks. Will keep trying...
It doesn't help that you don't receive any feedback from MCPE, because only three things can happen when dealing with packets:
I'm trying to create my own minimal server to debug the issue, already got the client joined the server (really, it was easy), but of course I can't figure out those chunks.
Perhaps we should enlist the help of one of the PocketMine-MP developers.
@robotman3000 the problem is figuring out what fields are required for a chunk packet
I think it is like that:
Chunk X - VarInt Chunk Z - VarInt Number of sections in this chunk - Byte Sections ??? - Byte (Nukkit always use 0 for this) Blocks ID - Byte Array Blocks Data - Byte Array Blocks Sky Light - Byte Array Blocks Light (? Probably light emitted from blocks like Glowstone) - Byte Array End of Sections Block Height (?) - Byte Array ? - Byte Array (Always 256 in Nukkit) Biome ID Array - Byte Array ? - Byte (Always 0 in Nukkit) Extra Data - Unsigned VarInt (Can be 0 if no extra data) Block Entities - Byte Array
If you send everything, it should work.
Here is what I done (but didn't work)
RakNetPacket rnp = new RakNetPacket(0xFE);
rnp.writeByte(0x3a);
try {
VarInt.writeVarInt(rnp, 0); // Chunk X
VarInt.writeVarInt(rnp, 0); // Chunk Z
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rnp.writeByte((byte) 16); // Send all chunk sections
int section = 0;
while (16 > section) {
rnp.writeByte((byte) 0); // Always zero
byte[] array = new byte[4096];
Arrays.fill(array, (byte) 1);
String build = "";
for (byte b : array) {
build += b;
}
byte[] blocks = new byte[4096];
byte[] data = new byte[2048];
byte[] skyLight = new byte[2048];
byte[] blockLight = new byte[2048];
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int i = (x << 7) | (z << 3);
for (int y = 0; y < 16; y += 2) {
blocks[(i << 1) | y] = (byte) 1;
blocks[(i << 1) | (y + 1)] = (byte) 1;
int b1 = 0;
int b2 = 0;
data[i | (y >> 1)] = (byte) ((b2 << 4) | b1);
b1 = 1;
b2 = 1;
skyLight[i | (y >> 1)] = (byte) ((b2 << 4) | b1);
b1 = 1;
b2 = 1;
blockLight[i | (y >> 1)] = (byte) ((b2 << 4) | b1);
}
}
}
section++;
ByteBuf bbx = Unpooled.buffer();
bbx.writeBytes(blocks);
bbx.writeBytes(data);
bbx.writeBytes(skyLight);
bbx.writeBytes(blockLight);
rnp.write(bbx.array());
}
int height = 0;
while (256 > height) {
rnp.writeByte((byte) height);
height++;
}
rnp.write(new byte[256]);
rnp.write(new byte[1]);
rnp.writeByte((byte) 0);
try {
VarInt.writeUnsignedVarInt(rnp, 0);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rnp.write(new byte[0]);
packet = rnp;
The problem with MCPE development is the lack of a good, explained, protocol documentation, the PC version has a very extensive and good protocol documentation, the only similar thing that exists is yawk.at's MCPE documentation, but that's outdated since 0.15.
6 days later and I still couldn't figure out how to send chunks
I tried doing this
package com.magicalpocket.network.packets;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;
import com.magicalpocket.utils.VarInt;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.marfgamer.jraknet.RakNetPacket;
public class FullChunkDataPacket extends DataPacket {
public int x;
public int z;
@Override
public void decode() {
}
@Override
public void encode() {
System.out.println("Chunk data...");
RakNetPacket rnp = new RakNetPacket(0xFE);
rnp.writeByte(0x3a);
try {
VarInt.writeVarInt(rnp, x); // Chunk X
VarInt.writeVarInt(rnp, z); // Chunk Z
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rnp.writeByte((byte) 16); // Chunk sections (?)
for (int i = 0; i < 16; i++) {
rnp.writeByte((byte) 0);
ByteBuffer buffer = ByteBuffer.allocate(10240);
byte[] blocks = new byte[4096];
byte[] data = new byte[2048];
byte[] skyLight = new byte[2048];
byte[] blockLight = new byte[2048];
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int temporary = (x << 7) | (z << 3);
for (int y = 0; y < 16; y += 2) {
blocks[(temporary << 1) | y] = (byte) 1;
blocks[(temporary << 1) | (y + 1)] = 1;
int b1 = 1;
int b2 = 1;
data[temporary | (y >> 1)] = (byte) ((b2 << 4) | b1);
b1 = 1;
b2 = 1;
skyLight[temporary | (y >> 1)] = (byte) ((b2 << 4) | b1);
b1 = 1;
b2 = 1;
blockLight[temporary | (y >> 1)] = (byte) ((b2 << 4) | b1);
}
}
}
rnp.write(buffer
.put(blocks)
.put(data)
.put(skyLight)
.put(blockLight)
.array());
}
int[] heightMap = new int[256];
Arrays.fill(heightMap, 1);
for (int height : heightMap) {
rnp.writeByte((byte) height);
}
rnp.write(new byte[256]);
rnp.write(new byte[256]);
rnp.writeByte((byte) 0);
try {
VarInt.writeUnsignedVarInt(rnp, 0);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rnp.write(new byte[0]);
packet = rnp;
}
}
But nope, didn't work.
Tried replaying the data sent by Nukkit when sending a chunk and...
Also didn't work.
Try replaying an exact packet stream from Nukkit and slowly remove packets, to see what is required to get chunks to appear
@robotman3000 I will try doing that later.
In theory, my code should work, but it doesn't.
package com.magicalpocket.network.packets;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import com.magicalpocket.utils.VarInt;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.marfgamer.jraknet.RakNetPacket;
public class FullChunkDataPacket extends DataPacket {
public int x;
public int z;
@Override
public void decode() {
}
@Override
public void encode() {
System.out.println("Chunk data...");
RakNetPacket rnp = new RakNetPacket(0xFE);
rnp.writeByte(0x3a);
try {
VarInt.writeVarInt(rnp, 0); // Chunk X
VarInt.writeVarInt(rnp, 0); // Chunk Z
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Gson gson = new Gson();
JsonReader reader;
try {
reader = new JsonReader(new FileReader("D:\\Minecraft Servers\\Nukkit\\nukkitdata.txt"));
byte[] wow = gson.fromJson(reader, byte[].class);
try {
VarInt.writeUnsignedVarInt(rnp, wow.length);
rnp.write(wow);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
packet = rnp;
}
}
But nope, NOTHING happens.
No idea with this one. MiNet documentation suggests something to look into