diff --git a/Cargo.lock b/Cargo.lock index d342c77b1..6058bc2a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" dependencies = [ - "concurrent-queue 2.1.0", + "concurrent-queue", "event-listener", "futures-core", ] @@ -105,7 +105,7 @@ checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" dependencies = [ "async-lock", "async-task", - "concurrent-queue 2.1.0", + "concurrent-queue", "fastrand", "futures-lite", "slab", @@ -176,11 +176,12 @@ dependencies = [ "azalea-chat", "azalea-client", "azalea-core", - "azalea-ecs", "azalea-physics", "azalea-protocol", "azalea-registry", "azalea-world", + "bevy_app", + "bevy_ecs", "bevy_tasks", "derive_more", "futures", @@ -284,11 +285,12 @@ dependencies = [ "azalea-chat", "azalea-core", "azalea-crypto", - "azalea-ecs", "azalea-physics", "azalea-protocol", "azalea-registry", "azalea-world", + "bevy_app", + "bevy_ecs", "bevy_log", "bevy_tasks", "bevy_time", @@ -331,26 +333,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "azalea-ecs" -version = "0.6.0" -dependencies = [ - "azalea-ecs-macros", - "bevy_app", - "bevy_ecs", - "tokio", -] - -[[package]] -name = "azalea-ecs-macros" -version = "0.6.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "toml 0.7.0", -] - [[package]] name = "azalea-language" version = "0.6.0" @@ -381,9 +363,11 @@ version = "0.6.0" dependencies = [ "azalea-block", "azalea-core", - "azalea-ecs", "azalea-registry", "azalea-world", + "bevy_app", + "bevy_ecs", + "bevy_time", "once_cell", "parking_lot", "uuid", @@ -461,9 +445,10 @@ dependencies = [ "azalea-buf", "azalea-chat", "azalea-core", - "azalea-ecs", "azalea-nbt", "azalea-registry", + "bevy_app", + "bevy_ecs", "derive_more", "enum-as-inner", "log", @@ -497,9 +482,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bevy_app" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "536e4d0018347478545ed8b6cb6e57b9279ee984868e81b7c0e78e0fb3222e42" +checksum = "960c6e444dc6a25dd51a2196f04872ae9e2e876802b66c391104849ec9225e38" dependencies = [ "bevy_derive", "bevy_ecs", @@ -512,9 +497,9 @@ dependencies = [ [[package]] name = "bevy_derive" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7baf73c58d41c353c6fd08e6764a2e7420c9f19e8227b391c50981db6d0282a6" +checksum = "cdf11701c01bf4dc7a3fac9f4547f3643d3db4cc1682af40c8c86e2f8734b617" dependencies = [ "bevy_macro_utils", "quote", @@ -523,9 +508,9 @@ dependencies = [ [[package]] name = "bevy_ecs" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c071d7c6bc9801253485e05d0c257284150de755391902746837ba21c0cf74" +checksum = "fdc5b19451128091e8507c9247888359ca0bfa895e7f6ca749ccc55c5463bef6" dependencies = [ "async-channel", "bevy_ecs_macros", @@ -536,16 +521,16 @@ dependencies = [ "downcast-rs", "event-listener", "fixedbitset", - "fxhash", + "rustc-hash", "serde", "thread_local", ] [[package]] name = "bevy_ecs_macros" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15bd45438eeb681ad74f2d205bb07a5699f98f9524462a30ec764afab2742ce" +checksum = "b1e79757319533bde006a4f30c268223ec6426371297182925932075ccfdae30" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -555,9 +540,9 @@ dependencies = [ [[package]] name = "bevy_log" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c480bac54cf4ae76edc3ae9ae3fa7c5e1b385e7f2111ef5ec3fd00cf3a7998b" +checksum = "47dcb09ec71145c80d88a84181cc1449d30f23c571bdd58c59c10eece82dfaa5" dependencies = [ "android_log-sys", "bevy_app", @@ -571,20 +556,20 @@ dependencies = [ [[package]] name = "bevy_macro_utils" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022bb69196deeea691b6997414af85bbd7f2b34a8914c4aa7a7ff4dfa44f7677" +checksum = "f24ca3363292f1435641fbafd5c24ce362137dd7d69bee56dcaaa2bc1d512ffe" dependencies = [ "quote", "syn", - "toml 0.5.11", + "toml_edit", ] [[package]] name = "bevy_math" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434c77ab766c806ed9062ef8a7285b3b02b47df51f188d4496199c3ac062eaf" +checksum = "5e45e46c2ac0a92db3ae622f2ed690928fe2612e7c9470a46d0ed4c2c77e2e95" dependencies = [ "glam", "serde", @@ -592,15 +577,15 @@ dependencies = [ [[package]] name = "bevy_ptr" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec44f7655039546bc5d34d98de877083473f3e9b2b81d560c528d6d74d3eff4" +checksum = "a96c24da064370917b92c2a84527e6a73b620c50ac5ef8b1af8c04ccf5256a7c" [[package]] name = "bevy_reflect" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6deae303a7f69dc243b2fa35b5e193cc920229f448942080c8eb2dbd9de6d37a" +checksum = "ab880e0eed9df5c99ce1a2f89edc11cdef1bc78413719b29e9ad7e3bc27f4c20" dependencies = [ "bevy_math", "bevy_ptr", @@ -618,9 +603,9 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bf4cb9cd5acb4193f890f36cb63679f1502e2de025e66a63b194b8b133d018" +checksum = "3b361b8671bdffe93978270dd770b03b48560c3127fdf9003f98111fb806bb11" dependencies = [ "bevy_macro_utils", "bit-set", @@ -632,14 +617,14 @@ dependencies = [ [[package]] name = "bevy_tasks" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680b16b53df9c9f24681dd95f4d772d83760bd19adf8bca00f358a3aad997853" +checksum = "3e368e4177fe70d695d5cb67fb7480fa262de79948d9b883a21788b9abf5a85a" dependencies = [ "async-channel", "async-executor", "async-task", - "concurrent-queue 1.2.4", + "concurrent-queue", "futures-lite", "once_cell", "wasm-bindgen-futures", @@ -647,31 +632,46 @@ dependencies = [ [[package]] name = "bevy_time" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c38a6d3ea929c7f81e6adf5a6c62cf7e8c40f5106c2174d6057e9d8ea624d" +checksum = "d2f2863cfc08fa38909e047a1bbc2dd71d0836057ed0840c69ace9dff3e0c298" dependencies = [ "bevy_app", "bevy_ecs", "bevy_reflect", "bevy_utils", "crossbeam-channel", + "thiserror", ] [[package]] name = "bevy_utils" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16750aae52cd35bd7b60eb61cee883420b250e11b4a290b8d44b2b2941795739" +checksum = "04d90ce493910ad9af3b4220ea6864c7d1472761086a98230ecac59c8d547e95" dependencies = [ "ahash 0.7.6", + "bevy_utils_proc_macros", "getrandom", "hashbrown", "instant", + "petgraph", + "thiserror", "tracing", "uuid", ] +[[package]] +name = "bevy_utils_proc_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a42e465c446800c57a5bf65b64f4fa1c1f3a74efc2a64a2a001e4a4f548a2e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -738,12 +738,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - [[package]] name = "cast" version = "0.3.0" @@ -802,15 +796,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - [[package]] name = "concurrent-queue" version = "2.1.0" @@ -1199,15 +1184,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.6" @@ -1239,9 +1215,9 @@ checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "glam" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" +checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c" dependencies = [ "bytemuck", "serde", @@ -1580,15 +1556,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1829,9 +1796,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -2003,6 +1970,12 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2111,15 +2084,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c68e921cef53841b8925c2abadd27c9b891d9613bdc43d6b823062866df38e8" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2209,9 +2173,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -2357,47 +2321,21 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f560bc7fb3eb31f5eee1340c68a2160cad39605b7b9c9ec32045ddbdee13b85" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - [[package]] name = "toml_datetime" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886f31a9b85b6182cabd4d8b07df3b451afcc216563748201490940d2a28ed36" -dependencies = [ - "serde", -] +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" [[package]] name = "toml_edit" -version = "0.19.0" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d8716cdc5d20ec88a18a839edaf545edc71efa4a5ff700ef4a102c26cd8fa" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" dependencies = [ "indexmap", - "nom8", - "serde", - "serde_spanned", "toml_datetime", + "winnow", ] [[package]] @@ -2822,6 +2760,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winnow" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" diff --git a/Cargo.toml b/Cargo.toml index febe65177..b7439bd12 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ members = [ "azalea-buf", "azalea-physics", "azalea-registry", - "azalea-ecs", ] [profile.release] diff --git a/azalea-client/Cargo.toml b/azalea-client/Cargo.toml index 6bb310690..f25aa2906 100644 --- a/azalea-client/Cargo.toml +++ b/azalea-client/Cargo.toml @@ -16,14 +16,15 @@ azalea-block = { path = "../azalea-block", version = "0.6.0" } azalea-chat = { path = "../azalea-chat", version = "0.6.0" } azalea-core = { path = "../azalea-core", version = "0.6.0" } azalea-crypto = { path = "../azalea-crypto", version = "0.6.0" } -azalea-ecs = { path = "../azalea-ecs", version = "0.6.0" } azalea-physics = { path = "../azalea-physics", version = "0.6.0" } azalea-protocol = { path = "../azalea-protocol", version = "0.6.0" } azalea-registry = { path = "../azalea-registry", version = "0.6.0" } azalea-world = { path = "../azalea-world", version = "0.6.0" } -bevy_log = "0.9.1" -bevy_tasks = "0.9.1" -bevy_time = "0.9.1" +bevy_app = "0.10.0" +bevy_ecs = "0.10.0" +bevy_log = "0.10.0" +bevy_tasks = "0.10.0" +bevy_time = "0.10.0" derive_more = { version = "0.99.17", features = ["deref", "deref_mut"] } futures = "0.3.25" log = "0.4.17" diff --git a/azalea-client/src/chat.rs b/azalea-client/src/chat.rs index e127f0d7b..0ae0250a7 100755 --- a/azalea-client/src/chat.rs +++ b/azalea-client/src/chat.rs @@ -1,18 +1,18 @@ //! Implementations of chat-related features. use azalea_chat::FormattedText; -use azalea_ecs::{ - app::{App, Plugin}, - entity::Entity, - event::{EventReader, EventWriter}, - schedule::IntoSystemDescriptor, -}; use azalea_protocol::packets::game::{ clientbound_player_chat_packet::ClientboundPlayerChatPacket, clientbound_system_chat_packet::ClientboundSystemChatPacket, serverbound_chat_command_packet::ServerboundChatCommandPacket, serverbound_chat_packet::{LastSeenMessagesUpdate, ServerboundChatPacket}, }; +use bevy_app::{App, Plugin}; +use bevy_ecs::{ + entity::Entity, + event::{EventReader, EventWriter}, + schedule::{IntoSystemConfig, IntoSystemConfigs}, +}; use std::{ sync::Arc, time::{SystemTime, UNIX_EPOCH}, @@ -159,12 +159,12 @@ impl Plugin for ChatPlugin { app.add_event::() .add_event::() .add_event::() - .add_system(handle_send_chat_event.label("handle_send_chat_event")) - .add_system( - handle_send_chat_kind_event - .label("handle_send_chat_kind_event") - .after(handle_send_chat_event) - .after(handle_send_packet_event), + .add_systems( + ( + handle_send_chat_event, + handle_send_chat_kind_event.after(handle_send_packet_event), + ) + .chain(), ); } } diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 661858dbb..79501fd46 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -6,25 +6,16 @@ use crate::{ death_event, handle_send_packet_event, update_in_loaded_chunk, GameProfileComponent, LocalPlayer, PhysicsState, SendPacketEvent, }, - movement::{local_player_ai_step, send_position, sprint_listener, walk_listener}, + movement::PlayerMovePlugin, packet_handling::{self, PacketHandlerPlugin, PacketReceiver}, player::retroactively_add_game_profile_component, task_pool::TaskPoolPlugin, - Account, PlayerInfo, StartSprintEvent, StartWalkEvent, + Account, PlayerInfo, }; use azalea_auth::{game_profile::GameProfile, sessionserver::ClientSessionServerError}; use azalea_chat::FormattedText; -use azalea_ecs::{ - app::{App, Plugin, PluginGroup, PluginGroupBuilder}, - bundle::Bundle, - component::Component, - entity::Entity, - schedule::{IntoSystemDescriptor, ReportExecutionOrderAmbiguities, Schedule, Stage, SystemSet}, - AppTickExt, -}; -use azalea_ecs::{ecs::Ecs, TickPlugin}; -use azalea_physics::PhysicsPlugin; +use azalea_physics::{PhysicsPlugin, PhysicsSet}; use azalea_protocol::{ connect::{Connection, ConnectionError}, packets::{ @@ -46,13 +37,23 @@ use azalea_protocol::{ resolver, ServerAddress, }; use azalea_world::{ - entity::{EntityPlugin, Local, WorldName}, - PartialWorld, World, WorldContainer, + entity::{EntityPlugin, EntityUpdateSet, Local, WorldName}, + Instance, PartialWorld, WorldContainer, +}; +use bevy_app::{App, CoreSchedule, Plugin, PluginGroup, PluginGroupBuilder}; +use bevy_ecs::{ + bundle::Bundle, + component::Component, + entity::Entity, + schedule::IntoSystemConfig, + schedule::{LogLevel, ScheduleBuildSettings, ScheduleLabel}, + world::World, }; use bevy_log::LogPlugin; +use bevy_time::{prelude::FixedTime, TimePlugin}; use log::{debug, error}; use parking_lot::{Mutex, RwLock}; -use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc}; +use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration}; use thiserror::Error; use tokio::{sync::mpsc, time}; use uuid::Uuid; @@ -86,7 +87,7 @@ pub struct Client { /// The entity component system. You probably don't need to access this /// directly. Note that if you're using a shared world (i.e. a swarm), this /// will contain all entities in all worlds. - pub ecs: Arc>, + pub ecs: Arc>, /// Use this to force the client to run the schedule outside of a tick. pub run_schedule_sender: mpsc::UnboundedSender<()>, @@ -120,7 +121,7 @@ impl Client { pub fn new( profile: GameProfile, entity: Entity, - ecs: Arc>, + ecs: Arc>, run_schedule_sender: mpsc::UnboundedSender<()>, ) -> Self { Self { @@ -180,7 +181,7 @@ impl Client { /// Create a [`Client`] when you already have the ECS made with /// [`start_ecs`]. You'd usually want to use [`Self::join`] instead. pub async fn start_client( - ecs_lock: Arc>, + ecs_lock: Arc>, account: &Account, address: &ServerAddress, resolved_address: &SocketAddr, @@ -226,7 +227,7 @@ impl Client { packet_writer_sender, // default to an empty world, it'll be set correctly later when we // get the login packet - Arc::new(RwLock::new(World::default())), + Arc::new(RwLock::new(Instance::default())), read_packets_task, write_packets_task, ); @@ -382,13 +383,13 @@ impl Client { }); } - pub fn local_player<'a>(&'a self, ecs: &'a mut Ecs) -> &'a LocalPlayer { + pub fn local_player<'a>(&'a self, ecs: &'a mut World) -> &'a LocalPlayer { self.query::<&LocalPlayer>(ecs) } pub fn local_player_mut<'a>( &'a self, - ecs: &'a mut Ecs, - ) -> azalea_ecs::ecs::Mut<'a, LocalPlayer> { + ecs: &'a mut World, + ) -> bevy_ecs::world::Mut<'a, LocalPlayer> { self.query::<&mut LocalPlayer>(ecs) } @@ -416,7 +417,7 @@ impl Client { /// client, then it'll be the same as the world the client has loaded. /// If the client using a shared world, then the shared world will be a /// superset of the client's world. - pub fn world(&self) -> Arc> { + pub fn world(&self) -> Arc> { let world_name = self.component::(); let ecs = self.ecs.lock(); let world_container = ecs.resource::(); @@ -493,33 +494,20 @@ pub struct JoinedClientBundle { pub struct AzaleaPlugin; impl Plugin for AzaleaPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_event::(); - - app.add_tick_system_set( - SystemSet::new() - .with_system(send_position.after("ai_step")) - .with_system(update_in_loaded_chunk.before(send_position).after("travel")) - .with_system( - local_player_ai_step - .before(azalea_physics::ai_step) - .label("ai_step"), - ), + // Minecraft ticks happen every 50ms + app.insert_resource(FixedTime::new(Duration::from_millis(50))); + + app.add_system( + update_in_loaded_chunk + .after(PhysicsSet) + .after(handle_send_packet_event), ); // fire the Death event when the player dies. app.add_system(death_event); - // walk and sprint event listeners - app.add_system(walk_listener.label("walk_listener")) - .add_system( - sprint_listener - .label("sprint_listener") - .before("walk_listener"), - ); - // add GameProfileComponent when we get an AddPlayerEvent - app.add_system(retroactively_add_game_profile_component.after("update_indexes")); + app.add_system(retroactively_add_game_profile_component.after(EntityUpdateSet::Index)); app.add_event::() .add_system(handle_send_packet_event); @@ -544,7 +532,12 @@ pub fn init_ecs_app() -> App { let mut app = App::new(); - app.insert_resource(ReportExecutionOrderAmbiguities); + app.edit_schedule(CoreSchedule::Main, |schedule| { + schedule.set_build_settings(ScheduleBuildSettings { + ambiguity_detection: LogLevel::Warn, + ..Default::default() + }); + }); app.add_plugins(DefaultPlugins); app @@ -554,17 +547,19 @@ pub fn init_ecs_app() -> App { /// first. #[doc(hidden)] pub fn start_ecs( - app: App, + mut app: App, run_schedule_receiver: mpsc::UnboundedReceiver<()>, run_schedule_sender: mpsc::UnboundedSender<()>, -) -> Arc> { +) -> Arc> { + app.setup(); + // all resources should have been added by now so we can take the ecs from the // app let ecs = Arc::new(Mutex::new(app.world)); tokio::spawn(run_schedule_loop( ecs.clone(), - app.schedule, + app.outer_schedule_label, run_schedule_receiver, )); tokio::spawn(tick_run_schedule_loop(run_schedule_sender)); @@ -573,14 +568,16 @@ pub fn start_ecs( } async fn run_schedule_loop( - ecs: Arc>, - mut schedule: Schedule, + ecs: Arc>, + outer_schedule_label: Box, mut run_schedule_receiver: mpsc::UnboundedReceiver<()>, ) { loop { // whenever we get an event from run_schedule_receiver, run the schedule run_schedule_receiver.recv().await; - schedule.run(&mut ecs.lock()); + let mut ecs = ecs.lock(); + ecs.run_schedule_ref(&*outer_schedule_label); + ecs.clear_trackers(); } } @@ -609,7 +606,7 @@ impl PluginGroup for DefaultPlugins { fn build(self) -> PluginGroupBuilder { PluginGroupBuilder::start::() .add(LogPlugin::default()) - .add(TickPlugin::default()) + .add(TimePlugin::default()) .add(PacketHandlerPlugin) .add(AzaleaPlugin) .add(EntityPlugin) @@ -618,5 +615,6 @@ impl PluginGroup for DefaultPlugins { .add(TaskPoolPlugin::default()) .add(ChatPlugin) .add(DisconnectPlugin) + .add(PlayerMovePlugin) } } diff --git a/azalea-client/src/disconnect.rs b/azalea-client/src/disconnect.rs index 9fd57e573..3b8d133ef 100644 --- a/azalea-client/src/disconnect.rs +++ b/azalea-client/src/disconnect.rs @@ -1,30 +1,30 @@ //! Disconnect a client from the server. -use azalea_ecs::{ - app::{App, CoreStage, Plugin}, +use bevy_app::{App, CoreSet, Plugin}; +use bevy_ecs::{ component::Component, entity::Entity, event::{EventReader, EventWriter}, query::Changed, - schedule::IntoSystemDescriptor, + schedule::IntoSystemConfigs, system::{Commands, Query}, - AppTickExt, }; use derive_more::Deref; -use crate::{client::JoinedClientBundle, movement::send_position, LocalPlayer}; +use crate::{client::JoinedClientBundle, LocalPlayer}; pub struct DisconnectPlugin; impl Plugin for DisconnectPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_system_to_stage(CoreStage::PostUpdate, handle_disconnect) - .add_tick_system( - update_read_packets_task_running_component - .before(disconnect_on_read_packets_ended) - .before(send_position), + app.add_event::().add_systems( + ( + update_read_packets_task_running_component, + disconnect_on_read_packets_ended, + remove_components_from_disconnected_players, ) - .add_tick_system(disconnect_on_read_packets_ended); + .in_base_set(CoreSet::PostUpdate) + .chain(), + ); } } @@ -35,7 +35,10 @@ pub struct DisconnectEvent { /// System that removes the [`JoinedClientBundle`] from the entity when it /// receives a [`DisconnectEvent`]. -pub fn handle_disconnect(mut commands: Commands, mut events: EventReader) { +pub fn remove_components_from_disconnected_players( + mut commands: Commands, + mut events: EventReader, +) { for DisconnectEvent { entity } in events.iter() { commands.entity(*entity).remove::(); } diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs index e39a7d2f8..8fe946591 100644 --- a/azalea-client/src/entity_query.rs +++ b/azalea-client/src/entity_query.rs @@ -1,10 +1,10 @@ use std::sync::Arc; -use azalea_ecs::{ +use bevy_ecs::{ component::Component, - ecs::Ecs, entity::Entity, query::{ROQueryItem, ReadOnlyWorldQuery, WorldQuery}, + world::World, }; use parking_lot::Mutex; @@ -22,7 +22,7 @@ impl Client { /// .is_some(); /// # } /// ``` - pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut Ecs) -> ::Item<'w> { + pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut World) -> ::Item<'w> { ecs.query::() .get_mut(ecs, self.entity) .expect("Our client is missing a required component.") @@ -38,7 +38,7 @@ impl Client { /// Note that this will very likely change in the future. /// ``` /// use azalea_client::{Client, GameProfileComponent}; - /// use azalea_ecs::query::With; + /// use bevy_ecs::query::With; /// use azalea_world::entity::{Position, metadata::Player}; /// /// # fn example(mut bot: Client, sender_name: String) { @@ -74,7 +74,7 @@ impl Client { } pub trait EntityPredicate { - fn find(&self, ecs_lock: Arc>) -> Option; + fn find(&self, ecs_lock: Arc>) -> Option; } impl EntityPredicate<(Q,), Filter> for F where @@ -82,7 +82,7 @@ where Q: ReadOnlyWorldQuery, Filter: ReadOnlyWorldQuery, { - fn find(&self, ecs_lock: Arc>) -> Option { + fn find(&self, ecs_lock: Arc>) -> Option { let mut ecs = ecs_lock.lock(); let mut query = ecs.query_filtered::<(Entity, Q), Filter>(); let entity = query.iter(&ecs).find(|(_, q)| (self)(q)).map(|(e, _)| e); diff --git a/azalea-client/src/events.rs b/azalea-client/src/events.rs index 085f53685..c7ff20aa5 100644 --- a/azalea-client/src/events.rs +++ b/azalea-client/src/events.rs @@ -3,18 +3,12 @@ use std::sync::Arc; -use azalea_ecs::{ - app::{App, Plugin}, - component::Component, - event::EventReader, - query::Added, - system::Query, - AppTickExt, -}; use azalea_protocol::packets::game::{ clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket, ClientboundGamePacket, }; use azalea_world::entity::MinecraftEntityId; +use bevy_app::{App, CoreSchedule, IntoSystemAppConfig, Plugin}; +use bevy_ecs::{component::Component, event::EventReader, query::Added, system::Query}; use derive_more::{Deref, DerefMut}; use tokio::sync::mpsc; @@ -115,7 +109,7 @@ impl Plugin for EventPlugin { .add_system(remove_player_listener) .add_system(death_listener) .add_system(keepalive_listener) - .add_tick_system(tick_listener); + .add_system(tick_listener.in_schedule(CoreSchedule::FixedUpdate)); } } diff --git a/azalea-client/src/lib.rs b/azalea-client/src/lib.rs index 8e119c0eb..44a4db6b9 100644 --- a/azalea-client/src/lib.rs +++ b/azalea-client/src/lib.rs @@ -26,7 +26,6 @@ mod player; pub mod task_pool; pub use account::Account; -pub use azalea_ecs as ecs; pub use client::{init_ecs_app, start_ecs, Client, ClientInformation, JoinError}; pub use events::Event; pub use local_player::{GameProfileComponent, LocalPlayer}; diff --git a/azalea-client/src/local_player.rs b/azalea-client/src/local_player.rs index d31f840f0..be847e786 100644 --- a/azalea-client/src/local_player.rs +++ b/azalea-client/src/local_player.rs @@ -2,14 +2,13 @@ use std::{collections::HashMap, io, sync::Arc}; use azalea_auth::game_profile::GameProfile; use azalea_core::ChunkPos; -use azalea_ecs::component::Component; -use azalea_ecs::entity::Entity; -use azalea_ecs::event::EventReader; -use azalea_ecs::{query::Added, system::Query}; use azalea_protocol::packets::game::ServerboundGamePacket; use azalea_world::{ entity::{self, Dead}, - PartialWorld, World, + Instance, PartialWorld, +}; +use bevy_ecs::{ + component::Component, entity::Entity, event::EventReader, query::Added, system::Query, }; use derive_more::{Deref, DerefMut}; use parking_lot::RwLock; @@ -44,7 +43,7 @@ pub struct LocalPlayer { pub partial_world: Arc>, /// The world is the combined [`PartialWorld`]s of all clients in the same /// world. (Only relevant if you're using a shared world, i.e. a swarm) - pub world: Arc>, + pub world: Arc>, /// A task that reads packets from the server. The client is disconnected /// when this task ends. @@ -88,7 +87,7 @@ impl LocalPlayer { pub fn new( entity: Entity, packet_writer: mpsc::UnboundedSender, - world: Arc>, + world: Arc>, read_packets_task: JoinHandle<()>, write_packets_task: JoinHandle<()>, ) -> Self { @@ -129,7 +128,7 @@ impl Drop for LocalPlayer { /// Update the [`LocalPlayerInLoadedChunk`] component for all [`LocalPlayer`]s. pub fn update_in_loaded_chunk( - mut commands: azalea_ecs::system::Commands, + mut commands: bevy_ecs::system::Commands, query: Query<(Entity, &LocalPlayer, &entity::Position)>, ) { for (entity, local_player, position) in &query { diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index f379501c5..f6123c709 100644 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -1,7 +1,8 @@ use crate::client::Client; -use crate::local_player::{LocalPlayer, LocalPlayerInLoadedChunk, PhysicsState}; -use azalea_ecs::entity::Entity; -use azalea_ecs::{event::EventReader, query::With, system::Query}; +use crate::local_player::{ + update_in_loaded_chunk, LocalPlayer, LocalPlayerInLoadedChunk, PhysicsState, +}; +use azalea_physics::{force_jump_listener, PhysicsSet}; use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket; use azalea_protocol::packets::game::{ serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket, @@ -13,6 +14,14 @@ use azalea_world::{ entity::{self, metadata::Sprinting, Attributes, Jumping, MinecraftEntityId}, MoveEntityError, }; +use bevy_app::{App, CoreSchedule, IntoSystemAppConfigs, Plugin}; +use bevy_ecs::{ + entity::Entity, + event::EventReader, + query::With, + schedule::{IntoSystemConfig, IntoSystemConfigs}, + system::Query, +}; use std::backtrace::Backtrace; use thiserror::Error; @@ -34,6 +43,28 @@ impl From for MovePlayerError { } } +pub struct PlayerMovePlugin; + +impl Plugin for PlayerMovePlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_systems( + (sprint_listener, walk_listener) + .chain() + .before(force_jump_listener), + ) + .add_systems( + ( + local_player_ai_step.in_set(PhysicsSet), + send_position.after(update_in_loaded_chunk), + ) + .chain() + .in_schedule(CoreSchedule::FixedUpdate), + ); + } +} + impl Client { /// Set whether we're jumping. This acts as if you held space in /// vanilla. If you want to jump once, use the `jump` function. diff --git a/azalea-client/src/packet_handling.rs b/azalea-client/src/packet_handling.rs index 9f8c5f1a4..76e6ee419 100644 --- a/azalea-client/src/packet_handling.rs +++ b/azalea-client/src/packet_handling.rs @@ -1,15 +1,6 @@ use std::{collections::HashSet, io::Cursor, sync::Arc}; use azalea_core::{ChunkPos, ResourceLocation, Vec3}; -use azalea_ecs::{ - app::{App, CoreStage, Plugin}, - component::Component, - ecs::Ecs, - entity::Entity, - event::{EventReader, EventWriter, Events}, - schedule::{StageLabel, SystemStage}, - system::{Commands, Query, ResMut, SystemState}, -}; use azalea_protocol::{ connect::{ReadConnection, WriteConnection}, packets::game::{ @@ -25,12 +16,21 @@ use azalea_protocol::{ use azalea_world::{ entity::{ metadata::{apply_metadata, Health, PlayerMetadataBundle}, - set_rotation, Dead, EntityBundle, EntityKind, LastSentPosition, MinecraftEntityId, Physics, - PlayerBundle, Position, WorldName, + set_rotation, Dead, EntityBundle, EntityKind, EntityUpdateSet, LastSentPosition, + MinecraftEntityId, Physics, PlayerBundle, Position, WorldName, }, entity::{LoadedBy, RelativeEntityUpdate}, PartialWorld, WorldContainer, }; +use bevy_app::{App, CoreSet, Plugin}; +use bevy_ecs::{ + component::Component, + entity::Entity, + event::{EventReader, EventWriter, Events}, + schedule::IntoSystemConfig, + system::{Commands, Query, ResMut, SystemState}, + world::World, +}; use log::{debug, error, trace, warn}; use parking_lot::Mutex; use tokio::sync::mpsc; @@ -46,7 +46,7 @@ use crate::{ /// ``` /// # use azalea_client::packet_handling::PacketEvent; /// # use azalea_protocol::packets::game::ClientboundGamePacket; -/// # use azalea_ecs::event::EventReader; +/// # use bevy_ecs::event::EventReader; /// /// fn handle_packets(mut events: EventReader) { /// for PacketEvent { @@ -72,25 +72,22 @@ pub struct PacketEvent { pub struct PacketHandlerPlugin; -#[derive(StageLabel)] -pub struct SendPacketEventsStage; - impl Plugin for PacketHandlerPlugin { fn build(&self, app: &mut App) { - app.add_stage_before( - CoreStage::PreUpdate, - SendPacketEventsStage, - SystemStage::parallel(), - ) - .add_system_to_stage(SendPacketEventsStage, send_packet_events) - .add_system_to_stage(CoreStage::PreUpdate, process_packet_events) - .init_resource::>() - .add_event::() - .add_event::() - .add_event::() - .add_event::() - .add_event::() - .add_event::(); + app.add_system(send_packet_events.in_base_set(CoreSet::First)) + .add_system( + process_packet_events + .in_base_set(CoreSet::PreUpdate) + // we want to index and deindex right after + .before(EntityUpdateSet::Deindex), + ) + .init_resource::>() + .add_event::() + .add_event::() + .add_event::() + .add_event::() + .add_event::() + .add_event::(); } } @@ -168,7 +165,7 @@ pub fn send_packet_events( } } -fn process_packet_events(ecs: &mut Ecs) { +fn process_packet_events(ecs: &mut World) { let mut events_owned = Vec::new(); let mut system_state: SystemState> = SystemState::new(ecs); let mut events = system_state.get_mut(ecs); @@ -715,8 +712,7 @@ fn process_packet_events(ecs: &mut Ecs) { if let Some(entity) = entity { let new_position = p.position; - commands.add(RelativeEntityUpdate { - entity, + commands.entity(entity).add(RelativeEntityUpdate { partial_world: local_player.partial_world.clone(), update: Box::new(move |entity| { let mut position = entity.get_mut::().unwrap(); @@ -747,8 +743,7 @@ fn process_packet_events(ecs: &mut Ecs) { if let Some(entity) = entity { let delta = p.delta.clone(); - commands.add(RelativeEntityUpdate { - entity, + commands.entity(entity).add(RelativeEntityUpdate { partial_world: local_player.partial_world.clone(), update: Box::new(move |entity_mut| { let mut position = entity_mut.get_mut::().unwrap(); @@ -776,8 +771,7 @@ fn process_packet_events(ecs: &mut Ecs) { if let Some(entity) = entity { let delta = p.delta.clone(); - commands.add(RelativeEntityUpdate { - entity, + commands.entity(entity).add(RelativeEntityUpdate { partial_world: local_player.partial_world.clone(), update: Box::new(move |entity_mut| { let mut position = entity_mut.get_mut::().unwrap(); diff --git a/azalea-client/src/player.rs b/azalea-client/src/player.rs index 3680e2d0d..c2c8a94e9 100755 --- a/azalea-client/src/player.rs +++ b/azalea-client/src/player.rs @@ -1,11 +1,11 @@ use azalea_auth::game_profile::GameProfile; use azalea_chat::FormattedText; use azalea_core::GameType; -use azalea_ecs::{ +use azalea_world::entity::EntityInfos; +use bevy_ecs::{ event::EventReader, system::{Commands, Res}, }; -use azalea_world::entity::EntityInfos; use uuid::Uuid; use crate::{packet_handling::AddPlayerEvent, GameProfileComponent}; diff --git a/azalea-client/src/task_pool.rs b/azalea-client/src/task_pool.rs index 59f704875..8df554f04 100644 --- a/azalea-client/src/task_pool.rs +++ b/azalea-client/src/task_pool.rs @@ -1,11 +1,16 @@ //! Borrowed from `bevy_core`. -use azalea_ecs::{ - app::{App, Plugin}, - schedule::IntoSystemDescriptor, - system::Resource, +use std::marker::PhantomData; + +use bevy_app::{App, CoreSet, Plugin}; +use bevy_ecs::{ + schedule::IntoSystemConfig, + system::{NonSend, Resource}, +}; +use bevy_tasks::{ + tick_global_task_pools_on_main_thread, AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, + TaskPoolBuilder, }; -use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder}; /// Setup of default task pools: `AsyncComputeTaskPool`, `ComputeTaskPool`, /// `IoTaskPool`. @@ -22,13 +27,16 @@ impl Plugin for TaskPoolPlugin { self.task_pool_options.create_default_pools(); #[cfg(not(target_arch = "wasm32"))] - app.add_system_to_stage( - azalea_ecs::app::CoreStage::Last, - bevy_tasks::tick_global_task_pools_on_main_thread.at_end(), - ); + app.add_system(tick_global_task_pools.in_base_set(CoreSet::Last)); } } +pub struct NonSendMarker(PhantomData<*mut ()>); +#[cfg(not(target_arch = "wasm32"))] +fn tick_global_task_pools(_main_thread_marker: Option>) { + tick_global_task_pools_on_main_thread(); +} + /// Helper for configuring and creating the default task pools. For end-users /// who want full control, set up [`TaskPoolPlugin`](TaskPoolPlugin) #[derive(Clone, Resource)] diff --git a/azalea-core/Cargo.toml b/azalea-core/Cargo.toml index 0baa40ac6..e31351e83 100644 --- a/azalea-core/Cargo.toml +++ b/azalea-core/Cargo.toml @@ -9,10 +9,10 @@ version = "0.6.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-buf = {path = "../azalea-buf", version = "^0.6.0" } -azalea-chat = {path = "../azalea-chat", version = "^0.6.0" } -azalea-nbt = {path = "../azalea-nbt", version = "^0.6.0" } -bevy_ecs = {version = "0.9.1", default-features = false, optional = true} +azalea-buf = { path = "../azalea-buf", version = "^0.6.0" } +azalea-chat = { path = "../azalea-chat", version = "^0.6.0" } +azalea-nbt = { path = "../azalea-nbt", version = "^0.6.0" } +bevy_ecs = { version = "0.10.0", default-features = false, optional = true } uuid = "^1.1.2" [features] diff --git a/azalea-ecs/Cargo.toml b/azalea-ecs/Cargo.toml deleted file mode 100644 index a596fd42a..000000000 --- a/azalea-ecs/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -description = "ECS stuff used in Azalea" -edition = "2021" -license = "MIT" -name = "azalea-ecs" -version = "0.6.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -azalea-ecs-macros = {path = "./azalea-ecs-macros", version = "^0.6.0"} -bevy_app = "0.9.1" -bevy_ecs = {version = "0.9.1", default-features = false} -tokio = {version = "1.25.0", features = ["time"]} diff --git a/azalea-ecs/azalea-ecs-macros/Cargo.toml b/azalea-ecs/azalea-ecs-macros/Cargo.toml deleted file mode 100755 index cd7b2c8d8..000000000 --- a/azalea-ecs/azalea-ecs-macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -description = "Azalea ECS Macros" -edition = "2021" -license = "MIT OR Apache-2.0" -name = "azalea-ecs-macros" -version = "0.6.0" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = "1.0" -toml = "0.7.0" diff --git a/azalea-ecs/azalea-ecs-macros/src/component.rs b/azalea-ecs/azalea-ecs-macros/src/component.rs deleted file mode 100644 index e076bbe19..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/component.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::utils::{get_lit_str, Symbol}; -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{quote, ToTokens}; -use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result}; - -use crate::utils; - -pub fn derive_resource(input: TokenStream) -> TokenStream { - let mut ast = parse_macro_input!(input as DeriveInput); - let azalea_ecs_path: Path = crate::azalea_ecs_path(); - - ast.generics - .make_where_clause() - .predicates - .push(parse_quote! { Self: Send + Sync + 'static }); - - let struct_name = &ast.ident; - let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); - - TokenStream::from(quote! { - impl #impl_generics #azalea_ecs_path::system::_BevyResource for #struct_name #type_generics #where_clause { - } - }) -} - -pub fn derive_component(input: TokenStream) -> TokenStream { - let mut ast = parse_macro_input!(input as DeriveInput); - let azalea_ecs_path: Path = crate::azalea_ecs_path(); - - let attrs = match parse_component_attr(&ast) { - Ok(attrs) => attrs, - Err(e) => return e.into_compile_error().into(), - }; - - let storage = storage_path(&azalea_ecs_path, attrs.storage); - - ast.generics - .make_where_clause() - .predicates - .push(parse_quote! { Self: Send + Sync + 'static }); - - let struct_name = &ast.ident; - let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); - - TokenStream::from(quote! { - impl #impl_generics #azalea_ecs_path::component::_BevyComponent for #struct_name #type_generics #where_clause { - type Storage = #storage; - } - }) -} - -pub const COMPONENT: Symbol = Symbol("component"); -pub const STORAGE: Symbol = Symbol("storage"); - -struct Attrs { - storage: StorageTy, -} - -#[derive(Clone, Copy)] -enum StorageTy { - Table, - SparseSet, -} - -// values for `storage` attribute -const TABLE: &str = "Table"; -const SPARSE_SET: &str = "SparseSet"; - -fn parse_component_attr(ast: &DeriveInput) -> Result { - let meta_items = utils::parse_attrs(ast, COMPONENT)?; - - let mut attrs = Attrs { - storage: StorageTy::Table, - }; - - for meta in meta_items { - use syn::{ - Meta::NameValue, - NestedMeta::{Lit, Meta}, - }; - match meta { - Meta(NameValue(m)) if m.path == STORAGE => { - attrs.storage = match get_lit_str(STORAGE, &m.lit)?.value().as_str() { - TABLE => StorageTy::Table, - SPARSE_SET => StorageTy::SparseSet, - s => { - return Err(Error::new_spanned( - m.lit, - format!( - "Invalid storage type `{s}`, expected '{TABLE}' or '{SPARSE_SET}'." - ), - )) - } - }; - } - Meta(meta_item) => { - return Err(Error::new_spanned( - meta_item.path(), - format!( - "unknown component attribute `{}`", - meta_item.path().into_token_stream() - ), - )); - } - Lit(lit) => { - return Err(Error::new_spanned( - lit, - "unexpected literal in component attribute", - )) - } - } - } - - Ok(attrs) -} - -fn storage_path(azalea_ecs_path: &Path, ty: StorageTy) -> TokenStream2 { - let typename = match ty { - StorageTy::Table => Ident::new("TableStorage", Span::call_site()), - StorageTy::SparseSet => Ident::new("SparseStorage", Span::call_site()), - }; - - quote! { #azalea_ecs_path::component::#typename } -} diff --git a/azalea-ecs/azalea-ecs-macros/src/fetch.rs b/azalea-ecs/azalea-ecs-macros/src/fetch.rs deleted file mode 100644 index 8a6b93baf..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/fetch.rs +++ /dev/null @@ -1,466 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use quote::{quote, ToTokens}; -use syn::{ - parse::{Parse, ParseStream}, - parse_quote, - punctuated::Punctuated, - Attribute, Data, DataStruct, DeriveInput, Field, Fields, -}; - -use crate::azalea_ecs_path; - -#[derive(Default)] -struct FetchStructAttributes { - pub is_mutable: bool, - pub derive_args: Punctuated, -} - -static MUTABLE_ATTRIBUTE_NAME: &str = "mutable"; -static DERIVE_ATTRIBUTE_NAME: &str = "derive"; - -mod field_attr_keywords { - syn::custom_keyword!(ignore); -} - -pub static WORLD_QUERY_ATTRIBUTE_NAME: &str = "world_query"; - -pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream { - let visibility = ast.vis; - - let mut fetch_struct_attributes = FetchStructAttributes::default(); - for attr in &ast.attrs { - if !attr - .path - .get_ident() - .map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME) - { - continue; - } - - attr.parse_args_with(|input: ParseStream| { - let meta = input.parse_terminated::(syn::Meta::parse)?; - for meta in meta { - let ident = meta.path().get_ident().unwrap_or_else(|| { - panic!( - "Unrecognized attribute: `{}`", - meta.path().to_token_stream() - ) - }); - if ident == MUTABLE_ATTRIBUTE_NAME { - if let syn::Meta::Path(_) = meta { - fetch_struct_attributes.is_mutable = true; - } else { - panic!( - "The `{MUTABLE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments" - ); - } - } else if ident == DERIVE_ATTRIBUTE_NAME { - if let syn::Meta::List(meta_list) = meta { - fetch_struct_attributes - .derive_args - .extend(meta_list.nested.iter().cloned()); - } else { - panic!( - "Expected a structured list within the `{DERIVE_ATTRIBUTE_NAME}` attribute" - ); - } - } else { - panic!( - "Unrecognized attribute: `{}`", - meta.path().to_token_stream() - ); - } - } - Ok(()) - }) - .unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_ATTRIBUTE_NAME}` attribute format")); - } - - let path = azalea_ecs_path(); - - let user_generics = ast.generics.clone(); - let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl(); - let user_generics_with_world = { - let mut generics = ast.generics.clone(); - generics.params.insert(0, parse_quote!('__w)); - generics - }; - let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) = - user_generics_with_world.split_for_impl(); - - let struct_name = ast.ident.clone(); - let read_only_struct_name = if fetch_struct_attributes.is_mutable { - Ident::new(&format!("{struct_name}ReadOnly"), Span::call_site()) - } else { - struct_name.clone() - }; - - let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site()); - let read_only_item_struct_name = if fetch_struct_attributes.is_mutable { - Ident::new(&format!("{struct_name}ReadOnlyItem"), Span::call_site()) - } else { - item_struct_name.clone() - }; - - let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site()); - let read_only_fetch_struct_name = if fetch_struct_attributes.is_mutable { - Ident::new(&format!("{struct_name}ReadOnlyFetch"), Span::call_site()) - } else { - fetch_struct_name.clone() - }; - - let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site()); - - let fields = match &ast.data { - Data::Struct(DataStruct { - fields: Fields::Named(fields), - .. - }) => &fields.named, - _ => panic!("Expected a struct with named fields"), - }; - - let mut ignored_field_attrs = Vec::new(); - let mut ignored_field_visibilities = Vec::new(); - let mut ignored_field_idents = Vec::new(); - let mut ignored_field_types = Vec::new(); - let mut field_attrs = Vec::new(); - let mut field_visibilities = Vec::new(); - let mut field_idents = Vec::new(); - let mut field_types = Vec::new(); - let mut read_only_field_types = Vec::new(); - - for field in fields { - let WorldQueryFieldInfo { is_ignored, attrs } = read_world_query_field_info(field); - - let field_ident = field.ident.as_ref().unwrap().clone(); - if is_ignored { - ignored_field_attrs.push(attrs); - ignored_field_visibilities.push(field.vis.clone()); - ignored_field_idents.push(field_ident.clone()); - ignored_field_types.push(field.ty.clone()); - } else { - field_attrs.push(attrs); - field_visibilities.push(field.vis.clone()); - field_idents.push(field_ident.clone()); - let field_ty = field.ty.clone(); - field_types.push(quote!(#field_ty)); - read_only_field_types.push(quote!(<#field_ty as #path::query::WorldQuery>::ReadOnly)); - } - } - - let derive_args = &fetch_struct_attributes.derive_args; - // `#[derive()]` is valid syntax - let derive_macro_call = quote! { #[derive(#derive_args)] }; - - let impl_fetch = |is_readonly: bool| { - let struct_name = if is_readonly { - &read_only_struct_name - } else { - &struct_name - }; - let item_struct_name = if is_readonly { - &read_only_item_struct_name - } else { - &item_struct_name - }; - let fetch_struct_name = if is_readonly { - &read_only_fetch_struct_name - } else { - &fetch_struct_name - }; - - let field_types = if is_readonly { - &read_only_field_types - } else { - &field_types - }; - - quote! { - #derive_macro_call - #[doc = "Automatically generated [`WorldQuery`] item type for [`"] - #[doc = stringify!(#struct_name)] - #[doc = "`], returned when iterating over query results."] - #[automatically_derived] - #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world { - #(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)* - #(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)* - } - - #[doc(hidden)] - #[doc = "Automatically generated internal [`WorldQuery`] fetch type for [`"] - #[doc = stringify!(#struct_name)] - #[doc = "`], used to define the world data accessed by this query."] - #[automatically_derived] - #visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world { - #(#field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)* - #(#ignored_field_idents: #ignored_field_types,)* - } - - // SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field - unsafe impl #user_impl_generics #path::query::WorldQuery - for #struct_name #user_ty_generics #user_where_clauses { - - type Item<'__w> = #item_struct_name #user_ty_generics_with_world; - type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world; - type ReadOnly = #read_only_struct_name #user_ty_generics; - type State = #state_struct_name #user_ty_generics; - - fn shrink<'__wlong: '__wshort, '__wshort>( - item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong> - ) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> { - #item_struct_name { - #( - #field_idents: <#field_types>::shrink(item.#field_idents), - )* - #( - #ignored_field_idents: item.#ignored_field_idents, - )* - } - } - - unsafe fn init_fetch<'__w>( - _world: &'__w #path::world::World, - state: &Self::State, - _last_change_tick: u32, - _change_tick: u32 - ) -> ::Fetch<'__w> { - #fetch_struct_name { - #(#field_idents: - <#field_types>::init_fetch( - _world, - &state.#field_idents, - _last_change_tick, - _change_tick - ), - )* - #(#ignored_field_idents: Default::default(),)* - } - } - - unsafe fn clone_fetch<'__w>( - _fetch: &::Fetch<'__w> - ) -> ::Fetch<'__w> { - #fetch_struct_name { - #( - #field_idents: <#field_types>::clone_fetch(& _fetch. #field_idents), - )* - #( - #ignored_field_idents: Default::default(), - )* - } - } - - const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*; - - const IS_ARCHETYPAL: bool = true #(&& <#field_types>::IS_ARCHETYPAL)*; - - /// SAFETY: we call `set_archetype` for each member that implements `Fetch` - #[inline] - unsafe fn set_archetype<'__w>( - _fetch: &mut ::Fetch<'__w>, - _state: &Self::State, - _archetype: &'__w #path::archetype::Archetype, - _table: &'__w #path::storage::Table - ) { - #(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _table);)* - } - - /// SAFETY: we call `set_table` for each member that implements `Fetch` - #[inline] - unsafe fn set_table<'__w>( - _fetch: &mut ::Fetch<'__w>, - _state: &Self::State, - _table: &'__w #path::storage::Table - ) { - #(<#field_types>::set_table(&mut _fetch.#field_idents, &_state.#field_idents, _table);)* - } - - /// SAFETY: we call `fetch` for each member that implements `Fetch`. - #[inline(always)] - unsafe fn fetch<'__w>( - _fetch: &mut ::Fetch<'__w>, - _entity: Entity, - _table_row: usize - ) -> ::Item<'__w> { - Self::Item { - #(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)* - #(#ignored_field_idents: Default::default(),)* - } - } - - #[allow(unused_variables)] - #[inline(always)] - unsafe fn filter_fetch<'__w>( - _fetch: &mut ::Fetch<'__w>, - _entity: Entity, - _table_row: usize - ) -> bool { - true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))* - } - - fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) { - #( <#field_types>::update_component_access(&state.#field_idents, _access); )* - } - - fn update_archetype_component_access( - state: &Self::State, - _archetype: &#path::archetype::Archetype, - _access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId> - ) { - #( - <#field_types>::update_archetype_component_access(&state.#field_idents, _archetype, _access); - )* - } - - fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics { - #state_struct_name { - #(#field_idents: <#field_types>::init_state(world),)* - #(#ignored_field_idents: Default::default(),)* - } - } - - fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool { - true #(&& <#field_types>::matches_component_set(&state.#field_idents, _set_contains_id))* - } - } - } - }; - - let mutable_impl = impl_fetch(false); - let readonly_impl = if fetch_struct_attributes.is_mutable { - let world_query_impl = impl_fetch(true); - quote! { - #[doc(hidden)] - #[doc = "Automatically generated internal [`WorldQuery`] type for [`"] - #[doc = stringify!(#struct_name)] - #[doc = "`], used for read-only access."] - #[automatically_derived] - #visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses { - #( #field_idents: #read_only_field_types, )* - #(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)* - } - - #world_query_impl - } - } else { - quote! {} - }; - - let read_only_asserts = if fetch_struct_attributes.is_mutable { - quote! { - // Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only. - // This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery` - // but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQuery` anyway - #( assert_readonly::<#read_only_field_types>(); )* - } - } else { - quote! { - // Statically checks that the safety guarantee of `ReadOnlyWorldQuery` for `$fetch_struct_name` actually holds true. - // We need this to make sure that we don't compile `ReadOnlyWorldQuery` if our struct contains nested `WorldQuery` - // members that don't implement it. I.e.: - // ``` - // #[derive(WorldQuery)] - // pub struct Foo { a: &'static mut MyComponent } - // ``` - #( assert_readonly::<#field_types>(); )* - } - }; - - TokenStream::from(quote! { - #mutable_impl - - #readonly_impl - - #[doc(hidden)] - #[doc = "Automatically generated internal [`WorldQuery`] state type for [`"] - #[doc = stringify!(#struct_name)] - #[doc = "`], used for caching."] - #[automatically_derived] - #visibility struct #state_struct_name #user_impl_generics #user_where_clauses { - #(#field_idents: <#field_types as #path::query::WorldQuery>::State,)* - #(#ignored_field_idents: #ignored_field_types,)* - } - - /// SAFETY: we assert fields are readonly below - unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQuery - for #read_only_struct_name #user_ty_generics #user_where_clauses {} - - #[allow(dead_code)] - const _: () = { - fn assert_readonly() - where - T: #path::query::ReadOnlyWorldQuery, - { - } - - // We generate a readonly assertion for every struct member. - fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world { - #read_only_asserts - } - }; - - // The original struct will most likely be left unused. As we don't want our users having - // to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed - // workaround. - #[allow(dead_code)] - const _: () = { - fn dead_code_workaround #user_impl_generics ( - q: #struct_name #user_ty_generics, - q2: #read_only_struct_name #user_ty_generics - ) #user_where_clauses { - #(q.#field_idents;)* - #(q.#ignored_field_idents;)* - #(q2.#field_idents;)* - #(q2.#ignored_field_idents;)* - - } - }; - }) -} - -struct WorldQueryFieldInfo { - /// Has `#[fetch(ignore)]` or `#[filter_fetch(ignore)]` attribute. - is_ignored: bool, - /// All field attributes except for `world_query` ones. - attrs: Vec, -} - -fn read_world_query_field_info(field: &Field) -> WorldQueryFieldInfo { - let is_ignored = field - .attrs - .iter() - .find(|attr| { - attr.path - .get_ident() - .map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME) - }) - .map_or(false, |attr| { - let mut is_ignored = false; - attr.parse_args_with(|input: ParseStream| { - if input - .parse::>()? - .is_some() - { - is_ignored = true; - } - Ok(()) - }) - .unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_ATTRIBUTE_NAME}` attribute format")); - - is_ignored - }); - - let attrs = field - .attrs - .iter() - .filter(|attr| { - attr.path - .get_ident() - .map_or(true, |ident| ident != WORLD_QUERY_ATTRIBUTE_NAME) - }) - .cloned() - .collect(); - - WorldQueryFieldInfo { is_ignored, attrs } -} diff --git a/azalea-ecs/azalea-ecs-macros/src/lib.rs b/azalea-ecs/azalea-ecs-macros/src/lib.rs deleted file mode 100755 index 9d4e9b2d2..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/lib.rs +++ /dev/null @@ -1,525 +0,0 @@ -//! A fork of bevy_ecs_macros that uses azalea_ecs instead of bevy_ecs. - -extern crate proc_macro; - -mod component; -mod fetch; -pub(crate) mod utils; - -use crate::fetch::derive_world_query_impl; -use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{format_ident, quote}; -use syn::{ - parse::{Parse, ParseStream}, - parse_macro_input, - punctuated::Punctuated, - spanned::Spanned, - token::Comma, - DeriveInput, Field, GenericParam, Ident, Index, LitInt, Meta, MetaList, NestedMeta, Result, - Token, TypeParam, -}; -use utils::{derive_label, get_named_struct_fields, BevyManifest}; - -struct AllTuples { - macro_ident: Ident, - start: usize, - end: usize, - idents: Vec, -} - -impl Parse for AllTuples { - fn parse(input: ParseStream) -> Result { - let macro_ident = input.parse::()?; - input.parse::()?; - let start = input.parse::()?.base10_parse()?; - input.parse::()?; - let end = input.parse::()?.base10_parse()?; - input.parse::()?; - let mut idents = vec![input.parse::()?]; - while input.parse::().is_ok() { - idents.push(input.parse::()?); - } - - Ok(AllTuples { - macro_ident, - start, - end, - idents, - }) - } -} - -#[proc_macro] -pub fn all_tuples(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as AllTuples); - let len = input.end - input.start; - let mut ident_tuples = Vec::with_capacity(len); - for i in input.start..=input.end { - let idents = input - .idents - .iter() - .map(|ident| format_ident!("{}{}", ident, i)); - if input.idents.len() < 2 { - ident_tuples.push(quote! { - #(#idents)* - }); - } else { - ident_tuples.push(quote! { - (#(#idents),*) - }); - } - } - - let macro_ident = &input.macro_ident; - let invocations = (input.start..=input.end).map(|i| { - let ident_tuples = &ident_tuples[..i]; - quote! { - #macro_ident!(#(#ident_tuples),*); - } - }); - TokenStream::from(quote! { - #( - #invocations - )* - }) -} - -enum BundleFieldKind { - Component, - Ignore, -} - -const BUNDLE_ATTRIBUTE_NAME: &str = "bundle"; -const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore"; - -#[proc_macro_derive(Bundle, attributes(bundle))] -pub fn derive_bundle(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let ecs_path = azalea_ecs_path(); - - let named_fields = match get_named_struct_fields(&ast.data) { - Ok(fields) => &fields.named, - Err(e) => return e.into_compile_error().into(), - }; - - let mut field_kind = Vec::with_capacity(named_fields.len()); - - 'field_loop: for field in named_fields.iter() { - for attr in &field.attrs { - if attr.path.is_ident(BUNDLE_ATTRIBUTE_NAME) { - if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() { - if let Some(&NestedMeta::Meta(Meta::Path(ref path))) = nested.first() { - if path.is_ident(BUNDLE_ATTRIBUTE_IGNORE_NAME) { - field_kind.push(BundleFieldKind::Ignore); - continue 'field_loop; - } - - return syn::Error::new( - path.span(), - format!( - "Invalid bundle attribute. Use `{BUNDLE_ATTRIBUTE_IGNORE_NAME}`" - ), - ) - .into_compile_error() - .into(); - } - - return syn::Error::new(attr.span(), format!("Invalid bundle attribute. Use `#[{BUNDLE_ATTRIBUTE_NAME}({BUNDLE_ATTRIBUTE_IGNORE_NAME})]`")).into_compile_error().into(); - } - } - } - - field_kind.push(BundleFieldKind::Component); - } - - let field = named_fields - .iter() - .map(|field| field.ident.as_ref().unwrap()) - .collect::>(); - let field_type = named_fields - .iter() - .map(|field| &field.ty) - .collect::>(); - - let mut field_component_ids = Vec::new(); - let mut field_get_components = Vec::new(); - let mut field_from_components = Vec::new(); - for ((field_type, field_kind), field) in - field_type.iter().zip(field_kind.iter()).zip(field.iter()) - { - match field_kind { - BundleFieldKind::Component => { - field_component_ids.push(quote! { - <#field_type as #ecs_path::bundle::_BevyBundle>::component_ids(components, storages, &mut *ids); - }); - field_get_components.push(quote! { - self.#field.get_components(&mut *func); - }); - field_from_components.push(quote! { - #field: <#field_type as #ecs_path::bundle::_BevyBundle>::from_components(ctx, &mut *func), - }); - } - - BundleFieldKind::Ignore => { - field_from_components.push(quote! { - #field: ::std::default::Default::default(), - }); - } - } - } - let generics = ast.generics; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let struct_name = &ast.ident; - - TokenStream::from(quote! { - /// SAFETY: ComponentId is returned in field-definition-order. [from_components] and [get_components] use field-definition-order - unsafe impl #impl_generics #ecs_path::bundle::_BevyBundle for #struct_name #ty_generics #where_clause { - fn component_ids( - components: &mut #ecs_path::component::Components, - storages: &mut #ecs_path::storage::Storages, - ids: &mut impl FnMut(#ecs_path::component::ComponentId) - ){ - #(#field_component_ids)* - } - - #[allow(unused_variables, non_snake_case)] - unsafe fn from_components<__T, __F>(ctx: &mut __T, func: &mut __F) -> Self - where - __F: FnMut(&mut __T) -> #ecs_path::ptr::OwningPtr<'_> - { - Self { - #(#field_from_components)* - } - } - - #[allow(unused_variables)] - fn get_components(self, func: &mut impl FnMut(#ecs_path::ptr::OwningPtr<'_>)) { - #(#field_get_components)* - } - } - }) -} - -fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec { - (0..count) - .map(|i| Ident::new(&fmt_string(i), Span::call_site())) - .collect::>() -} - -#[proc_macro] -pub fn impl_param_set(_input: TokenStream) -> TokenStream { - let mut tokens = TokenStream::new(); - let max_params = 8; - let params = get_idents(|i| format!("P{i}"), max_params); - let params_fetch = get_idents(|i| format!("PF{i}"), max_params); - let metas = get_idents(|i| format!("m{i}"), max_params); - let mut param_fn_muts = Vec::new(); - for (i, param) in params.iter().enumerate() { - let fn_name = Ident::new(&format!("p{i}"), Span::call_site()); - let index = Index::from(i); - param_fn_muts.push(quote! { - pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item { - // SAFETY: systems run without conflicts with other systems. - // Conflicting params in ParamSet are not accessible at the same time - // ParamSets are guaranteed to not conflict with other SystemParams - unsafe { - <#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick) - } - } - }); - } - - for param_count in 1..=max_params { - let param = ¶ms[0..param_count]; - let param_fetch = ¶ms_fetch[0..param_count]; - let meta = &metas[0..param_count]; - let param_fn_mut = ¶m_fn_muts[0..param_count]; - tokens.extend(TokenStream::from(quote! { - impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)> - { - type Fetch = ParamSetState<(#(#param::Fetch,)*)>; - } - - // SAFETY: All parameters are constrained to ReadOnlyFetch, so World is only read - - unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)> - where #(#param_fetch: ReadOnlySystemParamFetch,)* - { } - - // SAFETY: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts - // with any prior access, a panic will occur. - - unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)> - { - fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { - #( - // Pretend to add each param to the system alone, see if it conflicts - let mut #meta = system_meta.clone(); - #meta.component_access_set.clear(); - #meta.archetype_component_access.clear(); - #param_fetch::init(world, &mut #meta); - let #param = #param_fetch::init(world, &mut system_meta.clone()); - )* - #( - system_meta - .component_access_set - .extend(#meta.component_access_set); - system_meta - .archetype_component_access - .extend(&#meta.archetype_component_access); - )* - ParamSetState((#(#param,)*)) - } - - fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { - let (#(#param,)*) = &mut self.0; - #( - #param.new_archetype(archetype, system_meta); - )* - } - - fn apply(&mut self, world: &mut World) { - self.0.apply(world) - } - } - - - - impl<'w, 's, #(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamFetch<'w, 's> for ParamSetState<(#(#param_fetch,)*)> - { - type Item = ParamSet<'w, 's, (#(<#param_fetch as SystemParamFetch<'w, 's>>::Item,)*)>; - - #[inline] - unsafe fn get_param( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item { - ParamSet { - param_states: &mut state.0, - system_meta: system_meta.clone(), - world, - change_tick, - } - } - } - - impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> - { - - #(#param_fn_mut)* - } - })); - } - - tokens -} - -#[derive(Default)] -struct SystemParamFieldAttributes { - pub ignore: bool, -} - -static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param"; - -/// Implement `SystemParam` to use a struct as a parameter in a system -#[proc_macro_derive(SystemParam, attributes(system_param))] -pub fn derive_system_param(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let fields = match get_named_struct_fields(&ast.data) { - Ok(fields) => &fields.named, - Err(e) => return e.into_compile_error().into(), - }; - let path = azalea_ecs_path(); - - let field_attributes = fields - .iter() - .map(|field| { - ( - field, - field - .attrs - .iter() - .find(|a| *a.path.get_ident().as_ref().unwrap() == SYSTEM_PARAM_ATTRIBUTE_NAME) - .map_or_else(SystemParamFieldAttributes::default, |a| { - syn::custom_keyword!(ignore); - let mut attributes = SystemParamFieldAttributes::default(); - a.parse_args_with(|input: ParseStream| { - if input.parse::>()?.is_some() { - attributes.ignore = true; - } - Ok(()) - }) - .expect("Invalid 'system_param' attribute format."); - - attributes - }), - ) - }) - .collect::>(); - let mut fields = Vec::new(); - let mut field_indices = Vec::new(); - let mut field_types = Vec::new(); - let mut ignored_fields = Vec::new(); - let mut ignored_field_types = Vec::new(); - for (i, (field, attrs)) in field_attributes.iter().enumerate() { - if attrs.ignore { - ignored_fields.push(field.ident.as_ref().unwrap()); - ignored_field_types.push(&field.ty); - } else { - fields.push(field.ident.as_ref().unwrap()); - field_types.push(&field.ty); - field_indices.push(Index::from(i)); - } - } - - let generics = ast.generics; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - let lifetimeless_generics: Vec<_> = generics - .params - .iter() - .filter(|g| matches!(g, GenericParam::Type(_))) - .collect(); - - let mut punctuated_generics = Punctuated::<_, Token![,]>::new(); - punctuated_generics.extend(lifetimeless_generics.iter().map(|g| match g { - GenericParam::Type(g) => GenericParam::Type(TypeParam { - default: None, - ..g.clone() - }), - _ => unreachable!(), - })); - - let mut punctuated_generic_idents = Punctuated::<_, Token![,]>::new(); - punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g { - GenericParam::Type(g) => &g.ident, - _ => unreachable!(), - })); - - let struct_name = &ast.ident; - let fetch_struct_visibility = &ast.vis; - - TokenStream::from(quote! { - // We define the FetchState struct in an anonymous scope to avoid polluting the user namespace. - // The struct can still be accessed via SystemParam::Fetch, e.g. EventReaderState can be accessed via - // as SystemParam>::Fetch - const _: () = { - impl #impl_generics #path::system::SystemParam for #struct_name #ty_generics #where_clause { - type Fetch = FetchState <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents>; - } - - #[doc(hidden)] - #fetch_struct_visibility struct FetchState { - state: TSystemParamState, - marker: std::marker::PhantomData(#punctuated_generic_idents)> - } - - unsafe impl #path::system::SystemParamState for FetchState #where_clause { - fn init(world: &mut #path::world::World, system_meta: &mut #path::system::SystemMeta) -> Self { - Self { - state: TSystemParamState::init(world, system_meta), - marker: std::marker::PhantomData, - } - } - - fn new_archetype(&mut self, archetype: &#path::archetype::Archetype, system_meta: &mut #path::system::SystemMeta) { - self.state.new_archetype(archetype, system_meta) - } - - fn apply(&mut self, world: &mut #path::world::World) { - self.state.apply(world) - } - } - - impl #impl_generics #path::system::SystemParamFetch<'w, 's> for FetchState <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents> #where_clause { - type Item = #struct_name #ty_generics; - unsafe fn get_param( - state: &'s mut Self, - system_meta: &#path::system::SystemMeta, - world: &'w #path::world::World, - change_tick: u32, - ) -> Self::Item { - #struct_name { - #(#fields: <<#field_types as #path::system::SystemParam>::Fetch as #path::system::SystemParamFetch>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick),)* - #(#ignored_fields: <#ignored_field_types>::default(),)* - } - } - } - - // Safety: The `ParamState` is `ReadOnlySystemParamFetch`, so this can only read from the `World` - unsafe impl #path::system::ReadOnlySystemParamFetch for FetchState #where_clause {} - }; - }) -} - -/// Implement `WorldQuery` to use a struct as a parameter in a query -#[proc_macro_derive(WorldQuery, attributes(world_query))] -pub fn derive_world_query(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - derive_world_query_impl(ast) -} - -/// Generates an impl of the `SystemLabel` trait. -/// -/// This works only for unit structs, or enums with only unit variants. -/// You may force a struct or variant to behave as if it were fieldless with -/// `#[system_label(ignore_fields)]`. -#[proc_macro_derive(SystemLabel, attributes(system_label))] -pub fn derive_system_label(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let mut trait_path = azalea_ecs_path(); - trait_path.segments.push(format_ident!("schedule").into()); - trait_path - .segments - .push(format_ident!("SystemLabel").into()); - derive_label(input, &trait_path, "system_label") -} - -/// Generates an impl of the `StageLabel` trait. -/// -/// This works only for unit structs, or enums with only unit variants. -/// You may force a struct or variant to behave as if it were fieldless with -/// `#[stage_label(ignore_fields)]`. -#[proc_macro_derive(StageLabel, attributes(stage_label))] -pub fn derive_stage_label(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let mut trait_path = azalea_ecs_path(); - trait_path.segments.push(format_ident!("schedule").into()); - trait_path - .segments - .push(format_ident!("_BevyStageLabel").into()); - derive_label(input, &trait_path, "stage_label") -} - -/// Generates an impl of the `RunCriteriaLabel` trait. -/// -/// This works only for unit structs, or enums with only unit variants. -/// You may force a struct or variant to behave as if it were fieldless with -/// `#[run_criteria_label(ignore_fields)]`. -#[proc_macro_derive(RunCriteriaLabel, attributes(run_criteria_label))] -pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let mut trait_path = azalea_ecs_path(); - trait_path.segments.push(format_ident!("schedule").into()); - trait_path - .segments - .push(format_ident!("RunCriteriaLabel").into()); - derive_label(input, &trait_path, "run_criteria_label") -} - -pub(crate) fn azalea_ecs_path() -> syn::Path { - BevyManifest::default().get_path("azalea_ecs") -} - -#[proc_macro_derive(Resource)] -pub fn derive_resource(input: TokenStream) -> TokenStream { - component::derive_resource(input) -} - -#[proc_macro_derive(Component, attributes(component))] -pub fn derive_component(input: TokenStream) -> TokenStream { - component::derive_component(input) -} diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs b/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs deleted file mode 100644 index 05f0712ac..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![allow(dead_code)] - -use syn::DeriveInput; - -use super::symbol::Symbol; - -pub fn parse_attrs(ast: &DeriveInput, attr_name: Symbol) -> syn::Result> { - let mut list = Vec::new(); - for attr in ast.attrs.iter().filter(|a| a.path == attr_name) { - match attr.parse_meta()? { - syn::Meta::List(meta) => list.extend(meta.nested.into_iter()), - other => { - return Err(syn::Error::new_spanned( - other, - format!("expected #[{attr_name}(...)]"), - )) - } - } - } - Ok(list) -} - -pub fn get_lit_str(attr_name: Symbol, lit: &syn::Lit) -> syn::Result<&syn::LitStr> { - if let syn::Lit::Str(lit) = lit { - Ok(lit) - } else { - Err(syn::Error::new_spanned( - lit, - format!("expected {attr_name} attribute to be a string: `{attr_name} = \"...\"`"), - )) - } -} - -pub fn get_lit_bool(attr_name: Symbol, lit: &syn::Lit) -> syn::Result { - if let syn::Lit::Bool(lit) = lit { - Ok(lit.value()) - } else { - Err(syn::Error::new_spanned( - lit, - format!( - "expected {attr_name} attribute to be a bool value, `true` or `false`: `{attr_name} = ...`" - ), - )) - } -} diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs b/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs deleted file mode 100644 index c79e3efe4..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs +++ /dev/null @@ -1,227 +0,0 @@ -#![allow(dead_code)] - -extern crate proc_macro; - -mod attrs; -mod shape; -mod symbol; - -pub use attrs::*; -pub use shape::*; -pub use symbol::*; - -use proc_macro::TokenStream; -use quote::{quote, quote_spanned}; -use std::{env, path::PathBuf}; -use syn::spanned::Spanned; -use toml::{map::Map, Value}; - -pub struct BevyManifest { - manifest: Map, -} - -impl Default for BevyManifest { - fn default() -> Self { - Self { - manifest: env::var_os("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .map(|mut path| { - path.push("Cargo.toml"); - let manifest = std::fs::read_to_string(path).unwrap(); - toml::from_str(&manifest).unwrap() - }) - .unwrap(), - } - } -} - -impl BevyManifest { - pub fn maybe_get_path(&self, name: &str) -> Option { - const AZALEA: &str = "azalea"; - const AZALEA_ECS: &str = "azalea_ecs"; - const BEVY_ECS: &str = "bevy_ecs"; - const BEVY: &str = "bevy"; - - fn dep_package(dep: &Value) -> Option<&str> { - if dep.as_str().is_some() { - None - } else { - dep.as_table() - .unwrap() - .get("package") - .map(|name| name.as_str().unwrap()) - } - } - - let find_in_deps = |deps: &Map| -> Option { - let package = if let Some(dep) = deps.get(name) { - return Some(Self::parse_str(dep_package(dep).unwrap_or(name))); - } else if let Some(dep) = deps.get(AZALEA) { - dep_package(dep).unwrap_or(AZALEA) - } else if let Some(dep) = deps.get(AZALEA_ECS) { - dep_package(dep).unwrap_or(AZALEA_ECS) - } else if let Some(dep) = deps.get(BEVY_ECS) { - dep_package(dep).unwrap_or(BEVY_ECS) - } else if let Some(dep) = deps.get(BEVY) { - dep_package(dep).unwrap_or(BEVY) - } else { - return None; - }; - - let mut path = Self::parse_str::(package); - if let Some(module) = name.strip_prefix("azalea_") { - path.segments.push(Self::parse_str(module)); - } - Some(path) - }; - - let deps = self - .manifest - .get("dependencies") - .map(|deps| deps.as_table().unwrap()); - let deps_dev = self - .manifest - .get("dev-dependencies") - .map(|deps| deps.as_table().unwrap()); - - deps.and_then(find_in_deps) - .or_else(|| deps_dev.and_then(find_in_deps)) - } - - /// Returns the path for the crate with the given name. - /// - /// This is a convenience method for constructing a [manifest] and - /// calling the [`get_path`] method. - /// - /// This method should only be used where you just need the path and can't - /// cache the [manifest]. If caching is possible, it's recommended to create - /// the [manifest] yourself and use the [`get_path`] method. - /// - /// [`get_path`]: Self::get_path - /// [manifest]: Self - pub fn get_path_direct(name: &str) -> syn::Path { - Self::default().get_path(name) - } - - pub fn get_path(&self, name: &str) -> syn::Path { - self.maybe_get_path(name) - .unwrap_or_else(|| Self::parse_str(name)) - } - - pub fn parse_str(path: &str) -> T { - syn::parse(path.parse::().unwrap()).unwrap() - } -} - -/// Derive a label trait -/// -/// # Args -/// -/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label -/// trait -/// - `trait_path`: The path [`syn::Path`] to the label trait -pub fn derive_label( - input: syn::DeriveInput, - trait_path: &syn::Path, - attr_name: &str, -) -> TokenStream { - // return true if the variant specified is an `ignore_fields` attribute - fn is_ignore(attr: &syn::Attribute, attr_name: &str) -> bool { - if attr.path.get_ident().as_ref().unwrap() != &attr_name { - return false; - } - - syn::custom_keyword!(ignore_fields); - attr.parse_args_with(|input: syn::parse::ParseStream| { - let ignore = input.parse::>()?.is_some(); - Ok(ignore) - }) - .unwrap() - } - - let ident = input.ident.clone(); - - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause { - where_token: Default::default(), - predicates: Default::default(), - }); - where_clause - .predicates - .push(syn::parse2(quote! { Self: 'static }).unwrap()); - - let as_str = match input.data { - syn::Data::Struct(d) => { - // see if the user tried to ignore fields incorrectly - if let Some(attr) = d - .fields - .iter() - .flat_map(|f| &f.attrs) - .find(|a| is_ignore(a, attr_name)) - { - let err_msg = format!("`#[{attr_name}(ignore_fields)]` cannot be applied to fields individually: add it to the struct declaration"); - return quote_spanned! { - attr.span() => compile_error!(#err_msg); - } - .into(); - } - // Structs must either be fieldless, or explicitly ignore the fields. - let ignore_fields = input.attrs.iter().any(|a| is_ignore(a, attr_name)); - if matches!(d.fields, syn::Fields::Unit) || ignore_fields { - let lit = ident.to_string(); - quote! { #lit } - } else { - let err_msg = format!("Labels cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`"); - return quote_spanned! { - d.fields.span() => compile_error!(#err_msg); - } - .into(); - } - } - syn::Data::Enum(d) => { - // check if the user put #[label(ignore_fields)] in the wrong place - if let Some(attr) = input.attrs.iter().find(|a| is_ignore(a, attr_name)) { - let err_msg = format!("`#[{attr_name}(ignore_fields)]` can only be applied to enum variants or struct declarations"); - return quote_spanned! { - attr.span() => compile_error!(#err_msg); - } - .into(); - } - let arms = d.variants.iter().map(|v| { - // Variants must either be fieldless, or explicitly ignore the fields. - let ignore_fields = v.attrs.iter().any(|a| is_ignore(a, attr_name)); - if matches!(v.fields, syn::Fields::Unit) | ignore_fields { - let mut path = syn::Path::from(ident.clone()); - path.segments.push(v.ident.clone().into()); - let lit = format!("{ident}::{}", v.ident.clone()); - quote! { #path { .. } => #lit } - } else { - let err_msg = format!("Label variants cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`"); - quote_spanned! { - v.fields.span() => _ => { compile_error!(#err_msg); } - } - } - }); - quote! { - match self { - #(#arms),* - } - } - } - syn::Data::Union(_) => { - return quote_spanned! { - input.span() => compile_error!("Unions cannot be used as labels."); - } - .into(); - } - }; - - (quote! { - impl #impl_generics #trait_path for #ident #ty_generics #where_clause { - fn as_str(&self) -> &'static str { - #as_str - } - } - }) - .into() -} diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs b/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs deleted file mode 100644 index 98230749a..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs +++ /dev/null @@ -1,21 +0,0 @@ -use proc_macro::Span; -use syn::{Data, DataStruct, Error, Fields, FieldsNamed}; - -/// Get the fields of a data structure if that structure is a struct with named -/// fields; otherwise, return a compile error that points to the site of the -/// macro invocation. -pub fn get_named_struct_fields(data: &syn::Data) -> syn::Result<&FieldsNamed> { - match data { - Data::Struct(DataStruct { - fields: Fields::Named(fields), - .. - }) => Ok(fields), - _ => Err(Error::new( - // This deliberately points to the call site rather than the structure - // body; marking the entire body as the source of the error makes it - // impossible to figure out which `derive` has a problem. - Span::call_site().into(), - "Only structs with named fields are supported", - )), - } -} diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs b/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs deleted file mode 100644 index dc639f4d8..000000000 --- a/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::fmt::{self, Display}; -use syn::{Ident, Path}; - -#[derive(Copy, Clone)] -pub struct Symbol(pub &'static str); - -impl PartialEq for Ident { - fn eq(&self, word: &Symbol) -> bool { - self == word.0 - } -} - -impl<'a> PartialEq for &'a Ident { - fn eq(&self, word: &Symbol) -> bool { - *self == word.0 - } -} - -impl PartialEq for Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl<'a> PartialEq for &'a Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl Display for Symbol { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(self.0) - } -} diff --git a/azalea-ecs/src/lib.rs b/azalea-ecs/src/lib.rs deleted file mode 100644 index bc374e451..000000000 --- a/azalea-ecs/src/lib.rs +++ /dev/null @@ -1,157 +0,0 @@ -#![feature(trait_alias)] - -//! Re-export important parts of [`bevy_ecs`] and [`bevy_app`] and make them -//! more compatible with Azalea. -//! -//! This is completely compatible with `bevy_ecs`, so it won't cause issues if -//! you use plugins meant for Bevy. -//! -//! Changes: -//! - Add [`TickPlugin`], [`TickStage`] and [`AppTickExt`] (which adds -//! `app.add_tick_system` and `app.add_tick_system_set`). -//! - Change the macros to use azalea/azalea_ecs instead of bevy/bevy_ecs -//! - Rename `world::World` to [`ecs::Ecs`] -//! - Re-export `bevy_app` in the [`app`] module. -//! -//! [`bevy_ecs`]: https://docs.rs/bevy_ecs -//! [`bevy_app`]: https://docs.rs/bevy_app - -use std::time::{Duration, Instant}; - -pub mod ecs { - pub use bevy_ecs::world::World as Ecs; - pub use bevy_ecs::world::{EntityMut, EntityRef, Mut}; -} -pub mod component { - pub use azalea_ecs_macros::Component; - pub use bevy_ecs::component::{ComponentId, ComponentStorage, Components, TableStorage}; - - // we do this because re-exporting Component would re-export the macro as well, - // which is bad (since we have our own Component macro) - // instead, we have to do this so Component is a trait alias and the original - // impl-able trait is still available as _BevyComponent - pub trait Component = bevy_ecs::component::Component; - pub use bevy_ecs::component::Component as _BevyComponent; -} -pub mod bundle { - pub use azalea_ecs_macros::Bundle; - pub trait Bundle = bevy_ecs::bundle::Bundle; - pub use bevy_ecs::bundle::Bundle as _BevyBundle; -} -pub mod system { - pub use azalea_ecs_macros::Resource; - pub use bevy_ecs::system::{ - Command, Commands, EntityCommands, Query, Res, ResMut, SystemState, - }; - pub trait Resource = bevy_ecs::system::Resource; - pub use bevy_ecs::system::Resource as _BevyResource; -} -pub mod schedule { - pub use azalea_ecs_macros::StageLabel; - pub use bevy_ecs::schedule::{ - IntoRunCriteria, IntoSystemDescriptor, ReportExecutionOrderAmbiguities, Schedule, Stage, - SystemSet, SystemStage, - }; - pub trait StageLabel = bevy_ecs::schedule::StageLabel; - pub use bevy_ecs::schedule::StageLabel as _BevyStageLabel; -} -pub use bevy_app as app; -pub use bevy_ecs::{entity, event, ptr, query, storage}; - -use app::{App, CoreStage, Plugin}; -use bevy_ecs::schedule::*; -use ecs::Ecs; - -pub struct TickPlugin { - /// How often a tick should happen. 50 milliseconds by default. Set to 0 to - /// tick every update. - pub tick_interval: Duration, -} -impl Plugin for TickPlugin { - fn build(&self, app: &mut App) { - app.add_stage_before( - CoreStage::Update, - TickLabel, - TickStage { - interval: self.tick_interval, - next_tick: Instant::now(), - stage: Box::new(SystemStage::parallel()), - }, - ); - } -} -impl Default for TickPlugin { - fn default() -> Self { - Self { - tick_interval: Duration::from_millis(50), - } - } -} - -#[derive(StageLabel)] -struct TickLabel; - -/// A [`Stage`] that runs every 50 milliseconds. -pub struct TickStage { - pub interval: Duration, - pub next_tick: Instant, - stage: Box, -} - -impl Stage for TickStage { - fn run(&mut self, ecs: &mut Ecs) { - // if the interval is 0, that means it runs every tick - if self.interval.is_zero() { - self.stage.run(ecs); - return; - } - // keep calling run until it's caught up - // TODO: Minecraft bursts up to 10 ticks and then skips, we should too (but - // check the source so we do it right) - while Instant::now() > self.next_tick { - self.next_tick += self.interval; - self.stage.run(ecs); - } - } -} - -pub trait AppTickExt { - fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App; - fn add_tick_system(&mut self, system: impl IntoSystemDescriptor) -> &mut App; -} - -impl AppTickExt for App { - /// Adds a set of ECS systems that will run every 50 milliseconds. - /// - /// Note that you should NOT have `EventReader`s in tick systems, as this - /// will make them sometimes be missed. - fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App { - let tick_stage = self - .schedule - .get_stage_mut::(TickLabel) - .expect("Tick Stage not found"); - let stage = tick_stage - .stage - .downcast_mut::() - .expect("Fixed Timestep sub-stage is not a SystemStage"); - stage.add_system_set(system_set); - self - } - - /// Adds a new ECS system that will run every 50 milliseconds. - /// - /// Note that you should NOT have `EventReader`s in tick systems, as this - /// will make them sometimes be missed. - fn add_tick_system(&mut self, system: impl IntoSystemDescriptor) -> &mut App { - let tick_stage = self - .schedule - .get_stage_mut::(TickLabel) - .expect("Tick Stage not found"); - let stage = tick_stage - .stage - .downcast_mut::() - .expect("Fixed Timestep sub-stage is not a SystemStage"); - stage.add_system(system); - self - } -} diff --git a/azalea-physics/Cargo.toml b/azalea-physics/Cargo.toml index 9305080bd..dd5794712 100644 --- a/azalea-physics/Cargo.toml +++ b/azalea-physics/Cargo.toml @@ -9,13 +9,15 @@ version = "0.6.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-block = {path = "../azalea-block", version = "^0.6.0"} -azalea-core = {path = "../azalea-core", version = "^0.6.0"} -azalea-ecs = {version = "0.6.0", path = "../azalea-ecs"} -azalea-registry = {path = "../azalea-registry", version = "^0.6.0"} -azalea-world = {path = "../azalea-world", version = "^0.6.0"} +azalea-block = { path = "../azalea-block", version = "^0.6.0" } +azalea-core = { path = "../azalea-core", version = "^0.6.0" } +azalea-registry = { path = "../azalea-registry", version = "^0.6.0" } +azalea-world = { path = "../azalea-world", version = "^0.6.0" } +bevy_app = "0.10.0" +bevy_ecs = "0.10.0" once_cell = "1.16.0" parking_lot = "^0.12.1" [dev-dependencies] +bevy_time = "0.10.0" uuid = "^1.1.2" diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index 7d9340202..53efd2fec 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -7,7 +7,7 @@ mod world_collisions; use azalea_core::{Axis, Vec3, AABB, EPSILON}; use azalea_world::{ entity::{self}, - MoveEntityError, World, + Instance, MoveEntityError, }; pub use blocks::BlockWithShape; pub use discrete_voxel_shape::*; @@ -52,7 +52,7 @@ pub enum MoverType { // return var4; // } -fn collide(movement: &Vec3, world: &World, physics: &entity::Physics) -> Vec3 { +fn collide(movement: &Vec3, world: &Instance, physics: &entity::Physics) -> Vec3 { let entity_bounding_box = physics.bounding_box; // TODO: get_entity_collisions // let entity_collisions = world.get_entity_collisions(self, @@ -73,7 +73,7 @@ fn collide(movement: &Vec3, world: &World, physics: &entity::Physics) -> Vec3 { pub fn move_colliding( _mover_type: &MoverType, movement: &Vec3, - world: &World, + world: &Instance, position: &mut entity::Position, physics: &mut entity::Physics, ) -> Result<(), MoveEntityError> { @@ -186,7 +186,7 @@ pub fn move_colliding( fn collide_bounding_box( movement: &Vec3, entity_bounding_box: &AABB, - world: &World, + world: &Instance, entity_collisions: Vec, ) -> Vec3 { let mut collision_boxes: Vec = Vec::with_capacity(entity_collisions.len() + 1); diff --git a/azalea-physics/src/collision/world_collisions.rs b/azalea-physics/src/collision/world_collisions.rs index 9ffc62a5d..aa55150e6 100644 --- a/azalea-physics/src/collision/world_collisions.rs +++ b/azalea-physics/src/collision/world_collisions.rs @@ -2,16 +2,16 @@ use super::Shapes; use crate::collision::{BlockWithShape, VoxelShape, AABB}; use azalea_block::BlockState; use azalea_core::{ChunkPos, ChunkSectionPos, Cursor3d, CursorIterationType, EPSILON}; -use azalea_world::{Chunk, World}; +use azalea_world::{Chunk, Instance}; use parking_lot::RwLock; use std::sync::Arc; -pub fn get_block_collisions(world: &World, aabb: AABB) -> BlockCollisions<'_> { +pub fn get_block_collisions(world: &Instance, aabb: AABB) -> BlockCollisions<'_> { BlockCollisions::new(world, aabb) } pub struct BlockCollisions<'a> { - pub world: &'a World, + pub world: &'a Instance, pub aabb: AABB, pub entity_shape: VoxelShape, pub cursor: Cursor3d, @@ -19,7 +19,7 @@ pub struct BlockCollisions<'a> { } impl<'a> BlockCollisions<'a> { - pub fn new(world: &'a World, aabb: AABB) -> Self { + pub fn new(world: &'a Instance, aabb: AABB) -> Self { let origin_x = (aabb.min_x - EPSILON).floor() as i32 - 1; let origin_y = (aabb.min_y - EPSILON).floor() as i32 - 1; let origin_z = (aabb.min_z - EPSILON).floor() as i32 - 1; diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 0a8f8a8bc..e39540612 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -5,37 +5,38 @@ pub mod collision; use azalea_block::{Block, BlockState}; use azalea_core::{BlockPos, Vec3}; -use azalea_ecs::{ - app::{App, Plugin}, - entity::Entity, - event::{EventReader, EventWriter}, - query::With, - schedule::IntoSystemDescriptor, - system::{Query, Res}, - AppTickExt, -}; use azalea_world::{ entity::{ metadata::Sprinting, move_relative, Attributes, Jumping, Local, Physics, Position, WorldName, }, - World, WorldContainer, + Instance, WorldContainer, +}; +use bevy_app::{App, CoreSchedule, IntoSystemAppConfigs, Plugin}; +use bevy_ecs::{ + entity::Entity, + event::{EventReader, EventWriter}, + query::With, + schedule::{IntoSystemConfig, IntoSystemConfigs, SystemSet}, + system::{Query, Res}, }; use collision::{move_colliding, MoverType}; +/// A Bevy [`SystemSet`] for running physics that makes entities do things. +#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] +pub struct PhysicsSet; + pub struct PhysicsPlugin; impl Plugin for PhysicsPlugin { fn build(&self, app: &mut App) { app.add_event::() - .add_system( - force_jump_listener - .label("force_jump_listener") - .after("walk_listener") - .after("sprint_listener") - .before(azalea_world::entity::update_bounding_box), - ) - .add_tick_system(travel.label("travel").after(ai_step)) - .add_tick_system(ai_step.label("ai_step")); + .add_system(force_jump_listener.before(azalea_world::entity::update_bounding_box)) + .add_systems( + (ai_step, travel) + .chain() + .in_set(PhysicsSet) + .in_schedule(CoreSchedule::FixedUpdate), + ); } } @@ -156,7 +157,7 @@ pub fn ai_step( /// Jump even if we aren't on the ground. pub struct ForceJumpEvent(pub Entity); -fn force_jump_listener( +pub fn force_jump_listener( mut query: Query<(&mut Physics, &Position, &Sprinting, &WorldName)>, world_container: Res, mut events: EventReader, @@ -201,7 +202,7 @@ fn get_block_pos_below_that_affects_movement(position: &Position) -> BlockPos { fn handle_relative_friction_and_calculate_movement( block_friction: f32, - world: &World, + world: &Instance, physics: &mut Physics, position: &mut Position, attributes: &Attributes, @@ -251,7 +252,7 @@ fn get_friction_influenced_speed(physics: &Physics, attributes: &Attributes, fri /// Returns the what the entity's jump should be multiplied by based on the /// block they're standing on. -fn block_jump_factor(world: &World, position: &Position) -> f32 { +fn block_jump_factor(world: &Instance, position: &Position) -> f32 { let block_at_pos = world.chunks.get_block_state(&position.into()); let block_below = world .chunks @@ -279,7 +280,7 @@ fn block_jump_factor(world: &World, position: &Position) -> f32 { // public double getJumpBoostPower() { // return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F * // (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D; } -fn jump_power(world: &World, position: &Position) -> f32 { +fn jump_power(world: &Instance, position: &Position) -> f32 { 0.42 * block_jump_factor(world, position) } @@ -303,22 +304,21 @@ mod tests { use super::*; use azalea_core::{ChunkPos, ResourceLocation}; - use azalea_ecs::{app::App, TickPlugin}; use azalea_world::{ entity::{EntityBundle, EntityPlugin, MinecraftEntityId}, Chunk, PartialWorld, }; + use bevy_app::App; + use bevy_time::fixed_timestep::FixedTime; use uuid::Uuid; /// You need an app to spawn entities in the world and do updates. fn make_test_app() -> App { let mut app = App::new(); - app.add_plugin(TickPlugin { - tick_interval: Duration::ZERO, - }) - .add_plugin(PhysicsPlugin) - .add_plugin(EntityPlugin) - .init_resource::(); + app.add_plugin(PhysicsPlugin) + .add_plugin(EntityPlugin) + .insert_resource(FixedTime::new(Duration::from_millis(50))) + .init_resource::(); app } @@ -353,6 +353,7 @@ mod tests { // y should start at 70 assert_eq!(entity_pos.y, 70.); } + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); { let entity_pos = *app.world.get::(entity).unwrap(); @@ -361,6 +362,7 @@ mod tests { let entity_physics = app.world.get::(entity).unwrap().clone(); assert!(entity_physics.delta.y < 0.); } + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); { let entity_pos = *app.world.get::(entity).unwrap(); @@ -413,6 +415,7 @@ mod tests { block_state.is_some(), "Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed" ); + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); { let entity_pos = *app.world.get::(entity).unwrap(); @@ -421,6 +424,7 @@ mod tests { let entity_physics = app.world.get::(entity).unwrap().clone(); assert!(entity_physics.delta.y < 0.); } + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); { let entity_pos = *app.world.get::(entity).unwrap(); @@ -476,6 +480,7 @@ mod tests { ); // do a few steps so we fall on the slab for _ in 0..20 { + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); } let entity_pos = app.world.get::(entity).unwrap(); @@ -528,6 +533,7 @@ mod tests { ); // do a few steps so we fall on the slab for _ in 0..20 { + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); } let entity_pos = app.world.get::(entity).unwrap(); @@ -584,6 +590,7 @@ mod tests { ); // do a few steps so we fall on the wall for _ in 0..20 { + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); } @@ -645,6 +652,7 @@ mod tests { ); // do a few steps so we fall on the wall for _ in 0..20 { + app.world.run_schedule(CoreSchedule::FixedUpdate); app.update(); } diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml index fa669b2e3..1bbda7eb3 100644 --- a/azalea-protocol/Cargo.toml +++ b/azalea-protocol/Cargo.toml @@ -9,32 +9,39 @@ version = "0.6.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true} +async-compression = { version = "^0.3.8", features = [ + "tokio", + "zlib", +], optional = true } async-recursion = "1.0.0" -azalea-auth = {path = "../azalea-auth", version = "^0.6.0" } -azalea-block = {path = "../azalea-block", default-features = false, version = "^0.6.0" } -azalea-brigadier = {path = "../azalea-brigadier", version = "^0.6.0", features = ["azalea-buf"]} -azalea-buf = {path = "../azalea-buf", version = "^0.6.0" } -azalea-chat = {path = "../azalea-chat", version = "^0.6.0" } -azalea-core = {path = "../azalea-core", optional = true, version = "^0.6.0" } -azalea-crypto = {path = "../azalea-crypto", version = "^0.6.0" } -azalea-nbt = {path = "../azalea-nbt", version = "^0.6.0" } -azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.6.0" } -azalea-registry = {path = "../azalea-registry", version = "^0.6.0" } -azalea-world = {path = "../azalea-world", version = "^0.6.0" } -bevy_ecs = { version = "0.9.1", default-features = false } +azalea-auth = { path = "../azalea-auth", version = "^0.6.0" } +azalea-block = { path = "../azalea-block", default-features = false, version = "^0.6.0" } +azalea-brigadier = { path = "../azalea-brigadier", version = "^0.6.0", features = [ + "azalea-buf", +] } +azalea-buf = { path = "../azalea-buf", version = "^0.6.0" } +azalea-chat = { path = "../azalea-chat", version = "^0.6.0" } +azalea-core = { path = "../azalea-core", optional = true, version = "^0.6.0" } +azalea-crypto = { path = "../azalea-crypto", version = "^0.6.0" } +azalea-nbt = { path = "../azalea-nbt", version = "^0.6.0" } +azalea-protocol-macros = { path = "./azalea-protocol-macros", version = "^0.6.0" } +azalea-registry = { path = "../azalea-registry", version = "^0.6.0" } +azalea-world = { path = "../azalea-world", version = "^0.6.0" } +bevy_ecs = { version = "0.10.0", default-features = false } byteorder = "^1.4.3" bytes = "^1.1.0" flate2 = "1.0.23" futures = "0.3.24" futures-util = "0.3.24" log = "0.4.17" -serde = {version = "1.0.130", features = ["serde_derive"]} +serde = { version = "1.0.130", features = ["serde_derive"] } serde_json = "^1.0.72" thiserror = "1.0.37" -tokio = {version = "^1.24.2", features = ["io-util", "net", "macros"]} -tokio-util = {version = "0.7.4", features = ["codec"]} -trust-dns-resolver = {version = "^0.22.0", default-features = false, features = ["tokio-runtime"]} +tokio = { version = "^1.24.2", features = ["io-util", "net", "macros"] } +tokio-util = { version = "0.7.4", features = ["codec"] } +trust-dns-resolver = { version = "^0.22.0", default-features = false, features = [ + "tokio-runtime", +] } uuid = "1.1.2" [features] diff --git a/azalea-world/Cargo.toml b/azalea-world/Cargo.toml index 4d53cabda..113125a48 100644 --- a/azalea-world/Cargo.toml +++ b/azalea-world/Cargo.toml @@ -15,9 +15,10 @@ azalea-chat = { path = "../azalea-chat", version = "^0.6.0" } azalea-core = { path = "../azalea-core", version = "^0.6.0", features = [ "bevy_ecs", ] } -azalea-ecs = { version = "0.6.0", path = "../azalea-ecs" } azalea-nbt = { path = "../azalea-nbt", version = "^0.6.0" } azalea-registry = { path = "../azalea-registry", version = "^0.6.0" } +bevy_app = "0.10.0" +bevy_ecs = "0.10.0" derive_more = { version = "0.99.17", features = ["deref", "deref_mut"] } enum-as-inner = "0.5.1" log = "0.4.17" diff --git a/azalea-world/src/container.rs b/azalea-world/src/container.rs index 74d706591..fdd89a751 100644 --- a/azalea-world/src/container.rs +++ b/azalea-world/src/container.rs @@ -1,5 +1,5 @@ use azalea_core::ResourceLocation; -use azalea_ecs::system::Resource; +use bevy_ecs::system::Resource; use log::error; use nohash_hasher::IntMap; use parking_lot::RwLock; @@ -8,7 +8,7 @@ use std::{ sync::{Arc, Weak}, }; -use crate::{ChunkStorage, World}; +use crate::{ChunkStorage, Instance}; /// A container of [`World`]s. Worlds are stored as a Weak pointer here, so /// if no clients are using a world it will be forgotten. @@ -26,7 +26,7 @@ pub struct WorldContainer { // telling them apart. We hope most servers are nice and don't do that though. It's only an // issue when there's multiple clients with the same WorldContainer in different worlds // anyways. - pub worlds: HashMap>>, + pub worlds: HashMap>>, } impl WorldContainer { @@ -37,7 +37,7 @@ impl WorldContainer { } /// Get a world from the container. - pub fn get(&self, name: &ResourceLocation) -> Option>> { + pub fn get(&self, name: &ResourceLocation) -> Option>> { self.worlds.get(name).and_then(|world| world.upgrade()) } @@ -49,7 +49,7 @@ impl WorldContainer { name: ResourceLocation, height: u32, min_y: i32, - ) -> Arc> { + ) -> Arc> { if let Some(existing_lock) = self.worlds.get(&name).and_then(|world| world.upgrade()) { let existing = existing_lock.read(); if existing.chunks.height != height { @@ -66,7 +66,7 @@ impl WorldContainer { } existing_lock.clone() } else { - let world = Arc::new(RwLock::new(World { + let world = Arc::new(RwLock::new(Instance { chunks: ChunkStorage::new(height, min_y), entities_by_chunk: HashMap::new(), entity_by_id: IntMap::default(), diff --git a/azalea-world/src/entity/attributes.rs b/azalea-world/src/entity/attributes.rs index 6b10a2b4c..97b890dca 100644 --- a/azalea-world/src/entity/attributes.rs +++ b/azalea-world/src/entity/attributes.rs @@ -6,7 +6,7 @@ use std::{ }; use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; -use azalea_ecs::component::Component; +use bevy_ecs::component::Component; use thiserror::Error; use uuid::{uuid, Uuid}; diff --git a/azalea-world/src/entity/data.rs b/azalea-world/src/entity/data.rs index 346b277b0..65988a195 100755 --- a/azalea-world/src/entity/data.rs +++ b/azalea-world/src/entity/data.rs @@ -6,7 +6,7 @@ use azalea_buf::{ }; use azalea_chat::FormattedText; use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot}; -use azalea_ecs::component::Component; +use bevy_ecs::component::Component; use derive_more::Deref; use enum_as_inner::EnumAsInner; use nohash_hasher::IntSet; diff --git a/azalea-world/src/entity/dimensions.rs b/azalea-world/src/entity/dimensions.rs index daf854328..5e7163078 100755 --- a/azalea-world/src/entity/dimensions.rs +++ b/azalea-world/src/entity/dimensions.rs @@ -1,5 +1,5 @@ use azalea_core::{Vec3, AABB}; -use azalea_ecs::{query::Changed, system::Query}; +use bevy_ecs::{query::Changed, system::Query}; use super::{Physics, Position}; diff --git a/azalea-world/src/entity/info.rs b/azalea-world/src/entity/info.rs index 8615ef816..19e87627e 100644 --- a/azalea-world/src/entity/info.rs +++ b/azalea-world/src/entity/info.rs @@ -9,15 +9,14 @@ use crate::{ update_entity_by_id_index, update_uuid_index, PartialWorld, WorldContainer, }; use azalea_core::ChunkPos; -use azalea_ecs::{ - app::{App, CoreStage, Plugin}, +use bevy_app::{App, CoreSet, Plugin}; +use bevy_ecs::{ component::Component, - ecs::Ecs, - ecs::EntityMut, entity::Entity, query::{Added, Changed, With, Without}, - schedule::{IntoSystemDescriptor, SystemSet}, - system::{Command, Commands, Query, Res, ResMut, Resource}, + schedule::{IntoSystemConfig, IntoSystemConfigs, SystemSet}, + system::{Commands, EntityCommand, Query, Res, ResMut, Resource}, + world::{EntityMut, World}, }; use derive_more::{Deref, DerefMut}; use log::{debug, warn}; @@ -32,6 +31,18 @@ use uuid::Uuid; use super::Local; +/// A Bevy [`SystemSet`] for various types of entity updates. +#[derive(SystemSet, Debug, Hash, Eq, PartialEq, Clone)] +pub enum EntityUpdateSet { + /// Remove ECS entities that refer to an entity that was already in the ECS + /// before. + Deduplicate, + /// Create search indexes for entities. + Index, + /// Remove despawned entities from search indexes. + Deindex, +} + /// Plugin handling some basic entity functionality. pub struct EntityPlugin; impl Plugin for EntityPlugin { @@ -40,30 +51,31 @@ impl Plugin for EntityPlugin { // added to indexes during update (done by this plugin) // modified during update // despawned post-update (done by this plugin) - app.add_system_set_to_stage( - CoreStage::PreUpdate, - SystemSet::new().with_system(remove_despawned_entities_from_indexes), - ) - .add_system_set_to_stage( - CoreStage::PostUpdate, - SystemSet::new() - .with_system(deduplicate_entities.label("deduplicate_entities")) - .with_system(deduplicate_local_entities.label("deduplicate_entities")), + app.add_system( + remove_despawned_entities_from_indexes + .in_base_set(CoreSet::PreUpdate) + .in_set(EntityUpdateSet::Deindex), ) - .add_system_set( - SystemSet::new() - .with_system(update_entity_chunk_positions) - .with_system(update_uuid_index.label("update_indexes")) - .with_system(update_entity_by_id_index.label("update_indexes")), + .add_systems( + (deduplicate_entities, deduplicate_local_entities) + .in_base_set(CoreSet::PostUpdate) + .in_set(EntityUpdateSet::Deduplicate), ) - .add_system_set( - SystemSet::new() - .with_system(add_updates_received.label("add_updates_received")) - .with_system(debug_new_entity) - .with_system(debug_detect_updates_received_on_local_entities) - .with_system(add_dead) - .with_system(update_bounding_box), + .add_systems( + ( + update_entity_chunk_positions, + update_uuid_index, + update_entity_by_id_index, + ) + .in_set(EntityUpdateSet::Index), ) + .add_systems(( + add_updates_received, + debug_new_entity, + debug_detect_updates_received_on_local_entities, + add_dead, + update_bounding_box, + )) .init_resource::(); } } @@ -134,26 +146,24 @@ impl PartialEntityInfos { /// other clients within render distance will get too. You usually don't need /// this when the change isn't relative either. pub struct RelativeEntityUpdate { - pub entity: Entity, pub partial_world: Arc>, // a function that takes the entity and updates it pub update: Box, } -impl Command for RelativeEntityUpdate { - fn write(self, world: &mut Ecs) { +impl EntityCommand for RelativeEntityUpdate { + fn write(self, entity: Entity, world: &mut World) { let partial_entity_infos = &mut self.partial_world.write().entity_infos; - let mut entity = world.entity_mut(self.entity); + let mut entity_mut = world.entity_mut(entity); - if Some(self.entity) == partial_entity_infos.owner_entity { + if Some(entity) == partial_entity_infos.owner_entity { // if the entity owns this partial world, it's always allowed to update itself - (self.update)(&mut entity); + (self.update)(&mut entity_mut); return; }; - let entity_id = *entity.get::().unwrap(); - - let Some(updates_received) = entity.get_mut::() else { + let entity_id = *entity_mut.get::().unwrap(); + let Some(updates_received) = entity_mut.get_mut::() else { // a client tried to update another client, which isn't allowed return; }; @@ -170,9 +180,9 @@ impl Command for RelativeEntityUpdate { .updates_received .insert(entity_id, new_updates_received); - **entity.get_mut::().unwrap() = new_updates_received; + **entity_mut.get_mut::().unwrap() = new_updates_received; - let mut entity = world.entity_mut(self.entity); + let mut entity = world.entity_mut(entity); (self.update)(&mut entity); } } diff --git a/azalea-world/src/entity/metadata.rs b/azalea-world/src/entity/metadata.rs index 8960b045d..0a0bddc81 100644 --- a/azalea-world/src/entity/metadata.rs +++ b/azalea-world/src/entity/metadata.rs @@ -7,7 +7,7 @@ use super::{EntityDataItem, EntityDataValue, OptionalUnsignedInt, Pose, Rotation use azalea_block::BlockState; use azalea_chat::FormattedText; use azalea_core::{BlockPos, Direction, Particle, Slot}; -use azalea_ecs::{bundle::Bundle, component::Component}; +use bevy_ecs::{bundle::Bundle, component::Component}; use derive_more::{Deref, DerefMut}; use thiserror::Error; use uuid::Uuid; @@ -79,7 +79,7 @@ pub struct CanDuplicate(pub bool); pub struct Allay; impl Allay { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -160,7 +160,7 @@ pub struct Waiting(pub bool); pub struct AreaEffectCloud; impl AreaEffectCloud { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -245,7 +245,7 @@ pub struct RightLegPose(pub Rotations); pub struct ArmorStand; impl ArmorStand { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -356,7 +356,7 @@ pub struct ArrowEffectColor(pub i32); pub struct Arrow; impl Arrow { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -431,7 +431,7 @@ pub struct AxolotlFromBucket(pub bool); pub struct Axolotl; impl Axolotl { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -520,7 +520,7 @@ pub struct Resting(pub bool); pub struct Bat; impl Bat { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -596,7 +596,7 @@ pub struct BeeRemainingAngerTime(pub i32); pub struct Bee; impl Bee { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -687,7 +687,7 @@ pub struct Charged(pub bool); pub struct Blaze; impl Blaze { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -775,7 +775,7 @@ pub struct BubbleTime(pub i32); pub struct Boat; impl Boat { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -871,7 +871,7 @@ pub struct LastPoseChangeTick(pub i64); pub struct Camel; impl Camel { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -990,7 +990,7 @@ pub struct CatCollarColor(pub i32); pub struct Cat; impl Cat { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1090,7 +1090,7 @@ pub struct Climbing(pub bool); pub struct CaveSpider; impl CaveSpider { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1162,7 +1162,7 @@ impl Default for CaveSpiderMetadataBundle { pub struct ChestBoat; impl ChestBoat { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1229,7 +1229,7 @@ pub struct CustomDisplay(pub bool); pub struct ChestMinecart; impl ChestMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1283,7 +1283,7 @@ impl Default for ChestMinecartMetadataBundle { pub struct Chicken; impl Chicken { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1357,7 +1357,7 @@ pub struct CodFromBucket(pub bool); pub struct Cod; impl Cod { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1431,7 +1431,7 @@ pub struct LastOutput(pub FormattedText); pub struct CommandBlockMinecart; impl CommandBlockMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1495,7 +1495,7 @@ impl Default for CommandBlockMinecartMetadataBundle { pub struct Cow; impl Cow { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1573,7 +1573,7 @@ pub struct IsIgnited(pub bool); pub struct Creeper; impl Creeper { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1662,7 +1662,7 @@ pub struct MoistnessLevel(pub i32); pub struct Dolphin; impl Dolphin { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1756,7 +1756,7 @@ pub struct DonkeyChest(pub bool); pub struct Donkey; impl Donkey { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1856,7 +1856,7 @@ impl Default for DonkeyMetadataBundle { pub struct DragonFireball; impl DragonFireball { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1907,7 +1907,7 @@ pub struct DrownedConversion(pub bool); pub struct Drowned; impl Drowned { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -1983,7 +1983,7 @@ pub struct EggItemStack(pub Slot); pub struct Egg; impl Egg { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2037,7 +2037,7 @@ pub struct AttackTarget(pub i32); pub struct ElderGuardian; impl ElderGuardian { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2114,7 +2114,7 @@ pub struct ShowBottom(pub bool); pub struct EndCrystal; impl EndCrystal { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2171,7 +2171,7 @@ pub struct Phase(pub i32); pub struct EnderDragon; impl EnderDragon { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2240,7 +2240,7 @@ pub struct EnderPearlItemStack(pub Slot); pub struct EnderPearl; impl EnderPearl { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2296,7 +2296,7 @@ pub struct StaredAt(pub bool); pub struct Enderman; impl Enderman { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2379,7 +2379,7 @@ impl Default for EndermanMetadataBundle { pub struct Endermite; impl Endermite { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2451,7 +2451,7 @@ pub struct EvokerSpellCasting(pub u8); pub struct Evoker; impl Evoker { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2529,7 +2529,7 @@ impl Default for EvokerMetadataBundle { pub struct EvokerFangs; impl EvokerFangs { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2576,7 +2576,7 @@ pub struct ExperienceBottleItemStack(pub Slot); pub struct ExperienceBottle; impl ExperienceBottle { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2626,7 +2626,7 @@ impl Default for ExperienceBottleMetadataBundle { pub struct ExperienceOrb; impl ExperienceOrb { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2673,7 +2673,7 @@ pub struct EyeOfEnderItemStack(pub Slot); pub struct EyeOfEnder; impl EyeOfEnder { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2725,7 +2725,7 @@ pub struct StartPos(pub BlockPos); pub struct FallingBlock; impl FallingBlock { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2777,7 +2777,7 @@ pub struct FireballItemStack(pub Slot); pub struct Fireball; impl Fireball { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2833,7 +2833,7 @@ pub struct ShotAtAngle(pub bool); pub struct FireworkRocket; impl FireworkRocket { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2897,7 +2897,7 @@ pub struct Biting(pub bool); pub struct FishingBobber; impl FishingBobber { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -2970,7 +2970,7 @@ pub struct TrustedId1(pub Option); pub struct Fox; impl Fox { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3082,7 +3082,7 @@ pub struct TongueTarget(pub OptionalUnsignedInt); pub struct Frog; impl Frog { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3166,7 +3166,7 @@ pub struct Fuel(pub bool); pub struct FurnaceMinecart; impl FurnaceMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3227,7 +3227,7 @@ pub struct IsCharging(pub bool); pub struct Ghast; impl Ghast { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3294,7 +3294,7 @@ impl Default for GhastMetadataBundle { pub struct Giant; impl Giant { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3366,7 +3366,7 @@ pub struct Rotation(pub i32); pub struct GlowItemFrame; impl GlowItemFrame { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3418,7 +3418,7 @@ pub struct DarkTicksRemaining(pub i32); pub struct GlowSquid; impl GlowSquid { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3497,7 +3497,7 @@ pub struct HasRightHorn(pub bool); pub struct Goat; impl Goat { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3584,7 +3584,7 @@ impl Default for GoatMetadataBundle { pub struct Guardian; impl Guardian { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3664,7 +3664,7 @@ pub struct HoglinImmuneToZombification(pub bool); pub struct Hoglin; impl Hoglin { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3741,7 +3741,7 @@ impl Default for HoglinMetadataBundle { pub struct HopperMinecart; impl HopperMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3809,7 +3809,7 @@ pub struct HorseTypeVariant(pub i32); pub struct Horse; impl Horse { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3909,7 +3909,7 @@ impl Default for HorseMetadataBundle { pub struct Husk; impl Husk { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -3987,7 +3987,7 @@ pub struct IllusionerSpellCasting(pub u8); pub struct Illusioner; impl Illusioner { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4067,7 +4067,7 @@ pub struct PlayerCreated(pub bool); pub struct IronGolem; impl IronGolem { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4140,7 +4140,7 @@ pub struct ItemItem(pub Slot); pub struct Item; impl Item { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4190,7 +4190,7 @@ impl Default for ItemMetadataBundle { pub struct ItemFrame; impl ItemFrame { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4245,7 +4245,7 @@ impl Default for ItemFrameMetadataBundle { pub struct LeashKnot; impl LeashKnot { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4290,7 +4290,7 @@ impl Default for LeashKnotMetadataBundle { pub struct LightningBolt; impl LightningBolt { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4355,7 +4355,7 @@ pub struct LlamaVariant(pub i32); pub struct Llama; impl Llama { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4470,7 +4470,7 @@ impl Default for LlamaMetadataBundle { pub struct LlamaSpit; impl LlamaSpit { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4517,7 +4517,7 @@ pub struct SlimeSize(pub i32); pub struct MagmaCube; impl MagmaCube { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4583,7 +4583,7 @@ impl Default for MagmaCubeMetadataBundle { pub struct Marker; impl Marker { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4628,7 +4628,7 @@ impl Default for MarkerMetadataBundle { pub struct Minecart; impl Minecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4684,7 +4684,7 @@ pub struct MooshroomKind(pub String); pub struct Mooshroom; impl Mooshroom { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4778,7 +4778,7 @@ pub struct MuleChest(pub bool); pub struct Mule; impl Mule { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4880,7 +4880,7 @@ pub struct Trusting(pub bool); pub struct Ocelot; impl Ocelot { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -4959,7 +4959,7 @@ pub struct PaintingVariant(pub azalea_registry::PaintingVariant); pub struct Painting; impl Painting { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5027,7 +5027,7 @@ pub struct PandaFlags(pub u8); pub struct Panda; impl Panda { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5141,7 +5141,7 @@ pub struct ParrotVariant(pub i32); pub struct Parrot; impl Parrot { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5226,7 +5226,7 @@ pub struct PhantomSize(pub i32); pub struct Phantom; impl Phantom { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5297,7 +5297,7 @@ pub struct PigBoostTime(pub i32); pub struct Pig; impl Pig { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5387,7 +5387,7 @@ pub struct IsDancing(pub bool); pub struct Piglin; impl Piglin { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5477,7 +5477,7 @@ pub struct PiglinBruteImmuneToZombification(pub bool); pub struct PiglinBrute; impl PiglinBrute { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5554,7 +5554,7 @@ pub struct PillagerIsChargingCrossbow(pub bool); pub struct Pillager; impl Pillager { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5644,7 +5644,7 @@ pub struct ShoulderRight(pub azalea_nbt::Tag); pub struct Player; impl Player { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5732,7 +5732,7 @@ pub struct PolarBearStanding(pub bool); pub struct PolarBear; impl PolarBear { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5811,7 +5811,7 @@ pub struct PotionItemStack(pub Slot); pub struct Potion; impl Potion { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5865,7 +5865,7 @@ pub struct PuffState(pub i32); pub struct Pufferfish; impl Pufferfish { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -5942,7 +5942,7 @@ pub struct RabbitKind(pub i32); pub struct Rabbit; impl Rabbit { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6021,7 +6021,7 @@ pub struct RavagerIsCelebrating(pub bool); pub struct Ravager; impl Ravager { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6096,7 +6096,7 @@ pub struct SalmonFromBucket(pub bool); pub struct Salmon; impl Salmon { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6168,7 +6168,7 @@ pub struct Sheared(pub bool); pub struct Sheep; impl Sheep { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6252,7 +6252,7 @@ pub struct ShulkerColor(pub u8); pub struct Shulker; impl Shulker { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6332,7 +6332,7 @@ impl Default for ShulkerMetadataBundle { pub struct ShulkerBullet; impl ShulkerBullet { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6377,7 +6377,7 @@ impl Default for ShulkerBulletMetadataBundle { pub struct Silverfish; impl Silverfish { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6447,7 +6447,7 @@ pub struct StrayConversion(pub bool); pub struct Skeleton; impl Skeleton { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6532,7 +6532,7 @@ pub struct SkeletonHorseOwnerUuid(pub Option); pub struct SkeletonHorse; impl SkeletonHorse { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6627,7 +6627,7 @@ impl Default for SkeletonHorseMetadataBundle { pub struct Slime; impl Slime { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6696,7 +6696,7 @@ pub struct SmallFireballItemStack(pub Slot); pub struct SmallFireball; impl SmallFireball { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6748,7 +6748,7 @@ pub struct HasPumpkin(pub bool); pub struct SnowGolem; impl SnowGolem { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6821,7 +6821,7 @@ pub struct SnowballItemStack(pub Slot); pub struct Snowball; impl Snowball { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6871,7 +6871,7 @@ impl Default for SnowballMetadataBundle { pub struct SpawnerMinecart; impl SpawnerMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6933,7 +6933,7 @@ pub struct SpectralArrowPierceLevel(pub u8); pub struct SpectralArrow; impl SpectralArrow { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -6995,7 +6995,7 @@ impl Default for SpectralArrowMetadataBundle { pub struct Spider; impl Spider { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7069,7 +7069,7 @@ impl Default for SpiderMetadataBundle { pub struct Squid; impl Squid { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7134,7 +7134,7 @@ impl Default for SquidMetadataBundle { pub struct Stray; impl Stray { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7208,7 +7208,7 @@ pub struct StriderSaddle(pub bool); pub struct Strider; impl Strider { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7297,7 +7297,7 @@ pub struct TadpoleFromBucket(pub bool); pub struct Tadpole; impl Tadpole { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7369,7 +7369,7 @@ pub struct Fuse(pub i32); pub struct Tnt; impl Tnt { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7419,7 +7419,7 @@ impl Default for TntMetadataBundle { pub struct TntMinecart; impl TntMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7473,7 +7473,7 @@ impl Default for TntMinecartMetadataBundle { pub struct TraderLlama; impl TraderLlama { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7570,7 +7570,7 @@ pub struct Foil(pub bool); pub struct Trident; impl Trident { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7646,7 +7646,7 @@ pub struct TropicalFishTypeVariant(pub i32); pub struct TropicalFish; impl TropicalFish { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7733,7 +7733,7 @@ pub struct Travelling(pub bool); pub struct Turtle; impl Turtle { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7837,7 +7837,7 @@ pub struct VexFlags(pub u8); pub struct Vex; impl Vex { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7914,7 +7914,7 @@ pub struct VillagerVillagerData(pub VillagerData); pub struct Villager; impl Villager { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -7999,7 +7999,7 @@ pub struct VindicatorIsCelebrating(pub bool); pub struct Vindicator; impl Vindicator { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8074,7 +8074,7 @@ pub struct WanderingTraderUnhappyCounter(pub i32); pub struct WanderingTrader; impl WanderingTrader { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8150,7 +8150,7 @@ pub struct ClientAngerLevel(pub i32); pub struct Warden; impl Warden { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8227,7 +8227,7 @@ pub struct WitchUsingItem(pub bool); pub struct Witch; impl Witch { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8313,7 +8313,7 @@ pub struct Inv(pub i32); pub struct Wither; impl Wither { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8401,7 +8401,7 @@ impl Default for WitherMetadataBundle { pub struct WitherSkeleton; impl WitherSkeleton { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8471,7 +8471,7 @@ pub struct Dangerous(pub bool); pub struct WitherSkull; impl WitherSkull { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8527,7 +8527,7 @@ pub struct WolfRemainingAngerTime(pub i32); pub struct Wolf; impl Wolf { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8622,7 +8622,7 @@ pub struct ZoglinBaby(pub bool); pub struct Zoglin; impl Zoglin { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8695,7 +8695,7 @@ impl Default for ZoglinMetadataBundle { pub struct Zombie; impl Zombie { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8790,7 +8790,7 @@ pub struct ZombieHorseOwnerUuid(pub Option); pub struct ZombieHorse; impl ZombieHorse { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8889,7 +8889,7 @@ pub struct ZombieVillagerVillagerData(pub VillagerData); pub struct ZombieVillager; impl ZombieVillager { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -8977,7 +8977,7 @@ impl Default for ZombieVillagerMetadataBundle { pub struct ZombifiedPiglin; impl ZombifiedPiglin { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9051,7 +9051,7 @@ impl Default for ZombifiedPiglinMetadataBundle { pub struct AbstractAgeable; impl AbstractAgeable { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9121,7 +9121,7 @@ impl Default for AbstractAgeableMetadataBundle { pub struct AbstractAnimal; impl AbstractAnimal { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9190,7 +9190,7 @@ impl Default for AbstractAnimalMetadataBundle { pub struct AbstractCreature; impl AbstractCreature { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9252,7 +9252,7 @@ impl Default for AbstractCreatureMetadataBundle { pub struct AbstractEntity; impl AbstractEntity { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9337,7 +9337,7 @@ impl Default for AbstractEntityMetadataBundle { pub struct AbstractInsentient; impl AbstractInsentient { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9405,7 +9405,7 @@ impl Default for AbstractInsentientMetadataBundle { pub struct AbstractLiving; impl AbstractLiving { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9489,7 +9489,7 @@ impl Default for AbstractLivingMetadataBundle { pub struct AbstractMinecart; impl AbstractMinecart { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9564,7 +9564,7 @@ impl Default for AbstractMinecartMetadataBundle { pub struct AbstractMonster; impl AbstractMonster { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9629,7 +9629,7 @@ impl Default for AbstractMonsterMetadataBundle { pub struct AbstractTameable; impl AbstractTameable { pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem, ) -> Result<(), UpdateMetadataError> { match d.index { @@ -9712,7 +9712,7 @@ impl Default for AbstractTameableMetadataBundle { } pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, entity_kind: azalea_registry::EntityKind, items: Vec, ) -> Result<(), UpdateMetadataError> { @@ -10317,7 +10317,7 @@ pub fn apply_metadata( } pub fn apply_default_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind, ) { match kind { diff --git a/azalea-world/src/entity/mod.rs b/azalea-world/src/entity/mod.rs index 9b1191fbd..6f77f1bef 100644 --- a/azalea-world/src/entity/mod.rs +++ b/azalea-world/src/entity/mod.rs @@ -12,7 +12,7 @@ use self::{attributes::AttributeInstance, metadata::Health}; pub use attributes::Attributes; use azalea_block::BlockState; use azalea_core::{BlockPos, ChunkPos, ResourceLocation, Vec3, AABB}; -use azalea_ecs::{ +use bevy_ecs::{ bundle::Bundle, component::Component, entity::Entity, @@ -22,7 +22,9 @@ use azalea_ecs::{ pub use data::*; use derive_more::{Deref, DerefMut}; pub use dimensions::{update_bounding_box, EntityDimensions}; -pub use info::{EntityInfos, EntityPlugin, LoadedBy, PartialEntityInfos, RelativeEntityUpdate}; +pub use info::{ + EntityInfos, EntityPlugin, EntityUpdateSet, LoadedBy, PartialEntityInfos, RelativeEntityUpdate, +}; use std::fmt::Debug; use uuid::Uuid; diff --git a/azalea-world/src/world.rs b/azalea-world/src/world.rs index 8f1b2179d..41d830822 100644 --- a/azalea-world/src/world.rs +++ b/azalea-world/src/world.rs @@ -5,7 +5,7 @@ use crate::{ ChunkStorage, PartialChunkStorage, WorldContainer, }; use azalea_core::ChunkPos; -use azalea_ecs::{ +use bevy_ecs::{ entity::Entity, query::{Changed, With, Without}, system::{Commands, Query, Res, ResMut}, @@ -172,7 +172,7 @@ pub fn update_uuid_index( /// A world where the chunks are stored as weak pointers. This is used for /// shared worlds. #[derive(Default, Debug)] -pub struct World { +pub struct Instance { pub chunks: ChunkStorage, /// An index of all the entities we know are in the chunks of the world @@ -182,7 +182,7 @@ pub struct World { pub entity_by_id: IntMap, } -impl World { +impl Instance { /// Get an ECS [`Entity`] from a Minecraft entity ID. pub fn entity_by_id(&self, entity_id: &MinecraftEntityId) -> Option { self.entity_by_id.get(entity_id).copied() @@ -236,7 +236,7 @@ pub fn update_entity_by_id_index( } } -impl From for World { +impl From for Instance { /// Make an empty world from this `ChunkStorage`. This is meant to be a /// convenience function for tests. fn from(chunks: ChunkStorage) -> Self { diff --git a/azalea/Cargo.toml b/azalea/Cargo.toml index f64959ed6..dd2bb46cc 100644 --- a/azalea/Cargo.toml +++ b/azalea/Cargo.toml @@ -8,31 +8,31 @@ version = "0.6.0" [package.metadata.release] pre-release-replacements = [ - {file = "README.md", search = "`azalea = \"[a-z0-9\\.-]+\"`", replace = "`azalea = \"{{version}}\"`"}, + { file = "README.md", search = "`azalea = \"[a-z0-9\\.-]+\"`", replace = "`azalea = \"{{version}}\"`" }, ] [dependencies] anyhow = "^1.0.65" async-trait = "0.1.58" -azalea-block = {version = "0.6.0", path = "../azalea-block"} -azalea-chat = {version = "0.6.0", path = "../azalea-chat"} -azalea-client = {version = "0.6.0", path = "../azalea-client"} -azalea-core = {version = "0.6.0", path = "../azalea-core"} -azalea-ecs = {version = "0.6.0", path = "../azalea-ecs"} -azalea-physics = {version = "0.6.0", path = "../azalea-physics"} -azalea-protocol = {version = "0.6.0", path = "../azalea-protocol"} -azalea-registry = {version = "0.6.0", path = "../azalea-registry"} -azalea-world = {version = "0.6.0", path = "../azalea-world"} -bevy_tasks = "0.9.1" -derive_more = {version = "0.99.17", features = ["deref", "deref_mut"]} +azalea-block = { version = "0.6.0", path = "../azalea-block" } +azalea-chat = { version = "0.6.0", path = "../azalea-chat" } +azalea-client = { version = "0.6.0", path = "../azalea-client" } +azalea-core = { version = "0.6.0", path = "../azalea-core" } +azalea-physics = { version = "0.6.0", path = "../azalea-physics" } +azalea-protocol = { version = "0.6.0", path = "../azalea-protocol" } +azalea-registry = { version = "0.6.0", path = "../azalea-registry" } +azalea-world = { version = "0.6.0", path = "../azalea-world" } +bevy_app = "0.10.0" +bevy_ecs = "0.10.0" +bevy_tasks = "0.10.0" +derive_more = { version = "0.99.17", features = ["deref", "deref_mut"] } futures = "0.3.25" futures-lite = "1.12.0" log = "0.4.17" nohash-hasher = "0.2.0" num-traits = "0.2.15" -parking_lot = {version = "^0.12.1", features = ["deadlock_detection"]} +parking_lot = { version = "^0.12.1", features = ["deadlock_detection"] } priority-queue = "1.3.0" thiserror = "^1.0.37" tokio = "^1.24.2" uuid = "1.2.2" - diff --git a/azalea/examples/pvp.rs b/azalea/examples/pvp.rs index 180b6577f..fb5a768db 100755 --- a/azalea/examples/pvp.rs +++ b/azalea/examples/pvp.rs @@ -1,9 +1,9 @@ use std::time::Duration; +use azalea::ecs::query::With; use azalea::entity::metadata::Player; use azalea::{pathfinder, Account, Client, Event, GameProfileComponent}; use azalea::{prelude::*, swarm::prelude::*}; -use azalea_ecs::query::With; #[tokio::main] async fn main() { diff --git a/azalea/examples/testbot.rs b/azalea/examples/testbot.rs index dd1629ae1..7b7b32b08 100644 --- a/azalea/examples/testbot.rs +++ b/azalea/examples/testbot.rs @@ -52,17 +52,17 @@ async fn main() -> anyhow::Result<()> { } loop { - let e = SwarmBuilder::new() - .add_accounts(accounts.clone()) - .set_handler(handle) - .set_swarm_handler(swarm_handle) - .join_delay(Duration::from_millis(1000)) - .start("localhost") - .await; - // let e = azalea::ClientBuilder::new() + // let e = SwarmBuilder::new() + // .add_accounts(accounts.clone()) // .set_handler(handle) - // .start(Account::offline("bot"), "localhost") + // .set_swarm_handler(swarm_handle) + // .join_delay(Duration::from_millis(1000)) + // .start("localhost") // .await; + let e = azalea::ClientBuilder::new() + .set_handler(handle) + .start(Account::offline("bot"), "localhost") + .await; eprintln!("{e:?}"); } } diff --git a/azalea/src/bot.rs b/azalea/src/bot.rs index ce5b9fdcc..a45ae28df 100644 --- a/azalea/src/bot.rs +++ b/azalea/src/bot.rs @@ -1,14 +1,14 @@ -use azalea_core::Vec3; -use azalea_ecs::{ - app::{App, Plugin, PluginGroup, PluginGroupBuilder}, +use crate::app::{App, CoreSchedule, IntoSystemAppConfig, Plugin, PluginGroup, PluginGroupBuilder}; +use crate::ecs::{ component::Component, entity::Entity, event::EventReader, query::{With, Without}, - schedule::IntoSystemDescriptor, + schedule::IntoSystemConfig, system::{Commands, Query}, - AppTickExt, }; +use azalea_core::Vec3; +use azalea_physics::{force_jump_listener, PhysicsSet}; use azalea_world::entity::{metadata::Player, set_rotation, Jumping, Local, Physics, Position}; use std::f64::consts::PI; @@ -20,14 +20,14 @@ impl Plugin for BotPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_system(insert_bot) - .add_system( - look_at_listener - .before("force_jump_listener") - .before(azalea_world::entity::update_bounding_box), - ) - .add_system(jump_listener.label("jump_listener")) - .add_tick_system(stop_jumping.after("ai_step")); + .add_systems(( + insert_bot, + look_at_listener.before(force_jump_listener), + jump_listener, + stop_jumping + .in_schedule(CoreSchedule::FixedUpdate) + .after(PhysicsSet), + )); } } diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs index 827c3904e..c58ca7b1c 100644 --- a/azalea/src/lib.rs +++ b/azalea/src/lib.rs @@ -6,18 +6,15 @@ pub mod pathfinder; pub mod prelude; pub mod swarm; +use app::{App, Plugin, PluginGroup}; pub use azalea_block as blocks; pub use azalea_client::*; pub use azalea_core::{BlockPos, Vec3}; -use azalea_ecs::{ - app::{App, Plugin}, - component::Component, -}; pub use azalea_protocol as protocol; pub use azalea_registry::EntityKind; -pub use azalea_world::{entity, World}; +pub use azalea_world::{entity, Instance}; use bot::DefaultBotPlugins; -use ecs::app::PluginGroup; +use ecs::component::Component; use futures::Future; use protocol::{ resolver::{self, ResolverError}, @@ -26,7 +23,10 @@ use protocol::{ use thiserror::Error; use tokio::sync::mpsc; -pub type HandleFn = fn(Client, Event, S) -> Fut; +pub use bevy_app as app; +pub use bevy_ecs as ecs; + +pub type HandleFn = fn(Client, azalea_client::Event, S) -> Fut; #[derive(Error, Debug)] pub enum StartError { @@ -142,6 +142,7 @@ where // An event that causes the schedule to run. This is only used internally. let (run_schedule_sender, run_schedule_receiver) = mpsc::unbounded_channel(); + let ecs_lock = start_ecs(self.app, run_schedule_receiver, run_schedule_sender.clone()); let (bot, mut rx) = Client::start_client( diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index 8289d9c46..61a920389 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -4,18 +4,18 @@ mod mtdstarlite; use crate::bot::{JumpEvent, LookAtEvent}; use crate::{SprintDirection, WalkDirection}; -use azalea_client::{StartSprintEvent, StartWalkEvent}; -use azalea_core::{BlockPos, CardinalDirection}; -use azalea_ecs::{ - app::{App, Plugin}, +use crate::app::{App, CoreSchedule, IntoSystemAppConfig, Plugin}; +use crate::ecs::{ component::Component, entity::Entity, event::{EventReader, EventWriter}, query::{With, Without}, - schedule::IntoSystemDescriptor, + schedule::IntoSystemConfig, system::{Commands, Query, Res}, - AppTickExt, }; +use azalea_client::{StartSprintEvent, StartWalkEvent}; +use azalea_core::{BlockPos, CardinalDirection}; +use azalea_physics::PhysicsSet; use azalea_world::entity::metadata::Player; use azalea_world::entity::Local; use azalea_world::{ @@ -36,7 +36,13 @@ impl Plugin for PathfinderPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_tick_system(tick_execute_path.before("ai_step")) + .add_system( + // Adding `.in_schedule(CoreSchedule::FixedUpdate)` makes a system run every + // Minecraft tick (every 50 milliseconds). + tick_execute_path + .in_schedule(CoreSchedule::FixedUpdate) + .before(PhysicsSet), + ) .add_system(goto_listener) .add_system(add_default_pathfinder) .add_system(handle_tasks.before(path_found_listener)) diff --git a/azalea/src/pathfinder/moves.rs b/azalea/src/pathfinder/moves.rs index 011d8349b..3639c0914 100644 --- a/azalea/src/pathfinder/moves.rs +++ b/azalea/src/pathfinder/moves.rs @@ -1,10 +1,10 @@ use super::{Node, VerticalVel}; use azalea_core::{BlockPos, CardinalDirection}; use azalea_physics::collision::{self, BlockWithShape}; -use azalea_world::World; +use azalea_world::Instance; /// whether this block is passable -fn is_block_passable(pos: &BlockPos, world: &World) -> bool { +fn is_block_passable(pos: &BlockPos, world: &Instance) -> bool { if let Some(block) = world.chunks.get_block_state(pos) { block.shape() == &collision::empty_shape() } else { @@ -13,7 +13,7 @@ fn is_block_passable(pos: &BlockPos, world: &World) -> bool { } /// whether this block has a solid hitbox (i.e. we can stand on it) -fn is_block_solid(pos: &BlockPos, world: &World) -> bool { +fn is_block_solid(pos: &BlockPos, world: &Instance) -> bool { if let Some(block) = world.chunks.get_block_state(pos) { block.shape() == &collision::block_shape() } else { @@ -22,14 +22,14 @@ fn is_block_solid(pos: &BlockPos, world: &World) -> bool { } /// Whether this block and the block above are passable -fn is_passable(pos: &BlockPos, world: &World) -> bool { +fn is_passable(pos: &BlockPos, world: &Instance) -> bool { is_block_passable(pos, world) && is_block_passable(&pos.up(1), world) } /// Whether we can stand in this position. Checks if the block below is solid, /// and that the two blocks above that are passable. -fn is_standable(pos: &BlockPos, world: &World) -> bool { +fn is_standable(pos: &BlockPos, world: &Instance) -> bool { is_block_solid(&pos.down(1), world) && is_passable(pos, world) } @@ -37,7 +37,7 @@ const JUMP_COST: f32 = 0.5; const WALK_ONE_BLOCK_COST: f32 = 1.0; pub trait Move: Send + Sync { - fn cost(&self, world: &World, node: &Node) -> f32; + fn cost(&self, world: &Instance, node: &Node) -> f32; /// Returns by how much the entity's position should be changed when this /// move is executed. fn offset(&self) -> BlockPos; @@ -51,7 +51,7 @@ pub trait Move: Send + Sync { pub struct ForwardMove(pub CardinalDirection); impl Move for ForwardMove { - fn cost(&self, world: &World, node: &Node) -> f32 { + fn cost(&self, world: &Instance, node: &Node) -> f32 { if is_standable(&(node.pos + self.offset()), world) && node.vertical_vel == VerticalVel::None { @@ -67,7 +67,7 @@ impl Move for ForwardMove { pub struct AscendMove(pub CardinalDirection); impl Move for AscendMove { - fn cost(&self, world: &World, node: &Node) -> f32 { + fn cost(&self, world: &Instance, node: &Node) -> f32 { if node.vertical_vel == VerticalVel::None && is_block_passable(&node.pos.up(2), world) && is_standable(&(node.pos + self.offset()), world) @@ -89,7 +89,7 @@ impl Move for AscendMove { } pub struct DescendMove(pub CardinalDirection); impl Move for DescendMove { - fn cost(&self, world: &World, node: &Node) -> f32 { + fn cost(&self, world: &Instance, node: &Node) -> f32 { // check whether 3 blocks vertically forward are passable if node.vertical_vel == VerticalVel::None && is_standable(&(node.pos + self.offset()), world) @@ -112,7 +112,7 @@ impl Move for DescendMove { } pub struct DiagonalMove(pub CardinalDirection); impl Move for DiagonalMove { - fn cost(&self, world: &World, node: &Node) -> f32 { + fn cost(&self, world: &Instance, node: &Node) -> f32 { if node.vertical_vel != VerticalVel::None { return f32::INFINITY; } diff --git a/azalea/src/prelude.rs b/azalea/src/prelude.rs index a9ae6093e..b1a1fed36 100644 --- a/azalea/src/prelude.rs +++ b/azalea/src/prelude.rs @@ -3,4 +3,6 @@ pub use crate::{bot::BotClientExt, pathfinder::PathfinderClientExt, ClientBuilder}; pub use azalea_client::{Account, Client, Event}; -pub use azalea_ecs::{component::Component, system::Resource}; +// this is necessary to make the macros that reference bevy_ecs work +pub use crate::ecs as bevy_ecs; +pub use crate::ecs::{component::Component, system::Resource}; diff --git a/azalea/src/swarm/chat.rs b/azalea/src/swarm/chat.rs index 18c27cd69..303ce35b1 100644 --- a/azalea/src/swarm/chat.rs +++ b/azalea/src/swarm/chat.rs @@ -13,14 +13,14 @@ // in Swarm that's set to the smallest index of all the bots, and we remove all // messages from the queue that are before that index. -use azalea_client::chat::{ChatPacket, ChatReceivedEvent}; -use azalea_ecs::{ - app::{App, Plugin}, +use crate::ecs::{ component::Component, event::{EventReader, EventWriter}, - schedule::IntoSystemDescriptor, + schedule::IntoSystemConfigs, system::{Commands, Query, Res, ResMut, Resource}, }; +use azalea_client::chat::{ChatPacket, ChatReceivedEvent}; +use bevy_app::{App, Plugin}; use std::collections::VecDeque; use super::{Swarm, SwarmEvent}; @@ -30,8 +30,7 @@ pub struct SwarmChatPlugin; impl Plugin for SwarmChatPlugin { fn build(&self, app: &mut App) { app.add_event::() - .add_system(chat_listener.label("chat_listener")) - .add_system(update_min_index_and_shrink_queue.after("chat_listener")) + .add_systems((chat_listener, update_min_index_and_shrink_queue).chain()) .insert_resource(GlobalChatState { chat_queue: VecDeque::new(), chat_min_index: 0, @@ -151,7 +150,7 @@ fn update_min_index_and_shrink_queue( #[cfg(test)] mod tests { - use azalea_ecs::{ecs::Ecs, event::Events, system::SystemState}; + use bevy_ecs::{event::Events, prelude::World, system::SystemState}; use super::*; @@ -161,8 +160,7 @@ mod tests { // event mangement in drain_events app.init_resource::>() .init_resource::>() - .add_system(chat_listener.label("chat_listener")) - .add_system(update_min_index_and_shrink_queue.after("chat_listener")) + .add_systems((chat_listener, update_min_index_and_shrink_queue).chain()) .insert_resource(GlobalChatState { chat_queue: VecDeque::new(), chat_min_index: 0, @@ -170,7 +168,7 @@ mod tests { app } - fn drain_events(ecs: &mut Ecs) -> Vec { + fn drain_events(ecs: &mut World) -> Vec { let mut system_state: SystemState>> = SystemState::new(ecs); let mut events = system_state.get_mut(ecs); diff --git a/azalea/src/swarm/events.rs b/azalea/src/swarm/events.rs index 81d8c731e..62593029d 100644 --- a/azalea/src/swarm/events.rs +++ b/azalea/src/swarm/events.rs @@ -1,11 +1,7 @@ use azalea_client::LocalPlayer; -use azalea_ecs::{ - app::{App, Plugin}, - event::EventWriter, - query::With, - system::{Query, ResMut, Resource}, -}; use azalea_world::entity::MinecraftEntityId; +use bevy_app::{App, Plugin}; +use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; pub struct SwarmPlugin; diff --git a/azalea/src/swarm/mod.rs b/azalea/src/swarm/mod.rs index c0d9cb56a..970201537 100644 --- a/azalea/src/swarm/mod.rs +++ b/azalea/src/swarm/mod.rs @@ -6,19 +6,14 @@ pub mod prelude; use crate::{bot::DefaultBotPlugins, HandleFn}; use azalea_client::{chat::ChatPacket, init_ecs_app, start_ecs, Account, Client, Event, JoinError}; -use azalea_ecs::{ - app::{App, Plugin, PluginGroup, PluginGroupBuilder}, - component::Component, - ecs::Ecs, - entity::Entity, - system::Resource, -}; use azalea_protocol::{ connect::ConnectionError, resolver::{self, ResolverError}, ServerAddress, }; use azalea_world::WorldContainer; +use bevy_app::{App, Plugin, PluginGroup, PluginGroupBuilder}; +use bevy_ecs::{component::Component, entity::Entity, system::Resource, world::World}; use futures::future::join_all; use log::error; use parking_lot::{Mutex, RwLock}; @@ -35,7 +30,7 @@ use tokio::sync::mpsc; /// It's used to make the [`Swarm::add`] function work. #[derive(Clone, Resource)] pub struct Swarm { - pub ecs_lock: Arc>, + pub ecs_lock: Arc>, bots: Arc>>, diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py index 250b7e70c..e3e88edf5 100644 --- a/codegen/lib/code/entity.py +++ b/codegen/lib/code/entity.py @@ -46,7 +46,7 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings): use azalea_block::BlockState; use azalea_chat::FormattedText; use azalea_core::{BlockPos, Direction, Particle, Slot}; -use azalea_ecs::{bundle::Bundle, component::Component}; +use bevy_ecs::{bundle::Bundle, component::Component}; use derive_more::{Deref, DerefMut}; use thiserror::Error; use uuid::Uuid; @@ -183,7 +183,7 @@ def maybe_rename_field(name: str, index: int) -> str: # impl Allay { # pub fn apply_metadata( - # entity: &mut azalea_ecs::system::EntityCommands, + # entity: &mut bevy_ecs::system::EntityCommands, # d: EntityDataItem, # ) -> Result<(), UpdateMetadataError> { # match d.index { @@ -196,7 +196,7 @@ def maybe_rename_field(name: str, index: int) -> str: # } code.append(f'impl {struct_name} {{') code.append( - f' pub fn apply_metadata(entity: &mut azalea_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {{') + f' pub fn apply_metadata(entity: &mut bevy_ecs::system::EntityCommands, d: EntityDataItem) -> Result<(), UpdateMetadataError> {{') code.append(f' match d.index {{') parent_last_index = -1 @@ -400,7 +400,7 @@ def generate_fields(this_entity_id: str): # and now make the main apply_metadata # pub fn apply_metadata( - # entity: &mut azalea_ecs::system::EntityCommands, + # entity: &mut bevy_ecs::system::EntityCommands, # items: Vec, # ) -> Result<(), UpdateMetadataError> { # if entity.contains::() { @@ -414,7 +414,7 @@ def generate_fields(this_entity_id: str): # } code.append( f'''pub fn apply_metadata( - entity: &mut azalea_ecs::system::EntityCommands, + entity: &mut bevy_ecs::system::EntityCommands, entity_kind: azalea_registry::EntityKind, items: Vec, ) -> Result<(), UpdateMetadataError> {{ @@ -436,7 +436,7 @@ def generate_fields(this_entity_id: str): code.append('}') code.append('') - # pub fn apply_default_metadata(entity: &mut azalea_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) { + # pub fn apply_default_metadata(entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) { # match kind { # azalea_registry::EntityKind::AreaEffectCloud => { # entity.insert(AreaEffectCloudMetadataBundle::default()); @@ -444,7 +444,7 @@ def generate_fields(this_entity_id: str): # } # } code.append( - 'pub fn apply_default_metadata(entity: &mut azalea_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {') + 'pub fn apply_default_metadata(entity: &mut bevy_ecs::system::EntityCommands, kind: azalea_registry::EntityKind) {') code.append(' match kind {') for entity_id in burger_entity_data: if entity_id.startswith('~'):