mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
fix Swarm::into_iter, handler functions, DisconnectEvent, and add some more docs
This commit is contained in:
parent
b1cd39615e
commit
b617a96c72
5 changed files with 81 additions and 31 deletions
|
@ -8,4 +8,4 @@ pub mod style;
|
|||
pub mod text_component;
|
||||
pub mod translatable_component;
|
||||
|
||||
pub use component::{FormattedText, DEFAULT_STYLE};
|
||||
pub use component::{DEFAULT_STYLE, FormattedText};
|
||||
|
|
|
@ -16,8 +16,12 @@ impl Plugin for DisconnectPlugin {
|
|||
PostUpdate,
|
||||
(
|
||||
update_read_packets_task_running_component,
|
||||
disconnect_on_connection_dead,
|
||||
remove_components_from_disconnected_players,
|
||||
// this happens after `remove_components_from_disconnected_players` since that
|
||||
// system removes `IsConnectionAlive`, which ensures that
|
||||
// `DisconnectEvent` won't get called again from
|
||||
// `disconnect_on_connection_dead`
|
||||
disconnect_on_connection_dead,
|
||||
)
|
||||
.chain(),
|
||||
);
|
||||
|
@ -64,7 +68,9 @@ pub fn remove_components_from_disconnected_players(
|
|||
.remove::<PlayerMetadataBundle>()
|
||||
.remove::<InLoadedChunk>()
|
||||
// this makes it close the tcp connection
|
||||
.remove::<RawConnection>();
|
||||
.remove::<RawConnection>()
|
||||
// this makes it not send DisconnectEvent again
|
||||
.remove::<IsConnectionAlive>();
|
||||
// note that we don't remove the client from the ECS, so if they decide
|
||||
// to reconnect they'll keep their state
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ async fn handle(bot: Client, event: azalea::Event, state: State) -> anyhow::Resu
|
|||
}
|
||||
async fn swarm_handle(_swarm: Swarm, event: SwarmEvent, _state: SwarmState) -> anyhow::Result<()> {
|
||||
match &event {
|
||||
SwarmEvent::Disconnect(account, join_opts) => {
|
||||
SwarmEvent::Disconnect(account, _) => {
|
||||
println!("bot got kicked! {}", account.username);
|
||||
}
|
||||
SwarmEvent::Chat(chat) => {
|
||||
|
|
|
@ -124,7 +124,12 @@ impl ClientBuilder<NoState, ()> {
|
|||
/// Set the function that's called every time a bot receives an [`Event`].
|
||||
/// This is the way to handle normal per-bot events.
|
||||
///
|
||||
/// Currently you can have up to one client handler.
|
||||
/// Currently, you can have up to one client handler.
|
||||
///
|
||||
/// Note that if you're creating clients directly from the ECS using
|
||||
/// [`StartJoinServerEvent`] and the client wasn't already in the ECS, then
|
||||
/// the handler function won't be called for that client. This shouldn't be
|
||||
/// a concern for most bots, though.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea::prelude::*;
|
||||
|
@ -137,6 +142,8 @@ impl ClientBuilder<NoState, ()> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`StartJoinServerEvent`]: azalea_client::join::StartJoinServerEvent
|
||||
#[must_use]
|
||||
pub fn set_handler<S, Fut, R>(self, handler: HandleFn<S, Fut>) -> ClientBuilder<S, R>
|
||||
where
|
||||
|
|
|
@ -21,6 +21,7 @@ use azalea_client::{
|
|||
Account, Client, DefaultPlugins, Event, JoinError, StartClientOpts, chat::ChatPacket,
|
||||
join::ConnectOpts, start_ecs_runner,
|
||||
};
|
||||
use azalea_entity::LocalEntity;
|
||||
use azalea_protocol::{ServerAddress, resolver};
|
||||
use azalea_world::InstanceContainer;
|
||||
use bevy_app::{App, PluginGroup, PluginGroupBuilder, Plugins};
|
||||
|
@ -51,7 +52,9 @@ pub struct Swarm {
|
|||
|
||||
pub instance_container: Arc<RwLock<InstanceContainer>>,
|
||||
|
||||
/// This is used internally to make the client handler function work.
|
||||
bots_tx: mpsc::UnboundedSender<(Option<Event>, Client)>,
|
||||
/// This is used internally to make the swarm handler function work.
|
||||
swarm_tx: mpsc::UnboundedSender<SwarmEvent>,
|
||||
}
|
||||
|
||||
|
@ -149,6 +152,12 @@ where
|
|||
///
|
||||
/// Currently you can have up to one handler.
|
||||
///
|
||||
/// Note that if you're creating clients directly from the ECS using
|
||||
/// [`StartJoinServerEvent`] and the client wasn't already in the ECS, then
|
||||
/// the handler function won't be called for that client. This also applies
|
||||
/// to [`SwarmBuilder::set_swarm_handler`]. This shouldn't be a concern for
|
||||
/// most bots, though.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea::{prelude::*, swarm::prelude::*};
|
||||
/// # let swarm_builder = SwarmBuilder::new().set_swarm_handler(swarm_handle);
|
||||
|
@ -170,6 +179,8 @@ where
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`StartJoinServerEvent`]: azalea_client::join::StartJoinServerEvent
|
||||
#[must_use]
|
||||
pub fn set_handler<S, Fut, R>(self, handler: HandleFn<S, Fut>) -> SwarmBuilder<S, SS, R, SR>
|
||||
where
|
||||
|
@ -197,6 +208,12 @@ where
|
|||
///
|
||||
/// Currently you can have up to one swarm handler.
|
||||
///
|
||||
/// Note that if you're creating clients directly from the ECS using
|
||||
/// [`StartJoinServerEvent`] and the client wasn't already in the ECS, then
|
||||
/// this handler function won't be called for that client. This also applies
|
||||
/// to [`SwarmBuilder::set_handler`]. This shouldn't be a concern for
|
||||
/// most bots, though.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea::{prelude::*, swarm::prelude::*};
|
||||
/// # let swarm_builder = SwarmBuilder::new().set_handler(handle);
|
||||
|
@ -219,6 +236,8 @@ where
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`StartJoinServerEvent`]: azalea_client::join::StartJoinServerEvent
|
||||
#[must_use]
|
||||
pub fn set_swarm_handler<SS, Fut, SR>(
|
||||
self,
|
||||
|
@ -661,7 +680,7 @@ impl Swarm {
|
|||
|
||||
let bot = Client::start_client(StartClientOpts {
|
||||
ecs_lock: self.ecs_lock.clone(),
|
||||
account,
|
||||
account: account.clone(),
|
||||
connect_opts: ConnectOpts {
|
||||
address,
|
||||
resolved_address,
|
||||
|
@ -678,18 +697,23 @@ impl Swarm {
|
|||
|
||||
let cloned_bot = bot.clone();
|
||||
let swarm_tx = self.swarm_tx.clone();
|
||||
let bots_tx = self.bots_tx.clone();
|
||||
|
||||
let join_opts = join_opts.clone();
|
||||
tokio::spawn(Self::event_copying_task(
|
||||
rx, cloned_bot, swarm_tx, join_opts,
|
||||
rx, swarm_tx, bots_tx, cloned_bot, join_opts,
|
||||
));
|
||||
|
||||
Ok(bot)
|
||||
}
|
||||
|
||||
/// Copy the events from a client's receiver into bots_tx, until the bot is
|
||||
/// removed from the ECS.
|
||||
async fn event_copying_task(
|
||||
mut rx: mpsc::UnboundedReceiver<Event>,
|
||||
cloned_bot: Client,
|
||||
swarm_tx: mpsc::UnboundedSender<SwarmEvent>,
|
||||
bots_tx: mpsc::UnboundedSender<(Option<Event>, Client)>,
|
||||
bot: Client,
|
||||
join_opts: JoinOpts,
|
||||
) {
|
||||
while let Some(event) = rx.recv().await {
|
||||
|
@ -724,31 +748,32 @@ impl Swarm {
|
|||
}
|
||||
|
||||
if let Event::Disconnect(_) = event {
|
||||
//
|
||||
}
|
||||
|
||||
// we can't handle events here (since we can't copy the handler),
|
||||
// they're handled above in SwarmBuilder::start
|
||||
if let Err(e) = cloned_bots_tx.send((Some(event), cloned_bot.clone())) {
|
||||
error!("Error sending event to swarm: {e}");
|
||||
|
||||
let account = cloned_bot
|
||||
debug!(
|
||||
"sending SwarmEvent::Disconnect due to receiving an Event::Disconnect from client {}",
|
||||
bot.entity
|
||||
);
|
||||
let account = bot
|
||||
.get_component::<Account>()
|
||||
.expect("bot is missing required Account component");
|
||||
swarm_tx
|
||||
.send(SwarmEvent::Disconnect(Box::new(account), join_opts.clone()))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
debug!("client sender ended, removing from cloned_bots and sending SwarmEvent::Disconnect");
|
||||
|
||||
cloned_bots.lock().remove(&cloned_bot.entity);
|
||||
let account = cloned_bot
|
||||
.get_component::<Account>()
|
||||
.expect("bot is missing required Account component");
|
||||
swarm_tx
|
||||
.send(SwarmEvent::Disconnect(Box::new(account), join_opts))
|
||||
.unwrap();
|
||||
// we can't handle events here (since we can't copy the handler),
|
||||
// they're handled above in SwarmBuilder::start
|
||||
if let Err(e) = bots_tx.send((Some(event), bot.clone())) {
|
||||
error!(
|
||||
"Error sending event to swarm, aborting event_copying_task for {}: {e}",
|
||||
bot.entity
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
"client sender ended for {}, this won't trigger SwarmEvent::Disconnect unless the client already sent its own disconnect event",
|
||||
bot.entity
|
||||
);
|
||||
}
|
||||
|
||||
/// Add a new account to the swarm, retrying if it couldn't join. This will
|
||||
|
@ -801,6 +826,17 @@ impl Swarm {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an array of ECS [`Entity`]s for all [`LocalEntity`]s in our world.
|
||||
/// This will include clients that were disconnected without being removed
|
||||
/// from the ECS.
|
||||
///
|
||||
/// [`LocalEntity`]: azalea_entity::LocalEntity
|
||||
pub fn client_entities(&self) -> Box<[Entity]> {
|
||||
let mut ecs = self.ecs_lock.lock();
|
||||
let mut query = ecs.query_filtered::<Entity, With<LocalEntity>>();
|
||||
query.iter(&ecs).collect::<Box<[Entity]>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Swarm {
|
||||
|
@ -821,11 +857,12 @@ impl IntoIterator for Swarm {
|
|||
/// # }
|
||||
/// ```
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.bots
|
||||
.lock()
|
||||
.clone()
|
||||
.into_values()
|
||||
.collect::<Vec<_>>()
|
||||
let client_entities = self.client_entities();
|
||||
|
||||
client_entities
|
||||
.into_iter()
|
||||
.map(|entity| Client::new(entity, self.ecs_lock.clone()))
|
||||
.collect::<Box<[Client]>>()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue