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.
This commit is contained in:
Ryan Johnson 2023-03-15 16:12:59 -07:00 committed by GitHub
parent 255b78e02c
commit 2c0fb2d8c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 294 additions and 174 deletions

View file

@ -1,6 +1,7 @@
[workspace]
members = ["crates/*"]
exclude = ["rust-mc-bot"]
resolver = "2"
[profile.dev.package."*"]
opt-level = 3

View file

@ -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<VarInt>);
pub struct EntityRemoveBuf(Vec<VarInt>);
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 {
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,
respawn,
send_keepalive,
read_data_in_view,
update_view,
remove_entities,
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,
teleport,
update_view_dist,
update_compass_pos,
send_keepalive,
update_tracked_data,
update_op_level,
acknowledge_player_actions,
flush_packets,
)
.chain()
.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<EntityRemoveBuffer>>,
mut clients: Query<(&mut Client, &mut EntityRemoveBuf), Changed<EntityRemoveBuf>>,
) {
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<GameMod
}
}
/// Syncs the client's position and look with the server.
///
/// This should happen after chunks are loaded so the client doesn't fall though
/// the floor.
fn teleport(
mut clients: Query<
(&mut Client, &mut TeleportState, &Position, &Look),
@ -1069,7 +1097,7 @@ fn teleport(
}
}
fn update_view_dist(
fn update_old_view_dist(
mut clients: Query<(&mut OldViewDistance, &ViewDistance), Changed<ViewDistance>>,
) {
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<CompassPos>>) {
// 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<CompassPos>>) {
for (mut client, compass_pos) in &mut clients {
client.write_packet(&PlayerSpawnPositionS2c {
position: compass_pos.0,

View file

@ -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<EventLoopQuery>, ClientEvents, Commands)>,
mut clients_to_check: Local<Vec<Entity>>,
@ -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(

View file

@ -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<Location>>) {
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<Position>>) {
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<u8>);
pub struct ScratchBuf(pub Vec<u8>);
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<Position>>) {
for (pos, mut old_pos) in &mut query {
old_pos.0 = pos.0;
}
}
fn update_old_location(mut query: Query<(&Location, &mut OldLocation), Changed<Location>>) {
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<Entity, With<Despawned>>) {
for entity in &entities {
commands.entity(entity).despawn();
}
}

View file

@ -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<i32, Entity>,
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;
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),
);
}
}
/// Gets the [`Entity`] of the [`McEntity`] with the given protocol ID.
pub fn get_with_protocol_id(&self, id: i32) -> Option<Entity> {
self.protocol_id_to_mcentity.get(&id).cloned()
}
}
/// 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<McEntity>>,
mut manager: ResMut<McEntityManager>,
) {
@ -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<Despawned>>,
mut manager: ResMut<McEntityManager>,
) {
@ -81,7 +85,7 @@ pub(crate) fn deinit_despawned_mcentities(
}
}
pub(crate) fn update_mcentities(mut mcentities: Query<&mut McEntity, Changed<McEntity>>) {
fn update_mcentities(mut mcentities: Query<&mut McEntity, Changed<McEntity>>) {
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<McE
}
}
/// A [`Resource`] which maintains information about all the [`McEntity`]
/// components on the server.
#[derive(Resource, Debug)]
pub struct McEntityManager {
protocol_id_to_mcentity: FxHashMap<i32, Entity>,
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<Entity> {
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.
///

View file

@ -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<Server>,
@ -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)]
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;
}

View file

@ -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,8 +303,11 @@ impl OpenInventory {
}
}
/// The systems needed for updating the inventories.
pub(crate) fn update_inventories() -> SystemConfigs {
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
@ -317,7 +321,10 @@ pub(crate) fn update_inventories() -> SystemConfigs {
update_client_on_close_inventory.after(update_open_inventories),
update_player_inventories,
)
.into_configs()
.in_base_set(CoreSet::PostUpdate)
.before(FlushPacketsSet),
);
}
}
/// Send updates for each client's player inventory.

View file

@ -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;

View file

@ -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<PlayerList>,
server: Res<Server>,
mut clients: Query<&mut Client>,

View file

@ -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<Entity, With<Despawned>>) {
for entity in &entities {
commands.entity(entity).despawn();
}
}
fn increment_tick_counter(mut server: ResMut<Server>) {
server.current_tick += 1;
}

View file

@ -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> {