Compare commits

..

No commits in common. "main" and "v1.5.2" have entirely different histories.
main ... v1.5.2

47 changed files with 192 additions and 3931 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
ko_fi: nanit

View File

@ -5,16 +5,16 @@ The main goal of this project is maximum simplicity with a minimum number of sen
The limbo is empty; there is no ability to set a schematic building since this is not necessary.
You can send useful information via chat or boss bar.
The server is fully clear. It is only able to keep a lot of players while the main server is down.
No plugins, no logs. The server is fully clear. It is only able keep a lot of players while the main server is down.
General features:
* High performance. The server doesn't save or cache any useless (for limbo) data.
* Doesn't spawn threads per player. Use a fixed thread pool.
* Doesn't spawn threads per player. Uses a fixed thread pool.
* Support for **BungeeCord** and **Velocity** info forwarding.
* Support for [BungeeGuard](https://www.spigotmc.org/resources/79601/) handshake format.
* Multiple versions support.
* Fully configurable.
* Lightweight. App size around **3MB**.
* Lightweight. App size around **2MB**.
![](https://i.imgur.com/sT8p1Gz.png)
@ -35,8 +35,6 @@ Symbol `X` means all minor versions.
- [x] 1.17.X
- [x] 1.18.X
- [x] 1.19.X
- [x] 1.20.X
- [x] 1.21
The server **doesn't** support snapshots.
@ -51,16 +49,14 @@ Note that the server also will be closed correctly if you just press `Ctrl+C`.
### Installation
Required software: JRE 11+
The installation process is simple.
1. Download the latest version of the program [**here**](https://github.com/Nan1t/NanoLimbo/releases).
2. Put the jar file in the folder you want.
3. Create a start script as you did for Bukkit or BungeeCord, with a command like this:
`java -jar NanoLimbo-<version>.jar`
4. The server will create `settings.yml` file, which is the server configuration.
5. Configure it as you want and restart the server.
5. The server will create `settings.yml` file, which is the server configuration.
6. Configure it as you want and restart the server.
### Player info forwarding
@ -78,14 +74,16 @@ Then add your tokens to `tokens` list.
### Contributing
Feel free to create a pull request if you find some bug or optimization opportunity, or if you want
Feel free to create a pull request if you found some bug or optimization opportunity, or if you want
to add some functionality that is suitable for a limbo server and won't significantly load the server.
All PRs should target the `dev` branch to keep the `main` branch stable and clean.
### Building
Required software:
* JDK 11+
* JDK 1.8+
* Gradle 7+ (optional)
To build a minimized jar, go to the project root directory and run in the terminal:

View File

@ -1,17 +1,16 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2'
id 'com.github.gmazzo.buildconfig' version '3.1.0'
}
group 'ua.nanit'
version '1.8.1'
group 'ru.nanit'
version '1.5.2'
compileJava {
options.encoding = "UTF-8"
}
tasks.withType(JavaCompile).configureEach {
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
@ -24,18 +23,10 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
implementation 'ch.qos.logback:logback-classic:1.5.6'
implementation 'org.spongepowered:configurate-yaml:4.1.2'
implementation 'io.netty:netty-all:4.1.101.Final'
implementation 'io.netty:netty-all:4.1.93.Final'
implementation 'net.kyori:adventure-nbt:4.14.0'
implementation 'com.grack:nanojson:1.8'
implementation 'com.google.code.gson:gson:2.10.1'
}
buildConfig {
className("BuildConfig")
packageName("ua.nanit.limbo")
buildConfigField('String', 'LIMBO_VERSION', "\"${project.version}\"")
}
shadowJar {
@ -45,9 +36,7 @@ shadowJar {
attributes('Main-Class': 'ua.nanit.limbo.NanoLimbo')
}
minimize {
exclude(dependency('ch.qos.logback:logback-classic:.*:.*'))
}
minimize()
}
test {

View File

@ -18,7 +18,7 @@
package ua.nanit.limbo;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
public final class NanoLimbo {
@ -26,7 +26,7 @@ public final class NanoLimbo {
try {
new LimboServer().start();
} catch (Exception e) {
Log.error("Cannot start server: ", e);
Logger.error("Cannot start server: ", e);
}
}

View File

@ -71,11 +71,6 @@ public final class LimboConfig {
private int bossGroupSize;
private int workerGroupSize;
private boolean useTrafficLimits;
private int maxPacketSize;
private double interval;
private double maxPacketRate;
public LimboConfig(Path root) {
this.root = root;
}
@ -132,11 +127,6 @@ public final class LimboConfig {
useEpoll = conf.node("netty", "useEpoll").getBoolean(true);
bossGroupSize = conf.node("netty", "threads", "bossGroup").getInt(1);
workerGroupSize = conf.node("netty", "threads", "workerGroup").getInt(4);
useTrafficLimits = conf.node("traffic", "enable").getBoolean(false);
maxPacketSize = conf.node("traffic", "maxPacketSize").getInt(-1);
interval = conf.node("traffic", "interval").getDouble(-1.0);
maxPacketRate = conf.node("traffic", "maxPacketRate").getDouble(-1.0);
}
private BufferedReader getReader() throws IOException {
@ -260,20 +250,4 @@ public final class LimboConfig {
public int getWorkerGroupSize() {
return workerGroupSize;
}
public boolean isUseTrafficLimits() {
return useTrafficLimits;
}
public int getMaxPacketSize() {
return maxPacketSize;
}
public double getInterval() {
return interval;
}
public double getMaxPacketRate() {
return maxPacketRate;
}
}

View File

@ -21,7 +21,10 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.timeout.ReadTimeoutHandler;
import ua.nanit.limbo.connection.pipeline.*;
import ua.nanit.limbo.connection.pipeline.PacketDecoder;
import ua.nanit.limbo.connection.pipeline.PacketEncoder;
import ua.nanit.limbo.connection.pipeline.VarIntFrameDecoder;
import ua.nanit.limbo.connection.pipeline.VarIntLengthEncoder;
import ua.nanit.limbo.server.LimboServer;
import java.util.concurrent.TimeUnit;
@ -46,15 +49,6 @@ public class ClientChannelInitializer extends ChannelInitializer<Channel> {
TimeUnit.MILLISECONDS));
pipeline.addLast("frame_decoder", new VarIntFrameDecoder());
pipeline.addLast("frame_encoder", new VarIntLengthEncoder());
if (server.getConfig().isUseTrafficLimits()) {
pipeline.addLast("traffic_limit", new ChannelTrafficHandler(
server.getConfig().getMaxPacketSize(),
server.getConfig().getInterval(),
server.getConfig().getMaxPacketRate()
));
}
pipeline.addLast("decoder", decoder);
pipeline.addLast("encoder", encoder);
pipeline.addLast("handler", connection);

View File

@ -30,13 +30,12 @@ import ua.nanit.limbo.connection.pipeline.PacketDecoder;
import ua.nanit.limbo.connection.pipeline.PacketEncoder;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.Packet;
import ua.nanit.limbo.protocol.PacketSnapshot;
import ua.nanit.limbo.protocol.packets.login.PacketDisconnect;
import ua.nanit.limbo.protocol.packets.play.PacketKeepAlive;
import ua.nanit.limbo.protocol.registry.State;
import ua.nanit.limbo.protocol.registry.Version;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import ua.nanit.limbo.util.UuidUtil;
import javax.crypto.Mac;
@ -95,7 +94,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
@Override
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
if (state.equals(State.PLAY) || state.equals(State.CONFIGURATION)) {
if (state.equals(State.PLAY)) {
server.getConnections().removeConnection(this);
}
super.channelInactive(ctx);
@ -104,7 +103,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (channel.isActive()) {
Log.error("Unhandled exception: ", cause);
Logger.error("Unhandled exception: ", cause);
}
}
@ -115,7 +114,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
public void handlePacket(Object packet) {
if (packet instanceof Packet) {
((Packet) packet).handle(this, server);
((Packet)packet).handle(this, server);
}
}
@ -126,20 +125,8 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
}
sendPacket(PacketSnapshots.PACKET_LOGIN_SUCCESS);
server.getConnections().addConnection(this);
// Preparing for configuration mode
if (clientVersion.moreOrEqual(Version.V1_20_2)) {
updateEncoderState(State.CONFIGURATION);
return;
}
spawnPlayer();
}
public void spawnPlayer() {
updateState(State.PLAY);
server.getConnections().addConnection(this);
Runnable sendPlayPackets = () -> {
writePacket(PacketSnapshots.PACKET_JOIN_GAME);
@ -176,14 +163,6 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
if (PacketSnapshots.PACKET_HEADER_AND_FOOTER != null && clientVersion.moreOrEqual(Version.V1_8))
writePacket(PacketSnapshots.PACKET_HEADER_AND_FOOTER);
if (clientVersion.moreOrEqual(Version.V1_20_3)) {
writePacket(PacketSnapshots.PACKET_START_WAITING_CHUNKS);
for (PacketSnapshot chunk : PacketSnapshots.PACKETS_EMPTY_CHUNKS) {
writePacket(chunk);
}
}
sendKeepAlive();
};
@ -194,23 +173,6 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
}
}
public void onLoginAcknowledgedReceived() {
updateState(State.CONFIGURATION);
if (PacketSnapshots.PACKET_PLUGIN_MESSAGE != null)
writePacket(PacketSnapshots.PACKET_PLUGIN_MESSAGE);
if (clientVersion.moreOrEqual(Version.V1_20_5)) {
for (PacketSnapshot packet : PacketSnapshots.PACKETS_REGISTRY_DATA) {
writePacket(packet);
}
} else {
writePacket(PacketSnapshots.PACKET_REGISTRY_DATA);
}
sendPacket(PacketSnapshots.PACKET_FINISH_CONFIGURATION);
}
public void disconnectLogin(String reason) {
if (isConnected() && state == State.LOGIN) {
PacketDisconnect disconnect = new PacketDisconnect();
@ -264,10 +226,6 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
encoder.updateState(state);
}
public void updateEncoderState(State state) {
encoder.updateState(state);
}
public void updateVersion(Version version) {
clientVersion = version;
decoder.updateVersion(version);
@ -275,7 +233,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
}
public void setAddress(String host) {
this.address = new InetSocketAddress(host, ((InetSocketAddress) this.address).getPort());
this.address = new InetSocketAddress(host, ((InetSocketAddress)this.address).getPort());
}
boolean checkBungeeGuardHandshake(String handshake) {
@ -312,7 +270,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
setAddress(socketAddressHostname);
gameProfile.setUuid(uuid);
Log.debug("Successfully verified BungeeGuard token");
Logger.debug("Successfully verified BungeeGuard token");
return true;
}
@ -336,7 +294,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
byte[] mySignature = mac.doFinal(data);
if (!MessageDigest.isEqual(signature, mySignature))
return false;
} catch (InvalidKeyException | java.security.NoSuchAlgorithmException e) {
} catch (InvalidKeyException |java.security.NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
int version = buf.readVarInt();

View File

@ -20,8 +20,6 @@ package ua.nanit.limbo.connection;
import io.netty.buffer.Unpooled;
import ua.nanit.limbo.LimboConstants;
import ua.nanit.limbo.protocol.packets.PacketHandshake;
import ua.nanit.limbo.protocol.packets.configuration.PacketFinishConfiguration;
import ua.nanit.limbo.protocol.packets.login.PacketLoginAcknowledged;
import ua.nanit.limbo.protocol.packets.login.PacketLoginPluginRequest;
import ua.nanit.limbo.protocol.packets.login.PacketLoginPluginResponse;
import ua.nanit.limbo.protocol.packets.login.PacketLoginStart;
@ -29,7 +27,7 @@ import ua.nanit.limbo.protocol.packets.status.PacketStatusPing;
import ua.nanit.limbo.protocol.packets.status.PacketStatusRequest;
import ua.nanit.limbo.protocol.packets.status.PacketStatusResponse;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import ua.nanit.limbo.util.UuidUtil;
import java.util.concurrent.ThreadLocalRandom;
@ -46,7 +44,7 @@ public class PacketHandler {
conn.updateVersion(packet.getVersion());
conn.updateState(packet.getNextState());
Log.debug("Pinged from %s [%s]", conn.getAddress(),
Logger.debug("Pinged from %s [%s]", conn.getAddress(),
conn.getClientVersion().toString());
if (server.getConfig().getInfoForwarding().isLegacy()) {
@ -129,12 +127,4 @@ public class PacketHandler {
}
}
public void handle(ClientConnection conn, PacketLoginAcknowledged packet) {
conn.onLoginAcknowledgedReceived();
}
public void handle(ClientConnection conn, PacketFinishConfiguration packet) {
conn.spawnPlayer();
}
}

View File

@ -17,24 +17,15 @@
package ua.nanit.limbo.connection;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import ua.nanit.limbo.LimboConstants;
import ua.nanit.limbo.protocol.PacketSnapshot;
import ua.nanit.limbo.protocol.packets.configuration.PacketFinishConfiguration;
import ua.nanit.limbo.protocol.packets.configuration.PacketRegistryData;
import ua.nanit.limbo.protocol.packets.login.PacketLoginSuccess;
import ua.nanit.limbo.protocol.packets.play.*;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.data.Title;
import ua.nanit.limbo.util.NbtMessageUtil;
import ua.nanit.limbo.util.UuidUtil;
import ua.nanit.limbo.world.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@ -52,7 +43,7 @@ public final class PacketSnapshots {
public static PacketSnapshot PACKET_HEADER_AND_FOOTER;
public static PacketSnapshot PACKET_PLAYER_POS_AND_LOOK_LEGACY;
// For 1.19 we need to spawn player outside the world to avoid stuck in terrain loading
// For 1.19 we need to spawn player outside world to avoid stuck in terrain loading
public static PacketSnapshot PACKET_PLAYER_POS_AND_LOOK;
public static PacketSnapshot PACKET_TITLE_TITLE;
@ -63,12 +54,6 @@ public final class PacketSnapshots {
public static PacketSnapshot PACKET_TITLE_LEGACY_SUBTITLE;
public static PacketSnapshot PACKET_TITLE_LEGACY_TIMES;
public static PacketSnapshot PACKET_REGISTRY_DATA;
public static List<PacketSnapshot> PACKETS_REGISTRY_DATA;
public static PacketSnapshot PACKET_FINISH_CONFIGURATION;
public static List<PacketSnapshot> PACKETS_EMPTY_CHUNKS;
public static PacketSnapshot PACKET_START_WAITING_CHUNKS;
private PacketSnapshots() { }
@ -132,8 +117,8 @@ public final class PacketSnapshots {
if (server.getConfig().isUseHeaderAndFooter()) {
PacketPlayerListHeader header = new PacketPlayerListHeader();
header.setHeader(NbtMessageUtil.create(server.getConfig().getPlayerListHeader()));
header.setFooter(NbtMessageUtil.create(server.getConfig().getPlayerListFooter()));
header.setHeader(server.getConfig().getPlayerListHeader());
header.setFooter(server.getConfig().getPlayerListFooter());
PACKET_HEADER_AND_FOOTER = PacketSnapshot.of(header);
}
@ -146,7 +131,7 @@ public final class PacketSnapshots {
if (server.getConfig().isUseJoinMessage()) {
PacketChatMessage joinMessage = new PacketChatMessage();
joinMessage.setMessage(NbtMessageUtil.create(server.getConfig().getJoinMessage()));
joinMessage.setJsonData(server.getConfig().getJoinMessage());
joinMessage.setPosition(PacketChatMessage.PositionLegacy.SYSTEM_MESSAGE);
joinMessage.setSender(UUID.randomUUID());
PACKET_JOIN_MESSAGE = PacketSnapshot.of(joinMessage);
@ -193,65 +178,5 @@ public final class PacketSnapshots {
PACKET_TITLE_LEGACY_SUBTITLE = PacketSnapshot.of(legacySubtitle);
PACKET_TITLE_LEGACY_TIMES = PacketSnapshot.of(legacyTimes);
}
PacketRegistryData packetRegistryData = new PacketRegistryData();
packetRegistryData.setDimensionRegistry(server.getDimensionRegistry());
PACKET_REGISTRY_DATA = PacketSnapshot.of(packetRegistryData);
Dimension dimension1_21 = server.getDimensionRegistry().getDimension_1_21();
List<PacketSnapshot> packetRegistries = new ArrayList<>();
CompoundBinaryTag dimensionTag = dimension1_21.getData();
for (String registryType : dimensionTag.keySet()) {
CompoundBinaryTag compoundRegistryType = dimensionTag.getCompound(registryType);
PacketRegistryData registryData = new PacketRegistryData();
registryData.setDimensionRegistry(server.getDimensionRegistry());
ListBinaryTag values = compoundRegistryType.getList("value");
registryData.setMetadataWriter((message, version) -> {
message.writeString(registryType);
message.writeVarInt(values.size());
for (BinaryTag entry : values) {
CompoundBinaryTag entryTag = (CompoundBinaryTag) entry;
String name = entryTag.getString("name");
CompoundBinaryTag element = entryTag.getCompound("element");
message.writeString(name);
message.writeBoolean(true);
message.writeNamelessCompoundTag(element);
}
});
packetRegistries.add(PacketSnapshot.of(registryData));
}
PACKETS_REGISTRY_DATA = packetRegistries;
PACKET_FINISH_CONFIGURATION = PacketSnapshot.of(new PacketFinishConfiguration());
PacketGameEvent packetGameEvent = new PacketGameEvent();
packetGameEvent.setType((byte) 13); // Waiting for chunks type
packetGameEvent.setValue(0);
PACKET_START_WAITING_CHUNKS = PacketSnapshot.of(packetGameEvent);
int chunkXOffset = (int) 0 >> 4; // Default x position is 0
int chunkZOffset = (int) 0 >> 4; // Default z position is 0
int chunkEdgeSize = 1; // TODO Make configurable?
List<PacketSnapshot> emptyChunks = new ArrayList<>();
// Make multiple chunks for edges
for (int chunkX = chunkXOffset - chunkEdgeSize; chunkX <= chunkXOffset + chunkEdgeSize; ++chunkX) {
for (int chunkZ = chunkZOffset - chunkEdgeSize; chunkZ <= chunkZOffset + chunkEdgeSize; ++chunkZ) {
PacketEmptyChunk packetEmptyChunk = new PacketEmptyChunk();
packetEmptyChunk.setX(chunkX);
packetEmptyChunk.setZ(chunkZ);
emptyChunks.add(PacketSnapshot.of(packetEmptyChunk));
}
}
PACKETS_EMPTY_CHUNKS = emptyChunks;
}
}

View File

@ -1,111 +0,0 @@
package ua.nanit.limbo.connection.pipeline;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.jetbrains.annotations.NotNull;
import ua.nanit.limbo.server.Log;
import java.util.Arrays;
public class ChannelTrafficHandler extends ChannelInboundHandlerAdapter {
private final int maxPacketSize;
private final double maxPacketRate;
private final PacketBucket packetBucket;
public ChannelTrafficHandler(int maxPacketSize, double interval, double maxPacketRate) {
this.maxPacketSize = maxPacketSize;
this.maxPacketRate = maxPacketRate;
this.packetBucket = (interval > 0.0 && maxPacketRate > 0.0) ? new PacketBucket(interval * 1000.0, 150) : null;
}
@Override
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception {
if (msg instanceof ByteBuf) {
ByteBuf in = (ByteBuf) msg;
int bytes = in.readableBytes();
if (maxPacketSize > 0 && bytes > maxPacketSize) {
closeConnection(ctx, "Closed %s due to large packet size (%d bytes)", ctx.channel().remoteAddress(), bytes);
return;
}
if (packetBucket != null) {
packetBucket.incrementPackets(1);
if (packetBucket.getCurrentPacketRate() > maxPacketRate) {
closeConnection(ctx, "Closed %s due to many packets sent (%d in the last %.1f seconds)", ctx.channel().remoteAddress(), packetBucket.sum, (packetBucket.intervalTime / 1000.0));
return;
}
}
}
super.channelRead(ctx, msg);
}
private void closeConnection(ChannelHandlerContext ctx, String reason, Object... args) {
ctx.close();
Log.info(reason, args);
}
private static class PacketBucket {
private static final double NANOSECONDS_TO_MILLISECONDS = 1.0e-6;
private static final int MILLISECONDS_TO_SECONDS = 1000;
private final double intervalTime;
private final double intervalResolution;
private final int[] data;
private int newestData;
private double lastBucketTime;
private int sum;
public PacketBucket(final double intervalTime, final int totalBuckets) {
this.intervalTime = intervalTime;
this.intervalResolution = intervalTime / totalBuckets;
this.data = new int[totalBuckets];
}
public void incrementPackets(final int packets) {
double timeMs = System.nanoTime() * NANOSECONDS_TO_MILLISECONDS;
double timeDelta = timeMs - this.lastBucketTime;
if (timeDelta < 0.0) {
timeDelta = 0.0;
}
if (timeDelta < this.intervalResolution) {
this.data[this.newestData] += packets;
this.sum += packets;
return;
}
int bucketsToMove = (int)(timeDelta / this.intervalResolution);
double nextBucketTime = this.lastBucketTime + bucketsToMove * this.intervalResolution;
if (bucketsToMove >= this.data.length) {
Arrays.fill(this.data, 0);
this.data[0] = packets;
this.sum = packets;
this.newestData = 0;
this.lastBucketTime = timeMs;
return;
}
for (int i = 1; i < bucketsToMove; ++i) {
int index = (this.newestData + i) % this.data.length;
this.sum -= this.data[index];
this.data[index] = 0;
}
int newestDataIndex = (this.newestData + bucketsToMove) % this.data.length;
this.sum += packets - this.data[newestDataIndex];
this.data[newestDataIndex] = packets;
this.newestData = newestDataIndex;
this.lastBucketTime = nextBucketTime;
}
public double getCurrentPacketRate() {
return this.sum / (this.intervalTime / MILLISECONDS_TO_SECONDS);
}
}
}

View File

@ -24,7 +24,7 @@ import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.Packet;
import ua.nanit.limbo.protocol.registry.State;
import ua.nanit.limbo.protocol.registry.Version;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import java.util.List;
@ -47,20 +47,16 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
Packet packet = mappings.getPacket(packetId);
if (packet != null) {
Log.debug("Received packet %s[0x%s] (%d bytes)", packet.toString(), Integer.toHexString(packetId), msg.readableBytes());
Logger.debug("Received packet %s[0x%s]", packet.toString(), Integer.toHexString(packetId));
try {
packet.decode(msg, version);
} catch (Exception e) {
if (Log.isDebug()) {
Log.warning("Cannot decode packet 0x%s", e, Integer.toHexString(packetId));
} else {
Log.warning("Cannot decode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
}
Logger.warning("Cannot decode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
}
ctx.fireChannelRead(packet);
} else {
Log.debug("Undefined incoming packet: 0x" + Integer.toHexString(packetId));
Logger.debug("Undefined incoming packet: 0x" + Integer.toHexString(packetId));
}
}

View File

@ -25,7 +25,7 @@ import ua.nanit.limbo.protocol.Packet;
import ua.nanit.limbo.protocol.PacketSnapshot;
import ua.nanit.limbo.protocol.registry.State;
import ua.nanit.limbo.protocol.registry.Version;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
public class PacketEncoder extends MessageToByteEncoder<Packet> {
@ -51,7 +51,7 @@ public class PacketEncoder extends MessageToByteEncoder<Packet> {
}
if (packetId == -1) {
Log.warning("Undefined packet class: %s[0x%s] (%d bytes)", packet.getClass().getName(), Integer.toHexString(packetId), msg.readableBytes());
Logger.warning("Undefined packet class: %s[0x%s]", packet.getClass().getName(), Integer.toHexString(packetId));
return;
}
@ -60,11 +60,11 @@ public class PacketEncoder extends MessageToByteEncoder<Packet> {
try {
packet.encode(msg, version);
if (Log.isDebug()) {
Log.debug("Sending %s[0x%s] packet (%d bytes)", packet.toString(), Integer.toHexString(packetId), msg.readableBytes());
if (Logger.getLevel() >= Logger.Level.DEBUG.getIndex()) {
Logger.debug("Sending %s[0x%s] packet (%d bytes)", packet.toString(), Integer.toHexString(packetId), msg.readableBytes());
}
} catch (Exception e) {
Log.error("Cannot encode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
Logger.error("Cannot encode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
}
}

View File

@ -20,7 +20,7 @@ package ua.nanit.limbo.connection.pipeline;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import java.util.List;
@ -42,19 +42,18 @@ public class VarIntFrameDecoder extends ByteToMessageDecoder {
int readVarInt = reader.getReadVarInt();
int bytesRead = reader.getBytesRead();
if (readVarInt < 0) {
Log.error("[VarIntFrameDecoder] Bad data length");
Logger.error("[VarIntFrameDecoder] Bad data length");
} else if (readVarInt == 0) {
in.readerIndex(varIntEnd + 1);
} else {
int minimumRead = bytesRead + readVarInt;
if (in.isReadable(minimumRead)) {
out.add(in.retainedSlice(varIntEnd + 1, readVarInt));
in.skipBytes(minimumRead);
}
}
} else if (reader.getResult() == VarIntByteDecoder.DecodeResult.TOO_BIG) {
Log.error("[VarIntFrameDecoder] Too big data");
Logger.error("[VarIntFrameDecoder] Too big data");
}
}
}

View File

@ -21,8 +21,8 @@ import io.netty.buffer.*;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import io.netty.util.ByteProcessor;
import net.kyori.adventure.nbt.*;
import ua.nanit.limbo.protocol.registry.Version;
import net.kyori.adventure.nbt.BinaryTagIO;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import java.io.IOException;
import java.io.InputStream;
@ -73,37 +73,14 @@ public class ByteMessage extends ByteBuf {
}
public void writeVarInt(int value) {
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
// that the proxy will write, to improve inlining.
if ((value & (0xFFFFFFFF << 7)) == 0) {
buf.writeByte(value);
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
buf.writeShort(w);
} else {
writeVarIntFull(value);
}
}
while (true) {
if ((value & 0xFFFFFF80) == 0) {
buf.writeByte(value);
return;
}
private void writeVarIntFull(final int value) {
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
if ((value & (0xFFFFFFFF << 7)) == 0) {
buf.writeByte(value);
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
buf.writeShort(w);
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
buf.writeMedium(w);
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
buf.writeInt(w);
} else {
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
buf.writeInt(w);
buf.writeByte(value >>> 28);
buf.writeByte(value & 0x7F | 0x80);
value >>>= 7;
}
}
@ -216,63 +193,6 @@ public class ByteMessage extends ByteBuf {
}
}
public void writeNamelessCompoundTag(BinaryTag binaryTag) {
try (ByteBufOutputStream stream = new ByteBufOutputStream(buf)) {
stream.writeByte(binaryTag.type().id());
// TODO Find a way to improve this...
if (binaryTag instanceof CompoundBinaryTag) {
CompoundBinaryTag tag = (CompoundBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof ByteBinaryTag) {
ByteBinaryTag tag = (ByteBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof ShortBinaryTag) {
ShortBinaryTag tag = (ShortBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof IntBinaryTag) {
IntBinaryTag tag = (IntBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof LongBinaryTag) {
LongBinaryTag tag = (LongBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof DoubleBinaryTag) {
DoubleBinaryTag tag = (DoubleBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof StringBinaryTag) {
StringBinaryTag tag = (StringBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof ListBinaryTag) {
ListBinaryTag tag = (ListBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
else if (binaryTag instanceof EndBinaryTag) {
EndBinaryTag tag = (EndBinaryTag) binaryTag;
tag.type().write(tag, stream);
}
}
catch (IOException e) {
throw new EncoderException("Cannot write NBT CompoundTag");
}
}
public void writeNbtMessage(NbtMessage nbtMessage, Version version) {
if (version.moreOrEqual(Version.V1_20_3)) {
writeNamelessCompoundTag(nbtMessage.getTag());
}
else {
writeString(nbtMessage.getJson());
}
}
public <E extends Enum<E>> void writeEnumSet(EnumSet<E> enumset, Class<E> oclass) {
E[] enums = oclass.getEnumConstants();
BitSet bits = new BitSet(enums.length);

View File

@ -1,10 +0,0 @@
package ua.nanit.limbo.protocol;
import ua.nanit.limbo.protocol.registry.Version;
@FunctionalInterface
public interface MetadataWriter {
void writeData(ByteMessage message, Version version);
}

View File

@ -1,30 +0,0 @@
package ua.nanit.limbo.protocol;
import net.kyori.adventure.nbt.BinaryTag;
public class NbtMessage {
private String json;
private BinaryTag tag;
public NbtMessage(String json, BinaryTag tag) {
this.json = json;
this.tag = tag;
}
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
public BinaryTag getTag() {
return tag;
}
public void setTag(BinaryTag tag) {
this.tag = tag;
}
}

View File

@ -23,8 +23,8 @@ import java.util.HashMap;
import java.util.Map;
/**
* PacketSnapshot encodes a packet to byte array for each MC version.
* Some versions have the same snapshot, so there are mappings to avoid data copying
* PacketSnapshot encodes packet to byte array for each MC version.
* Some versions have same snapshot, so there are mappings to avoid data copying
*/
public class PacketSnapshot implements PacketOut {

View File

@ -1,19 +0,0 @@
package ua.nanit.limbo.protocol.packets.configuration;
import ua.nanit.limbo.connection.ClientConnection;
import ua.nanit.limbo.protocol.PacketIn;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.server.LimboServer;
public class PacketFinishConfiguration implements PacketIn, PacketOut {
@Override
public void handle(ClientConnection conn, LimboServer server) {
server.getPacketHandler().handle(conn, this);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

View File

@ -1,32 +0,0 @@
package ua.nanit.limbo.protocol.packets.configuration;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.MetadataWriter;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
import ua.nanit.limbo.world.DimensionRegistry;
public class PacketRegistryData implements PacketOut {
private DimensionRegistry dimensionRegistry;
private MetadataWriter metadataWriter;
public void setDimensionRegistry(DimensionRegistry dimensionRegistry) {
this.dimensionRegistry = dimensionRegistry;
}
public void setMetadataWriter(MetadataWriter metadataWriter) {
this.metadataWriter = metadataWriter;
}
@Override
public void encode(ByteMessage msg, Version version) {
if (metadataWriter != null) {
if (version.moreOrEqual(Version.V1_20_5)) {
metadataWriter.writeData(msg, version);
return;
}
}
msg.writeNamelessCompoundTag(dimensionRegistry.getCodec_1_20());
}
}

View File

@ -1,19 +0,0 @@
package ua.nanit.limbo.protocol.packets.login;
import ua.nanit.limbo.connection.ClientConnection;
import ua.nanit.limbo.protocol.PacketIn;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.server.LimboServer;
public class PacketLoginAcknowledged implements PacketIn, PacketOut {
@Override
public void handle(ClientConnection conn, LimboServer server) {
server.getPacketHandler().handle(conn, this);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

View File

@ -49,9 +49,6 @@ public class PacketLoginSuccess implements PacketOut {
if (version.moreOrEqual(Version.V1_19)) {
msg.writeVarInt(0);
}
if (version.moreOrEqual(Version.V1_20_5)) {
msg.writeBoolean(true);
}
}
@Override

View File

@ -49,7 +49,7 @@ public class PacketBossBar implements PacketOut {
public void encode(ByteMessage msg, Version version) {
msg.writeUuid(uuid);
msg.writeVarInt(0); // Create bossbar
msg.writeNbtMessage(bossBar.getText(), version);
msg.writeString(bossBar.getText());
msg.writeFloat(bossBar.getHealth());
msg.writeVarInt(bossBar.getColor().getIndex());
msg.writeVarInt(bossBar.getDivision().getIndex());

View File

@ -18,7 +18,6 @@
package ua.nanit.limbo.protocol.packets.play;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
@ -26,12 +25,12 @@ import java.util.UUID;
public class PacketChatMessage implements PacketOut {
private NbtMessage message;
private String jsonData;
private PositionLegacy position;
private UUID sender;
public void setMessage(NbtMessage message) {
this.message = message;
public void setJsonData(String jsonData) {
this.jsonData = jsonData;
}
public void setPosition(PositionLegacy position) {
@ -44,7 +43,7 @@ public class PacketChatMessage implements PacketOut {
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeNbtMessage(message, version);
msg.writeString(jsonData);
if (version.moreOrEqual(Version.V1_19_1)) {
msg.writeBoolean(position.index == PositionLegacy.ACTION_BAR.index);
} else if (version.moreOrEqual(Version.V1_19)) {

View File

@ -1,47 +0,0 @@
package ua.nanit.limbo.protocol.packets.play;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.LongArrayBinaryTag;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
public class PacketEmptyChunk implements PacketOut {
private int x;
private int z;
public void setX(int x) {
this.x = x;
}
public void setZ(int z) {
this.z = z;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeInt(x);
msg.writeInt(z);
LongArrayBinaryTag longArrayTag = LongArrayBinaryTag.longArrayBinaryTag(new long[37]);
CompoundBinaryTag tag = CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", longArrayTag).build();
CompoundBinaryTag rootTag = CompoundBinaryTag.builder()
.put("root", tag).build();
msg.writeNamelessCompoundTag(rootTag);
byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
msg.writeVarInt(sectionData.length * 16);
for (int i = 0; i < 16; i++) {
msg.writeBytes(sectionData);
}
msg.writeVarInt(0);
byte[] lightData = new byte[]{1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, -1, -1, 0, 0};
msg.ensureWritable(lightData.length);
msg.writeBytes(lightData, 1, lightData.length - 1);
}
}

View File

@ -1,25 +0,0 @@
package ua.nanit.limbo.protocol.packets.play;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
public class PacketGameEvent implements PacketOut {
private byte type;
private float value;
public void setType(byte type) {
this.type = type;
}
public void setValue(float value) {
this.value = value;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeByte(type);
msg.writeFloat(value);
}
}

View File

@ -38,8 +38,6 @@ public class PacketJoinGame implements PacketOut {
private boolean enableRespawnScreen;
private boolean isDebug;
private boolean isFlat;
private boolean limitedCrafting;
private boolean secureProfile;
public void setEntityId(int entityId) {
this.entityId = entityId;
@ -97,14 +95,6 @@ public class PacketJoinGame implements PacketOut {
isFlat = flat;
}
public void setLimitedCrafting(boolean limitedCrafting) {
this.limitedCrafting = limitedCrafting;
}
public void setSecureProfile(boolean secureProfile) {
this.secureProfile = secureProfile;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeInt(entityId);
@ -240,7 +230,7 @@ public class PacketJoinGame implements PacketOut {
msg.writeBoolean(false);
}
if (version.equals(Version.V1_20)) {
if (version.moreOrEqual(Version.V1_20)) {
msg.writeBoolean(isHardcore);
msg.writeByte(gameMode);
msg.writeByte(previousGameMode);
@ -259,47 +249,6 @@ public class PacketJoinGame implements PacketOut {
msg.writeBoolean(false);
msg.writeVarInt(0);
}
if (version.fromTo(Version.V1_20_2, Version.V1_20_3)) {
msg.writeBoolean(isHardcore);
msg.writeStringsArray(worldNames);
msg.writeVarInt(maxPlayers);
msg.writeVarInt(viewDistance);
msg.writeVarInt(viewDistance); // Simulation Distance
msg.writeBoolean(reducedDebugInfo);
msg.writeBoolean(enableRespawnScreen);
msg.writeBoolean(limitedCrafting);
msg.writeString(worldName);
msg.writeString(worldName);
msg.writeLong(hashedSeed);
msg.writeByte(gameMode);
msg.writeByte(previousGameMode);
msg.writeBoolean(isDebug);
msg.writeBoolean(isFlat);
msg.writeBoolean(false);
msg.writeVarInt(0);
}
if (version.moreOrEqual(Version.V1_20_5)) {
msg.writeBoolean(isHardcore);
msg.writeStringsArray(worldNames);
msg.writeVarInt(maxPlayers);
msg.writeVarInt(viewDistance);
msg.writeVarInt(viewDistance); // Simulation Distance
msg.writeBoolean(reducedDebugInfo);
msg.writeBoolean(enableRespawnScreen);
msg.writeBoolean(limitedCrafting);
msg.writeVarInt(dimensionRegistry.getDimension_1_20_5().getId());
msg.writeString(worldName);
msg.writeLong(hashedSeed);
msg.writeByte(gameMode);
msg.writeByte(previousGameMode);
msg.writeBoolean(isDebug);
msg.writeBoolean(isFlat);
msg.writeBoolean(false);
msg.writeVarInt(0);
msg.writeBoolean(secureProfile);
}
}
}

View File

@ -18,26 +18,25 @@
package ua.nanit.limbo.protocol.packets.play;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
public class PacketPlayerListHeader implements PacketOut {
private NbtMessage header;
private NbtMessage footer;
private String header;
private String footer;
public void setHeader(NbtMessage header) {
public void setHeader(String header) {
this.header = header;
}
public void setFooter(NbtMessage footer) {
public void setFooter(String footer) {
this.footer = footer;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeNbtMessage(header, version);
msg.writeNbtMessage(footer, version);
msg.writeString(header);
msg.writeString(footer);
}
}

View File

@ -39,5 +39,4 @@ public class PacketPluginMessage implements PacketOut {
msg.writeString(channel);
msg.writeString(message);
}
}

View File

@ -18,21 +18,20 @@
package ua.nanit.limbo.protocol.packets.play;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
public class PacketTitleSetSubTitle implements PacketOut {
private NbtMessage subtitle;
private String subtitle;
public void setSubtitle(NbtMessage subtitle) {
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeNbtMessage(subtitle, version);
msg.writeString(subtitle);
}
}

View File

@ -18,21 +18,20 @@
package ua.nanit.limbo.protocol.packets.play;
import ua.nanit.limbo.protocol.ByteMessage;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.protocol.PacketOut;
import ua.nanit.limbo.protocol.registry.Version;
public class PacketTitleSetTitle implements PacketOut {
private NbtMessage title;
private String title;
public void setTitle(NbtMessage title) {
public void setTitle(String title) {
this.title = title;
}
@Override
public void encode(ByteMessage msg, Version version) {
msg.writeNbtMessage(title, version);
msg.writeString(title);
}
}

View File

@ -21,7 +21,6 @@ import ua.nanit.limbo.protocol.Packet;
import ua.nanit.limbo.protocol.packets.PacketHandshake;
import ua.nanit.limbo.protocol.packets.login.*;
import ua.nanit.limbo.protocol.packets.play.*;
import ua.nanit.limbo.protocol.packets.configuration.*;
import ua.nanit.limbo.protocol.packets.status.PacketStatusPing;
import ua.nanit.limbo.protocol.packets.status.PacketStatusRequest;
import ua.nanit.limbo.protocol.packets.status.PacketStatusResponse;
@ -64,10 +63,6 @@ public enum State {
serverBound.register(PacketLoginPluginResponse::new,
map(0x02, Version.getMin(), Version.getMax())
);
serverBound.register(
PacketLoginAcknowledged::new,
map(0x03, V1_20_2, Version.getMax())
);
clientBound.register(PacketDisconnect::new,
map(0x00, Version.getMin(), Version.getMax())
);
@ -79,52 +74,7 @@ public enum State {
);
}
},
CONFIGURATION(3) {
{
clientBound.register(
PacketPluginMessage::new,
map(0x00, V1_20_2, V1_20_3),
map(0x01, V1_20_5, V1_21)
);
clientBound.register(
PacketDisconnect::new,
map(0x01, V1_20_2, V1_20_3),
map(0x02, V1_20_5, V1_21)
);
clientBound.register(
PacketFinishConfiguration::new,
map(0x02, V1_20_2, V1_20_3),
map(0x03, V1_20_5, V1_21)
);
clientBound.register(
PacketKeepAlive::new,
map(0x03, V1_20_2, V1_20_3),
map(0x04, V1_20_5, V1_21)
);
clientBound.register(
PacketRegistryData::new,
map(0x05, V1_20_2, V1_20_3),
map(0x07, V1_20_5, V1_21)
);
serverBound.register(
PacketPluginMessage::new,
map(0x01, V1_20_2, V1_20_3),
map(0x02, V1_20_2, V1_21)
);
serverBound.register(
PacketFinishConfiguration::new,
map(0x02, V1_20_2, V1_20_3),
map(0x03, V1_20_5, V1_21)
);
serverBound.register(
PacketKeepAlive::new,
map(0x03, V1_20_2, V1_20_3),
map(0x04, V1_20_5, V1_21)
);
}
},
PLAY(4) {
PLAY(3) {
{
serverBound.register(PacketKeepAlive::new,
map(0x00, V1_7_2, V1_8),
@ -138,10 +88,7 @@ public enum State {
map(0x11, V1_19, V1_19),
map(0x12, V1_19_1, V1_19_1),
map(0x11, V1_19_3, V1_19_3),
map(0x12, V1_19_4, V1_20),
map(0x14, V1_20_2, V1_20_2),
map(0x15, V1_20_3, V1_20_3),
map(0x18, V1_20_5, V1_21)
map(0x12, V1_19_4, V1_20)
);
clientBound.register(PacketDeclareCommands::new,
@ -152,8 +99,7 @@ public enum State {
map(0x12, V1_17, V1_18_2),
map(0x0F, V1_19, V1_19_1),
map(0x0E, V1_19_3, V1_19_3),
map(0x10, V1_19_4, V1_20),
map(0x11, V1_20_2, V1_21)
map(0x10, V1_19_4, V1_20)
);
clientBound.register(PacketJoinGame::new,
map(0x01, V1_7_2, V1_8),
@ -166,9 +112,7 @@ public enum State {
map(0x23, V1_19, V1_19),
map(0x25, V1_19_1, V1_19_1),
map(0x24, V1_19_3, V1_19_3),
map(0x28, V1_19_4, V1_20),
map(0x29, V1_20_2, V1_20_3),
map(0x2B, V1_20_5, V1_21)
map(0x28, V1_19_4, V1_20)
);
clientBound.register(PacketPluginMessage::new,
map(0x19, V1_13, V1_13_2),
@ -180,9 +124,7 @@ public enum State {
map(0x15, V1_19, V1_19),
map(0x16, V1_19_1, V1_19_1),
map(0x15, V1_19_3, V1_19_3),
map(0x17, V1_19_4, V1_20),
map(0x18, V1_20_2, V1_20_3),
map(0x19, V1_20_5, V1_21)
map(0x17, V1_19_4, V1_20)
);
clientBound.register(PacketPlayerAbilities::new,
map(0x39, V1_7_2, V1_8),
@ -197,9 +139,7 @@ public enum State {
map(0x2F, V1_19, V1_19),
map(0x31, V1_19_1, V1_19_1),
map(0x30, V1_19_3, V1_19_3),
map(0x34, V1_19_4, V1_20),
map(0x36, V1_20_2, V1_20_3),
map(0x38, V1_20_5, V1_21)
map(0x34, V1_19_4, V1_20)
);
clientBound.register(PacketPlayerPositionAndLook::new,
map(0x08, V1_7_2, V1_8),
@ -214,9 +154,7 @@ public enum State {
map(0x36, V1_19, V1_19),
map(0x39, V1_19_1, V1_19_1),
map(0x38, V1_19_3, V1_19_3),
map(0x3C, V1_19_4, V1_20),
map(0x3E, V1_20_2, V1_20_3),
map(0x40, V1_20_5, V1_21)
map(0x3C, V1_19_4, V1_20)
);
clientBound.register(PacketKeepAlive::new,
map(0x00, V1_7_2, V1_8),
@ -230,9 +168,7 @@ public enum State {
map(0x1E, V1_19, V1_19),
map(0x20, V1_19_1, V1_19_1),
map(0x1F, V1_19_3, V1_19_3),
map(0x23, V1_19_4, V1_20),
map(0x24, V1_20_2, V1_20_3),
map(0x26, V1_20_5, V1_21)
map(0x23, V1_19_4, V1_20)
);
clientBound.register(PacketChatMessage::new,
map(0x02, V1_7_2, V1_8),
@ -244,10 +180,7 @@ public enum State {
map(0x5F, V1_19, V1_19),
map(0x62, V1_19_1, V1_19_1),
map(0x60, V1_19_3, V1_19_3),
map(0x64, V1_19_4, V1_20),
map(0x67, V1_20_2, V1_20_2),
map(0x69, V1_20_3, V1_20_3),
map(0x6C, V1_20_5, V1_21)
map(0x64, V1_19_4, V1_20)
);
clientBound.register(PacketBossBar::new,
map(0x0C, V1_9, V1_14_4),
@ -255,8 +188,7 @@ public enum State {
map(0x0C, V1_16, V1_16_4),
map(0x0D, V1_17, V1_18_2),
map(0x0A, V1_19, V1_19_3),
map(0x0B, V1_19_4, V1_20),
map(0x0A, V1_20_2, V1_21)
map(0x0B, V1_19_4, V1_20)
);
clientBound.register(PacketPlayerInfo::new,
map(0x38, V1_7_2, V1_8),
@ -271,9 +203,7 @@ public enum State {
map(0x34, V1_19, V1_19),
map(0x37, V1_19_1, V1_19_1),
map(0x36, V1_19_3, V1_19_3),
map(0x3A, V1_19_4, V1_20),
map(0x3C, V1_20_2, V1_20_3),
map(0x3E, V1_20_5, V1_21)
map(0x3A, V1_19_4, V1_20)
);
clientBound.register(PacketTitleLegacy::new,
map(0x45, V1_8, V1_11_1),
@ -289,30 +219,21 @@ public enum State {
map(0x5A, V1_18, V1_19),
map(0x5D, V1_19_1, V1_19_1),
map(0x5B, V1_19_3, V1_19_3),
map(0x5F, V1_19_4, V1_20),
map(0x61, V1_20_2, V1_20_2),
map(0x63, V1_20_3, V1_20_3),
map(0x65, V1_20_5, V1_21)
map(0x5F, V1_19_4, V1_20)
);
clientBound.register(PacketTitleSetSubTitle::new,
map(0x57, V1_17, V1_17_1),
map(0x58, V1_18, V1_19),
map(0x5B, V1_19_1, V1_19_1),
map(0x59, V1_19_3, V1_19_3),
map(0x5D, V1_19_4, V1_20),
map(0x5F, V1_20_2, V1_20_2),
map(0x61, V1_20_3, V1_20_3),
map(0x63, V1_20_5, V1_21)
map(0x5D, V1_19_4, V1_20)
);
clientBound.register(PacketTitleTimes::new,
map(0x5A, V1_17, V1_17_1),
map(0x5B, V1_18, V1_19),
map(0x5E, V1_19_1, V1_19_1),
map(0x5C, V1_19_3, V1_19_3),
map(0x60, V1_19_4, V1_20),
map(0x62, V1_20_2, V1_20_2),
map(0x64, V1_20_3, V1_20_3),
map(0x66, V1_20_5, V1_21)
map(0x60, V1_19_4, V1_20)
);
clientBound.register(PacketPlayerListHeader::new,
map(0x47, V1_8, V1_8),
@ -329,25 +250,11 @@ public enum State {
map(0x60, V1_19, V1_19),
map(0x63, V1_19_1, V1_19_1),
map(0x61, V1_19_3, V1_19_3),
map(0x65, V1_19_4, V1_20),
map(0x68, V1_20_2, V1_20_2),
map(0x6A, V1_20_3, V1_20_3),
map(0x6D, V1_20_5, V1_21)
map(0x65, V1_19_4, V1_20)
);
clientBound.register(PacketSpawnPosition::new,
map(0x4C, V1_19_3, V1_19_3),
map(0x50, V1_19_4, V1_20),
map(0x52, V1_20_2, V1_20_2),
map(0x54, V1_20_3, V1_20_3),
map(0x56, V1_20_5, V1_21)
);
clientBound.register(PacketGameEvent::new,
map(0x20, V1_20_3, V1_20_3),
map(0x22, V1_20_5, V1_21)
);
clientBound.register(PacketEmptyChunk::new,
map(0x25, V1_20_3, V1_20_3),
map(0x27, V1_20_5, V1_21)
map(0x50, V1_19_4, V1_20)
);
}
};

View File

@ -68,13 +68,7 @@ public enum Version {
// 1.19.2 has same protocol number
V1_19_3(761),
V1_19_4(762),
V1_20(763),
// 1.20.1 has same protocol number
V1_20_2(764),
V1_20_3(765),
V1_20_5(766),
// 1.20.6 has same protocol number
V1_21(767);
V1_20(763);
private static final Map<Integer, Version> VERSION_MAP;
private static final Version MAX;

View File

@ -1,6 +1,9 @@
package ua.nanit.limbo.server;
import ua.nanit.limbo.server.commands.*;
import ua.nanit.limbo.server.commands.CmdConn;
import ua.nanit.limbo.server.commands.CmdHelp;
import ua.nanit.limbo.server.commands.CmdMem;
import ua.nanit.limbo.server.commands.CmdStop;
import java.util.*;
@ -16,10 +19,8 @@ public final class CommandManager extends Thread {
return commands.get(name.toLowerCase());
}
public void register(Command cmd, String... aliases) {
for (String alias : aliases) {
commands.put(alias.toLowerCase(), cmd);
}
public void register(String name, Command cmd) {
commands.put(name.toLowerCase(), cmd);
}
@Override
@ -40,20 +41,19 @@ public final class CommandManager extends Thread {
try {
handler.execute();
} catch (Throwable t) {
Log.error("Cannot execute command:", t);
Logger.error("Cannot execute command:", t);
}
continue;
}
Log.info("Unknown command. Type \"help\" to get commands list");
Logger.info("Unknown command. Type \"help\" to get commands list");
}
}
public void registerAll(LimboServer server) {
register(new CmdHelp(server), "help");
register(new CmdConn(server), "conn");
register(new CmdMem(), "mem");
register(new CmdStop(), "stop");
register(new CmdVersion(), "version", "ver");
register("help", new CmdHelp(server));
register("conn", new CmdConn(server));
register("mem", new CmdMem());
register("stop", new CmdStop());
}
}

View File

@ -43,12 +43,12 @@ public final class Connections {
public void addConnection(ClientConnection connection) {
connections.put(connection.getUuid(), connection);
Log.info("Player %s connected (%s) [%s]", connection.getUsername(),
Logger.info("Player %s connected (%s) [%s]", connection.getUsername(),
connection.getAddress(), connection.getClientVersion());
}
public void removeConnection(ClientConnection connection) {
connections.remove(connection.getUuid());
Log.info("Player %s disconnected", connection.getUsername());
Logger.info("Player %s disconnected", connection.getUsername());
}
}

View File

@ -72,14 +72,13 @@ public final class LimboServer {
}
public void start() throws Exception {
config = new LimboConfig(Paths.get("./"));
config.load();
Log.setLevel(config.getDebugLevel());
Log.info("Starting server...");
Logger.info("Starting server...");
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED);
config = new LimboConfig(Paths.get("./"));
config.load();
packetHandler = new PacketHandler(this);
dimensionRegistry = new DimensionRegistry(this);
dimensionRegistry.load(config.getDimensionType());
@ -93,7 +92,9 @@ public final class LimboServer {
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "NanoLimbo shutdown thread"));
Log.info("Server started on %s", config.getAddress());
Logger.info("Server started on %s", config.getAddress());
Logger.setLevel(config.getDebugLevel());
commandManager = new CommandManager();
commandManager.registerAll(this);
@ -109,12 +110,12 @@ public final class LimboServer {
bossGroup = new EpollEventLoopGroup(config.getBossGroupSize());
workerGroup = new EpollEventLoopGroup(config.getWorkerGroupSize());
channelClass = EpollServerSocketChannel.class;
Log.debug("Using Epoll transport type");
Logger.debug("Using Epoll transport type");
} else {
bossGroup = new NioEventLoopGroup(config.getBossGroupSize());
workerGroup = new NioEventLoopGroup(config.getWorkerGroupSize());
channelClass = NioServerSocketChannel.class;
Log.debug("Using Java NIO transport type");
Logger.debug("Using Java NIO transport type");
}
new ServerBootstrap()
@ -131,7 +132,7 @@ public final class LimboServer {
}
private void stop() {
Log.info("Stopping server...");
Logger.info("Stopping server...");
if (keepAliveTask != null) {
keepAliveTask.cancel(true);
@ -145,7 +146,7 @@ public final class LimboServer {
workerGroup.shutdownGracefully();
}
Log.info("Server stopped, Goodbye!");
Logger.info("Server stopped, Goodbye!");
}
}

View File

@ -17,71 +17,61 @@
package ua.nanit.limbo.server;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public final class Log {
public final class Logger {
private static final Logger LOGGER = (Logger) LoggerFactory.getLogger("Limbo");
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("hh:mm:ss");
private static int debugLevel = Level.INFO.getIndex();
private Log() {}
private Logger() {}
public static int getLevel() {
return debugLevel;
}
public static void info(Object msg, Object... args) {
LOGGER.info(String.format(msg.toString(), args));
print(Level.INFO, msg, null, args);
}
public static void debug(Object msg, Object... args) {
LOGGER.debug(String.format(msg.toString(), args));
print(Level.DEBUG, msg, null, args);
}
public static void warning(Object msg, Object... args) {
LOGGER.warn(String.format(msg.toString(), args));
print(Level.WARNING, msg, null, args);
}
public static void warning(Object msg, Throwable t, Object... args) {
LOGGER.warn(String.format(msg.toString(), args), t);
print(Level.WARNING, msg, t, args);
}
public static void error(Object msg, Object... args) {
LOGGER.error(msg.toString(), args);
print(Level.ERROR, msg, null, args);
}
public static void error(Object msg, Throwable t, Object... args) {
LOGGER.error(String.format(msg.toString(), args), t);
print(Level.ERROR, msg, t, args);
}
public static boolean isDebug() {
return debugLevel >= Level.DEBUG.getIndex();
public static void print(Level level, Object msg, Throwable t, Object... args) {
if (debugLevel >= level.getIndex()) {
System.out.printf("%s: %s%n", getPrefix(level), String.format(msg.toString(), args));
if (t != null) t.printStackTrace();
}
}
private static String getPrefix(Level level) {
return String.format("[%s] [%s]", getTime(), level.getDisplay());
}
private static String getTime() {
return LocalTime.now().format(FORMATTER);
}
static void setLevel(int level) {
debugLevel = level;
Logger logback = getRootLogger();
if (logback != null) {
logback.setLevel(convertLevel(level));
}
}
private static Logger getRootLogger() {
return (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
}
private static ch.qos.logback.classic.Level convertLevel(int level) {
switch (level) {
case 0:
return ch.qos.logback.classic.Level.ERROR;
case 1:
return ch.qos.logback.classic.Level.WARN;
case 2:
return ch.qos.logback.classic.Level.INFO;
case 3:
return ch.qos.logback.classic.Level.DEBUG;
default:
throw new IllegalStateException("Undefined log level: " + level);
}
}
public enum Level {

View File

@ -2,7 +2,7 @@ package ua.nanit.limbo.server.commands;
import ua.nanit.limbo.server.Command;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
public class CmdConn implements Command {
@ -14,7 +14,7 @@ public class CmdConn implements Command {
@Override
public void execute() {
Log.info("Connections: %d", server.getConnections().getCount());
Logger.info("Connections: %d", server.getConnections().getCount());
}
@Override

View File

@ -2,7 +2,7 @@ package ua.nanit.limbo.server.commands;
import ua.nanit.limbo.server.Command;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import java.util.Map;
@ -18,10 +18,10 @@ public class CmdHelp implements Command {
public void execute() {
Map<String, Command> commands = server.getCommandManager().getCommands();
Log.info("Available commands:");
Logger.info("Available commands:");
for (Map.Entry<String, Command> entry : commands.entrySet()) {
Log.info("%s - %s", entry.getKey(), entry.getValue().description());
Logger.info("%s - %s", entry.getKey(), entry.getValue().description());
}
}

View File

@ -1,7 +1,7 @@
package ua.nanit.limbo.server.commands;
import ua.nanit.limbo.server.Command;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
public class CmdMem implements Command {
@ -14,11 +14,11 @@ public class CmdMem implements Command {
long free = runtime.freeMemory() / mb;
long max = runtime.maxMemory() / mb;
Log.info("Memory usage:");
Log.info("Used: %d MB", used);
Log.info("Total: %d MB", total);
Log.info("Free: %d MB", free);
Log.info("Max: %d MB", max);
Logger.info("Memory usage:");
Logger.info("Used: %d MB", used);
Logger.info("Total: %d MB", total);
Logger.info("Free: %d MB", free);
Logger.info("Max: %d MB", max);
}
@Override

View File

@ -1,18 +0,0 @@
package ua.nanit.limbo.server.commands;
import ua.nanit.limbo.server.Command;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.BuildConfig;
public class CmdVersion implements Command {
@Override
public void execute() {
Log.info("Version: %s", BuildConfig.LIMBO_VERSION);
}
@Override
public String description() {
return "Display limbo version";
}
}

View File

@ -21,20 +21,18 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.util.Colors;
import ua.nanit.limbo.util.NbtMessageUtil;
import java.lang.reflect.Type;
public class BossBar {
private NbtMessage text;
private String text;
private float health;
private Color color;
private Division division;
public NbtMessage getText() {
public String getText() {
return text;
}
@ -50,7 +48,7 @@ public class BossBar {
return division;
}
public void setText(NbtMessage text) {
public void setText(String text) {
this.text = text;
}
@ -112,7 +110,7 @@ public class BossBar {
public BossBar deserialize(Type type, ConfigurationNode node) throws SerializationException {
BossBar bossBar = new BossBar();
bossBar.setText(NbtMessageUtil.create(Colors.of(node.node("text").getString(""))));
bossBar.setText(Colors.of(node.node("text").getString("")));
bossBar.setHealth(node.node("health").getFloat());
if (bossBar.getHealth() < 0 || bossBar.getHealth() > 1)

View File

@ -20,25 +20,23 @@ package ua.nanit.limbo.server.data;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.TypeSerializer;
import ua.nanit.limbo.protocol.NbtMessage;
import ua.nanit.limbo.util.Colors;
import ua.nanit.limbo.util.NbtMessageUtil;
import java.lang.reflect.Type;
public class Title {
private NbtMessage title;
private NbtMessage subtitle;
private String title;
private String subtitle;
private int fadeIn;
private int stay;
private int fadeOut;
public NbtMessage getTitle() {
public String getTitle() {
return title;
}
public NbtMessage getSubtitle() {
public String getSubtitle() {
return subtitle;
}
@ -54,11 +52,11 @@ public class Title {
return fadeOut;
}
public void setTitle(NbtMessage title) {
public void setTitle(String title) {
this.title = title;
}
public void setSubtitle(NbtMessage subtitle) {
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
@ -79,8 +77,8 @@ public class Title {
@Override
public Title deserialize(Type type, ConfigurationNode node) {
Title title = new Title();
title.setTitle(NbtMessageUtil.create(Colors.of(node.node("title").getString(""))));
title.setSubtitle(NbtMessageUtil.create(Colors.of(node.node("subtitle").getString(""))));
title.setTitle(Colors.of(node.node("title").getString("")));
title.setSubtitle(Colors.of(node.node("subtitle").getString("")));
title.setFadeIn(node.node("fadeIn").getInt(10));
title.setStay(node.node("stay").getInt(100));
title.setFadeOut(node.node("fadeOut").getInt(10));

View File

@ -1,110 +0,0 @@
package ua.nanit.limbo.util;
import com.google.gson.*;
import net.kyori.adventure.nbt.*;
import ua.nanit.limbo.protocol.NbtMessage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class NbtMessageUtil {
public static NbtMessage create(String json) {
BinaryTag compoundBinaryTag = fromJson(JsonParser.parseString(json));
return new NbtMessage(json, compoundBinaryTag);
}
public static BinaryTag fromJson(JsonElement json) {
if (json instanceof JsonPrimitive) {
JsonPrimitive jsonPrimitive = (JsonPrimitive) json;
if (jsonPrimitive.isNumber()) {
Number number = json.getAsNumber();
if (number instanceof Byte) {
return ByteBinaryTag.byteBinaryTag((Byte) number);
} else if (number instanceof Short) {
return ShortBinaryTag.shortBinaryTag((Short) number);
} else if (number instanceof Integer) {
return IntBinaryTag.intBinaryTag((Integer) number);
} else if (number instanceof Long) {
return LongBinaryTag.longBinaryTag((Long) number);
} else if (number instanceof Float) {
return FloatBinaryTag.floatBinaryTag((Float) number);
} else if (number instanceof Double) {
return DoubleBinaryTag.doubleBinaryTag((Double) number);
}
} else if (jsonPrimitive.isString()) {
return StringBinaryTag.stringBinaryTag(jsonPrimitive.getAsString());
} else if (jsonPrimitive.isBoolean()) {
return ByteBinaryTag.byteBinaryTag(jsonPrimitive.getAsBoolean() ? (byte) 1 : (byte) 0);
} else {
throw new IllegalArgumentException("Unknown JSON primitive: " + jsonPrimitive);
}
} else if (json instanceof JsonObject) {
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
for (Map.Entry<String, JsonElement> property : ((JsonObject) json).entrySet()) {
builder.put(property.getKey(), fromJson(property.getValue()));
}
return builder.build();
} else if (json instanceof JsonArray) {
List<JsonElement> jsonArray = ((JsonArray) json).asList();
if (jsonArray.isEmpty()) {
return ListBinaryTag.listBinaryTag(EndBinaryTag.endBinaryTag().type(), Collections.emptyList());
}
BinaryTagType tagByteType = ByteBinaryTag.ZERO.type();
BinaryTagType tagIntType = IntBinaryTag.intBinaryTag(0).type();
BinaryTagType tagLongType = LongBinaryTag.longBinaryTag(0).type();
BinaryTag listTag;
BinaryTagType listType = fromJson(jsonArray.get(0)).type();
if (listType.equals(tagByteType)) {
byte[] bytes = new byte[jsonArray.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (Byte) ((JsonPrimitive) jsonArray.get(i)).getAsNumber();
}
listTag = ByteArrayBinaryTag.byteArrayBinaryTag(bytes);
} else if (listType.equals(tagIntType)) {
int[] ints = new int[jsonArray.size()];
for (int i = 0; i < ints.length; i++) {
ints[i] = (Integer) ((JsonPrimitive) jsonArray.get(i)).getAsNumber();
}
listTag = IntArrayBinaryTag.intArrayBinaryTag(ints);
} else if (listType.equals(tagLongType)) {
long[] longs = new long[jsonArray.size()];
for (int i = 0; i < longs.length; i++) {
longs[i] = (Long) ((JsonPrimitive) jsonArray.get(i)).getAsNumber();
}
listTag = LongArrayBinaryTag.longArrayBinaryTag(longs);
} else {
List<BinaryTag> tagItems = new ArrayList<>(jsonArray.size());
for (JsonElement jsonEl : jsonArray) {
BinaryTag subTag = fromJson(jsonEl);
if (subTag.type() != listType) {
throw new IllegalArgumentException("Cannot convert mixed JsonArray to Tag");
}
tagItems.add(subTag);
}
listTag = ListBinaryTag.listBinaryTag(listType, tagItems);
}
return listTag;
} else if (json instanceof JsonNull) {
return EndBinaryTag.endBinaryTag();
}
throw new IllegalArgumentException("Unknown JSON element: " + json);
}
}

View File

@ -21,7 +21,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;
import net.kyori.adventure.nbt.TagStringIO;
import ua.nanit.limbo.server.LimboServer;
import ua.nanit.limbo.server.Log;
import ua.nanit.limbo.server.Logger;
import java.io.*;
import java.nio.charset.StandardCharsets;
@ -33,8 +33,6 @@ public final class DimensionRegistry {
private Dimension defaultDimension_1_16;
private Dimension defaultDimension_1_18_2;
private Dimension dimension_1_20_5;
private Dimension dimension_1_21;
private CompoundBinaryTag codec_1_16;
private CompoundBinaryTag codec_1_18_2;
@ -42,7 +40,6 @@ public final class DimensionRegistry {
private CompoundBinaryTag codec_1_19_1;
private CompoundBinaryTag codec_1_19_4;
private CompoundBinaryTag codec_1_20;
private CompoundBinaryTag codec_1_21;
private CompoundBinaryTag oldCodec;
public DimensionRegistry(LimboServer server) {
@ -73,10 +70,6 @@ public final class DimensionRegistry {
return codec_1_20;
}
public CompoundBinaryTag getCodec_1_21() {
return codec_1_21;
}
public CompoundBinaryTag getOldCodec() {
return oldCodec;
}
@ -89,30 +82,18 @@ public final class DimensionRegistry {
return defaultDimension_1_18_2;
}
public Dimension getDimension_1_20_5() {
return dimension_1_20_5;
}
public Dimension getDimension_1_21() {
return dimension_1_21;
}
public void load(String def) throws IOException {
// On 1.16-1.16.1 different codec format
oldCodec = readCodecFile("/dimension/codec_old.snbt");
codec_1_16 = readCodecFile("/dimension/codec_1_16.snbt");
codec_1_18_2 = readCodecFile("/dimension/codec_1_18_2.snbt");
codec_1_19 = readCodecFile("/dimension/codec_1_19.snbt");
codec_1_19_1 = readCodecFile("/dimension/codec_1_19_1.snbt");
codec_1_19_4 = readCodecFile("/dimension/codec_1_19_4.snbt");
codec_1_20 = readCodecFile("/dimension/codec_1_20.snbt");
codec_1_21 = readCodecFile("/dimension/codec_1_21.snbt");
// On 1.16-1.16.1 different codec format
oldCodec = readCodecFile("/dimension/codec_old.snbt");
defaultDimension_1_16 = getDefaultDimension(def, codec_1_16);
defaultDimension_1_18_2 = getDefaultDimension(def, codec_1_18_2);
dimension_1_20_5 = getModernDimension(def, codec_1_20);
dimension_1_21 = getModernDimension(def, codec_1_21);
}
private Dimension getDefaultDimension(String def, CompoundBinaryTag tag) {
@ -130,37 +111,29 @@ public final class DimensionRegistry {
case "the_end":
return new Dimension(1, "minecraft:the_end", theEnd);
default:
Log.warning("Undefined dimension type: '%s'. Using THE_END as default", def);
Logger.warning("Undefined dimension type: '%s'. Using THE_END as default", def);
return new Dimension(1, "minecraft:the_end", theEnd);
}
}
private Dimension getModernDimension(String def, CompoundBinaryTag tag) {
switch (def.toLowerCase()) {
case "overworld":
return new Dimension(0, "minecraft:overworld", tag);
case "the_nether":
return new Dimension(2, "minecraft:nether", tag);
case "the_end":
return new Dimension(3, "minecraft:the_end", tag);
default:
Log.warning("Undefined dimension type: '%s'. Using THE_END as default", def);
return new Dimension(3, "minecraft:the_end", tag);
}
}
private CompoundBinaryTag readCodecFile(String resPath) throws IOException {
InputStream in = server.getClass().getResourceAsStream(resPath);
if (in == null)
if(in == null)
throw new FileNotFoundException("Cannot find dimension registry file");
return TagStringIO.get().asCompound(streamToString(in));
}
private String streamToString(InputStream in) throws IOException {
try (BufferedReader bufReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
return bufReader.lines().collect(Collectors.joining("\n"));
}
InputStreamReader isReader = new InputStreamReader(in, StandardCharsets.UTF_8);
BufferedReader bufReader = new BufferedReader(isReader);
String content = bufReader.lines()
.collect(Collectors.joining("\n"));
isReader.close();
bufReader.close();
return content;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration>
<configuration>
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
<import class="ch.qos.logback.core.ConsoleAppender"/>
<import class="ch.qos.logback.core.FileAppender"/>
<timestamp key="bySecond" datePattern="yyyy-MM-dd"/>
<appender name="STDOUT" class="ConsoleAppender">
<encoder class="PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="FileAppender">
<file>logs/log-${bySecond}.txt</file>
<immediateFlush>true</immediateFlush>
<encoder class="PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

View File

@ -7,7 +7,7 @@ bind:
ip: 'localhost'
port: 65535
# Max number of players can join to server
# Max amount of players can join to server
# Set -1 to make it infinite
maxPlayers: 100
@ -16,7 +16,7 @@ ping:
description: '{"text": "&9NanoLimbo"}'
version: 'NanoLimbo'
# Return static protocol version number in ping result
# By default, its -1 to return the client version if it supported
# By default, its -1 to return the client version, if it supported
# https://wiki.vg/Protocol_version_numbers
protocol: -1
@ -24,7 +24,7 @@ ping:
dimension: THE_END
# Whether to display the player in the player list
# For 1.16.5 clients, the player list will be sent even if disabled, to avoid crash
# For 1.16.5 clients, player list will be sent even if disabled, to avoid crash
playerList:
enable: false
username: 'NanoLimbo'
@ -50,12 +50,12 @@ brandName:
enable: true
content: 'NanoLimbo'
# Message sends when player joins to the server
# Message sends when player join to server
joinMessage:
enable: true
text: '{"text": "&eWelcome to the Limbo!"}'
# BossBar displays when player joins to the server
# BossBar displays when player join to server
# For 1.9+ clients
bossBar:
enable: true
@ -87,7 +87,7 @@ title:
# - LEGACY
# - MODERN
# - BUNGEE_GUARD
# Don't use secret if you do not use MODERN type
# Don't use secret if you not use MODERN type
infoForwarding:
type: NONE
secret: '<YOUR_SECRET_HERE>'
@ -105,29 +105,11 @@ readTimeout: 30000
# 3 - Display errors, warnings, info, debug
debugLevel: 2
# Warning! Do not touch params of this block if you are not completely sure what is this!
# Warning! Do not touch params of this block, if you not completely sure what is this!
netty:
# Use a Linux native transport type, if it possible
# Use Linux native transport type, if it possible
useEpoll: true
# EventLoopGroup threads count
threads:
bossGroup: 1
workerGroup: 4
# Options to check incoming traffic and kick potentially malicious connections.
# Take into account that player can send many small packets, for example, just moving mouse.
traffic:
# If true, then additional handler will be added to the channel pipeline
enable: true
# Max packet size in bytes
# Unlimited if -1
maxPacketSize: 8192
# The interval to measure packets over
# Lowering this value will limit peak packets from players which would target people with bad connections
# Raising this value will allow higher peak packet rates, which will help with people who have poor connections
# Ignored if -1.0
interval: 7.0
# The maximum packets per second for players
# It is measured over the configured interval
# Ignored if -1.0
maxPacketRate: 500.0
workerGroup: 4