Chunk packet. Counting players and kicking if too many

This commit is contained in:
Nanit 2020-11-26 12:29:54 +02:00
parent 011a48724d
commit 7eb6f75908
10 changed files with 234 additions and 26 deletions

View File

@ -3,6 +3,7 @@ package ru.nanit.limbo;
import ru.nanit.limbo.server.LimboServer; import ru.nanit.limbo.server.LimboServer;
import ru.nanit.limbo.util.Logger; import ru.nanit.limbo.util.Logger;
import ru.nanit.limbo.world.DefaultDimension; import ru.nanit.limbo.world.DefaultDimension;
import ru.nanit.limbo.world.DefaultWorld;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -14,6 +15,7 @@ public final class NanoLimbo {
public void start() throws Exception { public void start() throws Exception {
LimboConfig.load(Paths.get("./settings.properties")); LimboConfig.load(Paths.get("./settings.properties"));
DefaultDimension.init(); DefaultDimension.init();
DefaultWorld.init();
server = new LimboServer(); server = new LimboServer();
server.start(); server.start();

View File

@ -4,11 +4,10 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import ru.nanit.limbo.LimboConfig; import ru.nanit.limbo.LimboConfig;
import ru.nanit.limbo.protocol.packets.login.*; import ru.nanit.limbo.protocol.packets.login.*;
import ru.nanit.limbo.protocol.packets.play.PacketJoinGame; import ru.nanit.limbo.protocol.packets.play.*;
import ru.nanit.limbo.protocol.packets.play.PacketPlayerPositionAndLook;
import ru.nanit.limbo.protocol.packets.play.PacketUpdateViewPos;
import ru.nanit.limbo.protocol.registry.Version; import ru.nanit.limbo.protocol.registry.Version;
import ru.nanit.limbo.protocol.pipeline.PacketDecoder; import ru.nanit.limbo.protocol.pipeline.PacketDecoder;
import ru.nanit.limbo.protocol.pipeline.PacketEncoder; import ru.nanit.limbo.protocol.pipeline.PacketEncoder;
@ -21,6 +20,7 @@ import ru.nanit.limbo.server.LimboServer;
import ru.nanit.limbo.util.Logger; import ru.nanit.limbo.util.Logger;
import ru.nanit.limbo.util.UuidUtil; import ru.nanit.limbo.util.UuidUtil;
import ru.nanit.limbo.world.DefaultDimension; import ru.nanit.limbo.world.DefaultDimension;
import ru.nanit.limbo.world.DefaultWorld;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -33,13 +33,14 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
private String username; private String username;
public ClientConnection(Channel channel, LimboServer server){ public ClientConnection(Channel channel, LimboServer server){
this.channel = channel;
this.server = server; this.server = server;
this.channel = channel;
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if (state.equals(State.PLAY)){ if (state.equals(State.PLAY)){
server.decrementPlayers();
Logger.info("Player %s disconnected", this.username); Logger.info("Player %s disconnected", this.username);
} }
super.channelInactive(ctx); super.channelInactive(ctx);
@ -47,7 +48,9 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Logger.error("Unhandled exception: %s", cause.getMessage()); if (channel.isActive()){
Logger.error("Unhandled exception: %s", cause.getMessage());
}
} }
@Override @Override
@ -71,6 +74,11 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
} }
if (packet instanceof PacketLoginStart){ if (packet instanceof PacketLoginStart){
if (server.getPlayersCount() >= LimboConfig.getMaxPlayers()){
disconnect("Too many players connected");
return;
}
this.username = ((PacketLoginStart) packet).getUsername(); this.username = ((PacketLoginStart) packet).getUsername();
PacketLoginSuccess loginSuccess = new PacketLoginSuccess(); PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
@ -80,9 +88,16 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
sendPacket(loginSuccess); sendPacket(loginSuccess);
updateState(State.PLAY); updateState(State.PLAY);
server.incrementPlayers();
Logger.info("Player %s connected", this.username); Logger.info("Player %s connected", this.username);
startJoinProcess(); startJoinProcess();
} }
if (packet instanceof PacketKeepAlive){
System.out.println("Get KeepAlive " + ((PacketKeepAlive)packet).getId());
}
} }
private void startJoinProcess(){ private void startJoinProcess(){
@ -118,9 +133,40 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
updateViewPos.setChunkX(0); updateViewPos.setChunkX(0);
updateViewPos.setChunkY(0); updateViewPos.setChunkY(0);
PacketChunkData chunkData = new PacketChunkData();
chunkData.setChunkX(0);
chunkData.setChunkZ(0);
chunkData.setFullChunk(false);
chunkData.setPrimaryBitMask(1);
chunkData.setHeightMaps(DefaultWorld.getHeightMaps());
chunkData.setData(new byte[0]);
chunkData.setBlockEntities(new CompoundBinaryTag[]{CompoundBinaryTag.empty()});
sendPacket(joinGame); sendPacket(joinGame);
sendPacket(positionAndLook); sendPacket(positionAndLook);
sendPacket(updateViewPos); sendPacket(updateViewPos);
sendPacket(chunkData);
sendPacket(updateViewPos);
sendPacket(positionAndLook);
sendKeepAlive();
}
public void disconnect(String reason){
if (isConnected() && state == State.LOGIN){
PacketDisconnect disconnect = new PacketDisconnect();
disconnect.setReason(reason);
sendPacketAndClose(disconnect);
}
}
public void sendKeepAlive(){
if (state.equals(State.PLAY)){
PacketKeepAlive keepAlive = new PacketKeepAlive();
keepAlive.setId(ThreadLocalRandom.current().nextLong());
sendPacket(keepAlive);
}
} }
public void sendPacket(Object packet){ public void sendPacket(Object packet){
@ -133,18 +179,6 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
channel.writeAndFlush(packet).addListener(ChannelFutureListener.CLOSE); channel.writeAndFlush(packet).addListener(ChannelFutureListener.CLOSE);
} }
public void disconnect(){
if (channel.isActive()){
channel.close();
}
}
public void disconnect(String reason){
PacketDisconnect packet = new PacketDisconnect();
packet.setReason(reason);
sendPacketAndClose(packet);
}
public boolean isConnected(){ public boolean isConnected(){
return channel.isActive(); return channel.isActive();
} }

