1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::{net::TcpListener, sync::{Arc, Mutex}, thread};
use rust_mc_proto::{DataBufferReader, DataBufferWriter, MCConnTcp, MinecraftConnection, Packet, ProtocolError};

/*

    Example of simple server that sends motd 
    to client like a vanilla minecraft server

*/

struct MinecraftServer {
    server_ip: String,
    server_port: u16,
    protocol_version: u16,
    motd: String
}

impl MinecraftServer {
    fn new(server_ip: &str,
            server_port: u16,
            protocol_version: u16,
            motd: &str) -> Self {
        MinecraftServer {
            server_ip: server_ip.to_string(),
            server_port,
            protocol_version,
            motd: motd.to_string()
        }
    }
}

fn accept_client(mut conn: MCConnTcp, server: Arc<Mutex<MinecraftServer>>) -> Result<(), ProtocolError> {
    let mut handshake = false;
    
    loop {
        let mut packet = match conn.read_packet() {
            Ok(i) => i,
            Err(_) => { 
                break; 
            },
        };

        if handshake {
            if packet.id() == 0x00 {
                let mut status = Packet::empty(0x00);

                let serv = server.lock().unwrap();

                let motd = serv.motd.clone();
                let motd = motd.replace(
                    "PROTOCOL_VERSION", 
                    &serv.protocol_version.to_string());

                status.write_string(&motd)?;
                conn.write_packet(&status)?;
            } else if packet.id() == 0x01 {
                let mut status = Packet::empty(0x01);
                status.write_long(packet.read_long()?)?;
                conn.write_packet(&status)?;
            }
        } else if packet.id() == 0x00 {
            let protocol_version = packet.read_i32_varint()?;
            let server_address = packet.read_string()?;
            let server_port = packet.read_unsigned_short()?;
            let next_state = packet.read_u8_varint()?;

            if next_state != 1 { break; }

            println!("Client handshake info:");
            println!("  IP: {}", conn.get_ref().peer_addr().unwrap());
            println!("  Protocol version: {}", protocol_version);
            println!("  Server address: {}", server_address);
            println!("  Server port: {}", server_port);

            handshake = true;
        } else {
            break;
        }
    }

    conn.close();

    Ok(())
}

fn main() {
    let server = MinecraftServer::new(
        "127.0.0.1", 
        25565, 
        765,
        "{
            \"version\":{
                \"protocol\":PROTOCOL_VERSION,
                \"name\":\"Version name\"
            },
            \"players\":{
                \"online\":0,
                \"max\":1,
                \"sample\":[
                    {
                        \"uuid\": \"\",
                        \"name\": \"Notch\"
                    }
                ]
            },
            \"description\": {
                \"text\": \"Hello World!\",
                \"color\": \"red\",
                \"bold\": true
            },
            \"favicon\": \"data:image/png;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=\"
        }"
    );

    let addr = server.server_ip.clone() + ":" + &server.server_port.to_string();
    let listener = TcpListener::bind(addr).unwrap();
    let server = Arc::new(Mutex::new(server));

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        let local_server = server.clone();

        thread::spawn(move || {
            accept_client(MinecraftConnection::new(stream), local_server).unwrap();
        });
    }
}