├── .gitignore
├── LICENSE
├── Limbo.iml
├── README.md
├── pom.xml
├── server.properties
└── src
└── main
├── java
└── nl
│ └── hpfxd
│ └── limbo
│ ├── Limbo.java
│ ├── Main.java
│ ├── logging
│ └── LimboLogFormatter.java
│ ├── network
│ ├── ChannelHandler.java
│ ├── NetworkManager.java
│ ├── packet
│ │ ├── Packet.java
│ │ └── packets
│ │ │ ├── login
│ │ │ ├── PacketLoginDisconnect.java
│ │ │ └── PacketLoginSuccess.java
│ │ │ ├── play
│ │ │ ├── PacketChatMessage.java
│ │ │ ├── PacketDisconnect.java
│ │ │ ├── PacketExtraTablistInfo.java
│ │ │ ├── PacketJoinGame.java
│ │ │ ├── PacketKeepAlive.java
│ │ │ ├── PacketPositionAndLook.java
│ │ │ └── PacketSpawnPosition.java
│ │ │ └── status
│ │ │ ├── PacketServerListPingResponse.java
│ │ │ └── PacketServerListPong.java
│ ├── pipeline
│ │ ├── PacketEncoder.java
│ │ ├── VarInt21Decoder.java
│ │ └── VarInt21Encoder.java
│ └── protocol
│ │ ├── ChatMessagePosition.java
│ │ ├── Location.java
│ │ ├── PacketUtils.java
│ │ ├── ProtocolState.java
│ │ └── ProtocolVersion.java
│ └── player
│ └── Player.java
└── resources
├── META-INF
└── native-image
│ └── nl.hpfxd
│ └── Limbo
│ └── native-image.properties
└── server.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /target/
3 | .idea/
4 | *.iml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Nathan M.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Limbo.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Limbo
2 | A simple and lightweight Minecraft limbo server.
3 | Usually used in a network of servers to host a large amount of players at a low CPU cost. (Queue/fallback server)
4 |
5 | **Currently implemented:**
6 | - Spawning in a void world
7 | - Server list ping
8 |
9 | **To Do**
10 | - World loading from a schematic file. (shouldn't be too difficult for 1.8.x)
11 | - Bungeecord IP forwarding (wouldn't really do much)
12 | - Support more versions
13 |
14 | ## Minecraft Protocol Versions Supported
15 | - 5 (1.7.6-1.7.10)
16 | - 47 (1.8.x) (Base version)
17 |
18 | 1.12.2 support was attempted, but when sending the join game packet my client would disconnect and I haven't been able to fix it.
19 | PRs to support more versions are welcome.
20 | You may also be able to run ViaVersion on your proxy to support newer versions, I haven't tested this though.
21 |
22 | ## Usage
23 | Just download the latest release and run it with Java, a configuration file will be created and you may edit it as you wish.
24 | Note: To run the server with a specific port without editing the configuration file (useful for deploying on a cloud system) just set the first argument to a port. Example: `java -jar Limbo.jar 25566` will run the server on port 25566.
25 | To compile it yourself just run `mvn package`.
26 |
27 | ### Native Builds
28 | Making native builds with [GraalVM](https://www.graalvm.org/) is supported and recommended.
29 | Native builds come with a much faster startup time (from 2 seconds to 3ms for me), as well as less overall CPU usage.
30 |
31 | Just install GraalVM and the `native-image` component and run `native-image -jar .jar` and you can run the server using `./Limbo`.
32 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | nl.hpfxd
8 | Limbo
9 | 1.1
10 |
11 |
12 | 1.8
13 | 1.8
14 |
15 |
16 |
17 |
18 | org.projectlombok
19 | lombok
20 | 1.18.12
21 |
22 |
23 | io.netty
24 | netty-all
25 | 4.1.51.Final
26 | compile
27 |
28 |
29 | org.json
30 | json
31 | 20200518
32 | compile
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.apache.maven.plugins
40 | maven-shade-plugin
41 | 3.2.4
42 |
43 | false
44 |
45 |
46 |
47 | package
48 |
49 | shade
50 |
51 |
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-jar-plugin
57 |
58 |
59 |
60 | true
61 | nl.hpfxd.limbo.Main
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/server.properties:
--------------------------------------------------------------------------------
1 | # Configuration file for github.com/hpfxd/Limbo
2 |
3 | # The address to listen on.
4 | network.address=0.0.0.0
5 | # The port to listen on.
6 | network.port=25565
7 | # The MOTD to show in the server list. (Chat component)
8 | server.motd={"text":"A Limbo server!\\ngithub.com/hpfxd/Limbo"}
9 | # The maximum number of players the server can hold.
10 | server.maxplayers=512
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/Limbo.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo;
2 |
3 | import lombok.Getter;
4 | import lombok.extern.java.Log;
5 | import nl.hpfxd.limbo.logging.LimboLogFormatter;
6 | import nl.hpfxd.limbo.network.NetworkManager;
7 | import org.json.JSONObject;
8 |
9 | import java.io.File;
10 | import java.io.FileInputStream;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.nio.file.Files;
14 | import java.util.Properties;
15 | import java.util.logging.Handler;
16 | import java.util.logging.LogManager;
17 | import java.util.logging.Logger;
18 |
19 | @Log
20 | public class Limbo {
21 | @Getter private static Limbo instance;
22 | @Getter private boolean running;
23 |
24 | @Getter private final Properties config = new Properties();
25 | @Getter private NetworkManager networkManager;
26 |
27 | // some config properties, just used so we don't have to look them up in a hashtable every time
28 | @Getter private JSONObject motd;
29 | @Getter private int maxPlayers;
30 | @Getter private int port = -1;
31 | @Getter private String joinMessage;
32 | @Getter private String actionBarMessage;
33 | @Getter private String playerListHeader;
34 | @Getter private String playerListFooter;
35 |
36 | public void start(String[] args) {
37 | this.configureLogger();
38 | if (args.length > 0) {
39 | try {
40 | port = Integer.parseInt(args[0]);
41 | } catch (NumberFormatException ignored) {}
42 | }
43 | instance = this;
44 |
45 | log.info("Starting Limbo.");
46 |
47 | try {
48 | this.loadConfig();
49 | } catch (IOException e) {
50 | e.printStackTrace();
51 | System.exit(1);
52 | }
53 |
54 | Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
55 |
56 | this.networkManager = new NetworkManager();
57 | this.networkManager.start();
58 | }
59 |
60 | public void shutdown() {
61 | if (!this.running) return;
62 | this.running = false;
63 | log.info("Shutting down.");
64 | this.networkManager.shutdown();
65 | instance = null;
66 | }
67 |
68 | private void loadConfig() throws IOException {
69 | File file = new File("server.properties");
70 |
71 | if (!file.exists()) {
72 | try (InputStream in = Limbo.class.getResourceAsStream("/server.properties")) {
73 | Files.copy(in, file.toPath());
74 | }
75 | }
76 |
77 | try (FileInputStream in = new FileInputStream(file)) {
78 | this.config.load(in);
79 | }
80 |
81 | if (this.port == -1) {
82 | this.port = Integer.parseInt(this.config.getProperty("network.port"));
83 | }
84 |
85 | this.motd = new JSONObject(this.config.getProperty("server.motd"));
86 | this.maxPlayers = Integer.parseInt(this.config.getProperty("server.maxplayers"));
87 | this.joinMessage = this.config.getProperty("server.joinMessage");
88 | this.actionBarMessage = this.config.getProperty("server.actionBarMessage");
89 | this.playerListHeader = this.config.getProperty("server.playerList.header");
90 | this.playerListFooter = this.config.getProperty("server.playerList.footer");
91 | if (this.joinMessage == null || this.joinMessage.equals("NONE")) this.joinMessage = null;
92 | if (this.actionBarMessage == null || this.actionBarMessage.equals("NONE")) this.actionBarMessage = null;
93 | if (this.playerListHeader == null || this.playerListHeader.equals("NONE")) this.playerListHeader = null;
94 |
95 | log.info("Config loaded.");
96 | }
97 |
98 | private void configureLogger() {
99 | try {
100 | Logger rootLogger = LogManager.getLogManager().getLogger("");
101 | LimboLogFormatter formatter = new LimboLogFormatter();
102 |
103 | for (Handler handler : rootLogger.getHandlers()) {
104 | handler.setFormatter(formatter);
105 | }
106 | } catch (Exception e) {
107 | log.info("Error configuring logger. " + e.getMessage());
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/Main.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo;
2 |
3 | public class Main {
4 | public static void main(String[] args) {
5 | new Limbo().start(args);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/logging/LimboLogFormatter.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.logging;
2 |
3 | import java.text.MessageFormat;
4 | import java.util.Date;
5 | import java.util.logging.Formatter;
6 | import java.util.logging.LogRecord;
7 |
8 | public class LimboLogFormatter extends Formatter {
9 | private static final MessageFormat messageFormat = new MessageFormat("[{3,date,hh:mm:ss.SSS}] [{2}/{1}] [{0}] {4}\n");
10 |
11 | @Override
12 | public String format(LogRecord record) {
13 | String[] str = record.getLoggerName().split("\\.");
14 | Object[] arguments = new Object[]{str[str.length - 1], record.getLevel(), Thread.currentThread().getName(), new Date(record.getMillis()), record.getMessage(), record.getSourceMethodName()};
15 | return messageFormat.format(arguments);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/ChannelHandler.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.channel.SimpleChannelInboundHandler;
6 | import lombok.Getter;
7 | import lombok.extern.java.Log;
8 | import nl.hpfxd.limbo.Limbo;
9 | import nl.hpfxd.limbo.player.Player;
10 |
11 | import java.util.logging.Level;
12 |
13 | @Log
14 | public class ChannelHandler extends SimpleChannelInboundHandler {
15 | @Getter private Player player;
16 |
17 | @Override
18 | public void channelActive(ChannelHandlerContext ctx) {
19 | log.fine("Player connected.");
20 | this.player = new Player(ctx.channel());
21 | Limbo.getInstance().getNetworkManager().getPlayers().add(this.player);
22 | }
23 |
24 | @Override
25 | public void channelInactive(ChannelHandlerContext ctx) {
26 | dispatchSession();
27 | }
28 |
29 | @Override
30 | protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
31 | this.player.onPacket(buf);
32 | }
33 |
34 | @Override
35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
36 | ctx.close();
37 | dispatchSession();
38 | log.log(Level.WARNING, "Player error.", cause);
39 | }
40 |
41 | private void dispatchSession() {
42 | if (this.player == null) return;
43 | log.fine("Player disconnected.");
44 | Limbo.getInstance().getNetworkManager().getPlayers().remove(this.player);
45 | this.player.destroy();
46 | this.player = null;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/NetworkManager.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.channel.*;
5 | import io.netty.channel.epoll.Epoll;
6 | import io.netty.channel.epoll.EpollEventLoopGroup;
7 | import io.netty.channel.epoll.EpollServerSocketChannel;
8 | import io.netty.channel.nio.NioEventLoopGroup;
9 | import io.netty.channel.socket.SocketChannel;
10 | import io.netty.channel.socket.nio.NioServerSocketChannel;
11 | import io.netty.handler.timeout.ReadTimeoutHandler;
12 | import lombok.Getter;
13 | import lombok.extern.java.Log;
14 | import nl.hpfxd.limbo.Limbo;
15 | import nl.hpfxd.limbo.network.pipeline.PacketEncoder;
16 | import nl.hpfxd.limbo.network.pipeline.VarInt21Decoder;
17 | import nl.hpfxd.limbo.network.pipeline.VarInt21Encoder;
18 | import nl.hpfxd.limbo.player.Player;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | @Log
24 | public class NetworkManager {
25 | @Getter private final List players = new ArrayList<>();
26 | private EventLoopGroup bossgroup;
27 |
28 | public void start() {
29 | log.info("Starting network manager.");
30 |
31 | if (Epoll.isAvailable()) {
32 | log.info("Using Epoll transport.");
33 | } else {
34 | log.info("Epoll not available, falling back to NIO. Reason: " + Epoll.unavailabilityCause().getMessage());
35 | }
36 | this.bossgroup = this.getEventLoopGroup();
37 | ServerBootstrap bootstrap = new ServerBootstrap()
38 | .group(this.bossgroup)
39 | .channel(this.getChannel())
40 | .childOption(ChannelOption.TCP_NODELAY, true)
41 | .childOption(ChannelOption.SO_KEEPALIVE, true)
42 | .childHandler(new ChannelInitializer() {
43 | @Override
44 | protected void initChannel(SocketChannel ch) {
45 | ch.pipeline()
46 | .addLast("timer", new ReadTimeoutHandler(30))
47 |
48 | .addLast("varintdecoder", new VarInt21Decoder())
49 |
50 | .addLast("varintencoder", new VarInt21Encoder())
51 | .addLast("packetencoder", new PacketEncoder())
52 |
53 | .addLast("handler", new ChannelHandler());
54 | }
55 | });
56 |
57 | try {
58 | Channel ch = bootstrap.bind(Limbo.getInstance().getConfig().getProperty("network.address"), Limbo.getInstance().getPort()).sync().channel();
59 | log.info("Listening for connections on " + ch.localAddress().toString() + ".");
60 | ch.closeFuture().sync();
61 | } catch (Exception e) {
62 | log.severe("Failed to bind to port!");
63 | log.severe("Make sure that no other servers are using the port in server.properties.");
64 | log.severe("Exception: " + e.getMessage());
65 | System.exit(1);
66 | }
67 | }
68 |
69 | public void shutdown() {
70 | this.bossgroup.shutdownGracefully();
71 | }
72 |
73 | private EventLoopGroup getEventLoopGroup() {
74 | return Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();
75 | }
76 |
77 | private Class extends ServerChannel> getChannel() {
78 | return Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/Packet.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.ByteBufUtil;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | /*
9 | * packet class is only used for outgoing packets
10 | * i'm too tired to come up with a way for incoming packets without using reflection
11 | */
12 | public class Packet
13 | {
14 | @Getter protected int packetId; // updated by the write method if changed in another version
15 | @Setter protected int protocolVersion = 47;
16 |
17 | protected Packet(int packetId)
18 | {
19 | this.packetId = packetId;
20 | }
21 |
22 | public void writeString(ByteBuf buf, CharSequence str)
23 | {
24 | int size = ByteBufUtil.utf8Bytes(str);
25 | writeVarInt(buf, size);
26 | ByteBufUtil.writeUtf8(buf, str);
27 | }
28 |
29 | public void writeVarInt(ByteBuf buf, int value) {
30 | while (true) {
31 | if ((value & 0xFFFFFF80) == 0) {
32 | buf.writeByte(value);
33 | return;
34 | }
35 |
36 | buf.writeByte(value & 0x7F | 0x80);
37 | value >>>= 7;
38 | }
39 | }
40 |
41 | public void encode(ByteBuf buf)
42 | {
43 |
44 | }
45 |
46 | public void decode(ByteBuf byteBuf)
47 | {
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/login/PacketLoginDisconnect.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.login;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 |
7 | public class PacketLoginDisconnect extends Packet {
8 | private final String reason;
9 |
10 | public PacketLoginDisconnect(String reason) {
11 | super(0x00);
12 | this.reason = reason;
13 | }
14 |
15 | @Override
16 | public void encode(ByteBuf buf) {
17 | PacketUtils.writeString(buf, this.reason);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/login/PacketLoginSuccess.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.login;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
5 | import nl.hpfxd.limbo.network.packet.Packet;
6 |
7 | import java.util.UUID;
8 |
9 | public class PacketLoginSuccess extends Packet {
10 | private final UUID uniqueId;
11 | private final String name;
12 |
13 | public PacketLoginSuccess(UUID uniqueId, String name) {
14 | super(0x02);
15 | this.uniqueId = uniqueId;
16 | this.name = name;
17 | }
18 |
19 | @Override
20 | public void encode(ByteBuf buf) {
21 | PacketUtils.writeString(buf, this.uniqueId.toString());
22 | PacketUtils.writeString(buf, this.name);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketChatMessage.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.ChatMessagePosition;
6 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
7 |
8 | public class PacketChatMessage extends Packet {
9 | private final String message;
10 | private final ChatMessagePosition position;
11 |
12 | public PacketChatMessage(String message, ChatMessagePosition position) {
13 | super(0x02);
14 | this.message = message;
15 | this.position = position;
16 | }
17 |
18 | @Override
19 | public void encode(ByteBuf buf) {
20 | this.writeString(buf, this.message);
21 |
22 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_8) {
23 | buf.writeByte(this.position.getId());
24 | }
25 | }
26 |
27 | @Override
28 | public void decode(ByteBuf byteBuf) {
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketDisconnect.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
7 |
8 | public class PacketDisconnect extends Packet {
9 | private final String reason;
10 |
11 | public PacketDisconnect(String reason) {
12 | super(0x40);
13 | this.reason = reason;
14 | }
15 |
16 | @Override
17 | public void encode(ByteBuf buf) {
18 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
19 | this.packetId = 0x1A;
20 | }
21 |
22 | PacketUtils.writeString(buf, this.reason);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketExtraTablistInfo.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 |
6 | public class PacketExtraTablistInfo extends Packet
7 | {
8 | private String header;
9 | private String footer;
10 |
11 | public PacketExtraTablistInfo(String header, String footer) {
12 | super(0x47);
13 | this.header = header;
14 | this.footer = footer;
15 | }
16 |
17 | @Override
18 | public void encode(ByteBuf buf) {
19 | // this packet isn't supported on 1.7, it shouldn't be sent.
20 | this.writeString(buf, header);
21 | this.writeString(buf, footer);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketJoinGame.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
7 |
8 | public class PacketJoinGame extends Packet {
9 | private final int entityId;
10 | private final int gamemode;
11 | private final int dimension;
12 | private final int difficulty;
13 | private final int maxPlayers;
14 | private final String levelType;
15 | private final boolean reducedDebugInfo;
16 |
17 | public PacketJoinGame(int entityId, int gamemode, int dimension, int difficulty, int maxPlayers, String levelType, boolean reducedDebugInfo) {
18 | super(0x01);
19 | this.entityId = entityId;
20 | this.gamemode = gamemode;
21 | this.dimension = dimension;
22 | this.difficulty = difficulty;
23 | this.maxPlayers = maxPlayers;
24 | this.levelType = levelType;
25 | this.reducedDebugInfo = reducedDebugInfo;
26 | }
27 | @Override
28 | public void encode(ByteBuf buf) {
29 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
30 | this.packetId = 0x23;
31 | }
32 |
33 | buf.writeInt(this.entityId);
34 | buf.writeByte(this.gamemode);
35 |
36 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
37 | buf.writeInt(this.dimension);
38 | } else {
39 | buf.writeByte(this.dimension);
40 | }
41 |
42 | buf.writeByte(this.difficulty);
43 | buf.writeByte(this.maxPlayers);
44 | PacketUtils.writeString(buf, this.levelType);
45 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_8) buf.writeBoolean(this.reducedDebugInfo);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketKeepAlive.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
7 |
8 | public class PacketKeepAlive extends Packet {
9 | private final int id;
10 |
11 | public PacketKeepAlive(int id) {
12 | super(0x00);
13 | this.id = id;
14 | }
15 |
16 | @Override
17 | public void encode(ByteBuf buf) {
18 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
19 | this.packetId = 0x1F;
20 | }
21 |
22 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
23 | buf.writeLong(this.id);
24 | } else if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_8) {
25 | PacketUtils.writeVarInt(buf, this.id);
26 | } else if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_7_10) {
27 | buf.writeInt(this.id);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketPositionAndLook.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
7 |
8 | public class PacketPositionAndLook extends Packet {
9 | private final int x;
10 | private final int y;
11 | private final int z;
12 | private final float yaw;
13 | private final float pitch;
14 |
15 | public PacketPositionAndLook(int x, int y, int z, float yaw, float pitch) {
16 | super(0x08);
17 | this.x = x;
18 | this.y = y;
19 | this.z = z;
20 | this.yaw = yaw;
21 | this.pitch = pitch;
22 | }
23 |
24 | @Override
25 | public void encode(ByteBuf buf) {
26 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
27 | this.packetId = 0x2F;
28 | }
29 |
30 | buf.writeDouble(this.x);
31 | buf.writeDouble(this.y);
32 | buf.writeDouble(this.z);
33 | buf.writeFloat(this.yaw);
34 | buf.writeFloat(this.pitch);
35 | buf.writeByte(0);
36 |
37 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
38 | PacketUtils.writeVarInt(buf, 0); // teleport id
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/play/PacketSpawnPosition.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.play;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.ProtocolVersion;
6 |
7 | public class PacketSpawnPosition extends Packet {
8 | public PacketSpawnPosition() {
9 | super(0x05);
10 | }
11 |
12 | @Override
13 | public void encode(ByteBuf buf) {
14 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_12_2) {
15 | this.packetId = 0x46;
16 | }
17 |
18 | if (this.protocolVersion >= ProtocolVersion.PROTOCOL_1_8) {
19 | buf.writeLong(0);
20 | } else {
21 | buf.writeInt(0);
22 | buf.writeInt(0);
23 | buf.writeInt(0);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/status/PacketServerListPingResponse.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.status;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
6 |
7 | public class PacketServerListPingResponse extends Packet {
8 | private final String json;
9 |
10 | public PacketServerListPingResponse(String json) {
11 | super(0x00);
12 | this.json = json;
13 | }
14 |
15 | @Override
16 | public void encode(ByteBuf buf) {
17 | PacketUtils.writeString(buf, json);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/packet/packets/status/PacketServerListPong.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.packet.packets.status;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import nl.hpfxd.limbo.network.packet.Packet;
5 |
6 | public class PacketServerListPong extends Packet {
7 | private final long id;
8 |
9 | public PacketServerListPong(long id) {
10 | super(0x01);
11 | this.id = id;
12 | }
13 | @Override
14 | public void encode(ByteBuf buf) {
15 | buf.writeLong(id);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/pipeline/PacketEncoder.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.pipeline;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.handler.codec.MessageToByteEncoder;
6 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
7 | import nl.hpfxd.limbo.network.packet.Packet;
8 |
9 | public class PacketEncoder extends MessageToByteEncoder {
10 | @Override
11 | protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) {
12 | try {
13 | PacketUtils.writeVarInt(out, packet.getPacketId());
14 | packet.encode(out);
15 | } catch (Throwable t) {
16 | t.printStackTrace();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/nl/hpfxd/limbo/network/pipeline/VarInt21Decoder.java:
--------------------------------------------------------------------------------
1 | package nl.hpfxd.limbo.network.pipeline;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.Unpooled;
5 | import io.netty.channel.ChannelHandlerContext;
6 | import io.netty.handler.codec.ByteToMessageDecoder;
7 | import io.netty.handler.codec.CorruptedFrameException;
8 | import nl.hpfxd.limbo.network.protocol.PacketUtils;
9 |
10 | import java.util.List;
11 |
12 | public class VarInt21Decoder extends ByteToMessageDecoder {
13 | @Override
14 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List