mirror of
https://github.com/Nan1t/NanoLimbo.git
synced 2025-07-16 14:10:13 +02:00
Chunk packet. Counting players and kicking if too many
This commit is contained in:
parent
011a48724d
commit
7eb6f75908
@ -3,6 +3,7 @@ package ru.nanit.limbo;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
import ru.nanit.limbo.util.Logger;
|
||||
import ru.nanit.limbo.world.DefaultDimension;
|
||||
import ru.nanit.limbo.world.DefaultWorld;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
@ -14,6 +15,7 @@ public final class NanoLimbo {
|
||||
public void start() throws Exception {
|
||||
LimboConfig.load(Paths.get("./settings.properties"));
|
||||
DefaultDimension.init();
|
||||
DefaultWorld.init();
|
||||
|
||||
server = new LimboServer();
|
||||
server.start();
|
||||
|
@ -4,11 +4,10 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import ru.nanit.limbo.LimboConfig;
|
||||
import ru.nanit.limbo.protocol.packets.login.*;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketJoinGame;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketPlayerPositionAndLook;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketUpdateViewPos;
|
||||
import ru.nanit.limbo.protocol.packets.play.*;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.protocol.pipeline.PacketDecoder;
|
||||
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.UuidUtil;
|
||||
import ru.nanit.limbo.world.DefaultDimension;
|
||||
import ru.nanit.limbo.world.DefaultWorld;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@ -33,13 +33,14 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
private String username;
|
||||
|
||||
public ClientConnection(Channel channel, LimboServer server){
|
||||
this.channel = channel;
|
||||
this.server = server;
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (state.equals(State.PLAY)){
|
||||
server.decrementPlayers();
|
||||
Logger.info("Player %s disconnected", this.username);
|
||||
}
|
||||
super.channelInactive(ctx);
|
||||
@ -47,7 +48,9 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
|
||||
@Override
|
||||
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
|
||||
@ -71,6 +74,11 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
if (packet instanceof PacketLoginStart){
|
||||
if (server.getPlayersCount() >= LimboConfig.getMaxPlayers()){
|
||||
disconnect("Too many players connected");
|
||||
return;
|
||||
}
|
||||
|
||||
this.username = ((PacketLoginStart) packet).getUsername();
|
||||
|
||||
PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
|
||||
@ -80,9 +88,16 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
|
||||
sendPacket(loginSuccess);
|
||||
updateState(State.PLAY);
|
||||
|
||||
server.incrementPlayers();
|
||||
Logger.info("Player %s connected", this.username);
|
||||
|
||||
startJoinProcess();
|
||||
}
|
||||
|
||||
if (packet instanceof PacketKeepAlive){
|
||||
System.out.println("Get KeepAlive " + ((PacketKeepAlive)packet).getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void startJoinProcess(){
|
||||
@ -118,9 +133,40 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
updateViewPos.setChunkX(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(positionAndLook);
|
||||
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){
|
||||
@ -133,18 +179,6 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
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(){
|
||||
return channel.isActive();
|
||||
}
|
||||
|
@ -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() {
|
||||
try {
|
||||
return BinaryTagIO.readDataInput(new ByteBufInputStream(buf));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -11,7 +11,7 @@ public class PacketPlayerPositionAndLook implements PacketOut {
|
||||
private double z;
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
private byte flags = 0x01;
|
||||
private byte flags = 0x08;
|
||||
private int teleportId;
|
||||
|
||||
public void setX(double x) {
|
||||
|
@ -3,9 +3,7 @@ package ru.nanit.limbo.protocol.registry;
|
||||
import ru.nanit.limbo.protocol.Packet;
|
||||
import ru.nanit.limbo.protocol.packets.*;
|
||||
import ru.nanit.limbo.protocol.packets.login.*;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketJoinGame;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketPlayerPositionAndLook;
|
||||
import ru.nanit.limbo.protocol.packets.play.PacketUpdateViewPos;
|
||||
import ru.nanit.limbo.protocol.packets.play.*;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusPing;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse;
|
||||
@ -38,9 +36,12 @@ public enum State {
|
||||
},
|
||||
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, 0x34, PacketPlayerPositionAndLook::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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7,11 +7,29 @@ import ru.nanit.limbo.LimboConfig;
|
||||
import ru.nanit.limbo.connection.ClientChannelInitializer;
|
||||
import ru.nanit.limbo.util.Logger;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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 {
|
||||
Logger.info("Starting server...");
|
||||
|
||||
playersCount = new AtomicInteger();
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||
.group(new NioEventLoopGroup(), new NioEventLoopGroup())
|
||||
.channel(NioServerSocketChannel.class)
|
||||
|
32
src/main/java/ru/nanit/limbo/world/DefaultWorld.java
Normal file
32
src/main/java/ru/nanit/limbo/world/DefaultWorld.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -5,12 +5,14 @@
|
||||
host=localhost
|
||||
port=65535
|
||||
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
|
||||
|
||||
# Read timeout for connections in milliseconds
|
||||
read-timeout=30000
|
||||
# If you use MODERN type of forwarding, enter your secret code here
|
||||
ip-forwarding-secret=<YOUR_SECRET_HERE>
|
||||
|
||||
ping-version=NanoLimbo
|
||||
ping-description={"text": "NanoLimbo"}
|
||||
# Read timeout for connections in milliseconds
|
||||
read-timeout=30000
|
Loading…
x
Reference in New Issue
Block a user