Send keep alive frequently. Removed unused packets. Moved initialization in server class

This commit is contained in:
Nanit 2020-11-26 19:58:16 +02:00
parent 7eb6f75908
commit bc05228da3
10 changed files with 83 additions and 181 deletions

18
settings.properties Normal file
View File

@ -0,0 +1,18 @@
#
# NanoLimbo configuration
#
host=localhost
port=65535
max-players=100
ping-version=NanoLimbo
ping-description={"text": "NanoLimbo"}
# Player info forwarding support. Available types: NONE, LEGACY, MODERN
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=30000

View File

@ -17,7 +17,7 @@ public final class LimboConfig {
public static void load(Path file) throws IOException { public static void load(Path file) throws IOException {
if (!Files.exists(file)){ if (!Files.exists(file)){
Files.copy(LimboConfig.class.getResourceAsStream("/settings.properties"), file); Files.copy(NanoLimbo.getResource("/settings.properties"), file);
} }
Properties properties = new Properties(); Properties properties = new Properties();

View File

@ -2,28 +2,14 @@ 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.DefaultWorld;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Paths;
public final class NanoLimbo { public final class NanoLimbo {
private LimboServer server;
public void start() throws Exception {
LimboConfig.load(Paths.get("./settings.properties"));
DefaultDimension.init();
DefaultWorld.init();
server = new LimboServer();
server.start();
}
public static void main(String[] args){ public static void main(String[] args){
try { try {
new NanoLimbo().start(); new LimboServer().start();
} catch (Exception e){ } catch (Exception e){
Logger.error("Cannot start server: ", e); Logger.error("Cannot start server: ", e);
} }

View File

@ -20,8 +20,8 @@ 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.UUID;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
public class ClientConnection extends ChannelInboundHandlerAdapter { public class ClientConnection extends ChannelInboundHandlerAdapter {
@ -30,8 +30,18 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
private final Channel channel; private final Channel channel;
private State state; private State state;
private UUID uuid;
private String username; private String username;
public UUID getUuid() {
return uuid;
}
public String getUsername() {
return username;
}
public ClientConnection(Channel channel, LimboServer server){ public ClientConnection(Channel channel, LimboServer server){
this.server = server; this.server = server;
this.channel = channel; this.channel = channel;
@ -40,14 +50,14 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
@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(); server.removeConnection(this);
Logger.info("Player %s disconnected", this.username); Logger.info("Player %s disconnected", this.username);
} }
super.channelInactive(ctx); super.channelInactive(ctx);
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (channel.isActive()){ if (channel.isActive()){
Logger.error("Unhandled exception: %s", cause.getMessage()); Logger.error("Unhandled exception: %s", cause.getMessage());
} }
@ -74,12 +84,13 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
} }
if (packet instanceof PacketLoginStart){ if (packet instanceof PacketLoginStart){
if (server.getPlayersCount() >= LimboConfig.getMaxPlayers()){ if (server.getConnectionsCount() >= LimboConfig.getMaxPlayers()){
disconnect("Too many players connected"); disconnect("Too many players connected");
return; return;
} }
this.username = ((PacketLoginStart) packet).getUsername(); this.username = ((PacketLoginStart) packet).getUsername();
this.uuid = UuidUtil.getOfflineModeUuid(this.username);
PacketLoginSuccess loginSuccess = new PacketLoginSuccess(); PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
@ -89,7 +100,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
sendPacket(loginSuccess); sendPacket(loginSuccess);
updateState(State.PLAY); updateState(State.PLAY);
server.incrementPlayers(); server.addConnection(this);
Logger.info("Player %s connected", this.username); Logger.info("Player %s connected", this.username);
startJoinProcess(); startJoinProcess();
@ -122,34 +133,14 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
PacketPlayerPositionAndLook positionAndLook = new PacketPlayerPositionAndLook(); PacketPlayerPositionAndLook positionAndLook = new PacketPlayerPositionAndLook();
positionAndLook.setX(0.0); positionAndLook.setX(0.0);
positionAndLook.setY(2.0); positionAndLook.setY(0.0);
positionAndLook.setZ(0.0); positionAndLook.setZ(0.0);
positionAndLook.setYaw(90.0F); positionAndLook.setYaw(90.0F);
positionAndLook.setPitch(0.0F); positionAndLook.setPitch(0.0F);
positionAndLook.setTeleportId(ThreadLocalRandom.current().nextInt()); positionAndLook.setTeleportId(ThreadLocalRandom.current().nextInt());
PacketUpdateViewPos updateViewPos = new PacketUpdateViewPos();
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(joinGame);
sendPacket(positionAndLook); sendPacket(positionAndLook);
sendPacket(updateViewPos);
sendPacket(chunkData);
sendPacket(updateViewPos);
sendPacket(positionAndLook);
sendKeepAlive(); sendKeepAlive();
} }

View File

@ -27,6 +27,12 @@ public class ByteMessage extends ByteBuf {
this.buf = buf; this.buf = buf;
} }
public byte[] toByteArray(){
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
return bytes;
}
/* Minecraft protocol methods */ /* Minecraft protocol methods */
public int readVarInt() { public int readVarInt() {
@ -127,6 +133,13 @@ public class ByteMessage extends ByteBuf {
} }
} }
public void writeLongArray(long[] array) {
writeVarInt(array.length);
for (long i : array) {
writeLong(i);
}
}
public void writeCompoundTagArray(CompoundBinaryTag[] compoundTags) { public void writeCompoundTagArray(CompoundBinaryTag[] compoundTags) {
try { try {
ByteBufOutputStream stream = new ByteBufOutputStream(buf); ByteBufOutputStream stream = new ByteBufOutputStream(buf);
@ -1125,4 +1138,8 @@ public class ByteMessage extends ByteBuf {
public boolean release(int decrement) { public boolean release(int decrement) {
return buf.release(decrement); return buf.release(decrement);
} }
public static ByteMessage create(){
return new ByteMessage(Unpooled.buffer());
}
} }

View File

@ -1,69 +0,0 @@
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

@ -1,26 +0,0 @@
package ru.nanit.limbo.protocol.packets.play;
import ru.nanit.limbo.protocol.ByteMessage;
import ru.nanit.limbo.protocol.PacketOut;
import ru.nanit.limbo.protocol.registry.Version;
public class PacketUpdateViewPos implements PacketOut {
private int chunkX;
private int chunkY;
public void setChunkX(int chunkX) {
this.chunkX = chunkX;
}
public void setChunkY(int chunkY) {
this.chunkY = chunkY;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeVarInt(chunkX);
msg.writeVarInt(chunkY);
}
}

View File

@ -17,6 +17,8 @@ public enum State {
HANDSHAKING(0){ HANDSHAKING(0){
{ {
serverBound.register(Version.getMinimal(), 0x00, PacketHandshake::new); serverBound.register(Version.getMinimal(), 0x00, PacketHandshake::new);
int[] i = new int[16 * 16 * 16];
} }
}, },
STATUS(1){ STATUS(1){
@ -36,12 +38,10 @@ 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, 0x1F, PacketKeepAlive::new); clientBound.register(Version.V1_16_4, 0x1F, PacketKeepAlive::new);
serverBound.register(Version.V1_16_4, 0x1F, PacketKeepAlive::new); serverBound.register(Version.V1_16_4, 0x10, PacketKeepAlive::new);
} }
}; };

View File

@ -5,30 +5,42 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import ru.nanit.limbo.LimboConfig; import ru.nanit.limbo.LimboConfig;
import ru.nanit.limbo.connection.ClientChannelInitializer; import ru.nanit.limbo.connection.ClientChannelInitializer;
import ru.nanit.limbo.connection.ClientConnection;
import ru.nanit.limbo.util.Logger; import ru.nanit.limbo.util.Logger;
import ru.nanit.limbo.world.DefaultDimension;
import java.util.concurrent.atomic.AtomicInteger; import java.nio.file.Paths;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public final class LimboServer { public final class LimboServer {
private AtomicInteger playersCount; private final Map<UUID, ClientConnection> connections = new ConcurrentHashMap<>();
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
public int getPlayersCount(){ public int getConnectionsCount(){
return playersCount.get(); return connections.size();
} }
public void incrementPlayers(){ public void addConnection(ClientConnection connection){
playersCount.incrementAndGet(); connections.put(connection.getUuid(), connection);
} }
public void decrementPlayers(){ public void removeConnection(ClientConnection connection){
playersCount.decrementAndGet(); connections.remove(connection.getUuid());
} }
public void start() throws Exception { public void start() throws Exception {
Logger.info("Starting server..."); Logger.info("Starting server...");
playersCount = new AtomicInteger(); LimboConfig.load(Paths.get("./settings.properties"));
DefaultDimension.init();
executor.scheduleAtFixedRate(this::broadcastKeepAlive, 0L, 5L, TimeUnit.SECONDS);
ServerBootstrap bootstrap = new ServerBootstrap() ServerBootstrap bootstrap = new ServerBootstrap()
.group(new NioEventLoopGroup(), new NioEventLoopGroup()) .group(new NioEventLoopGroup(), new NioEventLoopGroup())
@ -36,7 +48,12 @@ public final class LimboServer {
.childHandler(new ClientChannelInitializer(this)); .childHandler(new ClientChannelInitializer(this));
bootstrap.bind(LimboConfig.getHost(), LimboConfig.getPort()); bootstrap.bind(LimboConfig.getHost(), LimboConfig.getPort());
Logger.info("Server started on %s:%d", LimboConfig.getHost(), LimboConfig.getPort()); Logger.info("Server started on %s:%d", LimboConfig.getHost(), LimboConfig.getPort());
} }
private void broadcastKeepAlive(){
connections.values().forEach(ClientConnection::sendKeepAlive);
}
} }

View File

@ -1,32 +0,0 @@
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;
}
}