Merge branch 'proto_1.12.2' into world
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package mc.core.network.proto_1_12_2;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Direction {
|
||||
BOTTOM(0), // -Y
|
||||
TOP(1), // +Y
|
||||
NORTH(2), // -Z
|
||||
SOUTH(3), // +Z
|
||||
WEST(4), // -X
|
||||
EAST(5); // +X
|
||||
|
||||
public static Direction getById(final int id) {
|
||||
return Arrays.stream(Direction.values())
|
||||
.filter(direction -> direction.id == id)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
}
|
||||
@@ -80,13 +80,18 @@ public enum State {
|
||||
.put(0x0D, PlayerPositionPacket.class)
|
||||
.put(0x0E, PlayerPositionAndLookPacket.class)
|
||||
.put(0x0F, PlayerLookPacket.class)
|
||||
.put(0x13, PlayerAbilitiesPacket.class)
|
||||
.put(0x14, PlayerDiggingPacket.class)
|
||||
.put(0x15, EntityActionPacket.class)
|
||||
.put(0x1A, HeldItemChangePacket.class)
|
||||
.put(0x1D, AnimationPacket.class)
|
||||
.put(0x1F, PlayerBlockPlacementPacket.class)
|
||||
.build(),
|
||||
ImmutableMap.<Class<? extends SCPacket>, Integer>builder()
|
||||
.put(BossBarPacket.class, 0x0C)
|
||||
.put(ChatMessageServerPacket.class, 0x0F)
|
||||
.put(PluginMessagePacket.class, 0x18)
|
||||
.put(UnloadChunkPacket.class, 0x1D)
|
||||
.put(ChangeGameState.class, 0x1E)
|
||||
.put(KeepAlivePacket.class, 0x1F)
|
||||
.put(ChunkDataPacket.class, 0x20)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mc.core.network.CSPacket;
|
||||
import mc.core.network.NetInputStream;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Getter
|
||||
public class EntityActionPacket implements CSPacket {
|
||||
@RequiredArgsConstructor
|
||||
public enum Action {
|
||||
START_SNEAKING(0),
|
||||
STOP_SNEAKING(1),
|
||||
LEAVE_BED(2), // Leave bed is only sent when the “Leave Bed” button is clicked on the sleep GUI, not when waking up due today time.
|
||||
START_SPRINTING(3),
|
||||
STOP_SPRINTING(4),
|
||||
START_JUMP_WITH_HORSE(5),
|
||||
STOP_JUMP_WITH_HORSE(6),
|
||||
OPEN_HORSE_INVENTORY(7), // Open horse inventory is only sent when pressing the inventory key (default: E) while on a horse — all other methods of opening a horse's inventory (involving right-clicking or shift-right-clicking it) do not use this packet.
|
||||
START_FLYING_WITH_ELYTRA(8);
|
||||
|
||||
public static Action getById(final int id) {
|
||||
return Arrays.stream(Action.values())
|
||||
.filter(action -> action.id == id)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
}
|
||||
|
||||
private int entityId;
|
||||
private Action action;
|
||||
private int jumpBoost; // Only used by the “start jump with horse” action, in which case it ranges from 0 to 100. In all other cases it is 0.
|
||||
|
||||
@Override
|
||||
public void readSelf(NetInputStream netStream) {
|
||||
entityId = netStream.readVarInt();
|
||||
action = Action.getById(netStream.readVarInt());
|
||||
jumpBoost = netStream.readVarInt();
|
||||
}
|
||||
}
|
||||
@@ -4,22 +4,27 @@
|
||||
*/
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import mc.core.network.CSPacket;
|
||||
import mc.core.network.NetInputStream;
|
||||
import mc.core.network.NetOutputStream;
|
||||
import mc.core.network.SCPacket;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PlayerAbilitiesPacket implements SCPacket {
|
||||
public class PlayerAbilitiesPacket implements SCPacket, CSPacket {
|
||||
private boolean godMode = false;
|
||||
private boolean flying = false;
|
||||
private boolean canFly = false;
|
||||
private boolean instantDestroyBlocks = false;
|
||||
private float flyingSpeed = 0.05f;
|
||||
private float fieldOfView = flyingSpeed;
|
||||
private float walkingSpeed;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetOutputStream netStream) {
|
||||
@@ -33,4 +38,17 @@ public class PlayerAbilitiesPacket implements SCPacket {
|
||||
netStream.writeFloat(flyingSpeed);
|
||||
netStream.writeFloat(fieldOfView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSelf(NetInputStream netStream) {
|
||||
byte flag = netStream.readByte();
|
||||
//FIXME треубет проверки
|
||||
godMode = (flag == 0x08);
|
||||
canFly = (flag == 0x04);
|
||||
flying = (flag == 0x02);
|
||||
instantDestroyBlocks = (flag == 0x01);
|
||||
|
||||
flyingSpeed = netStream.readFloat();
|
||||
walkingSpeed = netStream.readFloat();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import mc.core.Location;
|
||||
import mc.core.network.CSPacket;
|
||||
import mc.core.network.NetInputStream;
|
||||
import mc.core.network.proto_1_12_2.Direction;
|
||||
import mc.core.utils.CompactedCoords;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class PlayerBlockPlacementPacket implements CSPacket {
|
||||
private Location location;
|
||||
private Direction face;
|
||||
/** true - main hand; false - off hand */
|
||||
private boolean hand;
|
||||
private float cursorX, cursorY, cursorZ;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetInputStream netStream) {
|
||||
long compactedCoords = netStream.readLong();
|
||||
double[] xyz = CompactedCoords.uncompressXYZ(compactedCoords);
|
||||
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
||||
face = Direction.getById(netStream.readVarInt());
|
||||
hand = (netStream.readVarInt() == 1);
|
||||
cursorX = netStream.readFloat();
|
||||
cursorY = netStream.readFloat();
|
||||
cursorZ = netStream.readFloat();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import mc.core.Location;
|
||||
import mc.core.network.CSPacket;
|
||||
import mc.core.network.NetInputStream;
|
||||
import mc.core.network.proto_1_12_2.Direction;
|
||||
import mc.core.utils.CompactedCoords;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class PlayerDiggingPacket implements CSPacket {
|
||||
@RequiredArgsConstructor
|
||||
public enum Status {
|
||||
STARTED_DIGGING(0),
|
||||
CANCELLED_DIGGING(1),
|
||||
FINISHED_DIGGING(2),
|
||||
DROP_ITEM_STACK(3),
|
||||
DROP_ITEM(4),
|
||||
/* Indicates that the currently held item should have its
|
||||
* state updated such as eating food, pulling back bows,
|
||||
* using buckets, etc. Location is always set to 0/0/0,
|
||||
* Face is always set to -Y.
|
||||
*/
|
||||
SHOOT_ARROW(5),
|
||||
FINISH_EATING(5),
|
||||
SWAP_ITEM_IN_HAND(6);
|
||||
|
||||
public static Status getById(final int id) {
|
||||
return Arrays.stream(Status.values())
|
||||
.filter(status -> status.id == id)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
}
|
||||
|
||||
private Status status;
|
||||
private Location location;
|
||||
private Direction face;
|
||||
|
||||
@Override
|
||||
public void readSelf(NetInputStream netStream) {
|
||||
status = Status.getById(netStream.readVarInt());
|
||||
long compactCoord = netStream.readLong();
|
||||
double[] xyz = CompactedCoords.uncompressXYZ(compactCoord);
|
||||
location = new Location(xyz[0], xyz[1], xyz[2], null);
|
||||
face = Direction.getById(netStream.readByte());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.Setter;
|
||||
import mc.core.network.NetOutputStream;
|
||||
import mc.core.network.SCPacket;
|
||||
|
||||
public class UnloadChunkPacket implements SCPacket {
|
||||
@Setter
|
||||
private int x, z;
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetOutputStream netStream) {
|
||||
netStream.writeInt(x);
|
||||
netStream.writeInt(z);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import mc.core.EntityLocation;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.WorldType;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
|
||||
public class DummyWorld implements World {
|
||||
private class DummyChunkSection implements ChunkSection {
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
if (y <= 3) return 0;
|
||||
else return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAddition(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddition(int x, int y, int z, int value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int localX, int localZ) {
|
||||
return Biome.PLAINS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(Block block) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, getWorld());
|
||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z, getWorld());
|
||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z, getWorld());
|
||||
else return blockFactory.create(BlockType.AIR, x, y, z, getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return DummyWorld.this;
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyChunk implements Chunk {
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return DummyWorld.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorld(World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkSection getChunkSection(int height) {
|
||||
if (height < 1) return new DummyChunkSection();
|
||||
else return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkSection(int height, ChunkSection chunkSection) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int localX, int localZ) {
|
||||
return Biome.PLAINS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int localX, int localZ, Biome biome) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final Chunk chunk = new DummyChunk();
|
||||
|
||||
@Override
|
||||
public WorldType getWorldType() {
|
||||
return WorldType.FLAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityLocation getSpawn() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpawn(EntityLocation location) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunk(int x, int z, Chunk chunk) {
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,29 @@ package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.World;
|
||||
import org.junit.Assert;
|
||||
import mc.core.world.WorldType;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TestChunkdataPacket {
|
||||
private static byte[] expectedPacketData;
|
||||
private World world;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClassTest() throws IOException {
|
||||
@@ -18,8 +32,48 @@ public class TestChunkdataPacket {
|
||||
expectedPacketData = ByteStreams.toByteArray(inputStream);
|
||||
}
|
||||
|
||||
private World createDummyWorld() {
|
||||
return new DummyWorld();
|
||||
@Before
|
||||
public void prepareWorld() {
|
||||
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||
when(chunkSection.getSkyLight(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
int y = (int)invocation.getArguments()[1];
|
||||
|
||||
if (y <= 3) return 0;
|
||||
else return 15;
|
||||
});
|
||||
when(chunkSection.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
int x = (int) args[0];
|
||||
int y = (int) args[1];
|
||||
int z = (int) args[2];
|
||||
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z, null);
|
||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z, null);
|
||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z, null);
|
||||
else return blockFactory.create(BlockType.AIR, x, y, z, null);
|
||||
});
|
||||
|
||||
world = mock(World.class);
|
||||
when(world.getWorldType()).thenReturn(WorldType.FLAT);
|
||||
when(world.getChunk(anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
|
||||
Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn((int) args[0]);
|
||||
when(chunk.getZ()).thenReturn((int) args[1]);
|
||||
when(chunk.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(anyInt())).thenAnswer(invocation1 -> {
|
||||
int height = (int)invocation1.getArguments()[0];
|
||||
|
||||
if (height < 1) return chunkSection;
|
||||
else return null;
|
||||
});
|
||||
|
||||
return chunk;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -27,14 +81,14 @@ public class TestChunkdataPacket {
|
||||
ChunkDataPacket packet = new ChunkDataPacket();
|
||||
packet.setX(0);
|
||||
packet.setZ(0);
|
||||
packet.setChunk(createDummyWorld().getChunk(0, 0));
|
||||
packet.setChunk(world.getChunk(0, 0));
|
||||
packet.setInitChunk(true);
|
||||
|
||||
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||
packet.writeSelf(netStream);
|
||||
byte[] actualPacketData = netStream.toByteArray();
|
||||
|
||||
Assert.assertEquals(expectedPacketData.length, actualPacketData.length);
|
||||
Assert.assertArrayEquals(expectedPacketData, actualPacketData);
|
||||
assertEquals(expectedPacketData.length, actualPacketData.length);
|
||||
assertArrayEquals(expectedPacketData, actualPacketData);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user