send players

This commit is contained in:
MeexReay 2025-05-07 17:55:32 +03:00
parent 4036be8cc1
commit 8b5084460e
5 changed files with 216 additions and 48 deletions

64
Cargo.lock generated
View File

@ -109,6 +109,15 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.17.0" version = "3.17.0"
@ -214,6 +223,16 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.11" version = "0.20.11"
@ -273,6 +292,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.15.0"
@ -330,6 +359,16 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@ -495,6 +534,16 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "md-5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if",
"digest",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -967,6 +1016,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.18"
@ -984,6 +1039,15 @@ name = "uuid"
version = "1.16.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [
"md-5",
]
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"

View File

@ -17,7 +17,7 @@ palette = "0.7.6"
craftflow-nbt = "2.1.0" craftflow-nbt = "2.1.0"
colog = "1.3.0" colog = "1.3.0"
log = "0.4.27" log = "0.4.27"
uuid = "1.16.0" uuid = { version = "1.16.0", features = ["v3"] }
dashmap = "6.1.0" dashmap = "6.1.0"
paste = "1.0.15" paste = "1.0.15"
ignore-result = "0.2.0" ignore-result = "0.2.0"

View File

@ -1,4 +1,7 @@
use std::{net::SocketAddr, sync::Arc}; use std::{
net::SocketAddr,
sync::{Arc, atomic::AtomicI32},
};
use dashmap::DashMap; use dashmap::DashMap;
use itertools::Itertools; use itertools::Itertools;
@ -15,6 +18,7 @@ use super::{
pub struct ServerContext { pub struct ServerContext {
pub config: Arc<Config>, pub config: Arc<Config>,
pub clients: DashMap<SocketAddr, Arc<ClientContext>>, pub clients: DashMap<SocketAddr, Arc<ClientContext>>,
pub world: WorldContext,
listeners: Vec<Box<dyn Listener>>, listeners: Vec<Box<dyn Listener>>,
handlers: Vec<Box<dyn PacketHandler>>, handlers: Vec<Box<dyn PacketHandler>>,
} }
@ -26,6 +30,7 @@ impl ServerContext {
listeners: Vec::new(), listeners: Vec::new(),
handlers: Vec::new(), handlers: Vec::new(),
clients: DashMap::new(), clients: DashMap::new(),
world: WorldContext::new(),
} }
} }
@ -92,3 +97,15 @@ impl ServerContext {
self.listeners.iter().sorted_by_key(sort_by).collect_vec() self.listeners.iter().sorted_by_key(sort_by).collect_vec()
} }
} }
pub struct WorldContext {
pub entity_id_counter: AtomicI32,
}
impl WorldContext {
pub fn new() -> WorldContext {
WorldContext {
entity_id_counter: AtomicI32::new(0),
}
}
}

View File

