1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

add gametick event and find_one_entity

This commit is contained in:
mat 2022-06-20 01:19:59 -05:00
parent 438d633b83
commit efd8749573
6 changed files with 98 additions and 11 deletions

1
Cargo.lock generated
View file

@ -235,6 +235,7 @@ dependencies = [
"azalea-core", "azalea-core",
"azalea-protocol", "azalea-protocol",
"tokio", "tokio",
"uuid",
] ]
[[package]] [[package]]

View file

@ -26,7 +26,10 @@ use std::{
fmt::Debug, fmt::Debug,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::{
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
time::{self, MissedTickBehavior},
};
#[derive(Default)] #[derive(Default)]
pub struct ClientState { pub struct ClientState {
@ -38,6 +41,8 @@ pub struct ClientState {
pub enum Event { pub enum Event {
Login, Login,
Chat(ChatPacket), Chat(ChatPacket),
/// A game tick, happens 20 times per second.
GameTick,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -153,20 +158,22 @@ impl Client {
conn: conn.clone(), conn: conn.clone(),
state: Arc::new(Mutex::new(ClientState::default())), state: Arc::new(Mutex::new(ClientState::default())),
}; };
// let client = Arc::new(Mutex::new(client));
// let weak_client = Arc::<_>::downgrade(&client);
// just start up the game loop and we're ready! // just start up the game loop and we're ready!
// tokio::spawn(Self::game_loop(conn, tx, handler, state))
let game_loop_state = client.state.clone(); let game_loop_state = client.state.clone();
tokio::spawn(Self::game_loop(conn, tx, game_loop_state)); tokio::spawn(Self::protocol_loop(
conn.clone(),
tx.clone(),
game_loop_state.clone(),
));
tokio::spawn(Self::game_tick_loop(conn, tx, game_loop_state));
Ok(client) Ok(client)
} }
async fn game_loop( async fn protocol_loop(
conn: Arc<tokio::sync::Mutex<GameConnection>>, conn: Arc<tokio::sync::Mutex<GameConnection>>,
tx: UnboundedSender<Event>, tx: UnboundedSender<Event>,
state: Arc<Mutex<ClientState>>, state: Arc<Mutex<ClientState>>,
@ -487,6 +494,33 @@ impl Client {
self.event_receiver.recv().await self.event_receiver.recv().await
} }
/// Runs game_tick every 50 milliseconds.
async fn game_tick_loop(
conn: Arc<tokio::sync::Mutex<GameConnection>>,
tx: UnboundedSender<Event>,
state: Arc<Mutex<ClientState>>,
) {
let mut game_tick_interval = time::interval(time::Duration::from_millis(50));
// TODO: Minecraft bursts up to 10 ticks and then skips, we should too
game_tick_interval.set_missed_tick_behavior(time::MissedTickBehavior::Burst);
loop {
game_tick_interval.tick().await;
Self::game_tick(&conn, &tx, &state).await;
}
}
/// Runs every 50 milliseconds.
async fn game_tick(
conn: &Arc<tokio::sync::Mutex<GameConnection>>,
tx: &UnboundedSender<Event>,
state: &Arc<Mutex<ClientState>>,
) {
if state.lock().unwrap().world.is_none() {
return;
}
tx.send(Event::GameTick).unwrap();
}
/// Gets the `World` the client is in. /// Gets the `World` the client is in.
/// ///
/// This is basically a shortcut for `let world = client.state.lock().unwrap().world.as_ref().unwrap()`. /// This is basically a shortcut for `let world = client.state.lock().unwrap().world.as_ref().unwrap()`.

View file

@ -79,6 +79,40 @@ impl EntityStorage {
.or_default() .or_default()
.insert(entity_id); .insert(entity_id);
} }
/// Get an iterator over all entities.
#[inline]
pub fn entities(&self) -> std::collections::hash_map::Values<'_, u32, Entity> {
self.by_id.values()
}
pub fn find_one_entity<F>(&self, mut f: F) -> Option<&Entity>
where
F: FnMut(&Entity) -> bool,
{
for entity in self.entities() {
if f(entity) {
return Some(entity);
}
}
None
}
pub fn find_one_entity_in_chunk<F>(&self, chunk: &ChunkPos, mut f: F) -> Option<&Entity>
where
F: FnMut(&Entity) -> bool,
{
if let Some(entities) = self.by_chunk.get(chunk) {
for entity_id in entities {
if let Some(entity) = self.by_id.get(entity_id) {
if f(entity) {
return Some(entity);
}
}
}
}
None
}
} }
impl Default for EntityStorage { impl Default for EntityStorage {

View file

@ -87,6 +87,19 @@ impl World {
pub fn entity_by_id(&self, id: u32) -> Option<&Entity> { pub fn entity_by_id(&self, id: u32) -> Option<&Entity> {
self.entity_storage.get_by_id(id) self.entity_storage.get_by_id(id)
} }
/// Get an iterator over all entities.
#[inline]
pub fn entities(&self) -> std::collections::hash_map::Values<'_, u32, Entity> {
self.entity_storage.entities()
}
pub fn find_one_entity<F>(&self, mut f: F) -> Option<&Entity>
where
F: FnMut(&Entity) -> bool,
{
self.entity_storage.find_one_entity(|entity| f(entity))
}
} }
impl Index<&ChunkPos> for World { impl Index<&ChunkPos> for World {

View file

@ -10,3 +10,4 @@ azalea-client = {path = "../azalea-client"}
azalea-core = {path = "../azalea-core"} azalea-core = {path = "../azalea-core"}
azalea-protocol = {path = "../azalea-protocol"} azalea-protocol = {path = "../azalea-protocol"}
tokio = "^1.19.2" tokio = "^1.19.2"
uuid = "^1.1.2"

View file

@ -20,12 +20,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match e { match e {
// TODO: have a "loaded" or "ready" event that fires when all chunks are loaded // TODO: have a "loaded" or "ready" event that fires when all chunks are loaded
Event::Login => {} Event::Login => {}
Event::Chat(_p) => { Event::GameTick => {
let world = client.world(); let world = client.world();
let b = world.get_block_state(&BlockPos::new(0, 0, 0)).unwrap(); if let Some(b) = world.find_one_entity(|e| {
// let world = state.world.as_ref().unwrap(); e.uuid == uuid::uuid!("6536bfed-8695-48fd-83a1-ecd24cf2a0fd")
// world. }) {
println!("{:?}", b); // let world = state.world.as_ref().unwrap();
// world.
println!("{:?}", b);
}
// world.get_block_state(state.player.entity.pos); // world.get_block_state(state.player.entity.pos);
// println!("{}", p.message.to_ansi(None)); // println!("{}", p.message.to_ansi(None));
// if p.message.to_ansi(None) == "<py5> ok" { // if p.message.to_ansi(None) == "<py5> ok" {
@ -35,6 +38,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// println!("block state: {:?}", c); // println!("block state: {:?}", c);
// } // }
} }
_ => {}
} }
} }