View File

@ -120,6 +120,27 @@ public class ByteMessage extends ByteBuf {
} }
} }
public void writeVarIntArray(int[] array) {
writeVarInt(array.length);
for (int i : array) {
writeVarInt(i);
}
}
public void writeCompoundTagArray(CompoundBinaryTag[] compoundTags) {
try {
ByteBufOutputStream stream = new ByteBufOutputStream(buf);
writeVarInt(compoundTags.length);
for (CompoundBinaryTag tag : compoundTags){
BinaryTagIO.writeDataOutput(tag, stream);
}
} catch (IOException e) {
throw new EncoderException("Cannot write NBT CompoundTag");
}
}
public CompoundBinaryTag readCompoundTag() { public CompoundBinaryTag readCompoundTag() {
try { try {
return BinaryTagIO.readDataInput(new ByteBufInputStream(buf)); return BinaryTagIO.readDataInput(new ByteBufInputStream(buf));

View File

@ -0,0 +1,69 @@
package ru.nanit.limbo.protocol.packets.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketChunkData implements PacketOut {
private int chunkX;
private int chunkZ;
private boolean fullChunk;
private int primaryBitMask;
private CompoundBinaryTag heightMaps;
private int[] biomes;
private byte[] data;
private CompoundBinaryTag[] blockEntities;
public void setChunkX(int chunkX) {
this.chunkX = chunkX;
}
public void setChunkZ(int chunkZ) {
this.chunkZ = chunkZ;
}
public void setFullChunk(boolean fullChunk) {
this.fullChunk = fullChunk;
}
public void setPrimaryBitMask(int primaryBitMask) {
this.primaryBitMask = primaryBitMask;
}
public void setHeightMaps(CompoundBinaryTag heightMaps) {
this.heightMaps = heightMaps;
}
public void setBiomes(int[] biomes) {
this.biomes = biomes;
}
public void setData(byte[] data) {
this.data = data;
}
public void setBlockEntities(CompoundBinaryTag[] blockEntities) {
this.blockEntities = blockEntities;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeInt(chunkX);
msg.writeInt(chunkZ);
msg.writeBoolean(fullChunk);
msg.writeVarInt(primaryBitMask);
msg.writeCompoundTag(heightMaps);
if (fullChunk){
msg.writeVarIntArray(biomes);
}
msg.writeBytesArray(data);
msg.writeCompoundTagArray(blockEntities);
}
}

View File

@ -0,0 +1,29 @@
package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.Packet;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketKeepAlive implements Packet {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeLong(id);
}
@Override
public void decode(ByteMessage msg, Version version) {
this.id = msg.readLong();
}
}

View File

@ -11,7 +11,7 @@ public class PacketPlayerPositionAndLook implements PacketOut {
private double z; private double z;
private float yaw; private float yaw;
private float pitch; private float pitch;
private byte flags = 0x01; private byte flags = 0x08;
private int teleportId; private int teleportId;
public void setX(double x) { public void setX(double x) {

View File

@ -3,9 +3,7 @@ package ru.nanit.limbo.protocol.registry;
import ru.nanit.limbo.protocol.Packet; import ru.nanit.limbo.protocol.Packet;
import ru.nanit.limbo.protocol.packets.*; import ru.nanit.limbo.protocol.packets.*;
import ru.nanit.limbo.protocol.packets.login.*; import ru.nanit.limbo.protocol.packets.login.*;
import ru.nanit.limbo.protocol.packets.play.PacketJoinGame; import ru.nanit.limbo.protocol.packets.play.*;
import ru.nanit.limbo.protocol.packets.play.PacketPlayerPositionAndLook;
import ru.nanit.limbo.protocol.packets.play.PacketUpdateViewPos;
import ru.nanit.limbo.protocol.packets.status.PacketStatusPing; import ru.nanit.limbo.protocol.packets.status.PacketStatusPing;
import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest; import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest;
import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse; import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse;
@ -38,9 +36,12 @@ public enum State {
}, },
PLAY(3){ PLAY(3){
{ {
clientBound.register(Version.V1_16_4, 0x20, PacketChunkData::new);
clientBound.register(Version.V1_16_4, 0x24, PacketJoinGame::new); clientBound.register(Version.V1_16_4, 0x24, PacketJoinGame::new);
clientBound.register(Version.V1_16_4, 0x34, PacketPlayerPositionAndLook::new); clientBound.register(Version.V1_16_4, 0x34, PacketPlayerPositionAndLook::new);
clientBound.register(Version.V1_16_4, 0x40, PacketUpdateViewPos::new); clientBound.register(Version.V1_16_4, 0x40, PacketUpdateViewPos::new);
clientBound.register(Version.V1_16_4, 0x1F, PacketKeepAlive::new);
serverBound.register(Version.V1_16_4, 0x1F, PacketKeepAlive::new);
} }
}; };

View File

@ -7,11 +7,29 @@ import ru.nanit.limbo.LimboConfig;
import ru.nanit.limbo.connection.ClientChannelInitializer; import ru.nanit.limbo.connection.ClientChannelInitializer;
import ru.nanit.limbo.util.Logger; import ru.nanit.limbo.util.Logger;
import java.util.concurrent.atomic.AtomicInteger;
public final class LimboServer { public final class LimboServer {
private AtomicInteger playersCount;
public int getPlayersCount(){
return playersCount.get();
}
public void incrementPlayers(){
playersCount.incrementAndGet();
}
public void decrementPlayers(){
playersCount.decrementAndGet();
}
public void start() throws Exception { public void start() throws Exception {
Logger.info("Starting server..."); Logger.info("Starting server...");
playersCount = new AtomicInteger();
ServerBootstrap bootstrap = new ServerBootstrap() ServerBootstrap bootstrap = new ServerBootstrap()
.group(new NioEventLoopGroup(), new NioEventLoopGroup()) .group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)

View File

@ -0,0 +1,32 @@
package ru.nanit.limbo.world;
import net.kyori.adventure.nbt.CompoundBinaryTag;
public final class DefaultWorld {
private static CompoundBinaryTag heightMaps;
private DefaultWorld(){}
public static void init(){
heightMaps = CompoundBinaryTag.builder()
.putLongArray("MOTION_BLOCKING", new long[]{
1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
1389823183635388492L, 1353688558756731469L, 1389823114781694027L, 1317765589597723213L,
1371773531899860042L, 1389823183635651149L, 1371773462911685197L, 1389823183635650636L,
1353688626805119565L, 1371773531900123211L, 1335639250618849869L, 1371738278674077258L,
1389823114781694028L, 1353723811310638154L, 1371738278674077259L, 1335674228429068364L,
1335674228429067338L, 1335674228698027594L, 1317624576693539402L, 1335709481520370249L,
1299610178184057417L, 1335638906349064264L, 1299574993811968586L, 1299574924958011464L,
1299610178184056904L, 1299574924958011464L, 1299610109330100296L, 1299574924958011464L,
1299574924823793736L, 1299574924958011465L, 1281525273222484040L, 1299574924958011464L,
1281525273222484040L, 9548107335L
})
.build();
}
public static CompoundBinaryTag getHeightMaps(){
return heightMaps;
}
}

View File

@ -5,12 +5,14 @@
host=localhost host=localhost
port=65535 port=65535
max-players=100 max-players=100
ping-version=NanoLimbo
ping-description={"text": "NanoLimbo"}
# Proxy forwarding support. Available types: NONE, LEGACY, MODERN # Player info forwarding support. Available types: NONE, LEGACY, MODERN
ip-forwarding=LEGACY ip-forwarding=LEGACY
# If you use MODERN type of forwarding, enter your secret code here
ip-forwarding-secret=<YOUR_SECRET_HERE>
# Read timeout for connections in milliseconds # Read timeout for connections in milliseconds
read-timeout=30000 read-timeout=30000
ping-version=NanoLimbo
ping-description={"text": "NanoLimbo"}