mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
start figuring out how functions in Client will work
generally just lifetimes being annoying but i think i can get it all to work
This commit is contained in:
parent
50f6578794
commit
21c08013b7
8 changed files with 123 additions and 141 deletions
|
@ -1,6 +1,5 @@
|
|||
//! Implementations of chat-related features.
|
||||
|
||||
use crate::LocalPlayer;
|
||||
use azalea_chat::FormattedText;
|
||||
use azalea_protocol::packets::game::{
|
||||
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
|
@ -13,6 +12,8 @@ use std::{
|
|||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use crate::client::Client;
|
||||
|
||||
/// A chat packet, either a system message or a chat message.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ChatPacket {
|
||||
|
@ -89,7 +90,7 @@ impl ChatPacket {
|
|||
}
|
||||
}
|
||||
|
||||
impl LocalPlayer {
|
||||
impl Client {
|
||||
/// Sends chat message to the server. This only sends the chat packet and
|
||||
/// not the command packet. The [`Client::chat`] function handles checking
|
||||
/// whether the message is a command and using the proper packet for you,
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
pub use crate::chat::ChatPacket;
|
||||
use crate::{
|
||||
local_player::LocalPlayer,
|
||||
movement::{send_position, WalkDirection},
|
||||
local_player::{send_tick_event, update_in_loaded_chunk, LocalPlayer},
|
||||
movement::send_position,
|
||||
packet_handling,
|
||||
plugins::PluginStates,
|
||||
Account, PlayerInfo,
|
||||
};
|
||||
|
||||
use azalea_auth::{game_profile::GameProfile, sessionserver::SessionServerError};
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
use azalea_protocol::{
|
||||
connect::{Connection, ConnectionError, ReadConnection, WriteConnection},
|
||||
connect::{Connection, ConnectionError},
|
||||
packets::{
|
||||
game::{
|
||||
clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
|
||||
serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket,
|
||||
serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
ClientboundGamePacket, ServerboundGamePacket,
|
||||
},
|
||||
handshake::{
|
||||
|
@ -32,45 +27,31 @@ use azalea_protocol::{
|
|||
},
|
||||
ConnectionProtocol, PROTOCOL_VERSION,
|
||||
},
|
||||
read::ReadPacketError,
|
||||
resolver, ServerAddress,
|
||||
};
|
||||
use azalea_world::{
|
||||
entity::{
|
||||
self,
|
||||
metadata::{self, PlayerMetadataBundle},
|
||||
Entity,
|
||||
},
|
||||
EntityInfos, PartialChunkStorage, PartialWorld, World, WorldContainer,
|
||||
};
|
||||
use azalea_world::{entity::Entity, EntityInfos, PartialWorld, World, WorldContainer};
|
||||
use bevy_app::App;
|
||||
use bevy_ecs::{
|
||||
prelude::Component,
|
||||
query::{QueryState, WorldQuery},
|
||||
schedule::{IntoSystemDescriptor, Schedule, Stage, StageLabel, SystemStage},
|
||||
system::{Query, SystemState},
|
||||
schedule::{IntoSystemDescriptor, Schedule, Stage, SystemSet},
|
||||
};
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use iyes_loopless::prelude::*;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use log::{debug, error, warn};
|
||||
use parking_lot::{Mutex, MutexGuard, RwLock};
|
||||
use std::{
|
||||
any,
|
||||
backtrace::Backtrace,
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
io::{self, Cursor},
|
||||
ops::DerefMut,
|
||||
io::{self},
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use tokio::{
|
||||
sync::mpsc::{self, Receiver, Sender},
|
||||
sync::mpsc::{self, Receiver},
|
||||
task::JoinHandle,
|
||||
time::{self},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub type ClientInformation = ServerboundClientInformationPacket;
|
||||
|
||||
|
@ -202,7 +183,7 @@ impl Client {
|
|||
pub async fn join(
|
||||
account: &Account,
|
||||
address: impl TryInto<ServerAddress>,
|
||||
) -> Result<(Self, Receiver<Event>), JoinError> {
|
||||
) -> Result<(Self, mpsc::UnboundedReceiver<Event>), JoinError> {
|
||||
let address: ServerAddress = address.try_into().map_err(|_| JoinError::InvalidAddress)?;
|
||||
let resolved_address = resolver::resolve_address(&address).await?;
|
||||
|
||||
|
@ -213,8 +194,8 @@ impl Client {
|
|||
// The buffer has to be 1 to avoid a bug where if it lags events are
|
||||
// received a bit later instead of the instant they were fired.
|
||||
// That bug especially causes issues with the pathfinder.
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
tx.send(Event::Init).await.expect("Failed to send event");
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
tx.send(Event::Init).unwrap();
|
||||
|
||||
// An event that causes the schedule to run. This is only used internally.
|
||||
let (run_schedule_sender, run_schedule_receiver) = mpsc::unbounded_channel();
|
||||
|
@ -228,7 +209,7 @@ impl Client {
|
|||
let entity = entity_mut.id();
|
||||
|
||||
// we got the GameConnection, so the server is now connected :)
|
||||
let client = Client::new(game_profile.clone(), None, entity, ecs_lock);
|
||||
let client = Client::new(game_profile.clone(), None, entity, ecs_lock.clone());
|
||||
|
||||
let world = client.world();
|
||||
|
||||
|
@ -247,7 +228,7 @@ impl Client {
|
|||
run_schedule_sender,
|
||||
};
|
||||
|
||||
tokio::spawn(packet_receiver.read_task(read_conn));
|
||||
tokio::spawn(packet_receiver.clone().read_task(read_conn));
|
||||
|
||||
ecs.entity_mut(entity)
|
||||
.insert((local_player, packet_receiver));
|
||||
|
@ -377,12 +358,19 @@ impl Client {
|
|||
|
||||
/// Write a packet directly to the server.
|
||||
pub async fn write_packet(&self, packet: ServerboundGamePacket) -> Result<(), std::io::Error> {
|
||||
self.local_player_mut().write_packet_async(packet).await
|
||||
self.local_player_mut(&self.ecs.lock())
|
||||
.write_packet_async(packet)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Disconnect this client from the server, ending all tasks.
|
||||
pub async fn disconnect(&self) -> Result<(), std::io::Error> {
|
||||
if let Err(e) = self.local_player_mut().write_conn.shutdown().await {
|
||||
if let Err(e) = self
|
||||
.local_player_mut(&self.ecs.lock())
|
||||
.write_conn
|
||||
.shutdown()
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
"Error shutting down connection, but it might be fine: {}",
|
||||
e
|
||||
|
@ -395,11 +383,14 @@ impl Client {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn local_player(&self) -> &LocalPlayer {
|
||||
self.query::<&LocalPlayer>()
|
||||
pub fn local_player(&self, ecs: &bevy_ecs::world::World) -> &LocalPlayer {
|
||||
self.query::<&LocalPlayer>(ecs)
|
||||
}
|
||||
pub fn local_player_mut(&self) -> &mut LocalPlayer {
|
||||
self.query::<&mut LocalPlayer>().into_inner()
|
||||
pub fn local_player_mut(
|
||||
&self,
|
||||
ecs: &bevy_ecs::world::World,
|
||||
) -> bevy_ecs::world::Mut<LocalPlayer> {
|
||||
self.query::<&mut LocalPlayer>(ecs)
|
||||
}
|
||||
|
||||
/// Get a reference to our (potentially shared) world.
|
||||
|
@ -410,25 +401,18 @@ impl Client {
|
|||
/// superset of the client's world.
|
||||
pub fn world(&self) -> Arc<RwLock<World>> {
|
||||
let world_name = self
|
||||
.local_player()
|
||||
.local_player(&self.ecs.lock())
|
||||
.world_name
|
||||
.as_ref()
|
||||
.expect("World name must be known if we're doing Client::world");
|
||||
let world_container = self.world_container.read();
|
||||
world_container.get(&world_name).unwrap()
|
||||
}
|
||||
|
||||
/// Query data of our player's entity.
|
||||
pub fn query<'w, 's, Q: WorldQuery>(&'w self) -> <Q as WorldQuery>::Item<'_> {
|
||||
let mut ecs = &mut self.ecs.lock();
|
||||
QueryState::<Q>::new(ecs)
|
||||
.get_mut(ecs, self.entity)
|
||||
.expect("Player entity should always exist when being queried")
|
||||
}
|
||||
|
||||
/// Returns whether we have a received the login packet yet.
|
||||
pub fn logged_in(&self) -> bool {
|
||||
// the login packet tells us the world name
|
||||
self.local_player().world_name.is_some()
|
||||
self.local_player(&self.ecs.lock()).world_name.is_some()
|
||||
}
|
||||
|
||||
/// Tell the server we changed our game options (i.e. render distance, main
|
||||
|
@ -451,11 +435,15 @@ impl Client {
|
|||
client_information: ServerboundClientInformationPacket,
|
||||
) -> Result<(), std::io::Error> {
|
||||
{
|
||||
self.local_player_mut().client_information = client_information;
|
||||
self.local_player_mut(&self.ecs.lock()).client_information = client_information;
|
||||
}
|
||||
|
||||
if self.logged_in() {
|
||||
let client_information_packet = self.local_player().client_information.clone().get();
|
||||
let client_information_packet = self
|
||||
.local_player(&self.ecs.lock())
|
||||
.client_information
|
||||
.clone()
|
||||
.get();
|
||||
log::debug!(
|
||||
"Sending client information (already logged in): {:?}",
|
||||
client_information_packet
|
||||
|
@ -465,6 +453,16 @@ impl Client {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Query data of our player's entity.
|
||||
pub fn query<'w, Q: WorldQuery>(
|
||||
&self,
|
||||
ecs: &'w bevy_ecs::world::World,
|
||||
) -> <Q as WorldQuery>::Item<'w> {
|
||||
ecs.query::<Q>()
|
||||
.get_mut(&mut ecs, self.entity)
|
||||
.expect("Player entity should always exist when being queried")
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the protocol and game tick loop.
|
||||
|
@ -477,18 +475,20 @@ pub async fn start_ecs(
|
|||
// you might be able to just drop the lock or put it in its own scope to fix
|
||||
|
||||
let mut app = App::new();
|
||||
|
||||
app.add_fixed_timestep(Duration::from_millis(50), "tick");
|
||||
|
||||
app.add_fixed_timestep_system("tick", 0, send_position);
|
||||
// .add_system(LocalPlayer::update_in_loaded_chunk)
|
||||
// .add_system(send_position)
|
||||
// .add_system(LocalPlayer::ai_step);
|
||||
|
||||
app.add_system(packet_handling::handle_packets.label("handle_packets"));
|
||||
|
||||
// should happen last
|
||||
app.add_system(packet_handling::clear_packets.after("handle_packets"));
|
||||
app.add_fixed_timestep(Duration::from_millis(50), "tick")
|
||||
.add_fixed_timestep_system_set(
|
||||
"tick",
|
||||
0,
|
||||
SystemSet::new()
|
||||
.with_system(send_position)
|
||||
.with_system(update_in_loaded_chunk)
|
||||
.with_system(send_position)
|
||||
.with_system(LocalPlayer::ai_step)
|
||||
.with_system(send_tick_event),
|
||||
)
|
||||
.add_system(packet_handling::handle_packets.label("handle_packets"))
|
||||
// should happen last
|
||||
.add_system(packet_handling::clear_packets.after("handle_packets"));
|
||||
|
||||
// all resources should have been added by now so we can take the ecs from the
|
||||
// app
|
||||
|
|
|
@ -22,7 +22,7 @@ mod player;
|
|||
mod plugins;
|
||||
|
||||
pub use account::Account;
|
||||
pub use client::{ChatPacket, ClientInformation, Event, JoinError, LocalPlayer, PhysicsState};
|
||||
pub use client::{ChatPacket, ClientInformation, Event, JoinError};
|
||||
pub use movement::{SprintDirection, WalkDirection};
|
||||
pub use player::PlayerInfo;
|
||||
pub use plugins::{Plugin, PluginState, PluginStates, Plugins};
|
||||
|
|
|
@ -1,30 +1,19 @@
|
|||
use std::{collections::HashMap, io, sync::Arc};
|
||||
|
||||
use azalea_auth::game_profile::GameProfile;
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
use azalea_protocol::{
|
||||
connect::{Connection, ReadConnection, WriteConnection},
|
||||
packets::game::{
|
||||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket, ClientboundGamePacket,
|
||||
ServerboundGamePacket,
|
||||
},
|
||||
};
|
||||
use azalea_core::{ChunkPos, ResourceLocation};
|
||||
use azalea_protocol::{connect::WriteConnection, packets::game::ServerboundGamePacket};
|
||||
use azalea_world::{
|
||||
entity::{self, metadata::PlayerMetadataBundle, Entity, EntityId},
|
||||
EntityInfos, PartialWorld, World, WorldContainer,
|
||||
entity::{self, Entity},
|
||||
EntityInfos, PartialWorld, World,
|
||||
};
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
event::EventReader,
|
||||
system::{Query, Res, ResMut},
|
||||
};
|
||||
use log::debug;
|
||||
use bevy_ecs::{component::Component, system::Query};
|
||||
use parking_lot::RwLock;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{ChatPacket, ClientInformation, Event, PlayerInfo, WalkDirection};
|
||||
use crate::{ClientInformation, Event, PlayerInfo, WalkDirection};
|
||||
|
||||
/// A player that you control that is currently in a Minecraft server.
|
||||
#[derive(Component)]
|
||||
|
@ -44,7 +33,7 @@ pub struct LocalPlayer {
|
|||
pub world: Arc<RwLock<World>>,
|
||||
pub world_name: Option<ResourceLocation>,
|
||||
|
||||
pub tx: mpsc::Sender<Event>,
|
||||
pub tx: mpsc::UnboundedSender<Event>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -78,7 +67,7 @@ impl LocalPlayer {
|
|||
write_conn: WriteConnection<ServerboundGamePacket>,
|
||||
world: Arc<RwLock<World>>,
|
||||
entity_infos: &mut EntityInfos,
|
||||
tx: mpsc::Sender<Event>,
|
||||
tx: mpsc::UnboundedSender<Event>,
|
||||
) -> Self {
|
||||
let client_information = ClientInformation::default();
|
||||
|
||||
|
@ -117,40 +106,35 @@ impl LocalPlayer {
|
|||
pub fn write_packet(&mut self, packet: ServerboundGamePacket) {
|
||||
tokio::spawn(self.write_packet_async(packet));
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the [`LocalPlayerInLoadedChunk`] component for all
|
||||
/// [`LocalPlayer`]s.
|
||||
fn update_in_loaded_chunk(
|
||||
mut commands: bevy_ecs::system::Commands,
|
||||
query: Query<(entity::EcsEntityId, &LocalPlayer, &entity::Position)>,
|
||||
) {
|
||||
for (ecs_entity_id, local_player, position) in &query {
|
||||
let player_chunk_pos = ChunkPos::from(position);
|
||||
let in_loaded_chunk = local_player
|
||||
.world
|
||||
.read()
|
||||
.get_chunk(&player_chunk_pos)
|
||||
.is_some();
|
||||
if in_loaded_chunk {
|
||||
commands
|
||||
.entity(ecs_entity_id)
|
||||
.insert(LocalPlayerInLoadedChunk);
|
||||
} else {
|
||||
commands
|
||||
.entity(ecs_entity_id)
|
||||
.remove::<LocalPlayerInLoadedChunk>();
|
||||
}
|
||||
}
|
||||
pub fn send_tick_event(query: Query<&LocalPlayer>) {
|
||||
for local_player in &query {
|
||||
local_player.tx.send(Event::Tick).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn send_event(event: Event, tx: &mpsc::Sender<Event>) {
|
||||
tokio::spawn(tx.send(event));
|
||||
}
|
||||
|
||||
fn send_tick_event(query: Query<&LocalPlayer>) {
|
||||
for local_player in &query {
|
||||
let tx = local_player.tx.clone();
|
||||
Self::send_event(Event::Tick, &tx);
|
||||
/// Update the [`LocalPlayerInLoadedChunk`] component for all [`LocalPlayer`]s.
|
||||
pub fn update_in_loaded_chunk(
|
||||
mut commands: bevy_ecs::system::Commands,
|
||||
query: Query<(Entity, &LocalPlayer, &entity::Position)>,
|
||||
) {
|
||||
for (ecs_entity_id, local_player, position) in &query {
|
||||
let player_chunk_pos = ChunkPos::from(position);
|
||||
let in_loaded_chunk = local_player
|
||||
.world
|
||||
.read()
|
||||
.chunks
|
||||
.get(&player_chunk_pos)
|
||||
.is_some();
|
||||
if in_loaded_chunk {
|
||||
commands
|
||||
.entity(ecs_entity_id)
|
||||
.insert(LocalPlayerInLoadedChunk);
|
||||
} else {
|
||||
commands
|
||||
.entity(ecs_entity_id)
|
||||
.remove::<LocalPlayerInLoadedChunk>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::client::Client;
|
||||
use crate::local_player::{LocalPlayer, LocalPlayerInLoadedChunk, PhysicsState};
|
||||
use azalea_core::Vec3;
|
||||
use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket;
|
||||
use azalea_protocol::packets::game::{
|
||||
serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket,
|
||||
|
@ -39,13 +38,15 @@ impl Client {
|
|||
/// If you're making a realistic client, calling this function every tick is
|
||||
/// recommended.
|
||||
pub fn set_jumping(&mut self, jumping: bool) {
|
||||
let physics = self.query::<&mut entity::Physics>();
|
||||
let ecs = self.ecs.lock();
|
||||
let mut physics = self.query::<&mut entity::Physics>(&ecs).into_inner();
|
||||
physics.jumping = jumping;
|
||||
}
|
||||
|
||||
/// Returns whether the player will try to jump next tick.
|
||||
pub fn jumping(&self) -> bool {
|
||||
let physics = self.query::<&mut entity::Physics>();
|
||||
let ecs = self.ecs.lock();
|
||||
let physics = self.query::<&mut entity::Physics>(&ecs).into_inner();
|
||||
physics.jumping
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,8 @@ impl Client {
|
|||
/// f3 screen.
|
||||
/// `y_rot` goes from -180 to 180, and `x_rot` goes from -90 to 90.
|
||||
pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) {
|
||||
let mut physics = self.query::<&mut entity::Physics>();
|
||||
let ecs = self.ecs.lock();
|
||||
let mut physics = self.query::<&mut entity::Physics>(&ecs);
|
||||
|
||||
entity::set_rotation(&mut physics, y_rot, x_rot);
|
||||
}
|
||||
|
@ -65,22 +67,19 @@ pub(crate) fn send_position(
|
|||
(
|
||||
Entity,
|
||||
&MinecraftEntityId,
|
||||
&LocalPlayer,
|
||||
&mut LocalPlayer,
|
||||
&entity::Position,
|
||||
&entity::LastSentPosition,
|
||||
&mut entity::LastSentPosition,
|
||||
&mut entity::Physics,
|
||||
&entity::metadata::Sprinting,
|
||||
),
|
||||
&LocalPlayerInLoadedChunk,
|
||||
>,
|
||||
) {
|
||||
for (entity, id, local_player, position, last_sent_position, physics, sprinting) in &query {
|
||||
local_player.send_sprinting_if_needed(
|
||||
entity.into(),
|
||||
id,
|
||||
sprinting,
|
||||
&mut local_player.physics_state,
|
||||
);
|
||||
for (entity, id, mut local_player, position, mut last_sent_position, mut physics, sprinting) in
|
||||
query.iter_mut()
|
||||
{
|
||||
local_player.send_sprinting_if_needed(entity.into(), id, sprinting);
|
||||
|
||||
let packet = {
|
||||
// TODO: the camera being able to be controlled by other entities isn't
|
||||
|
@ -173,9 +172,8 @@ impl LocalPlayer {
|
|||
entity: Entity,
|
||||
id: &MinecraftEntityId,
|
||||
sprinting: &entity::metadata::Sprinting,
|
||||
physics_state: &mut PhysicsState,
|
||||
) {
|
||||
let was_sprinting = physics_state.was_sprinting;
|
||||
let was_sprinting = self.physics_state.was_sprinting;
|
||||
if **sprinting != was_sprinting {
|
||||
let sprinting_action = if **sprinting {
|
||||
azalea_protocol::packets::game::serverbound_player_command_packet::Action::StartSprinting
|
||||
|
@ -190,14 +188,14 @@ impl LocalPlayer {
|
|||
}
|
||||
.get(),
|
||||
);
|
||||
physics_state.was_sprinting = **sprinting;
|
||||
self.physics_state.was_sprinting = **sprinting;
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes the bot do one physics tick. Note that this is already handled
|
||||
/// automatically by the client.
|
||||
pub fn ai_step(
|
||||
query: Query<
|
||||
mut query: Query<
|
||||
(
|
||||
Entity,
|
||||
&mut LocalPlayer,
|
||||
|
@ -216,7 +214,7 @@ impl LocalPlayer {
|
|||
mut position,
|
||||
mut sprinting,
|
||||
mut attributes,
|
||||
) in &mut query
|
||||
) in query.iter_mut()
|
||||
{
|
||||
let physics_state = &mut local_player.physics_state;
|
||||
|
||||
|
|
|
@ -598,7 +598,7 @@ pub fn handle_packet(entity: Entity, packet: &ClientboundGamePacket) {
|
|||
|
||||
/// A system that clears all packets in the clientbound packet events.
|
||||
pub fn clear_packets(mut query: Query<&mut PacketReceiver>) {
|
||||
for mut packets in query.iter_mut() {
|
||||
for packets in query.iter_mut() {
|
||||
packets.packets.lock().clear();
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ pub fn clear_packets(mut query: Query<&mut PacketReceiver>) {
|
|||
impl PacketReceiver {
|
||||
/// Loop that reads from the connection and adds the packets to the queue +
|
||||
/// runs the schedule.
|
||||
pub async fn read_task(&self, mut read_conn: ReadConnection<ClientboundGamePacket>) {
|
||||
pub async fn read_task(self, mut read_conn: ReadConnection<ClientboundGamePacket>) {
|
||||
while let Ok(packet) = read_conn.read().await {
|
||||
self.packets.lock().push(packet);
|
||||
// tell the client to run all the systems
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use azalea_auth::game_profile::GameProfile;
|
||||
use azalea_chat::FormattedText;
|
||||
use azalea_core::GameType;
|
||||
use azalea_world::PartialWorld;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// A player in the tab list.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Event, LocalPlayer};
|
||||
use crate::{client::Client, Event};
|
||||
use async_trait::async_trait;
|
||||
use nohash_hasher::NoHashHasher;
|
||||
use std::{
|
||||
|
@ -81,7 +81,7 @@ impl IntoIterator for PluginStates {
|
|||
/// fields must be atomic. Unique `PluginState`s are built from [`Plugin`]s.
|
||||
#[async_trait]
|
||||
pub trait PluginState: Send + Sync + PluginStateClone + Any + 'static {
|
||||
async fn handle(self: Box<Self>, event: Event, bot: LocalPlayer);
|
||||
async fn handle(self: Box<Self>, event: Event, bot: Client);
|
||||
}
|
||||
|
||||
/// Plugins can keep their own personal state, listen to [`Event`]s, and add
|
||||
|
|
Loading…
Add table
Reference in a new issue