PlayerDiggingAndMorePacket
This commit is contained in:
@@ -53,17 +53,18 @@ public enum State {
|
||||
|
||||
PLAY(3,
|
||||
// client side
|
||||
Map.of(
|
||||
0x00, TeleportConfirmPacket.class,
|
||||
0x04, ClientSettingsPacket.class,
|
||||
0x09, PluginMessagePacket.class,
|
||||
0x0B, KeepAlivePacket.class,
|
||||
0x0C, PlayerOnGroundPacket.class,
|
||||
0x0D, PlayerPositionPacket.class,
|
||||
0x0E, CPlayerPositionAndLookPacket.class,
|
||||
0x0F, PlayerLookPacket.class,
|
||||
0x13, CPlayerAbilitiesPacket.class,
|
||||
0x15, EntityActionPacket.class
|
||||
Map.ofEntries(
|
||||
Map.entry(0x00, TeleportConfirmPacket.class),
|
||||
Map.entry(0x04, ClientSettingsPacket.class),
|
||||
Map.entry(0x09, PluginMessagePacket.class),
|
||||
Map.entry(0x0B, KeepAlivePacket.class),
|
||||
Map.entry(0x0C, PlayerOnGroundPacket.class),
|
||||
Map.entry(0x0D, PlayerPositionPacket.class),
|
||||
Map.entry(0x0E, CPlayerPositionAndLookPacket.class),
|
||||
Map.entry(0x0F, PlayerLookPacket.class),
|
||||
Map.entry(0x13, CPlayerAbilitiesPacket.class),
|
||||
Map.entry(0x14, PlayerDiggingAndMorePacket.class),
|
||||
Map.entry(0x15, EntityActionPacket.class)
|
||||
),
|
||||
// server side
|
||||
Map.of(
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package mc.protocol.packets.play.client;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.protocol.buffer.NetByteBuf;
|
||||
import mc.protocol.model.BlockLocation;
|
||||
import mc.protocol.packets.ClientSidePacket;
|
||||
import mc.protocol.utils.DiggingStatus;
|
||||
import mc.protocol.utils.Face;
|
||||
import mc.protocol.utils.SerializeUtil;
|
||||
|
||||
/**
|
||||
* Клиент копает, ломает блок (и не только).
|
||||
*
|
||||
* <p>Структура пакета</p>
|
||||
* <pre>
|
||||
* | FIELD | TYPE | NOTES |
|
||||
* |----------|----------|------------------------------------------|
|
||||
* | Status | VarInt | Действие Игрока к блоку |
|
||||
* | Location | Position | Позиция блока |
|
||||
* | Face | Byte | Сторона блока, с которой взаимодействуют |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Возможные действия Игрока к блоку</p>
|
||||
* <pre>
|
||||
* | VALUE | DESCRIPTION | NOTES |
|
||||
* |--------- |-------------------------|---------------------------------------------------------------------------------------|
|
||||
* | 0 | Начал ломать | |
|
||||
* | 1 | Прекратил ломать | Отправляется, когда Игрок отпустил клавишу "копания" |
|
||||
* | 2 | Закончил ломать | Отправляется, когда Игрок закончил ломать блок. Т.е. блок готов сломаться |
|
||||
* | 3 | Бросает стек предметов | Отправляется, когда Игрок с помощью клавиши "Выкинуть предмет"(Q) |
|
||||
* | | | с модификатором(??) для выкидывания полного стека. |
|
||||
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||
* | 4 | Бросает предмет | Отправляется, когда Игрок выкидывает предмет. |
|
||||
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||
* | 5 | Стреляет стрелой / | Указывает, что текущего состояние удерживаемого предмета должно |
|
||||
* | | Заканчивает есть / | быть обновлено. Например, поедание еды, натягивание луков, использование ведер и т.д. |
|
||||
* | | и т.д. | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||
* | 6 | Поменять предмет в руке | Отправляется когда Игрок меняет предмет предмет во второй руке через "свап". |
|
||||
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||
* </pre>
|
||||
*
|
||||
* <p>Значения Стороны блока</p>
|
||||
* <pre>
|
||||
* | VALUE | OFFCET | FACE |
|
||||
* |-------|--------|--------|
|
||||
* | 0 | -Y | Bottom |
|
||||
* | 1 | +Y | Top |
|
||||
* | 2 | -Z | North |
|
||||
* | 3 | +Z | South |
|
||||
* | 4 | -X | West |
|
||||
* | 5 | +X | East |
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Digging">Player Digging</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class PlayerDiggingAndMorePacket implements ClientSidePacket {
|
||||
|
||||
private DiggingStatus status;
|
||||
private BlockLocation location;
|
||||
private Face face;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetByteBuf netByteBuf) {
|
||||
this.status = DiggingStatus.valueById(netByteBuf.readVarInt());
|
||||
this.location = SerializeUtil.long2location(netByteBuf.readLong());
|
||||
this.face = Face.valueById(netByteBuf.readByte());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() {
|
||||
this.status = null;
|
||||
this.location = null;
|
||||
this.face = null;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import lombok.Data;
|
||||
import mc.protocol.buffer.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.pool.ProtocolObjectPool;
|
||||
import mc.protocol.utils.ChunkSerializeUtil;
|
||||
import mc.protocol.utils.SerializeUtil;
|
||||
import mc.protocol.world.Chunk;
|
||||
import mc.protocol.world.ChunkSection;
|
||||
|
||||
@@ -101,7 +101,7 @@ public class ChunkDataPacket implements ServerSidePacket {
|
||||
|
||||
for (int h = 0; h < 16; h++) {
|
||||
ChunkSection section = chunk.getSection(h);
|
||||
NetByteBuf data = ChunkSerializeUtil.serializeSection(section);
|
||||
NetByteBuf data = SerializeUtil.serializeChunkSection(section);
|
||||
dataStructure.writeBytes(data); // Data
|
||||
ProtocolObjectPool.netByteBuf().returnObject(data);
|
||||
}
|
||||
|
||||
32
protocol/src/main/java/mc/protocol/utils/DiggingStatus.java
Normal file
32
protocol/src/main/java/mc/protocol/utils/DiggingStatus.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum DiggingStatus {
|
||||
|
||||
STARTED(0),
|
||||
CANCELLED(1),
|
||||
FINISHED(2),
|
||||
DROP_ITEM_STACK(3),
|
||||
DROP_ITEM(4),
|
||||
HELT_UPDATE_STATE(5),
|
||||
SWAP_HAND(6);
|
||||
|
||||
@Nullable
|
||||
public static DiggingStatus valueById(int id) {
|
||||
for (DiggingStatus diggingStatus : DiggingStatus.values()) {
|
||||
if (diggingStatus.getId() == id) {
|
||||
return diggingStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
}
|
||||
31
protocol/src/main/java/mc/protocol/utils/Face.java
Normal file
31
protocol/src/main/java/mc/protocol/utils/Face.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Face {
|
||||
|
||||
BOTTOM(0),
|
||||
TOP(1),
|
||||
NORTH(2),
|
||||
SOUTH(3),
|
||||
WEST(4),
|
||||
EAST(5);
|
||||
|
||||
@Nullable
|
||||
public static Face valueById(int id) {
|
||||
for (Face face : Face.values()) {
|
||||
if (face.getId() == id) {
|
||||
return face;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import io.netty.buffer.Unpooled;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import mc.protocol.buffer.NetByteBuf;
|
||||
import mc.protocol.model.BlockLocation;
|
||||
import mc.protocol.pool.ProtocolObjectPool;
|
||||
import mc.protocol.world.Block;
|
||||
import mc.protocol.world.ChunkSection;
|
||||
@@ -12,12 +13,12 @@ import mc.utils.array.BitByteArray;
|
||||
import mc.utils.array.BitLongArray;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ChunkSerializeUtil {
|
||||
public final class SerializeUtil {
|
||||
|
||||
private static final int BITS_PER_BLOCK = 13;
|
||||
private static final int ALL_BLOCKS = 16 * 16 * 16;
|
||||
|
||||
public static NetByteBuf serializeSection(ChunkSection section) {
|
||||
public static NetByteBuf serializeChunkSection(ChunkSection section) {
|
||||
BitArray blockArray = new BitLongArray(BITS_PER_BLOCK, ALL_BLOCKS);
|
||||
BitArray blockLight = new BitByteArray(4, ALL_BLOCKS);
|
||||
BitArray skyLight = new BitByteArray(4, ALL_BLOCKS);
|
||||
@@ -56,4 +57,21 @@ public final class ChunkSerializeUtil {
|
||||
blockState & 0b1111
|
||||
};
|
||||
}
|
||||
|
||||
public static long location2long(BlockLocation blockLocation) {
|
||||
return ((long) (blockLocation.getX() & 0x3FFFFFF) << 38)
|
||||
| ((long) (blockLocation.getZ() & 0x3FFFFFF) << 12)
|
||||
| (blockLocation.getY() & 0xFFF);
|
||||
}
|
||||
|
||||
public static BlockLocation long2location(long value) {
|
||||
BlockLocation blockLocation = new BlockLocation();
|
||||
blockLocation.set(
|
||||
(int) (value >> 38),
|
||||
(int) (value & 0xFFF),
|
||||
(int) (value << 26 >> 38)
|
||||
);
|
||||
|
||||
return blockLocation;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package mc.server.di;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import mc.protocol.model.Location;
|
||||
import mc.protocol.utils.ChunkSerializeUtil;
|
||||
import mc.protocol.utils.SerializeUtil;
|
||||
import mc.protocol.world.World;
|
||||
import mc.server.world.FlatWorld;
|
||||
import mc.utils.array.BitArray;
|
||||
@@ -46,7 +46,7 @@ public class FlatWorldModule extends WorldModule {
|
||||
|
||||
k += count;
|
||||
for (int j = 0; j < count; j++) {
|
||||
flatConfig.put(ChunkSerializeUtil.blockIdMetaSerialize(blockId, blockMeta));
|
||||
flatConfig.put(SerializeUtil.blockIdMetaSerialize(blockId, blockMeta));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package mc.server.world;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mc.protocol.model.BlockLocation;
|
||||
import mc.protocol.utils.ChunkSerializeUtil;
|
||||
import mc.protocol.utils.SerializeUtil;
|
||||
import mc.protocol.world.Block;
|
||||
import mc.protocol.world.ChunkSection;
|
||||
import mc.utils.array.BitArray;
|
||||
@@ -26,7 +26,7 @@ public class FlatChunkSection implements ChunkSection {
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
return blocks.computeIfAbsent(y, y0 -> {
|
||||
int blockState = chunkConfig.get((this.y << 4) + y);
|
||||
int[] blockIdMeta = ChunkSerializeUtil.blockIdMetaDeserialize(blockState);
|
||||
int[] blockIdMeta = SerializeUtil.blockIdMetaDeserialize(blockState);
|
||||
|
||||
SomeBlock block = new SomeBlock();
|
||||
block.setId(blockIdMeta[0]);
|
||||
@@ -44,7 +44,7 @@ public class FlatChunkSection implements ChunkSection {
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return sky.computeIfAbsent(y, y0 -> {
|
||||
int blockState = chunkConfig.get((this.y << 4) + y);
|
||||
int[] blockIdMeta = ChunkSerializeUtil.blockIdMetaDeserialize(blockState);
|
||||
int[] blockIdMeta = SerializeUtil.blockIdMetaDeserialize(blockState);
|
||||
|
||||
if (blockIdMeta[0] != 0/*AIR*/) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user