mirror of
https://github.com/GeyserMC/MCProtocolLib.git
synced 2024-12-12 08:41:00 -05:00
Tweaks for reading and writing block position
Also improved tests code
This commit is contained in:
parent
074d2b1849
commit
0f45de347b
4 changed files with 100 additions and 60 deletions
|
@ -30,39 +30,12 @@ import java.util.UUID;
|
||||||
|
|
||||||
public class NetUtil {
|
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_Y_SHIFT = 0xFFF;
|
||||||
private static final int POSITION_Z_SIZE = POSITION_X_SIZE;
|
private static final int POSITION_WRITE_SHIFT = 0x3FFFFFF;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompoundTag readNBT(NetInput in) throws IOException {
|
public static CompoundTag readNBT(NetInput in) throws IOException {
|
||||||
byte b = in.readByte();
|
byte b = in.readByte();
|
||||||
|
@ -83,14 +56,20 @@ public class NetUtil {
|
||||||
|
|
||||||
public static Position readPosition(NetInput in) throws IOException {
|
public static Position readPosition(NetInput in) throws IOException {
|
||||||
long val = in.readLong();
|
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 x = (int) (val >> POSITION_X_SIZE);
|
||||||
int z = (int) (val << 64 - POSITION_Z_SIZE >> 64 - POSITION_Z_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);
|
return new Position(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writePosition(NetOutput out, Position pos) throws IOException {
|
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 {
|
public static ItemStack readItem(NetInput in) throws IOException {
|
||||||
|
|
60
src/test/java/org/spacehq/mc/protocol/ByteBufHelper.java
Normal file
60
src/test/java/org/spacehq/mc/protocol/ByteBufHelper.java
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
package org.spacehq.mc.protocol;
|
package org.spacehq.mc.protocol;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
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.event.session.SessionAdapter;
|
||||||
import org.spacehq.packetlib.packet.Packet;
|
import org.spacehq.packetlib.packet.Packet;
|
||||||
import org.spacehq.packetlib.tcp.TcpSessionFactory;
|
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.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static org.junit.Assert.*;
|
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.MinecraftConstants.*;
|
||||||
import static org.spacehq.mc.protocol.data.SubProtocol.STATUS;
|
import static org.spacehq.mc.protocol.data.SubProtocol.STATUS;
|
||||||
import static org.spacehq.mc.protocol.data.game.values.entity.player.GameMode.SURVIVAL;
|
import static org.spacehq.mc.protocol.data.game.values.entity.player.GameMode.SURVIVAL;
|
||||||
|
@ -120,27 +117,11 @@ public class MinecraftProtocolTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockBreak() throws IOException {
|
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);
|
assertPosition(packet.getRecord().getPosition(), 1, 61, -1);
|
||||||
ByteBufNetInput in = new ByteBufNetInput(buffer);
|
assertBlock(packet.getRecord(), 3, 2);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
20
src/test/java/org/spacehq/mc/protocol/util/NetUtilTest.java
Normal file
20
src/test/java/org/spacehq/mc/protocol/util/NetUtilTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue