Tweaks for reading and writing block position

Also improved tests code
This commit is contained in:
Vladislavs Golubs 2015-09-25 01:32:55 +03:00 committed by Steven Smith
parent 074d2b1849
commit 0f45de347b
4 changed files with 100 additions and 60 deletions

View file

@ -30,39 +30,12 @@ import java.util.UUID;
public class NetUtil {
private static final int[] EXPONENTS_OF_TWO = new int[] { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
private static final int POSITION_X_SIZE = 38;
private static final int POSITION_Y_SIZE = 26;
private static final int POSITION_Z_SIZE = 38;
private static final int POSITION_X_SIZE = 1 + lastExponentOfTwo(nextPowerOfTwo(30000000));
private static final int POSITION_Z_SIZE = POSITION_X_SIZE;
private static final int POSITION_Y_SIZE = 64 - POSITION_X_SIZE - POSITION_Z_SIZE;
private static final int POSITION_Y_SHIFT = POSITION_Z_SIZE;
private static final int POSITION_X_SHIFT = POSITION_Y_SHIFT + POSITION_Y_SIZE;
private static final long POSITION_X_MASK = (1L << POSITION_X_SIZE) - 1;
private static final long POSITION_Y_MASK = (1L << POSITION_Y_SIZE) - 1;
private static final long POSITION_Z_MASK = (1L << POSITION_Z_SIZE) - 1;
private static int nextPowerOfTwo(int i) {
int minusOne = i - 1;
minusOne |= minusOne >> 1;
minusOne |= minusOne >> 2;
minusOne |= minusOne >> 4;
minusOne |= minusOne >> 8;
minusOne |= minusOne >> 16;
return minusOne + 1;
}
private static boolean isPowerOfTwo(int i) {
return i != 0 && (i & i - 1) == 0;
}
public static int nextExponentOfTwo(int i) {
int power = isPowerOfTwo(i) ? i : nextPowerOfTwo(i);
return EXPONENTS_OF_TWO[(int) (power * 125613361L >> 27) & 31];
}
public static int lastExponentOfTwo(int i) {
return nextExponentOfTwo(i) - (isPowerOfTwo(i) ? 0 : 1);
}
private static final int POSITION_Y_SHIFT = 0xFFF;
private static final int POSITION_WRITE_SHIFT = 0x3FFFFFF;
public static CompoundTag readNBT(NetInput in) throws IOException {
byte b = in.readByte();
@ -83,14 +56,20 @@ public class NetUtil {
public static Position readPosition(NetInput in) throws IOException {
long val = in.readLong();
int x = (int) (val << 64 - POSITION_X_SHIFT - POSITION_X_SIZE >> 64 - POSITION_X_SIZE);
int y = (int) (val << 64 - POSITION_Y_SHIFT - POSITION_Y_SIZE >> 64 - POSITION_Y_SIZE);
int z = (int) (val << 64 - POSITION_Z_SIZE >> 64 - POSITION_Z_SIZE);
int x = (int) (val >> POSITION_X_SIZE);
int y = (int) ((val >> POSITION_Y_SIZE) & POSITION_Y_SHIFT);
int z = (int) ((val << POSITION_Z_SIZE) >> POSITION_Z_SIZE);
return new Position(x, y, z);
}
public static void writePosition(NetOutput out, Position pos) throws IOException {
out.writeLong((pos.getX() & POSITION_X_MASK) << POSITION_X_SHIFT | (pos.getY() & POSITION_Y_MASK) << POSITION_Y_SHIFT | (pos.getZ() & POSITION_Z_MASK));
long x = pos.getX() & POSITION_WRITE_SHIFT;
long y = pos.getY() & POSITION_Y_SHIFT;
long z = pos.getZ() & POSITION_WRITE_SHIFT;
out.writeLong(x << POSITION_X_SIZE | y << POSITION_Y_SIZE | z);
}
public static ItemStack readItem(NetInput in) throws IOException {

View file

@ -0,0 +1,60 @@
package org.spacehq.mc.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.spacehq.mc.protocol.data.game.Position;
import org.spacehq.mc.protocol.data.game.values.world.block.BlockChangeRecord;
import org.spacehq.packetlib.packet.Packet;
import org.spacehq.packetlib.tcp.io.ByteBufNetInput;
import org.spacehq.packetlib.tcp.io.ByteBufNetOutput;
import java.lang.reflect.Constructor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class ByteBufHelper {
private static final ByteBuf buffer = Unpooled.buffer();
public static final ByteBufNetOutput out = new ByteBufNetOutput(buffer);
public static final ByteBufNetInput in = new ByteBufNetInput(buffer);
@SuppressWarnings("unchecked")
public static <T> T writeAndRead(Packet writable){
if(buffer.isReadable()) {
buffer.release();
}
try {
writable.write(out);
// Creating new fresh packet to reset fields.
Constructor constructor = writable.getClass().getDeclaredConstructor();
constructor.setAccessible(true);
Packet readable = (Packet) constructor.newInstance();
readable.read(in);
assertFalse("Buffer is not empty", buffer.isReadable());
return (T) readable;
} catch(Exception e) {
throw new IllegalStateException("Failed parse packet", e);
} finally {
buffer.release();
}
}
public static void assertPosition(Position position, int x, int y, int z) {
assertEquals("Received incorrect X position", x, position.getX());
assertEquals("Received incorrect Y position", y, position.getY());
assertEquals("Received incorrect Z position", z, position.getZ());
}
public static void assertBlock(BlockChangeRecord record, int block, int data) {
assertEquals("Received incorrect block id", block, record.getId());
assertEquals("Received incorrect block data", data, record.getData());
}
}

View file

@ -1,7 +1,5 @@
package org.spacehq.mc.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -25,14 +23,13 @@ import org.spacehq.packetlib.event.session.PacketReceivedEvent;
import org.spacehq.packetlib.event.session.SessionAdapter;
import org.spacehq.packetlib.packet.Packet;
import org.spacehq.packetlib.tcp.TcpSessionFactory;
import org.spacehq.packetlib.tcp.io.ByteBufNetInput;
import org.spacehq.packetlib.tcp.io.ByteBufNetOutput;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.*;
import static org.spacehq.mc.protocol.ByteBufHelper.*;
import static org.spacehq.mc.protocol.MinecraftConstants.*;
import static org.spacehq.mc.protocol.data.SubProtocol.STATUS;
import static org.spacehq.mc.protocol.data.game.values.entity.player.GameMode.SURVIVAL;
@ -120,27 +117,11 @@ public class MinecraftProtocolTest {
@Test
public void testBlockBreak() throws IOException {
ByteBuf buffer = Unpooled.buffer();
BlockChangeRecord record = new BlockChangeRecord(new Position(1, 61, -1), 3, 2);
ServerBlockChangePacket packet = writeAndRead(new ServerBlockChangePacket(record));
ByteBufNetOutput out = new ByteBufNetOutput(buffer);
ByteBufNetInput in = new ByteBufNetInput(buffer);
Position position = new Position(1, 61, -1);
BlockChangeRecord record = new BlockChangeRecord(position, 3, 2);
new ServerBlockChangePacket(record).write(out);
ServerBlockChangePacket packet = new ServerBlockChangePacket(record);
packet.read(in);
record = packet.getRecord();
position = record.getPosition();
assertFalse("Buffer is not empty", buffer.isReadable());
assertEquals("Received incorrect X position", 1, position.getX());
assertEquals("Received incorrect Y position", 61, position.getY());
assertEquals("Received incorrect Z position", -1, position.getZ());
assertEquals("Received incorrect block id", 3, record.getId());
assertEquals("Received incorrect block data", 2, record.getData());
assertPosition(packet.getRecord().getPosition(), 1, 61, -1);
assertBlock(packet.getRecord(), 3, 2);
}
@After

View file

@ -0,0 +1,20 @@
package org.spacehq.mc.protocol.util;
import org.junit.Test;
import org.spacehq.mc.protocol.data.game.Position;
import java.io.IOException;
import static org.spacehq.mc.protocol.ByteBufHelper.*;
import static org.spacehq.mc.protocol.util.NetUtil.readPosition;
import static org.spacehq.mc.protocol.util.NetUtil.writePosition;
public class NetUtilTest {
@Test
public void testPosition() throws IOException {
writePosition(out, new Position(1, 61, -1));
assertPosition(readPosition(in), 1, 61, -1);
}
}