Merge remote-tracking branch 'origin/master'

This commit is contained in:
Eoghanmc22 2020-08-21 13:48:29 -04:00
commit f26501c5fa
15 changed files with 112 additions and 160 deletions

View File

@ -86,8 +86,6 @@ dependencies {
api 'io.netty:netty-codec:4.1.51.Final'
implementation 'io.netty:netty-transport-native-epoll:4.1.51.Final:linux-x86_64'
api 'com.github.jhg023:Pbbl:1.0.2'
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
api 'it.unimi.dsi:fastutil:8.4.1'

View File

@ -42,7 +42,7 @@ public class StoneBlock extends CustomBlock {
@Override
public int getBreakDelay(Player player, BlockPosition position, byte stage, Set<Player> breakers) {
return 5;
return -2;
}
@Override

View File

@ -86,6 +86,8 @@ public class MinecraftServer {
public static final int CHUNK_VIEW_DISTANCE = 10;
public static final int ENTITY_VIEW_DISTANCE = 5;
public static final int COMPRESSION_THRESHOLD = 256;
// TODO
public static final int MAX_PACKET_SIZE = 300_000;
// Can be modified at performance cost when increased
public static final int TICK_PER_SECOND = 20;
private static final int MS_TO_SEC = 1000;

View File

@ -306,12 +306,19 @@ public class Player extends LivingEntity implements CommandSender {
// Target block stage
if (targetCustomBlock != null) {
this.targetBlockBreakCount++;
final boolean processStage = targetBlockBreakCount >= targetBreakDelay;
final boolean processStage = targetBreakDelay < 0 || targetBlockBreakCount >= targetBreakDelay;
// Check if the player did finish his current break delay
if (processStage) {
// Negative value should skip abs(value) stage
final byte stageIncrease = (byte) (targetBreakDelay > 0 ? 1 : Math.abs(targetBreakDelay));
// Should increment the target block stage
if (targetCustomBlock.enableMultiPlayerBreaking()) {
// Let the custom block object manages the breaking
final boolean canContinue = this.targetCustomBlock.processStage(instance, targetBlockPosition, this);
final boolean canContinue = this.targetCustomBlock.processStage(instance, targetBlockPosition, this, stageIncrease);
if (canContinue) {
final Set<Player> breakers = targetCustomBlock.getBreakers(instance, targetBlockPosition);
refreshBreakDelay(breakers);
@ -321,7 +328,7 @@ public class Player extends LivingEntity implements CommandSender {
} else {
// Let the player object manages the breaking
// The custom block doesn't support multi player breaking
if (targetStage + 1 >= CustomBlock.MAX_STAGE) {
if (targetStage + stageIncrease >= CustomBlock.MAX_STAGE) {
// Break the block
instance.breakBlock(this, targetBlockPosition);
resetTargetBlock();
@ -334,7 +341,7 @@ public class Player extends LivingEntity implements CommandSender {
chunk.sendPacketToViewers(blockBreakAnimationPacket);
refreshBreakDelay(targetBreakers);
this.targetStage++;
this.targetStage += stageIncrease;
}
}
}
@ -1909,7 +1916,7 @@ public class Player extends LivingEntity implements CommandSender {
/**
* Reset data from the current block the player is mining.
* If the currently mined block (or if there isn't any) is not a CustomBlock, nothing append
* If the currently mined block (or if there isn't any) is not a {@link CustomBlock}, nothing happen
*/
public void resetTargetBlock() {
if (targetCustomBlock != null) {
@ -1962,18 +1969,21 @@ public class Player extends LivingEntity implements CommandSender {
* @return a {@link PlayerInfoPacket} to add the player
*/
protected PlayerInfoPacket getAddPlayerToList() {
final String textures = skin == null ? "" : skin.getTextures();
final String signature = skin == null ? null : skin.getSignature();
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addPlayer =
new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), getGameMode(), getLatency());
addPlayer.displayName = displayName;
// Skin support
if (skin != null) {
final String textures = skin.getTextures();
final String signature = skin.getSignature();
PlayerInfoPacket.AddPlayer.Property prop =
new PlayerInfoPacket.AddPlayer.Property("textures", textures, signature);
addPlayer.properties.add(prop);
}
playerInfoPacket.playerInfos.add(addPlayer);
return playerInfoPacket;

View File

@ -54,9 +54,9 @@ public class PlayerSkin {
final JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
final JsonArray propertiesArray = jsonObject.get("properties").getAsJsonArray();
Iterator<JsonElement> iterator = propertiesArray.iterator();
final Iterator<JsonElement> iterator = propertiesArray.iterator();
while (iterator.hasNext()) {
JsonObject propertyObject = iterator.next().getAsJsonObject();
final JsonObject propertyObject = iterator.next().getAsJsonObject();
final String name = propertyObject.get("name").getAsString();
if (!name.equals("textures"))
continue;
@ -82,7 +82,7 @@ public class PlayerSkin {
try {
final String response = URLUtils.getText(url);
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
final JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
final String uuid = jsonObject.get("id").getAsString();
return fromUuid(uuid);
} catch (IOException e) {

View File

@ -132,6 +132,7 @@ public abstract class CustomBlock {
* @param stage the current break stage of the block (0-10)
* @param breakers the list containing all the players currently digging this block
* @return the time in tick to pass to the next state, 0 to instant break it.
* negative value allow to skip stages (-2 will skip 2 stages per tick)
* @see #enableCustomBreakDelay() to enable/disable it
*/
public int getBreakDelay(Player player, BlockPosition position, byte stage, Set<Player> breakers) {
@ -373,10 +374,11 @@ public abstract class CustomBlock {
* @param instance the instance of the block
* @param blockPosition the position of the block
* @param player the player who processed one stage on the block
* @param stageIncrease the number of stage increase
* @return true if the block can continue being digged
* @throws IllegalStateException if {@link #enableMultiPlayerBreaking()} is disabled
*/
public synchronized boolean processStage(Instance instance, BlockPosition blockPosition, Player player) {
public synchronized boolean processStage(Instance instance, BlockPosition blockPosition, Player player, byte stageIncrease) {
Check.stateCondition(!enableMultiPlayerBreaking(),
"CustomBlock#processState requires having the multi player breaking feature enabled");
@ -384,7 +386,7 @@ public abstract class CustomBlock {
InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
Object2ByteMap<BlockPosition> breakStageMap = instanceBreakData.breakStageMap;
byte stage = breakStageMap.getByte(blockPosition);
if (stage + 1 >= MAX_STAGE) {
if (stage + stageIncrease >= MAX_STAGE) {
instance.breakBlock(player, blockPosition);
return false;
} else {
@ -397,7 +399,8 @@ public abstract class CustomBlock {
chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, stage));
// Refresh the stage
breakStageMap.put(blockPosition, ++stage);
stage += stageIncrease;
breakStageMap.put(blockPosition, stage);
return true;
}
}

View File

@ -64,13 +64,13 @@ public class PlayerDiggingListener {
}
} else {
// Player is not mining a custom block, be sure that he doesn't have the effect
removeEffect(player);
player.resetTargetBlock();
}
}
break;
case CANCELLED_DIGGING:
// Remove custom block target
removeEffect(player);
player.resetTargetBlock();
sendAcknowledgePacket(player, blockPosition, blockStateId,
ClientPlayerDiggingPacket.Status.CANCELLED_DIGGING, true);
@ -119,7 +119,7 @@ public class PlayerDiggingListener {
private static void breakBlock(Instance instance, Player player, BlockPosition blockPosition) {
// Finished digging, remove effect if any
removeEffect(player);
player.resetTargetBlock();
// Unverified block break, client is fully responsive
instance.breakBlock(player, blockPosition);
@ -148,10 +148,6 @@ public class PlayerDiggingListener {
player.getPlayerConnection().sendPacket(entityEffectPacket);
}
private static void removeEffect(Player player) {
player.resetTargetBlock();
}
private static void sendAcknowledgePacket(Player player, BlockPosition blockPosition, int blockStateId,
ClientPlayerDiggingPacket.Status status, boolean success) {
AcknowledgePlayerDiggingPacket acknowledgePlayerDiggingPacket = new AcknowledgePlayerDiggingPacket();

View File

@ -22,6 +22,8 @@ public final class PacketWriterUtils {
/**
* Write the packet in the writer thread pool
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param serverPacket the packet to write
* @param consumer the consumer called once the packet has been written
@ -35,6 +37,8 @@ public final class PacketWriterUtils {
/**
* Write a packet in the writer thread pool and send it to every players in {@code players}
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param players the players list to send the packet to
* @param serverPacket the packet to write and send
@ -59,6 +63,8 @@ public final class PacketWriterUtils {
/**
* Write a packet and send it to a player connection
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param playerConnection the connection to send the packet to
* @param serverPacket the packet to write and send
@ -71,6 +77,8 @@ public final class PacketWriterUtils {
/**
* Write a packet and send it to a player
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param player the player to send the packet to
* @param serverPacket the packet to write and send

View File

@ -12,8 +12,8 @@ public class PacketFramer extends ByteToMessageCodec<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
int packetSize = from.readableBytes();
int headerSize = Utils.getVarIntSize(packetSize);
final int packetSize = from.readableBytes();
final int headerSize = Utils.getVarIntSize(packetSize);
if (headerSize > 3) {
throw new IllegalStateException("Unable to fit " + headerSize + " into 3");
@ -35,12 +35,12 @@ public class PacketFramer extends ByteToMessageCodec<ByteBuf> {
return;
}
byte b = buf.readByte();
final byte b = buf.readByte();
if (b >= 0) {
buf.resetReaderIndex();
int j = Utils.readVarInt(buf);
final int j = Utils.readVarInt(buf);
if (buf.readableBytes() < j) {
buf.resetReaderIndex();

View File

@ -1,5 +1,7 @@
package net.minestom.server.network.packet.server.play;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
@ -11,8 +13,6 @@ import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Utils;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.buffer.BufferUtils;
import net.minestom.server.utils.buffer.BufferWrapper;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
@ -47,7 +47,7 @@ public class ChunkDataPacket implements ServerPacket {
writer.writeBoolean(fullChunk);
int mask = 0;
BufferWrapper blocks = BufferUtils.getBuffer(MAX_BUFFER_SIZE);
ByteBuf blocks = Unpooled.buffer(MAX_BUFFER_SIZE);
for (byte i = 0; i < CHUNK_SECTION_COUNT; i++) {
if (fullChunk || (sections.length == CHUNK_SECTION_COUNT && sections[i] != 0)) {
short[] section = getSection(i);
@ -91,8 +91,8 @@ public class ChunkDataPacket implements ServerPacket {
}
// Data
writer.writeVarInt(blocks.getSize());
writer.writeBufferAndFree(blocks);
writer.writeVarInt(blocks.writerIndex());
writer.getBuffer().writeBytes(blocks);
// Block entities
writer.writeVarInt(blockEntities.size());

View File

@ -21,11 +21,10 @@ public final class PacketUtils {
* @param packet the packet to write into {@code buf}
*/
public static void writePacket(ByteBuf buf, ServerPacket packet) {
BinaryWriter writer = new BinaryWriter();
Utils.writeVarIntBuf(buf, packet.getId());
packet.write(writer);
buf.writeBytes(writer.toByteArray());
final ByteBuf packetBuffer = getPacketBuffer(packet);
writePacket(buf, packetBuffer, packet.getId());
}
/**
@ -35,11 +34,40 @@ public final class PacketUtils {
* @return a {@link ByteBuf} containing {@code packet}
*/
public static ByteBuf writePacket(ServerPacket packet) {
ByteBuf buffer = Unpooled.buffer();
final ByteBuf packetBuffer = getPacketBuffer(packet);
writePacket(buffer, packet);
// Add 5 for the packet id and for the packet size
final int size = packetBuffer.writerIndex() + 5 + 5;
ByteBuf buffer = Unpooled.buffer(size);
writePacket(buffer, packetBuffer, packet.getId());
return buffer;
}
/**
* Write a packet buffer into {@code buf}
*
* @param buf the buffer which will receive the packet id/data
* @param packetBuffer the buffer containing the raw packet data
* @param packetId the packet id
*/
private static void writePacket(ByteBuf buf, ByteBuf packetBuffer, int packetId) {
Utils.writeVarIntBuf(buf, packetId);
buf.writeBytes(packetBuffer);
}
/**
* Get the buffer representing the raw packet data
*
* @param packet the packet to write
* @return the {@link ByteBuf} containing the raw packet data
*/
private static ByteBuf getPacketBuffer(ServerPacket packet) {
BinaryWriter writer = new BinaryWriter();
packet.write(writer);
return writer.getBuffer();
}
}

View File

@ -3,7 +3,6 @@ package net.minestom.server.utils;
import io.netty.buffer.ByteBuf;
import net.minestom.server.instance.Chunk;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.buffer.BufferWrapper;
public final class Utils {
@ -30,17 +29,6 @@ public final class Utils {
} while (value != 0);
}
public static void writeVarIntBuffer(BufferWrapper buffer, int value) {
do {
byte temp = (byte) (value & 0b01111111);
value >>>= 7;
if (value != 0) {
temp |= 0b10000000;
}
buffer.putByte(temp);
} while (value != 0);
}
public static void writeVarInt(BinaryWriter writer, int value) {
do {
byte temp = (byte) (value & 0b01111111);
@ -103,14 +91,14 @@ public final class Utils {
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
0, 5};
public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
public static void writeBlocks(ByteBuf buffer, short[] blocksId, int bitsPerEntry) {
short count = 0;
for (short id : blocksId)
if (id != 0)
count++;
buffer.putShort(count);
buffer.putByte((byte) bitsPerEntry);
buffer.writeShort(count);
buffer.writeByte((byte) bitsPerEntry);
int[] blocksData = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z];
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
@ -121,28 +109,28 @@ public final class Utils {
}
}
}
long[] data = encodeBlocks(blocksData, bitsPerEntry);
buffer.putVarInt(data.length);
final long[] data = encodeBlocks(blocksData, bitsPerEntry);
writeVarIntBuf(buffer, data.length);
for (int i = 0; i < data.length; i++) {
buffer.putLong(data[i]);
buffer.writeLong(data[i]);
}
}
public static long[] encodeBlocks(int[] blocks, int bitsPerEntry) {
long maxEntryValue = (1L << bitsPerEntry) - 1;
char valuesPerLong = (char) (64 / bitsPerEntry);
int magicIndex = 3 * (valuesPerLong - 1);
long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
int divideShift = MAGIC[magicIndex + 2];
int size = (blocks.length + valuesPerLong - 1) / valuesPerLong;
final long maxEntryValue = (1L << bitsPerEntry) - 1;
final char valuesPerLong = (char) (64 / bitsPerEntry);
final int magicIndex = 3 * (valuesPerLong - 1);
final long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
final long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
final int divideShift = MAGIC[magicIndex + 2];
final int size = (blocks.length + valuesPerLong - 1) / valuesPerLong;
long[] data = new long[size];
for (int i = 0; i < blocks.length; i++) {
long value = blocks[i];
int cellIndex = (int) (i * divideMul + divideAdd >> 32L >> divideShift);
int bitIndex = (i - cellIndex * valuesPerLong) * bitsPerEntry;
final long value = blocks[i];
final int cellIndex = (int) (i * divideMul + divideAdd >> 32L >> divideShift);
final int bitIndex = (i - cellIndex * valuesPerLong) * bitsPerEntry;
data[cellIndex] = data[cellIndex] & ~(maxEntryValue << bitIndex) | (value & maxEntryValue) << bitIndex;
}

View File

@ -7,13 +7,11 @@ import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.SerializerUtils;
import net.minestom.server.utils.Utils;
import net.minestom.server.utils.buffer.BufferWrapper;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.function.Consumer;
@ -210,15 +208,6 @@ public class BinaryWriter extends OutputStream {
consumer.accept(this);
}
public void writeBufferAndFree(BufferWrapper buffer) {
ByteBuffer byteBuffer = buffer.getByteBuffer();
final int size = buffer.getSize();
byte[] cache = new byte[size];
byteBuffer.position(0).get(cache, 0, size);
writeBytes(cache);
buffer.free();
}
/**
* Write an {@link UUID}
* It is done by writing both long, the most & least significant bits
@ -263,6 +252,15 @@ public class BinaryWriter extends OutputStream {
return bytes;
}
/**
* Get the raw buffer used by this binary writer
*
* @return the raw buffer
*/
public ByteBuf getBuffer() {
return buffer;
}
@Override
public void write(int b) {
writeByte((byte) b);

View File

@ -1,22 +0,0 @@
package net.minestom.server.utils.buffer;
import com.github.pbbl.heap.ByteBufferPool;
import java.nio.ByteBuffer;
public final class BufferUtils {
private static final ByteBufferPool pool = new ByteBufferPool();
private BufferUtils() {
}
public static BufferWrapper getBuffer(int size) {
return new BufferWrapper(pool.take(size));
}
protected static void giveBuffer(ByteBuffer byteBuffer) {
pool.give(byteBuffer);
}
}

View File

@ -1,57 +0,0 @@
package net.minestom.server.utils.buffer;
import net.minestom.server.utils.Utils;
import java.nio.ByteBuffer;
public class BufferWrapper {
private final ByteBuffer byteBuffer;
private int size;
protected BufferWrapper(ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
public void putByte(byte b) {
this.byteBuffer.put(b);
size += Byte.BYTES;
}
public void putShort(short s) {
this.byteBuffer.putShort(s);
size += Short.BYTES;
}
public void putInt(int n) {
this.byteBuffer.putInt(n);
size += Integer.BYTES;
}
public void putLong(long l) {
this.byteBuffer.putLong(l);
size += Long.BYTES;
}
public void putVarInt(int n) {
Utils.writeVarIntBuffer(this, n);
size += Utils.getVarIntSize(n);
}
public void putBytes(byte[] bytes) {
this.byteBuffer.put(bytes);
size += Byte.BYTES * bytes.length;
}
public void free() {
BufferUtils.giveBuffer(getByteBuffer());
}
public int getSize() {
return size;
}
public ByteBuffer getByteBuffer() {
return byteBuffer;
}
}