chunk data packet!!!

This commit is contained in:
MeexReay 2025-05-05 00:17:17 +03:00
parent fd2c27adab
commit caa08c9c25
6 changed files with 260 additions and 76 deletions

View File

@ -175,5 +175,24 @@ fn main() -> Result<(), ProtocolError> {
fs::write("registry-data.bin", &data).unwrap();
let packet = conn.read_packet()?;
conn.write_packet(&packet)?; // finish conf
loop {
let mut packet = conn.read_packet()?;
if packet.id() == 0x41 {
let id = packet.read_varint()?;
conn.write_packet(&Packet::build(0x00, |packet| packet.write_varint(id))?)?;
}
if packet.id() == 0x27 {
// here you can read "Chunk Data and Update Light" packet
break;
}
}
Ok(())
}

View File

@ -156,7 +156,7 @@ fn main() {
let mut server = ServerContext::new(config);
server.add_listener(Box::new(ExampleListener)); // Добавляем пример листенера
// server.add_packet_handler(Box::new(ExamplePacketHandler)); // Добавляем пример пакет хандлера
server.add_packet_handler(Box::new(ExamplePacketHandler)); // Добавляем пример пакет хандлера
// Бетонируем сервер контекст от изменений
let server = Arc::new(server);

View File

@ -17,7 +17,7 @@ pub mod protocol;
// Ошибки сервера
#[derive(Debug)]
pub enum ServerError {
UnexpectedPacket, // Неожиданный пакет
UnexpectedPacket(u8), // Неожиданный пакет
Protocol(ProtocolError), // Ошибка в протоколе при работе с rust_mc_proto
ConnectionClosed, // Соединение закрыто, единственная ошибка которая не логируется у handle_connection
SerTextComponent, // Ошибка при сериализации текст-компонента
@ -25,7 +25,6 @@ pub enum ServerError {
SerNbt, // Ошибка при сериализации nbt
DeNbt, // Ошибка при десериализации nbt
UnexpectedState, // Указывает на то что этот пакет не может быть отправлен в данном режиме (в основном через ProtocolHelper)
ReadLoopMode, // Ошибка когда вызывается read_any_packet во время работы read_loop
Other(String), // Другая ошибка, либо очень специфичная, либо хз, лучше не использовать и создавать новое поле ошибки
}

View File

@ -1,15 +1,10 @@
use std::{
hash::Hash,
net::{SocketAddr, TcpStream},
sync::{
Arc, RwLock,
atomic::{AtomicBool, Ordering},
mpsc::{self, Sender},
},
collections::VecDeque, hash::Hash, net::{SocketAddr, TcpStream}, sync::{
atomic::{AtomicBool, Ordering}, Arc, Mutex, RwLock
}, thread, time::Duration
};
use dashmap::DashMap;
use rust_mc_proto::{MinecraftConnection, Packet};
use rust_mc_proto::{MinecraftConnection, Packet, ProtocolError};
use uuid::Uuid;
use crate::server::{ServerError, context::ServerContext, protocol::ConnectionState};
@ -26,8 +21,9 @@ pub struct ClientContext {
client_info: RwLock<Option<ClientInfo>>,
player_info: RwLock<Option<PlayerInfo>>,
state: RwLock<ConnectionState>,
packet_waiters: DashMap<usize, (u8, Sender<Packet>)>,
packet_buffer: Mutex<VecDeque<Packet>>,
read_loop: AtomicBool,
is_alive: AtomicBool
}
// Реализуем сравнение через адрес
@ -56,8 +52,9 @@ impl ClientContext {
client_info: RwLock::new(None),
player_info: RwLock::new(None),
state: RwLock::new(ConnectionState::Handshake),
packet_waiters: DashMap::new(),
packet_buffer: Mutex::new(VecDeque::new()),
read_loop: AtomicBool::new(false),
is_alive: AtomicBool::new(true)
}
}
@ -121,22 +118,40 @@ impl ClientContext {
packet.get_mut().set_position(0);
}
if !cancelled {
self.conn.write().unwrap().write_packet(&packet)?;
match self.conn.write().unwrap().write_packet(&packet) {
Ok(_) => {},
Err(ProtocolError::ConnectionClosedError) => {
self.is_alive.store(false, Ordering::SeqCst);
return Err(ServerError::ConnectionClosed);
},
Err(e) => {
return Err(e.into());
}
};
}
Ok(())
}
pub fn run_read_loop(
self: &Arc<Self>,
callback: impl Fn(Packet) -> Result<(), ServerError>,
self: &Arc<Self>
) -> Result<(), ServerError> {
let state = self.state();
self.read_loop.store(true, Ordering::SeqCst);
let mut conn = self.conn.read().unwrap().try_clone()?; // так можно делать т.к сокет это просто поинтер
loop {
let mut packet = conn.read_packet()?;
let mut packet = match conn.read_packet() {
Ok(v) => v,
Err(ProtocolError::ConnectionClosedError) => {
self.is_alive.store(false, Ordering::SeqCst);
return Err(ServerError::ConnectionClosed);
},
Err(e) => {
return Err(e.into());
}
};
let mut cancelled = false;
let state = self.state();
for handler in self
.server
.packet_handlers(|o| o.on_incoming_packet_priority())
@ -151,31 +166,33 @@ impl ClientContext {
packet.get_mut().set_position(0);
}
if !cancelled {
let mut skip = false;
for (_, (id, sender)) in self.packet_waiters.clone() {
if id == packet.id() {
sender.send(packet.clone()).unwrap();
skip = true;
break;
}
}
if !skip {
callback(packet.clone())?;
}
self.packet_buffer.lock().unwrap().push_back(packet);
}
}
}
pub fn read_any_packet(self: &Arc<Self>) -> Result<Packet, ServerError> {
if self.read_loop.load(Ordering::SeqCst) {
Err(ServerError::ReadLoopMode)
loop {
if let Some(packet) = self.packet_buffer.lock().unwrap().pop_front() {
return Ok(packet);
}
thread::sleep(Duration::from_millis(10));
}
} else {
let state = self.state();
let mut conn = self.conn.read().unwrap().try_clone()?; // так можно делать т.к сокет это просто поинтер
loop {
let mut packet = conn.read_packet()?;
let mut packet = match self.conn.write().unwrap().read_packet() {
Ok(v) => v,
Err(ProtocolError::ConnectionClosedError) => {
self.is_alive.store(false, Ordering::SeqCst);
return Err(ServerError::ConnectionClosed);
},
Err(e) => {
return Err(e.into());
}
};
let mut cancelled = false;
for handler in self
.server
@ -199,22 +216,32 @@ impl ClientContext {
pub fn read_packet(self: &Arc<Self>, id: u8) -> Result<Packet, ServerError> {
if self.read_loop.load(Ordering::SeqCst) {
let (tx, rx) = mpsc::channel::<Packet>();
let key: usize = (&tx as *const Sender<Packet>).addr();
self.packet_waiters.insert(key, (id, tx));
loop {
if let Ok(packet) = rx.recv() {
self.packet_waiters.remove(&key);
break Ok(packet);
{
let mut locked = self.packet_buffer.lock().unwrap();
for (i, packet) in locked.clone().iter().enumerate() {
if packet.id() == id {
locked.remove(i);
return Ok(packet.clone());
}
}
}
thread::sleep(Duration::from_millis(10));
}
} else {
let packet = self.read_any_packet()?;
let packet = match self.read_any_packet() {
Ok(v) => v,
Err(ServerError::ConnectionClosed) => {
self.is_alive.store(false, Ordering::SeqCst);
return Err(ServerError::ConnectionClosed);
},
Err(e) => {
return Err(e);
}
};
if packet.id() != id {
Err(ServerError::UnexpectedPacket)
Err(ServerError::UnexpectedPacket(packet.id()))
} else {
Ok(packet)
}
@ -224,10 +251,15 @@ impl ClientContext {
pub fn close(self: &Arc<Self>) {
self.conn.write().unwrap().close();
}
pub fn set_compression(self: &Arc<Self>, threshold: Option<usize>) {
self.conn.write().unwrap().set_compression(threshold);
}
pub fn is_alive(self: &Arc<Self>) -> bool {
self.is_alive.load(Ordering::SeqCst)
}
pub fn protocol_helper(self: &Arc<Self>) -> ProtocolHelper {
ProtocolHelper::new(self.clone())
}

View File

@ -75,8 +75,8 @@ pub fn handle_connection(
packet.write_long(timestamp)?;
client.write_packet(&packet)?;
}
_ => {
return Err(ServerError::UnexpectedPacket);
id => {
return Err(ServerError::UnexpectedPacket(id));
}
}
}
@ -181,7 +181,7 @@ pub fn handle_connection(
}
_ => {
// Тип подключения не рукопожатный
return Err(ServerError::UnexpectedPacket);
return Err(ServerError::UnexpectedState);
}
}

View File

@ -1,8 +1,8 @@
use std::{io::Cursor, sync::Arc, thread};
use std::{io::Cursor, sync::Arc, thread, time::{Duration, SystemTime, UNIX_EPOCH}};
use rust_mc_proto::{DataWriter, Packet, read_packet};
use crate::server::{data::text_component::TextComponent, player::context::ClientContext, ServerError};
use crate::server::{player::context::ClientContext, ServerError};
use super::id::*;
@ -12,9 +12,7 @@ pub fn send_update_tags(client: Arc<ClientContext>) -> Result<(), ServerError> {
client.write_packet(&Packet::from_bytes(
clientbound::configuration::UPDATE_TAGS,
include_bytes!("update-tags.bin"),
))?;
Ok(())
))
}
pub fn send_registry_data(client: Arc<ClientContext>) -> Result<(), ServerError> {
@ -49,16 +47,10 @@ pub fn handle_configuration_state(
client.read_packet(serverbound::configuration::KNOWN_PACKS)?;
send_registry_data(client.clone())?;
send_update_tags(client.clone())?;
Ok(())
send_update_tags(client.clone())
}
// Отдельная функция для работы с самой игрой
pub fn handle_play_state(
client: Arc<ClientContext>, // Контекст клиента
) -> Result<(), ServerError> {
pub fn send_login(client: Arc<ClientContext>) -> Result<(), ServerError> {
// Отправка пакета Login
let mut packet = Packet::empty(clientbound::play::LOGIN);
@ -89,33 +81,175 @@ pub fn handle_play_state(
packet.write_boolean(false)?; // Enforces Secure Chat
client.write_packet(&packet)
}
pub fn send_game_event(client: Arc<ClientContext>, event: u8, value: f32) -> Result<(), ServerError> {
let mut packet = Packet::empty(clientbound::play::GAME_EVENT);
packet.write_byte(event)?;
packet.write_float(value)?;
client.write_packet(&packet)
}
pub fn sync_player_pos(
client: Arc<ClientContext>,
x: f64,
y: f64,
z: f64,
vel_x: f64,
vel_y: f64,
vel_z: f64,
yaw: f32,
pitch: f32,
flags: i32
) -> Result<(), ServerError> {
let timestamp = (SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() & 0xFFFFFFFF) as i32;
let mut packet = Packet::empty(clientbound::play::SYNCHRONIZE_PLAYER_POSITION);
packet.write_varint(timestamp)?;
packet.write_double(x)?;
packet.write_double(y)?;
packet.write_double(z)?;
packet.write_double(vel_x)?;
packet.write_double(vel_y)?;
packet.write_double(vel_z)?;
packet.write_float(yaw)?;
packet.write_float(pitch)?;
packet.write_int(flags)?;
client.write_packet(&packet)?;
client.read_packet(serverbound::play::CONFIRM_TELEPORTATION)?;
Ok(())
}
pub fn set_center_chunk(client: Arc<ClientContext>, x: i32, z: i32) -> Result<(), ServerError> {
let mut packet = Packet::empty(clientbound::play::SET_CENTER_CHUNK);
packet.write_varint(x)?;
packet.write_varint(z)?;
client.write_packet(&packet)
}
pub fn send_example_chunk(client: Arc<ClientContext>, x: i32, z: i32) -> Result<(), ServerError> {
let mut packet = Packet::empty(clientbound::play::CHUNK_DATA_AND_UPDATE_LIGHT);
packet.write_int(x)?;
packet.write_int(z)?;
// heightmap
packet.write_varint(1)?; // heightmaps count
packet.write_varint(0)?; // MOTION_BLOCKING
packet.write_varint(256)?; // Length of the following long array (16 * 16 = 256)
for _ in 0..256 {
packet.write_long(0)?; // height - 0
}
// sending chunk data
let mut chunk_data = Vec::new();
// we want to fill the area from -64 to 0, so it will be 4 chunk sections
for _ in 0..4 {
chunk_data.write_short(4096)?; // non-air blocks count, 16 * 16 * 16 = 4096 stone blocks
// blocks paletted container
chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format
chunk_data.write_varint(1)?; // block state id in the registry (1 for stone)
// biomes palleted container
chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format
chunk_data.write_varint(27)?; // biome id in the registry
}
// air chunk sections
for _ in 0..20 {
chunk_data.write_short(0)?; // non-air blocks count, 0
// blocks paletted container
chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format
chunk_data.write_varint(0)?; // block state id in the registry (0 for air)
// biomes palleted container
chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format
chunk_data.write_varint(27)?; // biome id in the registry
}
packet.write_usize_varint(chunk_data.len())?;
packet.write_bytes(&chunk_data)?;
packet.write_byte(0)?;
// light data
packet.write_byte(0)?;
packet.write_byte(0)?;
packet.write_byte(0)?;
packet.write_byte(0)?;
packet.write_byte(0)?;
packet.write_byte(0)?;
client.write_packet(&packet)?;
Ok(())
}
pub fn send_keep_alive(client: Arc<ClientContext>) -> Result<(), ServerError> {
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64;
let mut packet = Packet::empty(clientbound::play::KEEP_ALIVE);
packet.write_long(timestamp)?;
client.write_packet(&packet)?;
client.read_packet(serverbound::play::KEEP_ALIVE)?;
Ok(())
}
// Отдельная функция для работы с самой игрой
pub fn handle_play_state(
client: Arc<ClientContext>, // Контекст клиента
) -> Result<(), ServerError> {
thread::spawn({
let client = client.clone();
move || {
let _ = client.clone().run_read_loop({
let client = client.clone();
move |packet| {
// TODO: Сделать базовые приколы типа keep-alive и другое
Ok(())
}
});
let _ = client.run_read_loop();
client.close();
}
});
// Отключение игрока с сообщением
client.protocol_helper().disconnect(TextComponent::rainbow(
"server is in developement suka".to_string(),
))?;
send_login(client.clone())?;
sync_player_pos(client.clone(), 8.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0)?;
send_game_event(client.clone(), 13, 0.0)?; // 13 - Start waiting for level chunks
set_center_chunk(client.clone(), 0, 0)?;
send_example_chunk(client.clone(), 0, 0)?;
// loop {}
let mut ticks_alive = 0u64;
// TODO: Сделать отправку чанков
while client.is_alive() {
if ticks_alive % 200 == 0 { // 10 secs timer
send_keep_alive(client.clone())?;
}
if ticks_alive % 20 == 0 { // 1 sec timer
// do something
}
thread::sleep(Duration::from_millis(50)); // 1 tick
ticks_alive += 1;
}
Ok(())
}