mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-11 15:21:31 +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]
|
[workspace]
|
||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
exclude = ["rust-mc-bot"]
|
exclude = ["rust-mc-bot"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::net::IpAddr;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::query::WorldQuery;
|
use bevy_ecs::query::WorldQuery;
|
||||||
use bevy_ecs::schedule::SystemConfigs;
|
|
||||||
use bevy_ecs::system::Command;
|
use bevy_ecs::system::Command;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use glam::{DVec3, Vec3};
|
use glam::{DVec3, Vec3};
|
||||||
|
@ -38,10 +38,10 @@ use crate::component::{
|
||||||
};
|
};
|
||||||
use crate::dimension::DimensionId;
|
use crate::dimension::DimensionId;
|
||||||
use crate::entity::{velocity_to_packet_units, EntityStatus, McEntity, TrackedData};
|
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::inventory::{Inventory, InventoryKind};
|
||||||
use crate::packet::WritePacket;
|
use crate::packet::WritePacket;
|
||||||
use crate::prelude::ScratchBuffer;
|
use crate::prelude::ScratchBuf;
|
||||||
use crate::server::{NewClientInfo, Server};
|
use crate::server::{NewClientInfo, Server};
|
||||||
use crate::view::{ChunkPos, ChunkView};
|
use crate::view::{ChunkPos, ChunkView};
|
||||||
|
|
||||||
|
@ -52,8 +52,8 @@ pub mod event;
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub(crate) struct ClientBundle {
|
pub(crate) struct ClientBundle {
|
||||||
client: Client,
|
client: Client,
|
||||||
scratch: ScratchBuffer,
|
scratch: ScratchBuf,
|
||||||
entity_remove_buffer: EntityRemoveBuffer,
|
entity_remove_buffer: EntityRemoveBuf,
|
||||||
username: Username,
|
username: Username,
|
||||||
uuid: UniqueId,
|
uuid: UniqueId,
|
||||||
ip: Ip,
|
ip: Ip,
|
||||||
|
@ -95,8 +95,8 @@ impl ClientBundle {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client: Client { conn, enc, dec },
|
client: Client { conn, enc, dec },
|
||||||
scratch: ScratchBuffer::default(),
|
scratch: ScratchBuf::default(),
|
||||||
entity_remove_buffer: EntityRemoveBuffer(vec![]),
|
entity_remove_buffer: EntityRemoveBuf(vec![]),
|
||||||
username: Username(info.username),
|
username: Username(info.username),
|
||||||
uuid: UniqueId(info.uuid),
|
uuid: UniqueId(info.uuid),
|
||||||
ip: Ip(info.ip),
|
ip: Ip(info.ip),
|
||||||
|
@ -396,9 +396,9 @@ impl Command for DisconnectClient {
|
||||||
///
|
///
|
||||||
/// You should not need to use this directly under normal circumstances.
|
/// You should not need to use this directly under normal circumstances.
|
||||||
#[derive(Component, Debug)]
|
#[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) {
|
pub fn push(&mut self, entity_id: i32) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
entity_id != 0,
|
entity_id != 0,
|
||||||
|
@ -599,25 +599,45 @@ pub fn despawn_disconnected_clients(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_clients() -> SystemConfigs {
|
pub(crate) struct ClientPlugin;
|
||||||
(
|
|
||||||
initial_join,
|
/// When clients have their packet buffer flushed. Any system that writes
|
||||||
update_chunk_load_dist,
|
/// packets to clients should happen before this. Otherwise, the data
|
||||||
respawn,
|
/// will arrive one tick late.
|
||||||
send_keepalive,
|
#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
read_data_in_view,
|
pub(crate) struct FlushPacketsSet;
|
||||||
update_view,
|
|
||||||
remove_entities,
|
impl Plugin for ClientPlugin {
|
||||||
update_game_mode,
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
teleport,
|
app.add_systems(
|
||||||
update_view_dist,
|
(
|
||||||
update_compass_pos,
|
initial_join,
|
||||||
update_tracked_data,
|
update_chunk_load_dist,
|
||||||
update_op_level,
|
read_data_in_view
|
||||||
acknowledge_player_actions,
|
.after(UpdateInstancesPreClientSet)
|
||||||
flush_packets,
|
.after(update_chunk_load_dist),
|
||||||
)
|
update_view.after(initial_join).after(read_data_in_view),
|
||||||
.chain()
|
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)]
|
#[derive(WorldQuery)]
|
||||||
|
@ -766,8 +786,8 @@ fn update_chunk_load_dist(
|
||||||
fn read_data_in_view(
|
fn read_data_in_view(
|
||||||
mut clients: Query<(
|
mut clients: Query<(
|
||||||
&mut Client,
|
&mut Client,
|
||||||
&mut ScratchBuffer,
|
&mut ScratchBuf,
|
||||||
&mut EntityRemoveBuffer,
|
&mut EntityRemoveBuf,
|
||||||
&OldLocation,
|
&OldLocation,
|
||||||
&OldPosition,
|
&OldPosition,
|
||||||
&OldViewDistance,
|
&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
|
/// Updates the clients' view, i.e. the set of chunks that are visible from the
|
||||||
/// client's chunk position.
|
/// 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(
|
fn update_view(
|
||||||
mut clients: Query<
|
mut clients: Query<
|
||||||
(
|
(
|
||||||
&mut Client,
|
&mut Client,
|
||||||
&mut ScratchBuffer,
|
&mut ScratchBuf,
|
||||||
&mut EntityRemoveBuffer,
|
&mut EntityRemoveBuf,
|
||||||
&Location,
|
&Location,
|
||||||
&OldLocation,
|
&OldLocation,
|
||||||
&Position,
|
&Position,
|
||||||
|
@ -1004,8 +1027,9 @@ fn update_view(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes all the entities that are queued to be removed for each client.
|
||||||
fn remove_entities(
|
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 {
|
for (mut client, mut buf) in &mut clients {
|
||||||
if !buf.0.is_empty() {
|
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(
|
fn teleport(
|
||||||
mut clients: Query<
|
mut clients: Query<
|
||||||
(&mut Client, &mut TeleportState, &Position, &Look),
|
(&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>>,
|
mut clients: Query<(&mut OldViewDistance, &ViewDistance), Changed<ViewDistance>>,
|
||||||
) {
|
) {
|
||||||
for (mut old_dist, dist) in &mut clients {
|
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>>) {
|
/// Sets the client's compass position.
|
||||||
// This also closes the "downloading terrain" screen when first joining, so
|
///
|
||||||
// we should do this after the initial chunks are written.
|
/// 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 {
|
for (mut client, compass_pos) in &mut clients {
|
||||||
client.write_packet(&PlayerSpawnPositionS2c {
|
client.write_packet(&PlayerSpawnPositionS2c {
|
||||||
position: compass_pos.0,
|
position: compass_pos.0,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::query::WorldQuery;
|
use bevy_ecs::query::WorldQuery;
|
||||||
|
use bevy_ecs::schedule::ScheduleLabel;
|
||||||
use bevy_ecs::system::{SystemParam, SystemState};
|
use bevy_ecs::system::{SystemParam, SystemState};
|
||||||
use glam::{DVec3, Vec3};
|
use glam::{DVec3, Vec3};
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
|
@ -39,7 +41,6 @@ use crate::client::Client;
|
||||||
use crate::component::{Look, OnGround, Ping, Position};
|
use crate::component::{Look, OnGround, Ping, Position};
|
||||||
use crate::entity::{EntityAnimation, EntityKind, McEntity, TrackedData};
|
use crate::entity::{EntityAnimation, EntityKind, McEntity, TrackedData};
|
||||||
use crate::inventory::Inventory;
|
use crate::inventory::Inventory;
|
||||||
use crate::server::EventLoopSchedule;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct QueryBlockNbt {
|
pub struct QueryBlockNbt {
|
||||||
|
@ -527,7 +528,7 @@ macro_rules! events {
|
||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
/// Inserts [`Events`] resources into the world for each client event.
|
/// 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());
|
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)]
|
#[derive(WorldQuery)]
|
||||||
#[world_query(mutable)]
|
#[world_query(mutable)]
|
||||||
pub(crate) struct EventLoopQuery {
|
pub(crate) struct EventLoopQuery {
|
||||||
|
@ -659,7 +685,7 @@ pub(crate) struct EventLoopQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An exclusive system for running the event loop schedule.
|
/// An exclusive system for running the event loop schedule.
|
||||||
pub(crate) fn run_event_loop(
|
fn run_event_loop(
|
||||||
world: &mut World,
|
world: &mut World,
|
||||||
state: &mut SystemState<(Query<EventLoopQuery>, ClientEvents, Commands)>,
|
state: &mut SystemState<(Query<EventLoopQuery>, ClientEvents, Commands)>,
|
||||||
mut clients_to_check: Local<Vec<Entity>>,
|
mut clients_to_check: Local<Vec<Entity>>,
|
||||||
|
@ -1384,7 +1410,7 @@ fn handle_one_packet(
|
||||||
/// is subject to change.
|
/// is subject to change.
|
||||||
///
|
///
|
||||||
/// This system must be scheduled to run in the
|
/// This system must be scheduled to run in the
|
||||||
/// [`EventLoopSchedule`](crate::server::EventLoopSchedule). Otherwise, it may
|
/// [`EventLoopSchedule`]. Otherwise, it may
|
||||||
/// not function correctly.
|
/// not function correctly.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn default_event_handler(
|
pub fn default_event_handler(
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
/// Contains shared components and world queries.
|
/// Contains shared components and world queries.
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use glam::{DVec3, Vec3};
|
use glam::{DVec3, Vec3};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use valence_protocol::types::{GameMode as ProtocolGameMode, Property};
|
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::util::{from_yaw_and_pitch, to_yaw_and_pitch};
|
||||||
use crate::view::ChunkPos;
|
use crate::view::ChunkPos;
|
||||||
use crate::NULL_ENTITY;
|
use crate::NULL_ENTITY;
|
||||||
|
@ -111,12 +113,6 @@ impl Default for Location {
|
||||||
pub struct OldLocation(Entity);
|
pub struct OldLocation(Entity);
|
||||||
|
|
||||||
impl OldLocation {
|
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 {
|
pub fn new(instance: Entity) -> Self {
|
||||||
Self(instance)
|
Self(instance)
|
||||||
}
|
}
|
||||||
|
@ -153,12 +149,6 @@ impl Position {
|
||||||
pub struct OldPosition(DVec3);
|
pub struct OldPosition(DVec3);
|
||||||
|
|
||||||
impl OldPosition {
|
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 {
|
pub fn new(pos: DVec3) -> Self {
|
||||||
Self(pos)
|
Self(pos)
|
||||||
}
|
}
|
||||||
|
@ -201,4 +191,39 @@ impl Look {
|
||||||
pub struct OnGround(pub bool);
|
pub struct OnGround(pub bool);
|
||||||
|
|
||||||
#[derive(Component, Default, Debug)]
|
#[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::fmt::Formatter;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use bevy_app::{App, CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
pub use data::{EntityKind, TrackedData};
|
pub use data::{EntityKind, TrackedData};
|
||||||
use glam::{DVec3, UVec3, Vec3};
|
use glam::{DVec3, UVec3, Vec3};
|
||||||
|
@ -21,6 +22,7 @@ use valence_protocol::var_int::VarInt;
|
||||||
use crate::component::Despawned;
|
use crate::component::Despawned;
|
||||||
use crate::config::DEFAULT_TPS;
|
use crate::config::DEFAULT_TPS;
|
||||||
use crate::packet::WritePacket;
|
use crate::packet::WritePacket;
|
||||||
|
use crate::prelude::FlushPacketsSet;
|
||||||
use crate::util::Aabb;
|
use crate::util::Aabb;
|
||||||
use crate::NULL_ENTITY;
|
use crate::NULL_ENTITY;
|
||||||
|
|
||||||
|
@ -28,30 +30,32 @@ pub mod data;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/entity_event.rs"));
|
include!(concat!(env!("OUT_DIR"), "/entity_event.rs"));
|
||||||
|
|
||||||
/// A [`Resource`] which maintains information about all the [`McEntity`]
|
pub(crate) struct EntityPlugin;
|
||||||
/// components on the server.
|
|
||||||
#[derive(Resource, Debug)]
|
|
||||||
pub struct McEntityManager {
|
|
||||||
protocol_id_to_mcentity: FxHashMap<i32, Entity>,
|
|
||||||
next_protocol_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McEntityManager {
|
/// When new Minecraft entities are initialized and added to
|
||||||
pub(crate) fn new() -> Self {
|
/// [`McEntityManager`]. Systems that need all Minecraft entities to be in a
|
||||||
Self {
|
/// valid state should run after this.
|
||||||
protocol_id_to_mcentity: HashMap::default(),
|
#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
next_protocol_id: 1,
|
pub(crate) struct InitEntitiesSet;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the [`Entity`] of the [`McEntity`] with the given protocol ID.
|
impl Plugin for EntityPlugin {
|
||||||
pub fn get_with_protocol_id(&self, id: i32) -> Option<Entity> {
|
fn build(&self, app: &mut App) {
|
||||||
self.protocol_id_to_mcentity.get(&id).cloned()
|
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.
|
/// Sets the protocol ID of new mcentities and adds them to the
|
||||||
pub(crate) fn init_mcentities(
|
/// [`McEntityManager`].
|
||||||
|
fn init_mcentities(
|
||||||
mut entities: Query<(Entity, &mut McEntity), Added<McEntity>>,
|
mut entities: Query<(Entity, &mut McEntity), Added<McEntity>>,
|
||||||
mut manager: ResMut<McEntityManager>,
|
mut manager: ResMut<McEntityManager>,
|
||||||
) {
|
) {
|
||||||
|
@ -72,7 +76,7 @@ pub(crate) fn init_mcentities(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes despawned mcentities from the mcentity manager.
|
/// Removes despawned mcentities from the mcentity manager.
|
||||||
pub(crate) fn deinit_despawned_mcentities(
|
fn remove_despawned_from_manager(
|
||||||
entities: Query<&mut McEntity, With<Despawned>>,
|
entities: Query<&mut McEntity, With<Despawned>>,
|
||||||
mut manager: ResMut<McEntityManager>,
|
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 {
|
for mut ent in &mut mcentities {
|
||||||
ent.data.clear_modifications();
|
ent.data.clear_modifications();
|
||||||
ent.old_position = ent.position;
|
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
|
/// A component for Minecraft entities. For Valence to recognize a
|
||||||
/// Minecraft entity, it must have this component attached.
|
/// Minecraft entity, it must have this component attached.
|
||||||
///
|
///
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::hash_map::Entry;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
pub use chunk::{Block, BlockEntity, BlockMut, BlockRef, Chunk};
|
pub use chunk::{Block, BlockEntity, BlockMut, BlockRef, Chunk};
|
||||||
pub use chunk_entry::*;
|
pub use chunk_entry::*;
|
||||||
|
@ -20,8 +21,9 @@ use valence_protocol::Packet;
|
||||||
|
|
||||||
use crate::component::Despawned;
|
use crate::component::Despawned;
|
||||||
use crate::dimension::DimensionId;
|
use crate::dimension::DimensionId;
|
||||||
use crate::entity::McEntity;
|
use crate::entity::{InitEntitiesSet, McEntity};
|
||||||
use crate::packet::{PacketWriter, WritePacket};
|
use crate::packet::{PacketWriter, WritePacket};
|
||||||
|
use crate::prelude::FlushPacketsSet;
|
||||||
use crate::server::{Server, SharedServer};
|
use crate::server::{Server, SharedServer};
|
||||||
use crate::view::ChunkPos;
|
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 instances: Query<&mut Instance>,
|
||||||
mut entities: Query<(Entity, &mut McEntity, Option<&Despawned>)>,
|
mut entities: Query<(Entity, &mut McEntity, Option<&Despawned>)>,
|
||||||
server: Res<Server>,
|
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 {
|
for mut instance in &mut instances {
|
||||||
instance.partition.retain(|_, cell| {
|
instance.partition.retain(|_, cell| {
|
||||||
cell.packet_buf.clear();
|
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 instance in &instances {
|
||||||
for (pos, cell) in &instance.partition {
|
for (pos, cell) in &instance.partition {
|
||||||
for &id in &cell.entities {
|
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::iter::FusedIterator;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::schedule::SystemConfigs;
|
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
use valence_protocol::item::ItemStack;
|
use valence_protocol::item::ItemStack;
|
||||||
use valence_protocol::packet::s2c::play::{
|
use valence_protocol::packet::s2c::play::{
|
||||||
|
@ -47,6 +47,7 @@ use crate::client::event::{
|
||||||
use crate::client::{Client, CursorItem, PlayerInventoryState};
|
use crate::client::{Client, CursorItem, PlayerInventoryState};
|
||||||
use crate::component::GameMode;
|
use crate::component::GameMode;
|
||||||
use crate::packet::WritePacket;
|
use crate::packet::WritePacket;
|
||||||
|
use crate::prelude::FlushPacketsSet;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Component)]
|
#[derive(Debug, Clone, Component)]
|
||||||
pub struct Inventory {
|
pub struct Inventory {
|
||||||
|
@ -302,22 +303,28 @@ impl OpenInventory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The systems needed for updating the inventories.
|
pub(crate) struct InventoryPlugin;
|
||||||
pub(crate) fn update_inventories() -> SystemConfigs {
|
|
||||||
(
|
impl Plugin for InventoryPlugin {
|
||||||
handle_set_held_item,
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
handle_click_container
|
app.add_systems(
|
||||||
.before(update_open_inventories)
|
(
|
||||||
.before(update_player_inventories),
|
handle_set_held_item,
|
||||||
handle_set_slot_creative
|
handle_click_container
|
||||||
.before(update_open_inventories)
|
.before(update_open_inventories)
|
||||||
.before(update_player_inventories),
|
.before(update_player_inventories),
|
||||||
update_open_inventories,
|
handle_set_slot_creative
|
||||||
handle_close_container,
|
.before(update_open_inventories)
|
||||||
update_client_on_close_inventory.after(update_open_inventories),
|
.before(update_player_inventories),
|
||||||
update_player_inventories,
|
update_open_inventories,
|
||||||
)
|
handle_close_container,
|
||||||
.into_configs()
|
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.
|
/// Send updates for each client's player inventory.
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub mod prelude {
|
||||||
pub use bevy_app::prelude::*;
|
pub use bevy_app::prelude::*;
|
||||||
pub use bevy_ecs::prelude::*;
|
pub use bevy_ecs::prelude::*;
|
||||||
pub use biome::{Biome, BiomeId};
|
pub use biome::{Biome, BiomeId};
|
||||||
|
pub use client::event::{EventLoopSchedule, EventLoopSet};
|
||||||
pub use client::*;
|
pub use client::*;
|
||||||
pub use component::*;
|
pub use component::*;
|
||||||
pub use config::{
|
pub use config::{
|
||||||
|
@ -66,7 +67,7 @@ pub mod prelude {
|
||||||
pub use protocol::ident::Ident;
|
pub use protocol::ident::Ident;
|
||||||
pub use protocol::item::{ItemKind, ItemStack};
|
pub use protocol::item::{ItemKind, ItemStack};
|
||||||
pub use protocol::text::{Color, Text, TextFormat};
|
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 uuid::Uuid;
|
||||||
pub use valence_nbt::Compound;
|
pub use valence_nbt::Compound;
|
||||||
pub use valence_protocol::block::BlockKind;
|
pub use valence_protocol::block::BlockKind;
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use bevy_app::{CoreSet, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::schedule::SystemConfigs;
|
use bevy_ecs::schedule::SystemConfigs;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
@ -18,6 +19,7 @@ use valence_protocol::types::Property;
|
||||||
use crate::client::Client;
|
use crate::client::Client;
|
||||||
use crate::component::{GameMode, Ping, Properties, UniqueId, Username};
|
use crate::component::{GameMode, Ping, Properties, UniqueId, Username};
|
||||||
use crate::packet::{PacketWriter, WritePacket};
|
use crate::packet::{PacketWriter, WritePacket};
|
||||||
|
use crate::prelude::FlushPacketsSet;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
|
||||||
/// The global list of players on a server visible by pressing the tab key by
|
/// The global list of players on a server visible by pressing the tab key by
|
||||||
|
@ -92,7 +94,7 @@ impl PlayerList {
|
||||||
|
|
||||||
impl PlayerList {
|
impl PlayerList {
|
||||||
/// Create a new empty player list.
|
/// Create a new empty player list.
|
||||||
pub(crate) fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cached_update_packets: vec![],
|
cached_update_packets: vec![],
|
||||||
entries: HashMap::new(),
|
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.
|
/// 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>,
|
player_list: ResMut<PlayerList>,
|
||||||
server: Res<Server>,
|
server: Res<Server>,
|
||||||
mut clients: Query<&mut Client>,
|
mut clients: Query<&mut Client>,
|
||||||
|
|
|
@ -8,7 +8,6 @@ use anyhow::ensure;
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_app::{ScheduleRunnerPlugin, ScheduleRunnerSettings};
|
use bevy_app::{ScheduleRunnerPlugin, ScheduleRunnerSettings};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::schedule::ScheduleLabel;
|
|
||||||
use flume::{Receiver, Sender};
|
use flume::{Receiver, Sender};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rsa::{PublicKeyParts, RsaPrivateKey};
|
use rsa::{PublicKeyParts, RsaPrivateKey};
|
||||||
|
@ -20,19 +19,16 @@ use valence_protocol::ident;
|
||||||
use valence_protocol::types::Property;
|
use valence_protocol::types::Property;
|
||||||
|
|
||||||
use crate::biome::{validate_biomes, Biome, BiomeId};
|
use crate::biome::{validate_biomes, Biome, BiomeId};
|
||||||
use crate::client::event::{register_client_events, run_event_loop};
|
use crate::client::event::EventLoopSet;
|
||||||
use crate::client::{update_clients, ClientBundle};
|
use crate::client::{ClientBundle, ClientPlugin};
|
||||||
use crate::component::{Despawned, OldLocation, OldPosition};
|
|
||||||
use crate::config::{AsyncCallbacks, ConnectionMode, ServerPlugin};
|
use crate::config::{AsyncCallbacks, ConnectionMode, ServerPlugin};
|
||||||
use crate::dimension::{validate_dimensions, Dimension, DimensionId};
|
use crate::dimension::{validate_dimensions, Dimension, DimensionId};
|
||||||
use crate::entity::{
|
use crate::entity::EntityPlugin;
|
||||||
deinit_despawned_mcentities, init_mcentities, update_mcentities, McEntityManager,
|
use crate::instance::{Instance, InstancePlugin};
|
||||||
};
|
use crate::inventory::InventoryPlugin;
|
||||||
use crate::instance::{
|
use crate::player_list::PlayerListPlugin;
|
||||||
check_instance_invariants, update_instances_post_client, update_instances_pre_client, Instance,
|
use crate::prelude::event::ClientEventPlugin;
|
||||||
};
|
use crate::prelude::ComponentPlugin;
|
||||||
use crate::inventory::update_inventories;
|
|
||||||
use crate::player_list::{update_player_list, PlayerList};
|
|
||||||
use crate::server::connect::do_accept_loop;
|
use crate::server::connect::do_accept_loop;
|
||||||
|
|
||||||
mod byte_channel;
|
mod byte_channel;
|
||||||
|
@ -305,17 +301,7 @@ pub fn build_plugin(
|
||||||
let shared = server.shared.clone();
|
let shared = server.shared.clone();
|
||||||
|
|
||||||
// Insert resources.
|
// Insert resources.
|
||||||
app.insert_resource(server)
|
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);
|
|
||||||
|
|
||||||
// Make the app loop forever at the configured TPS.
|
// Make the app loop forever at the configured TPS.
|
||||||
{
|
{
|
||||||
|
@ -333,59 +319,41 @@ pub fn build_plugin(
|
||||||
.in_base_set(StartupSet::PostStartup),
|
.in_base_set(StartupSet::PostStartup),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add `CoreSet:::PreUpdate` systems.
|
// Spawn new clients before the event loop starts.
|
||||||
app.add_systems(
|
app.add_system(
|
||||||
(spawn_new_clients.before(run_event_loop), run_event_loop).in_base_set(CoreSet::PreUpdate),
|
spawn_new_clients
|
||||||
|
.in_base_set(CoreSet::PreUpdate)
|
||||||
|
.before(EventLoopSet),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add internal valence systems that run after `CoreSet::Update`.
|
app.add_system(increment_tick_counter.in_base_set(CoreSet::Last));
|
||||||
app.add_systems(
|
|
||||||
(
|
// Add internal plugins.
|
||||||
init_mcentities,
|
app.add_plugin(ComponentPlugin)
|
||||||
check_instance_invariants,
|
.add_plugin(ClientPlugin)
|
||||||
update_player_list.before(update_instances_pre_client),
|
.add_plugin(ClientEventPlugin)
|
||||||
update_instances_pre_client.after(init_mcentities),
|
.add_plugin(EntityPlugin)
|
||||||
update_instances_post_client.after(update_instances_pre_client),
|
.add_plugin(InstancePlugin)
|
||||||
deinit_despawned_mcentities.after(update_instances_post_client),
|
.add_plugin(InventoryPlugin)
|
||||||
despawn_marked_entities.after(deinit_despawned_mcentities),
|
.add_plugin(PlayerListPlugin);
|
||||||
update_mcentities.after(despawn_marked_entities),
|
|
||||||
OldPosition::update.after(despawn_marked_entities),
|
/*
|
||||||
OldLocation::update.after(despawn_marked_entities),
|
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(())
|
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>) {
|
fn increment_tick_counter(mut server: ResMut<Server>) {
|
||||||
server.current_tick += 1;
|
server.current_tick += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{Decode, Encode};
|
|
||||||
|
|
||||||
use super::team::TeamColor;
|
use super::team::TeamColor;
|
||||||
|
use crate::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
#[derive(Copy, Clone, Debug, Encode, Decode)]
|
||||||
pub struct ScoreboardDisplayS2c<'a> {
|
pub struct ScoreboardDisplayS2c<'a> {
|
||||||
|
|
Loading…
Reference in a new issue