ursinn/MinecraftServer

View on GitHub
src/main/java/com/github/joshj1091/mcserver/connection/UserConnection.java

Summary

Maintainability
A
1 hr
Test Coverage
package com.github.joshj1091.mcserver.connection;

import com.github.joshj1091.mcserver.MCServer;
import com.github.joshj1091.mcserver.protocol.Direction;
import com.github.joshj1091.mcserver.protocol.Packet;
import com.github.joshj1091.mcserver.protocol.Protocol;
import com.github.joshj1091.mcserver.protocol.packets.incoming.HandshakePacket;
import com.github.joshj1091.mcserver.protocol.packets.incoming.LoginStartPacket;
import com.github.joshj1091.mcserver.protocol.packets.incoming.PingRequestPacket;
import com.github.joshj1091.mcserver.protocol.packets.outgoing.LoginDisconnectPacket;
import com.github.joshj1091.mcserver.protocol.packets.outgoing.PongResponsePacket;
import com.github.joshj1091.mcserver.protocol.packets.outgoing.StatusResponsePacket;
import com.github.joshj1091.mcserver.util.ByteReader;
import com.github.joshj1091.mcserver.util.DataUtil;
import lombok.Getter;
import lombok.Setter;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class UserConnection {

    private final MCServer server = MCServer.getMCServer();
    private final Socket socket;
    private boolean acceptData = true;

    /**
     * Protocol state
     */
    @Getter
    @Setter
    private int state;

    /**
     * Standard Packet Format
     * <p>
     * | Field            | Data Type      |
     * -------------------------------------
     * | Packet Size      | VarInt         |
     * | Packet ID        | VarInt         |
     * | Data             | Byte Array     |
     *
     * @param socket the connection socket
     * @throws IOException if there are any I/O errors
     */
    public UserConnection(final Socket socket) throws IOException {
        this.socket = socket;
        this.state = 0;

        server.log("Accepted connection from " + socket.getInetAddress().toString());
        DataInputStream inputStream = new DataInputStream(socket.getInputStream());
        while (acceptData) {
            int size = DataUtil.readUnsignedVarInt(inputStream);
            byte[] buffer = new byte[size];
            inputStream.readFully(buffer);
            ByteReader reader = new ByteReader(buffer);
            int id = DataUtil.readUnsignedVarInt(reader);

            Packet packet = Protocol.getPacket(state, Direction.SERVERBOUND, reader, id);
            handlePacket(packet);
        }
    }

    private void handlePacket(Packet packet) {
        if (state == 0) {
            if (packet.getId() == 0x00) { // handshake packet
                HandshakePacket handshakePacket = (HandshakePacket) packet;
                this.state = handshakePacket.getNextState();
            }
        } else if (state == 1) {
            if (packet.getId() == 0x00) { // status request
                server.log("Got status request");

                StatusResponsePacket response = new StatusResponsePacket("1.9.0", 107, 50, 5, "Hello from Josh's server");
                sendData(response.encode());
            } else if (packet.getId() == 0x01) {
                server.log("Got ping request");

                PingRequestPacket pingRequestPacket = (PingRequestPacket) packet;
                PongResponsePacket response = new PongResponsePacket(pingRequestPacket.getLongBytes());
                sendData(response.encode());
            }
        } else if (state == 2) {
            if (packet.getId() == 0x00) {
                server.log("Login start packet");
                LoginStartPacket loginStartPacket = (LoginStartPacket) packet;
                server.log("Found name: " + loginStartPacket.getName());

                LoginDisconnectPacket loginDisconnectPacket = new LoginDisconnectPacket("§4This server doesn't support logging in,§d " + loginStartPacket.getName());
                sendData(loginDisconnectPacket.encode());
            }
        }
    }

    private void sendData(byte[] data) {
        byte[] dataLength = DataUtil.intToUnsignedVarInt(data.length);

        write(dataLength);
        write(data);
    }

    private void write(byte[] data) {
        try {
            socket.getOutputStream().write(data);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public void close() throws IOException {
        acceptData = false;
        socket.close();
    }
}