Skip to main content

minimal/
minimal.rs

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