summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 8f925e33b31ec273614d16661ff671206d76d6b6 (plain)
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
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, TcpStream};

use anyhow::Result;
use craftio_rs::{CraftIo, CraftSyncReader, CraftSyncWriter, CraftTcpConnection};
use mcproto_rs::protocol::State;
use mcproto_rs::status::{StatusFaviconSpec, StatusPlayersSpec, StatusSpec, StatusVersionSpec};
use mcproto_rs::types::{Chat, TextComponent};
use mcproto_rs::types::Chat::Text;
use mcproto_rs::v1_19::{HandshakeNextState, Packet759, RawPacket759, StatusPingSpec, StatusPongSpec, StatusResponseSpec};
use mcproto_rs::v1_19::Packet759Kind::{Handshake, PlayServerPlayerAbilities};
use tokio;

pub struct MinecraftClient {
    connection: CraftTcpConnection,
}

impl MinecraftClient {
    pub fn new(connection: CraftTcpConnection) -> Self {
        Self { connection }
    }

    pub fn from_stream(stream: TcpStream) -> anyhow::Result<Self> {
        Ok(Self {
            connection: CraftTcpConnection::from_std(stream, mcproto_rs::protocol::PacketDirection::ServerBound)?,
        })
    }
    pub async fn read_next_packet(&mut self) -> Result<Option<Packet759>> {
        if let Some(raw) = self.connection.read_packet::<RawPacket759>()? {
            println!("Client -> Server: {:?}", raw);
            Ok(Some(raw))
        } else {
            Ok(None)
        }
    }
    pub async fn send_packet(&mut self, packet: Packet759) -> Result<()> {
        self.connection.write_packet(packet)?;
        Ok(())
    }
}

macro_rules! assert_packet {
    ($packet_type:ident, $obj:expr) => {if let Packet759::$packet_type(packet_data) = $obj { packet_data } else {panic!("Expected packet of type {}", stringify!($packet_type))}};
}

#[tokio::main]
async fn main() -> Result<()> {
    println!("Starting server");
    let bind = TcpListener::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 25565))?;
    loop {
        if let Ok((socket, address)) = bind.accept() {
            println!("Connection accepted from {}", address);
            let mut client = MinecraftClient::from_stream(socket)?;
            if let Err(x) = handle_conn(client).await {
                println!("Error: {:?}", x);
            }
        }
    }
}

async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
    let hs = assert_packet!(Handshake, client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))?);
    println!("Hs: {:?}", hs);
    if hs.next_state == HandshakeNextState::Login {
        client.connection.set_state(State::Login);
        let loginstart = assert_packet!(LoginStart, client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))?);
        println!("Login: {:?}", loginstart)
    } else {
        client.connection.set_state(State::Status);
        loop {
            println!("Polling status packet");
            match client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))? {
                Packet759::StatusRequest(_) => {
                    client.send_packet(Packet759::StatusResponse(StatusResponseSpec {
                        response: StatusSpec {
                            version: Some(StatusVersionSpec { name: "1.19 mgasi".to_string(), protocol: 759 }),
                            players: StatusPlayersSpec {
                                max: 100,
                                online: 0,
                                sample: vec![],
                            },
                            description: Chat::from_text("hehehe"),
                            favicon: None,
                        },
                    })).await?;
                }
                Packet759::StatusPing(StatusPingSpec { payload }) => {
                    client.send_packet(Packet759::StatusPong(StatusPongSpec {
                        payload,
                    })).await?;
                    return Ok(())
                }
                _ => anyhow::bail!("")
            }
        }
    }
    Ok(())
}