mirror of
https://github.com/Nan1t/NanoLimbo.git
synced 2025-07-16 22:20:14 +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.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();
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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 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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
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
|
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"}
|
|
Loading…
x
Reference in New Issue
Block a user