mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 14:31:30 +11:00
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:
parent
255b78e02c
commit
2c0fb2d8c4
|
@ -1,6 +1,7 @@
|
|||
[workspace]
|
||||
members = ["crates/*"]
|
||||
exclude = ["rust-mc-bot"]
|
||||
resolver = "2"
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
|
|
|
@ -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 {
|
||||
(
|
||||
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<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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/// 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()
|
||||
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<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.
|
||||
///
|
||||
|
|
|
@ -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)]
|
||||
#[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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in a new issue