From 2c0fb2d8c497ea5a62999380d3399f0d962ba426 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 15 Mar 2023 16:12:59 -0700 Subject: [PATCH] Refactor Schedule (#289) ## Description - Tweak the system schedule to be more parallel-friendly and explicit. Dependencies between systems is clearer. - System and resource configuration is better encapsulated in each module by using plugins. The schedule graph for `Main` now looks like this (using `bevy_mod_debugdump`): ![graph](https://user-images.githubusercontent.com/31678482/225321113-0ec4f4dd-86f6-45fe-8158-12a451536770.svg) ### Unresolved - What to do about ambiguous systems? Many systems here are ambiguous because they take `&mut Client`, but the order they write packets isn't really important. Marking them as ambiguous explicitly with `.ambiguous_with*` across module boundaries seems difficult and cumbersome. ## Test Plan Steps: 1. Run examples. Check that I didn't screw up the system order. --- Cargo.toml | 1 + crates/valence/src/client.rs | 104 +++++++++++------ crates/valence/src/client/event.rs | 34 +++++- crates/valence/src/component.rs | 51 ++++++--- crates/valence/src/entity.rs | 68 +++++++---- crates/valence/src/instance.rs | 39 +++++-- crates/valence/src/inventory.rs | 41 ++++--- crates/valence/src/lib.rs | 3 +- crates/valence/src/player_list.rs | 18 ++- crates/valence/src/server.rs | 106 ++++++------------ .../src/packet/s2c/play/scoreboard_display.rs | 3 +- 11 files changed, 294 insertions(+), 174 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b25f675..e4c5970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = ["crates/*"] exclude = ["rust-mc-bot"] +resolver = "2" [profile.dev.package."*"] opt-level = 3 diff --git a/crates/valence/src/client.rs b/crates/valence/src/client.rs index c2a9356..941fe05 100644 --- a/crates/valence/src/client.rs +++ b/crates/valence/src/client.rs @@ -3,9 +3,9 @@ use std::net::IpAddr; use std::num::Wrapping; use std::time::Instant; +use bevy_app::{CoreSet, Plugin}; use bevy_ecs::prelude::*; use bevy_ecs::query::WorldQuery; -use bevy_ecs::schedule::SystemConfigs; use bevy_ecs::system::Command; use bytes::BytesMut; use glam::{DVec3, Vec3}; @@ -38,10 +38,10 @@ use crate::component::{ }; use crate::dimension::DimensionId; use crate::entity::{velocity_to_packet_units, EntityStatus, McEntity, TrackedData}; -use crate::instance::Instance; +use crate::instance::{Instance, UpdateInstancesPreClientSet}; use crate::inventory::{Inventory, InventoryKind}; use crate::packet::WritePacket; -use crate::prelude::ScratchBuffer; +use crate::prelude::ScratchBuf; use crate::server::{NewClientInfo, Server}; use crate::view::{ChunkPos, ChunkView}; @@ -52,8 +52,8 @@ pub mod event; #[derive(Bundle)] pub(crate) struct ClientBundle { client: Client, - scratch: ScratchBuffer, - entity_remove_buffer: EntityRemoveBuffer, + scratch: ScratchBuf, + entity_remove_buffer: EntityRemoveBuf, username: Username, uuid: UniqueId, ip: Ip, @@ -95,8 +95,8 @@ impl ClientBundle { ) -> Self { Self { client: Client { conn, enc, dec }, - scratch: ScratchBuffer::default(), - entity_remove_buffer: EntityRemoveBuffer(vec![]), + scratch: ScratchBuf::default(), + entity_remove_buffer: EntityRemoveBuf(vec![]), username: Username(info.username), uuid: UniqueId(info.uuid), ip: Ip(info.ip), @@ -396,9 +396,9 @@ impl Command for DisconnectClient { /// /// You should not need to use this directly under normal circumstances. #[derive(Component, Debug)] -pub struct EntityRemoveBuffer(Vec); +pub struct EntityRemoveBuf(Vec); -impl EntityRemoveBuffer { +impl EntityRemoveBuf { pub fn push(&mut self, entity_id: i32) { debug_assert!( entity_id != 0, @@ -599,25 +599,45 @@ pub fn despawn_disconnected_clients( } } -pub(crate) fn update_clients() -> SystemConfigs { - ( - initial_join, - update_chunk_load_dist, - respawn, - send_keepalive, - read_data_in_view, - update_view, - remove_entities, - update_game_mode, - teleport, - update_view_dist, - update_compass_pos, - update_tracked_data, - update_op_level, - acknowledge_player_actions, - flush_packets, - ) - .chain() +pub(crate) struct ClientPlugin; + +/// When clients have their packet buffer flushed. Any system that writes +/// packets to clients should happen before this. Otherwise, the data +/// will arrive one tick late. +#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct FlushPacketsSet; + +impl Plugin for ClientPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.add_systems( + ( + initial_join, + update_chunk_load_dist, + read_data_in_view + .after(UpdateInstancesPreClientSet) + .after(update_chunk_load_dist), + update_view.after(initial_join).after(read_data_in_view), + respawn.after(update_view), + remove_entities.after(update_view), + update_spawn_position.after(update_view), + update_old_view_dist.after(update_view), + teleport.after(update_view), + update_game_mode, + send_keepalive, + update_tracked_data, + update_op_level, + acknowledge_player_actions, + ) + .in_base_set(CoreSet::PostUpdate) + .before(FlushPacketsSet), + ) + .configure_set( + FlushPacketsSet + .in_base_set(CoreSet::PostUpdate) + .after(UpdateInstancesPreClientSet), + ) + .add_system(flush_packets.in_set(FlushPacketsSet)); + } } #[derive(WorldQuery)] @@ -766,8 +786,8 @@ fn update_chunk_load_dist( fn read_data_in_view( mut clients: Query<( &mut Client, - &mut ScratchBuffer, - &mut EntityRemoveBuffer, + &mut ScratchBuf, + &mut EntityRemoveBuf, &OldLocation, &OldPosition, &OldViewDistance, @@ -845,12 +865,15 @@ fn read_data_in_view( /// Updates the clients' view, i.e. the set of chunks that are visible from the /// client's chunk position. +/// +/// This handles the situation when a client changes instances or chunk +/// position. It must run after [`read_data_in_view`]. fn update_view( mut clients: Query< ( &mut Client, - &mut ScratchBuffer, - &mut EntityRemoveBuffer, + &mut ScratchBuf, + &mut EntityRemoveBuf, &Location, &OldLocation, &Position, @@ -1004,8 +1027,9 @@ fn update_view( ); } +/// Removes all the entities that are queued to be removed for each client. fn remove_entities( - mut clients: Query<(&mut Client, &mut EntityRemoveBuffer), Changed>, + mut clients: Query<(&mut Client, &mut EntityRemoveBuf), Changed>, ) { for (mut client, mut buf) in &mut clients { if !buf.0.is_empty() { @@ -1032,6 +1056,10 @@ fn update_game_mode(mut clients: Query<(&mut Client, &GameMode), Changed>, ) { for (mut old_dist, dist) in &mut clients { @@ -1077,9 +1105,11 @@ fn update_view_dist( } } -fn update_compass_pos(mut clients: Query<(&mut Client, &CompassPos), Changed>) { - // This also closes the "downloading terrain" screen when first joining, so - // we should do this after the initial chunks are written. +/// Sets the client's compass position. +/// +/// This also closes the "downloading terrain" screen when first joining, so +/// it should happen after the initial chunks are written. +fn update_spawn_position(mut clients: Query<(&mut Client, &CompassPos), Changed>) { for (mut client, compass_pos) in &mut clients { client.write_packet(&PlayerSpawnPositionS2c { position: compass_pos.0, diff --git a/crates/valence/src/client/event.rs b/crates/valence/src/client/event.rs index bce5efd..f9a4e16 100644 --- a/crates/valence/src/client/event.rs +++ b/crates/valence/src/client/event.rs @@ -1,8 +1,10 @@ use std::cmp; use anyhow::bail; +use bevy_app::{CoreSet, Plugin}; use bevy_ecs::prelude::*; use bevy_ecs::query::WorldQuery; +use bevy_ecs::schedule::ScheduleLabel; use bevy_ecs::system::{SystemParam, SystemState}; use glam::{DVec3, Vec3}; use paste::paste; @@ -39,7 +41,6 @@ use crate::client::Client; use crate::component::{Look, OnGround, Ping, Position}; use crate::entity::{EntityAnimation, EntityKind, McEntity, TrackedData}; use crate::inventory::Inventory; -use crate::server::EventLoopSchedule; #[derive(Clone, Debug)] pub struct QueryBlockNbt { @@ -527,7 +528,7 @@ macro_rules! events { )* ) => { /// Inserts [`Events`] resources into the world for each client event. - pub(crate) fn register_client_events(world: &mut World) { + fn register_client_events(world: &mut World) { $( $( world.insert_resource(Events::<$name>::default()); @@ -641,6 +642,31 @@ events! { } } +pub(crate) struct ClientEventPlugin; + +/// The [`ScheduleLabel`] for the event loop [`Schedule`]. +#[derive(ScheduleLabel, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] +pub struct EventLoopSchedule; + +/// The default base set for [`EventLoopSchedule`]. +#[derive(SystemSet, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] +pub struct EventLoopSet; + +impl Plugin for ClientEventPlugin { + fn build(&self, app: &mut bevy_app::App) { + register_client_events(&mut app.world); + + app.configure_set(EventLoopSet.in_base_set(CoreSet::PreUpdate)) + .add_system(run_event_loop.in_set(EventLoopSet)); + + // Add the event loop schedule. + let mut event_loop = Schedule::new(); + event_loop.set_default_base_set(EventLoopSet); + + app.add_schedule(EventLoopSchedule, event_loop); + } +} + #[derive(WorldQuery)] #[world_query(mutable)] pub(crate) struct EventLoopQuery { @@ -659,7 +685,7 @@ pub(crate) struct EventLoopQuery { } /// An exclusive system for running the event loop schedule. -pub(crate) fn run_event_loop( +fn run_event_loop( world: &mut World, state: &mut SystemState<(Query, ClientEvents, Commands)>, mut clients_to_check: Local>, @@ -1384,7 +1410,7 @@ fn handle_one_packet( /// is subject to change. /// /// This system must be scheduled to run in the -/// [`EventLoopSchedule`](crate::server::EventLoopSchedule). Otherwise, it may +/// [`EventLoopSchedule`]. Otherwise, it may /// not function correctly. #[allow(clippy::too_many_arguments)] pub fn default_event_handler( diff --git a/crates/valence/src/component.rs b/crates/valence/src/component.rs index d4d703d..44c3a26 100644 --- a/crates/valence/src/component.rs +++ b/crates/valence/src/component.rs @@ -1,11 +1,13 @@ use std::fmt; +use bevy_app::{CoreSet, Plugin}; /// Contains shared components and world queries. use bevy_ecs::prelude::*; use glam::{DVec3, Vec3}; use uuid::Uuid; use valence_protocol::types::{GameMode as ProtocolGameMode, Property}; +use crate::prelude::FlushPacketsSet; use crate::util::{from_yaw_and_pitch, to_yaw_and_pitch}; use crate::view::ChunkPos; use crate::NULL_ENTITY; @@ -111,12 +113,6 @@ impl Default for Location { pub struct OldLocation(Entity); impl OldLocation { - pub(crate) fn update(mut query: Query<(&Location, &mut OldLocation), Changed>) { - for (loc, mut old_loc) in &mut query { - old_loc.0 = loc.0; - } - } - pub fn new(instance: Entity) -> Self { Self(instance) } @@ -153,12 +149,6 @@ impl Position { pub struct OldPosition(DVec3); impl OldPosition { - pub(crate) fn update(mut query: Query<(&Position, &mut OldPosition), Changed>) { - for (pos, mut old_pos) in &mut query { - old_pos.0 = pos.0; - } - } - pub fn new(pos: DVec3) -> Self { Self(pos) } @@ -201,4 +191,39 @@ impl Look { pub struct OnGround(pub bool); #[derive(Component, Default, Debug)] -pub struct ScratchBuffer(pub Vec); +pub struct ScratchBuf(pub Vec); + +pub(crate) struct ComponentPlugin; + +impl Plugin for ComponentPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.add_systems( + (update_old_position, update_old_location) + .in_base_set(CoreSet::PostUpdate) + .after(FlushPacketsSet), + ) + // This is fine because we're applying system buffers later. + .add_system(despawn_marked_entities.in_base_set(CoreSet::PostUpdate + )); + } +} + +fn update_old_position(mut query: Query<(&Position, &mut OldPosition), Changed>) { + for (pos, mut old_pos) in &mut query { + old_pos.0 = pos.0; + } +} + +fn update_old_location(mut query: Query<(&Location, &mut OldLocation), Changed>) { + for (loc, mut old_loc) in &mut query { + old_loc.0 = loc.0; + } +} + +/// Despawns all the entities marked as despawned with the [`Despawned`] +/// component. +fn despawn_marked_entities(mut commands: Commands, entities: Query>) { + for entity in &entities { + commands.entity(entity).despawn(); + } +} diff --git a/crates/valence/src/entity.rs b/crates/valence/src/entity.rs index c06a7e9..fbacc0d 100644 --- a/crates/valence/src/entity.rs +++ b/crates/valence/src/entity.rs @@ -3,6 +3,7 @@ use std::fmt; use std::fmt::Formatter; use std::ops::Range; +use bevy_app::{App, CoreSet, Plugin}; use bevy_ecs::prelude::*; pub use data::{EntityKind, TrackedData}; use glam::{DVec3, UVec3, Vec3}; @@ -21,6 +22,7 @@ use valence_protocol::var_int::VarInt; use crate::component::Despawned; use crate::config::DEFAULT_TPS; use crate::packet::WritePacket; +use crate::prelude::FlushPacketsSet; use crate::util::Aabb; use crate::NULL_ENTITY; @@ -28,30 +30,32 @@ pub mod data; include!(concat!(env!("OUT_DIR"), "/entity_event.rs")); -/// A [`Resource`] which maintains information about all the [`McEntity`] -/// components on the server. -#[derive(Resource, Debug)] -pub struct McEntityManager { - protocol_id_to_mcentity: FxHashMap, - next_protocol_id: i32, -} +pub(crate) struct EntityPlugin; -impl McEntityManager { - pub(crate) fn new() -> Self { - Self { - protocol_id_to_mcentity: HashMap::default(), - next_protocol_id: 1, - } - } +/// When new Minecraft entities are initialized and added to +/// [`McEntityManager`]. Systems that need all Minecraft entities to be in a +/// valid state should run after this. +#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct InitEntitiesSet; - /// Gets the [`Entity`] of the [`McEntity`] with the given protocol ID. - pub fn get_with_protocol_id(&self, id: i32) -> Option { - self.protocol_id_to_mcentity.get(&id).cloned() +impl Plugin for EntityPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(McEntityManager::new()) + .configure_set(InitEntitiesSet.in_base_set(CoreSet::PostUpdate)) + .add_system(init_mcentities.in_set(InitEntitiesSet)) + .add_systems( + ( + remove_despawned_from_manager.after(init_mcentities), + update_mcentities.after(FlushPacketsSet), + ) + .in_base_set(CoreSet::PostUpdate), + ); } } -/// Sets the protocol ID of new mcentities. -pub(crate) fn init_mcentities( +/// Sets the protocol ID of new mcentities and adds them to the +/// [`McEntityManager`]. +fn init_mcentities( mut entities: Query<(Entity, &mut McEntity), Added>, mut manager: ResMut, ) { @@ -72,7 +76,7 @@ pub(crate) fn init_mcentities( } /// Removes despawned mcentities from the mcentity manager. -pub(crate) fn deinit_despawned_mcentities( +fn remove_despawned_from_manager( entities: Query<&mut McEntity, With>, mut manager: ResMut, ) { @@ -81,7 +85,7 @@ pub(crate) fn deinit_despawned_mcentities( } } -pub(crate) fn update_mcentities(mut mcentities: Query<&mut McEntity, Changed>) { +fn update_mcentities(mut mcentities: Query<&mut McEntity, Changed>) { for mut ent in &mut mcentities { ent.data.clear_modifications(); ent.old_position = ent.position; @@ -94,6 +98,28 @@ pub(crate) fn update_mcentities(mut mcentities: Query<&mut McEntity, Changed, + next_protocol_id: i32, +} + +impl McEntityManager { + fn new() -> Self { + Self { + protocol_id_to_mcentity: HashMap::default(), + next_protocol_id: 1, + } + } + + /// Gets the [`Entity`] of the [`McEntity`] with the given protocol ID. + pub fn get_with_protocol_id(&self, id: i32) -> Option { + self.protocol_id_to_mcentity.get(&id).cloned() + } +} + /// A component for Minecraft entities. For Valence to recognize a /// Minecraft entity, it must have this component attached. /// diff --git a/crates/valence/src/instance.rs b/crates/valence/src/instance.rs index 6f57b24..c563b51 100644 --- a/crates/valence/src/instance.rs +++ b/crates/valence/src/instance.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry; use std::collections::BTreeSet; use std::iter::FusedIterator; +use bevy_app::{CoreSet, Plugin}; use bevy_ecs::prelude::*; pub use chunk::{Block, BlockEntity, BlockMut, BlockRef, Chunk}; pub use chunk_entry::*; @@ -20,8 +21,9 @@ use valence_protocol::Packet; use crate::component::Despawned; use crate::dimension::DimensionId; -use crate::entity::McEntity; +use crate::entity::{InitEntitiesSet, McEntity}; use crate::packet::{PacketWriter, WritePacket}; +use crate::prelude::FlushPacketsSet; use crate::server::{Server, SharedServer}; use crate::view::ChunkPos; @@ -433,7 +435,31 @@ impl Instance { } } -pub(crate) fn update_instances_pre_client( +pub(crate) struct InstancePlugin; + +#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct UpdateInstancesPreClientSet; + +impl Plugin for InstancePlugin { + fn build(&self, app: &mut bevy_app::App) { + app.configure_set( + UpdateInstancesPreClientSet + .after(InitEntitiesSet) + .in_base_set(CoreSet::PostUpdate), + ) + .add_system(update_instances_pre_client.in_set(UpdateInstancesPreClientSet)) + .add_system( + update_instances_post_client + .after(FlushPacketsSet) + .in_base_set(CoreSet::PostUpdate), + ); + + #[cfg(debug_assertions)] + app.add_system(check_instance_invariants.in_base_set(CoreSet::PostUpdate)); + } +} + +fn update_instances_pre_client( mut instances: Query<&mut Instance>, mut entities: Query<(Entity, &mut McEntity, Option<&Despawned>)>, server: Res, @@ -575,7 +601,7 @@ pub(crate) fn update_instances_pre_client( } } -pub(crate) fn update_instances_post_client(mut instances: Query<&mut Instance>) { +fn update_instances_post_client(mut instances: Query<&mut Instance>) { for mut instance in &mut instances { instance.partition.retain(|_, cell| { cell.packet_buf.clear(); @@ -594,8 +620,8 @@ pub(crate) fn update_instances_post_client(mut instances: Query<&mut Instance>) } } -pub(crate) fn check_instance_invariants(instances: Query<&Instance>, entities: Query<&McEntity>) { - #[cfg(debug_assertions)] +#[cfg(debug_assertions)] +fn check_instance_invariants(instances: Query<&Instance>, entities: Query<&McEntity>) { for instance in &instances { for (pos, cell) in &instance.partition { for &id in &cell.entities { @@ -606,7 +632,4 @@ pub(crate) fn check_instance_invariants(instances: Query<&Instance>, entities: Q } } } - - let _ = instances; - let _ = entities; } diff --git a/crates/valence/src/inventory.rs b/crates/valence/src/inventory.rs index 9b68589..d1c0b6c 100644 --- a/crates/valence/src/inventory.rs +++ b/crates/valence/src/inventory.rs @@ -30,8 +30,8 @@ use std::borrow::Cow; use std::iter::FusedIterator; use std::ops::Range; +use bevy_app::{CoreSet, Plugin}; use bevy_ecs::prelude::*; -use bevy_ecs::schedule::SystemConfigs; use tracing::{debug, warn}; use valence_protocol::item::ItemStack; use valence_protocol::packet::s2c::play::{ @@ -47,6 +47,7 @@ use crate::client::event::{ use crate::client::{Client, CursorItem, PlayerInventoryState}; use crate::component::GameMode; use crate::packet::WritePacket; +use crate::prelude::FlushPacketsSet; #[derive(Debug, Clone, Component)] pub struct Inventory { @@ -302,22 +303,28 @@ impl OpenInventory { } } -/// The systems needed for updating the inventories. -pub(crate) fn update_inventories() -> SystemConfigs { - ( - handle_set_held_item, - handle_click_container - .before(update_open_inventories) - .before(update_player_inventories), - handle_set_slot_creative - .before(update_open_inventories) - .before(update_player_inventories), - update_open_inventories, - handle_close_container, - update_client_on_close_inventory.after(update_open_inventories), - update_player_inventories, - ) - .into_configs() +pub(crate) struct InventoryPlugin; + +impl Plugin for InventoryPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.add_systems( + ( + handle_set_held_item, + handle_click_container + .before(update_open_inventories) + .before(update_player_inventories), + handle_set_slot_creative + .before(update_open_inventories) + .before(update_player_inventories), + update_open_inventories, + handle_close_container, + update_client_on_close_inventory.after(update_open_inventories), + update_player_inventories, + ) + .in_base_set(CoreSet::PostUpdate) + .before(FlushPacketsSet), + ); + } } /// Send updates for each client's player inventory. diff --git a/crates/valence/src/lib.rs b/crates/valence/src/lib.rs index a07a038..f1e1990 100644 --- a/crates/valence/src/lib.rs +++ b/crates/valence/src/lib.rs @@ -49,6 +49,7 @@ pub mod prelude { pub use bevy_app::prelude::*; pub use bevy_ecs::prelude::*; pub use biome::{Biome, BiomeId}; + pub use client::event::{EventLoopSchedule, EventLoopSet}; pub use client::*; pub use component::*; pub use config::{ @@ -66,7 +67,7 @@ pub mod prelude { pub use protocol::ident::Ident; pub use protocol::item::{ItemKind, ItemStack}; pub use protocol::text::{Color, Text, TextFormat}; - pub use server::{EventLoopSchedule, EventLoopSet, NewClientInfo, Server, SharedServer}; + pub use server::{NewClientInfo, Server, SharedServer}; pub use uuid::Uuid; pub use valence_nbt::Compound; pub use valence_protocol::block::BlockKind; diff --git a/crates/valence/src/player_list.rs b/crates/valence/src/player_list.rs index c1423b0..8d32c5b 100644 --- a/crates/valence/src/player_list.rs +++ b/crates/valence/src/player_list.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; use std::iter::FusedIterator; use std::mem; +use bevy_app::{CoreSet, Plugin}; use bevy_ecs::prelude::*; use bevy_ecs::schedule::SystemConfigs; use tracing::warn; @@ -18,6 +19,7 @@ use valence_protocol::types::Property; use crate::client::Client; use crate::component::{GameMode, Ping, Properties, UniqueId, Username}; use crate::packet::{PacketWriter, WritePacket}; +use crate::prelude::FlushPacketsSet; use crate::server::Server; /// The global list of players on a server visible by pressing the tab key by @@ -92,7 +94,7 @@ impl PlayerList { impl PlayerList { /// Create a new empty player list. - pub(crate) fn new() -> Self { + fn new() -> Self { Self { cached_update_packets: vec![], entries: HashMap::new(), @@ -551,8 +553,20 @@ impl<'a> VacantEntry<'a> { } } +pub(crate) struct PlayerListPlugin; + +impl Plugin for PlayerListPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.insert_resource(PlayerList::new()).add_system( + update_player_list + .before(FlushPacketsSet) + .in_base_set(CoreSet::PostUpdate), + ); + } +} + /// Manage all player lists on the server and send updates to clients. -pub(crate) fn update_player_list( +fn update_player_list( player_list: ResMut, server: Res, mut clients: Query<&mut Client>, diff --git a/crates/valence/src/server.rs b/crates/valence/src/server.rs index 8bddbd4..a8b9e78 100644 --- a/crates/valence/src/server.rs +++ b/crates/valence/src/server.rs @@ -8,7 +8,6 @@ use anyhow::ensure; use bevy_app::prelude::*; use bevy_app::{ScheduleRunnerPlugin, ScheduleRunnerSettings}; use bevy_ecs::prelude::*; -use bevy_ecs::schedule::ScheduleLabel; use flume::{Receiver, Sender}; use rand::rngs::OsRng; use rsa::{PublicKeyParts, RsaPrivateKey}; @@ -20,19 +19,16 @@ use valence_protocol::ident; use valence_protocol::types::Property; use crate::biome::{validate_biomes, Biome, BiomeId}; -use crate::client::event::{register_client_events, run_event_loop}; -use crate::client::{update_clients, ClientBundle}; -use crate::component::{Despawned, OldLocation, OldPosition}; +use crate::client::event::EventLoopSet; +use crate::client::{ClientBundle, ClientPlugin}; use crate::config::{AsyncCallbacks, ConnectionMode, ServerPlugin}; use crate::dimension::{validate_dimensions, Dimension, DimensionId}; -use crate::entity::{ - deinit_despawned_mcentities, init_mcentities, update_mcentities, McEntityManager, -}; -use crate::instance::{ - check_instance_invariants, update_instances_post_client, update_instances_pre_client, Instance, -}; -use crate::inventory::update_inventories; -use crate::player_list::{update_player_list, PlayerList}; +use crate::entity::EntityPlugin; +use crate::instance::{Instance, InstancePlugin}; +use crate::inventory::InventoryPlugin; +use crate::player_list::PlayerListPlugin; +use crate::prelude::event::ClientEventPlugin; +use crate::prelude::ComponentPlugin; use crate::server::connect::do_accept_loop; mod byte_channel; @@ -305,17 +301,7 @@ pub fn build_plugin( let shared = server.shared.clone(); // Insert resources. - app.insert_resource(server) - .insert_resource(McEntityManager::new()) - .insert_resource(PlayerList::new()); - register_client_events(&mut app.world); - - // Add the event loop schedule. - let mut event_loop = Schedule::new(); - event_loop.configure_set(EventLoopSet); - event_loop.set_default_base_set(EventLoopSet); - - app.add_schedule(EventLoopSchedule, event_loop); + app.insert_resource(server); // Make the app loop forever at the configured TPS. { @@ -333,59 +319,41 @@ pub fn build_plugin( .in_base_set(StartupSet::PostStartup), ); - // Add `CoreSet:::PreUpdate` systems. - app.add_systems( - (spawn_new_clients.before(run_event_loop), run_event_loop).in_base_set(CoreSet::PreUpdate), + // Spawn new clients before the event loop starts. + app.add_system( + spawn_new_clients + .in_base_set(CoreSet::PreUpdate) + .before(EventLoopSet), ); - // Add internal valence systems that run after `CoreSet::Update`. - app.add_systems( - ( - init_mcentities, - check_instance_invariants, - update_player_list.before(update_instances_pre_client), - update_instances_pre_client.after(init_mcentities), - update_instances_post_client.after(update_instances_pre_client), - deinit_despawned_mcentities.after(update_instances_post_client), - despawn_marked_entities.after(deinit_despawned_mcentities), - update_mcentities.after(despawn_marked_entities), - OldPosition::update.after(despawn_marked_entities), - OldLocation::update.after(despawn_marked_entities), + app.add_system(increment_tick_counter.in_base_set(CoreSet::Last)); + + // Add internal plugins. + app.add_plugin(ComponentPlugin) + .add_plugin(ClientPlugin) + .add_plugin(ClientEventPlugin) + .add_plugin(EntityPlugin) + .add_plugin(InstancePlugin) + .add_plugin(InventoryPlugin) + .add_plugin(PlayerListPlugin); + + /* + println!( + "{}", + bevy_mod_debugdump::schedule_graph_dot( + app, + CoreSchedule::Main, + &bevy_mod_debugdump::schedule_graph::Settings { + ambiguity_enable: false, + ..Default::default() + }, ) - .in_base_set(CoreSet::PostUpdate), - ) - .add_systems( - update_inventories() - .in_base_set(CoreSet::PostUpdate) - .before(init_mcentities), - ) - .add_systems( - update_clients() - .in_base_set(CoreSet::PostUpdate) - .after(update_instances_pre_client) - .before(update_instances_post_client), - ) - .add_system(increment_tick_counter.in_base_set(CoreSet::Last)); + ); + */ Ok(()) } -/// The [`ScheduleLabel`] for the event loop [`Schedule`]. -#[derive(ScheduleLabel, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] -pub struct EventLoopSchedule; - -/// The default base set for [`EventLoopSchedule`]. -#[derive(SystemSet, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] -pub struct EventLoopSet; - -/// Despawns all the entities marked as despawned with the [`Despawned`] -/// component. -fn despawn_marked_entities(mut commands: Commands, entities: Query>) { - for entity in &entities { - commands.entity(entity).despawn(); - } -} - fn increment_tick_counter(mut server: ResMut) { server.current_tick += 1; } diff --git a/crates/valence_protocol/src/packet/s2c/play/scoreboard_display.rs b/crates/valence_protocol/src/packet/s2c/play/scoreboard_display.rs index 1a204be..41caa33 100644 --- a/crates/valence_protocol/src/packet/s2c/play/scoreboard_display.rs +++ b/crates/valence_protocol/src/packet/s2c/play/scoreboard_display.rs @@ -1,6 +1,5 @@ -use crate::{Decode, Encode}; - use super::team::TeamColor; +use crate::{Decode, Encode}; #[derive(Copy, Clone, Debug, Encode, Decode)] pub struct ScoreboardDisplayS2c<'a> {