Skip to main content

minimal/
minimal.rs

1use std::io;
2
3use nurtex_protocol::connection::utils::handle_encryption_request;
4use nurtex_protocol::connection::{ConnectionState, NurtexConnection};
5use nurtex_protocol::packets::configuration::{
6  ClientsideConfigurationPacket, ServersideAcknowledgeFinishConfiguration, ServersideClientInformation, ServersideConfigurationPacket, ServersideKnownPacks,
7  ServersideResourcePackResponse,
8};
9use nurtex_protocol::packets::handshake::{ServersideGreet, ServersideHandshakePacket};
10use nurtex_protocol::packets::login::{ClientsideLoginPacket, ServersideLoginAcknowledged, ServersideLoginPacket, ServersideLoginStart};
11use nurtex_protocol::packets::play::{ClientsidePlayPacket, ServersidePlayPacket};
12use nurtex_protocol::types::{AccurateHand, ChatMode, ClientIntention, DisplayedSkinParts, ParticleStatus, ResourcePackState};
13
14#[tokio::main]
15async fn main() -> io::Result<()> {
16  let target_host = "locahost".to_string();
17  let target_port = 25565;
18
19  // Создаём подключение (состояние Handshake)
20  let conn = match NurtexConnection::new(&target_host, 25565).await {
21    Ok(c) => c,
22    Err(_) => return Ok(()),
23  };
24
25  // Отправляем привестствие
26  conn
27    .write_handshake_packet(ServersideHandshakePacket::Greet(ServersideGreet {
28      protocol_version: 774, // Версия 1.21.11
29      server_host: target_host,
30      server_port: target_port,
31      intention: ClientIntention::Login,
32    }))
33    .await?;
34
35  // Меняем состояние подключения на Login
36  conn.set_state(ConnectionState::Login).await;
37
38  // Отправляем пакет LoginStart где указываем имя клиента и UUID (для оффлайн серверов просто нулевой)
39  conn
40    .write_login_packet(ServersideLoginPacket::LoginStart(ServersideLoginStart {
41      username: "NurtexBot".to_string(),
42      uuid: uuid::Uuid::nil(),
43    }))
44    .await?;
45
46  // Создаём цикл для обработки Clientside пакетов в состоянии Login
47  loop {
48    if let Some(p) = conn.read_login_packet().await {
49      match p {
50        ClientsideLoginPacket::Compression(p) => {
51          // Устанавливаем порог сжатия
52          conn.set_compression_threshold(p.compression_threshold).await;
53        }
54        ClientsideLoginPacket::EncryptionRequest(request) => {
55          // Пробуем обработать запрос шифрования
56          if let Some((response, secret_key)) = handle_encryption_request(&request) {
57            conn.write_login_packet(ServersideLoginPacket::EncryptionResponse(response)).await?;
58            conn.set_encryption_key(secret_key).await;
59          }
60        }
61        ClientsideLoginPacket::LoginSuccess(_p) => {
62          // Всё, логин пройден, отправляем LoginAcknowledged и выходим из цикла
63          conn.write_login_packet(ServersideLoginPacket::LoginAcknowledged(ServersideLoginAcknowledged)).await?;
64          break;
65        }
66        _ => {}
67      }
68    } else {
69      break;
70    }
71  }
72
73  // Меняем состояние подключения на Configuration
74  conn.set_state(ConnectionState::Configuration).await;
75
76  // Отправляем опции клиента
77  conn
78    .write_configuration_packet(ServersideConfigurationPacket::ClientInformation(ServersideClientInformation {
79      locale: "en_US".to_string(),
80      view_distance: 10,
81      chat_mode: ChatMode::Enabled,
82      chat_colors: true,
83      displayed_skin_parts: DisplayedSkinParts::default(),
84      main_hand: AccurateHand::Right,
85      enable_text_filtering: false,
86      allow_server_listings: true,
87      particle_status: ParticleStatus::Minimal,
88    }))
89    .await?;
90
91  // Создаём цикл для обработки Clientside пакетов в состоянии Configuration
92  loop {
93    if let Some(p) = conn.read_configuration_packet().await {
94      match p {
95        ClientsideConfigurationPacket::KeepAlive(p) => {
96          // Отправляем ответ на KeepAlive
97          conn
98            .write_configuration_packet(ServersideConfigurationPacket::KeepAlive(nurtex_protocol::packets::configuration::MultisideKeepAlive {
99              id: p.id,
100            }))
101            .await?;
102        }
103        ClientsideConfigurationPacket::Ping(p) => {
104          // Отправляем ответ на Ping
105          conn
106            .write_configuration_packet(ServersideConfigurationPacket::Pong(nurtex_protocol::packets::configuration::ServersidePong { id: p.id }))
107            .await?;
108        }
109        ClientsideConfigurationPacket::KnownPacks(p) => {
110          // Отправляем паки
111          conn
112            .write_configuration_packet(ServersideConfigurationPacket::KnownPacks(ServersideKnownPacks { known_packs: p.known_packs }))
113            .await?;
114        }
115        ClientsideConfigurationPacket::FinishConfiguration(_) => {
116          // Всё, конфигурация пройдена, отправляем AcknowledgeFinishConfiguration и выходим из цикла
117          conn
118            .write_configuration_packet(ServersideConfigurationPacket::AcknowledgeFinishConfiguration(ServersideAcknowledgeFinishConfiguration))
119            .await?;
120          break;
121        }
122        ClientsideConfigurationPacket::AddResourcePack(p) => {
123          // Принимаем ресурс пак
124          conn
125            .write_configuration_packet(ServersideConfigurationPacket::ResourcePackResponse(ServersideResourcePackResponse {
126              uuid: p.uuid,
127              state: ResourcePackState::Accepted,
128            }))
129            .await?;
130        }
131        _ => {}
132      }
133    } else {
134      break;
135    }
136  }
137
138  // Меняем состояние подключения на Play
139  conn.set_state(ConnectionState::Play).await;
140
141  // Создаём цикл обработки пакетов в состоянии Play
142  loop {
143    if let Some(p) = conn.read_play_packet().await {
144      match p {
145        ClientsidePlayPacket::KeepAlive(p) => {
146          // Отправляем ответ на KeepAlive
147          conn
148            .write_play_packet(ServersidePlayPacket::KeepAlive(nurtex_protocol::packets::play::MultisideKeepAlive { id: p.id }))
149            .await?;
150        }
151        ClientsidePlayPacket::Ping(p) => {
152          // Отправляем ответ на Ping
153          conn
154            .write_play_packet(ServersidePlayPacket::Pong(nurtex_protocol::packets::play::ServersidePong { id: p.id }))
155            .await?;
156        }
157        _ => {}
158      }
159    }
160  }
161}