@ -1,3 +1,4 @@
use std::sync::atomic::Ordering;
use std::{sync::Arc, thread, time::Duration}; use std::{sync::Arc, thread, time::Duration};
use config::handle_configuration_state; use config::handle_configuration_state;
@ -6,7 +7,9 @@ use helper::{
unload_chunk, unload_chunk,
}; };
use rust_mc_proto::{DataReader, DataWriter, Packet}; use rust_mc_proto::{DataReader, DataWriter, Packet};
use uuid::Uuid;
use crate::player::context::EntityInfo;
use crate::{ use crate::{
ServerError, data::text_component::TextComponent, event::PacketHandler, ServerError, data::text_component::TextComponent, event::PacketHandler,
player::context::ClientContext, player::context::ClientContext,
@ -57,7 +60,7 @@ pub fn send_login(client: Arc<ClientContext>) -> Result<(), ServerError> {
// Отправка пакета Login // Отправка пакета Login
let mut packet = Packet::empty(clientbound::play::LOGIN); let mut packet = Packet::empty(clientbound::play::LOGIN);
packet.write_int(0)?; // Entity ID packet.write_int(client.entity_info().entity_id)?; // Entity ID
packet.write_boolean(false)?; // Is hardcore packet.write_boolean(false)?; // Is hardcore
packet.write_varint(4)?; // Dimension Names packet.write_varint(4)?; // Dimension Names
packet.write_string("minecraft:overworld")?; packet.write_string("minecraft:overworld")?;
@ -96,10 +99,13 @@ pub fn send_example_chunk(client: Arc<ClientContext>, x: i32, z: i32) -> Result<
// heightmap // heightmap
packet.write_varint(1)?; // heightmaps count packet.write_varint(1)?; // heightmaps count
packet.write_varint(0)?; // MOTION_BLOCKING packet.write_varint(0)?; // MOTION_BLOCKING - 0
packet.write_varint(256)?; // Length of the following long array (16 * 16 = 256) // bits per entry is ceil(log2(385)) = 9 where 385 is the world height
for _ in 0..256 { // so, the length of the following array is (9 * 16 * 16) / 8 = 37
packet.write_long(0)?; // height - 0 // ... idk how it came to that
packet.write_varint(37)?; // Length of the following long array
for _ in 0..37 {
packet.write_long(0)?; // THIS WORKS ONLY BECAUSE OUR HEIGHT IS 0
} }
// sending chunk data // sending chunk data
@ -117,7 +123,7 @@ pub fn send_example_chunk(client: Arc<ClientContext>, x: i32, z: i32) -> Result<
// biomes palleted container // biomes palleted container
chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format chunk_data.write_byte(0)?; // Bits Per Entry, use Single valued palette format
chunk_data.write_varint(27)?; // biome id in the registry chunk_data.write_varint(1)?; // biome id in the registry
} }
// air chunk sections // air chunk sections
@ -181,10 +187,60 @@ pub fn send_example_chunks_in_distance(
Ok(()) Ok(())
} }
pub fn send_player(
receiver: Arc<ClientContext>,
player: Arc<ClientContext>,
) -> Result<(), ServerError> {
// Отправка пакета Login
let mut packet = Packet::empty(clientbound::play::SPAWN_ENTITY);
let (x, y, z) = player.entity_info().position();
let (yaw, pitch) = player.entity_info().rotation();
let (vel_x, vel_y, vel_z) = player.entity_info().velocity();
packet.write_varint(player.entity_info().entity_id)?; // Entity ID
packet.write_uuid(&player.entity_info().uuid)?; // Entity UUID
packet.write_varint(148)?; // Entity type TODO: move to const
packet.write_double(x)?;
packet.write_double(y)?;
packet.write_double(z)?;
packet.write_byte((pitch / 360.0 * 256.0) as u8)?;
packet.write_byte((yaw / 360.0 * 256.0) as u8)?;
packet.write_byte((yaw / 360.0 * 256.0) as u8)?; // head yaw TODO: make player head yaw field
packet.write_varint(0)?;
packet.write_short(vel_x as i16)?;
packet.write_short(vel_y as i16)?;
packet.write_short(vel_z as i16)?;
receiver.write_packet(&packet)
}
pub fn get_offline_uuid(name: &str) -> Uuid {
let mut namespaces_bytes: [u8; 16] = [0; 16];
for (i, byte) in format!("OfflinePlayer:{}", &name[..2])
.as_bytes()
.iter()
.enumerate()
{
namespaces_bytes[i] = *byte;
}
let namespace = Uuid::from_bytes(namespaces_bytes);
Uuid::new_v3(&namespace, (&name[2..]).as_bytes())
}
// Отдельная функция для работы с самой игрой // Отдельная функция для работы с самой игрой
pub fn handle_play_state( pub fn handle_play_state(
client: Arc<ClientContext>, // Контекст клиента client: Arc<ClientContext>, // Контекст клиента
) -> Result<(), ServerError> { ) -> Result<(), ServerError> {
client.set_entity_info(EntityInfo::new(
client
.server
.world
.entity_id_counter
.fetch_add(1, Ordering::SeqCst),
get_offline_uuid(&client.player_info().unwrap().name), // TODO: authenticated uuid
));
thread::spawn({ thread::spawn({
let client = client.clone(); let client = client.clone();
@ -195,7 +251,7 @@ pub fn handle_play_state(
}); });
send_login(client.clone())?; 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)?; // idk why, but now you need to set y to 3 here 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 send_game_event(client.clone(), 13, 0.0)?; // 13 - Start waiting for level chunks
set_center_chunk(client.clone(), 0, 0)?; set_center_chunk(client.clone(), 0, 0)?;
@ -207,12 +263,21 @@ pub fn handle_play_state(
// sync_player_pos(client.clone(), 8.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0)?; // sync_player_pos(client.clone(), 8.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0)?;
for player in client.server.players() {
send_player(client.clone(), player.clone())?;
send_player(player.clone(), client.clone())?;
}
thread::spawn({ thread::spawn({
let client = client.clone(); let client = client.clone();
move || -> Result<(), ServerError> { move || -> Result<(), ServerError> {
while client.is_alive() { while client.is_alive() {
let mut packet = client.read_any_packet()?; let mut packet = client.read_packet(&[
serverbound::play::SET_PLAYER_POSITION,
serverbound::play::SET_PLAYER_POSITION_AND_ROTATION,
serverbound::play::SET_PLAYER_ROTATION,
])?;
match packet.id() { match packet.id() {
serverbound::play::SET_PLAYER_POSITION => { serverbound::play::SET_PLAYER_POSITION => {
@ -221,7 +286,7 @@ pub fn handle_play_state(
let z = packet.read_double()?; let z = packet.read_double()?;
let _ = packet.read_byte()?; // flags let _ = packet.read_byte()?; // flags
client.set_position((x, y, z)); client.entity_info().set_position((x, y, z));
} }
serverbound::play::SET_PLAYER_POSITION_AND_ROTATION => { serverbound::play::SET_PLAYER_POSITION_AND_ROTATION => {
let x = packet.read_double()?; let x = packet.read_double()?;
@ -231,19 +296,17 @@ pub fn handle_play_state(
let pitch = packet.read_float()?; let pitch = packet.read_float()?;
let _ = packet.read_byte()?; // flags let _ = packet.read_byte()?; // flags
client.set_position((x, y, z)); client.entity_info().set_position((x, y, z));
client.set_rotation((yaw, pitch)); client.entity_info().set_rotation((yaw, pitch));
} }
serverbound::play::SET_PLAYER_ROTATION => { serverbound::play::SET_PLAYER_ROTATION => {
let yaw = packet.read_float()?; let yaw = packet.read_float()?;
let pitch = packet.read_float()?; let pitch = packet.read_float()?;
let _ = packet.read_byte()?; // flags let _ = packet.read_byte()?; // flags
client.set_rotation((yaw, pitch)); client.entity_info().set_rotation((yaw, pitch));
}
_ => {
client.push_packet_back(packet);
} }
_ => {}
} }
} }
@ -261,7 +324,7 @@ pub fn handle_play_state(
if ticks_alive % 20 == 0 { if ticks_alive % 20 == 0 {
// 1 sec timer // 1 sec timer
let (x, _, z) = client.position(); let (x, _, z) = client.entity_info().position();
let (chunk_x, chunk_z) = ((x / 16.0) as i64, (z / 16.0) as i64); let (chunk_x, chunk_z) = ((x / 16.0) as i64, (z / 16.0) as i64);
let (chunk_x, chunk_z) = (chunk_x as i32, chunk_z as i32); let (chunk_x, chunk_z) = (chunk_x as i32, chunk_z as i32);

View File

@ -29,9 +29,7 @@ pub struct ClientContext {
packet_buffer: Mutex<VecDeque<Packet>>, packet_buffer: Mutex<VecDeque<Packet>>,
read_loop: AtomicBool, read_loop: AtomicBool,
is_alive: AtomicBool, is_alive: AtomicBool,
position: RwLock<(f64, f64, f64)>, entity_info: RwLock<Option<Arc<EntityInfo>>>,
velocity: RwLock<(f64, f64, f64)>,
rotation: RwLock<(f32, f32)>,
} }
// Реализуем сравнение через адрес // Реализуем сравнение через адрес
@ -63,9 +61,7 @@ impl ClientContext {
packet_buffer: Mutex::new(VecDeque::new()), packet_buffer: Mutex::new(VecDeque::new()),
read_loop: AtomicBool::new(false), read_loop: AtomicBool::new(false),
is_alive: AtomicBool::new(true), is_alive: AtomicBool::new(true),
position: RwLock::new((0.0, 0.0, 0.0)), entity_info: RwLock::new(None),
velocity: RwLock::new((0.0, 0.0, 0.0)),
rotation: RwLock::new((0.0, 0.0)),
} }
} }
@ -81,6 +77,10 @@ impl ClientContext {
*self.player_info.write().unwrap() = Some(player_info); *self.player_info.write().unwrap() = Some(player_info);
} }
pub fn set_entity_info(self: &Arc<Self>, entity_info: EntityInfo) {
*self.entity_info.write().unwrap() = Some(Arc::new(entity_info));
}
pub fn set_state(self: &Arc<Self>, state: ConnectionState) -> Result<(), ServerError> { pub fn set_state(self: &Arc<Self>, state: ConnectionState) -> Result<(), ServerError> {
*self.state.write().unwrap() = state.clone(); *self.state.write().unwrap() = state.clone();
@ -107,34 +107,14 @@ impl ClientContext {
self.player_info.read().unwrap().clone() self.player_info.read().unwrap().clone()
} }
pub fn entity_info(self: &Arc<Self>) -> Arc<EntityInfo> {
self.entity_info.read().unwrap().clone().unwrap()
}
pub fn state(self: &Arc<Self>) -> ConnectionState { pub fn state(self: &Arc<Self>) -> ConnectionState {
self.state.read().unwrap().clone() self.state.read().unwrap().clone()
} }
pub fn set_position(self: &Arc<Self>, position: (f64, f64, f64)) {
*self.position.write().unwrap() = position;
}
pub fn set_velocity(self: &Arc<Self>, velocity: (f64, f64, f64)) {
*self.velocity.write().unwrap() = velocity;
}
pub fn set_rotation(self: &Arc<Self>, rotation: (f32, f32)) {
*self.rotation.write().unwrap() = rotation;
}
pub fn position(self: &Arc<Self>) -> (f64, f64, f64) {
self.position.read().unwrap().clone()
}
pub fn velocity(self: &Arc<Self>) -> (f64, f64, f64) {
self.velocity.read().unwrap().clone()
}
pub fn rotation(self: &Arc<Self>) -> (f32, f32) {
self.rotation.read().unwrap().clone()
}
pub fn write_packet(self: &Arc<Self>, packet: &Packet) -> Result<(), ServerError> { pub fn write_packet(self: &Arc<Self>, packet: &Packet) -> Result<(), ServerError> {
let state = self.state(); let state = self.state();
let mut packet = packet.clone(); let mut packet = packet.clone();
@ -304,3 +284,47 @@ pub struct PlayerInfo {
pub name: String, pub name: String,
pub uuid: Uuid, pub uuid: Uuid,
} }
pub struct EntityInfo {
pub entity_id: i32,
pub uuid: Uuid,
position: RwLock<(f64, f64, f64)>,
velocity: RwLock<(f64, f64, f64)>,
rotation: RwLock<(f32, f32)>,
}
impl EntityInfo {
pub fn new(entity_id: i32, uuid: Uuid) -> EntityInfo {
EntityInfo {
entity_id,
uuid,
position: RwLock::new((0.0, 0.0, 0.0)),
velocity: RwLock::new((0.0, 0.0, 0.0)),
rotation: RwLock::new((0.0, 0.0)),
}
}
pub fn set_position(self: &Arc<Self>, position: (f64, f64, f64)) {
*self.position.write().unwrap() = position;
}
pub fn set_velocity(self: &Arc<Self>, velocity: (f64, f64, f64)) {
*self.velocity.write().unwrap() = velocity;
}
pub fn set_rotation(self: &Arc<Self>, rotation: (f32, f32)) {
*self.rotation.write().unwrap() = rotation;
}
pub fn position(self: &Arc<Self>) -> (f64, f64, f64) {
self.position.read().unwrap().clone()
}
pub fn velocity(self: &Arc<Self>) -> (f64, f64, f64) {
self.velocity.read().unwrap().clone()
}
pub fn rotation(self: &Arc<Self>) -> (f32, f32) {
self.rotation.read().unwrap().clone()
}
}