From d5fa5e32b37754b3b5c136e58821e48cd3b7c2ff Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:51:30 -0600 Subject: Rename Instance to World (#304) --- CHANGELOG.md | 1 + Cargo.lock | 1 + azalea-client/src/client.rs | 10 +- azalea-client/src/local_player.rs | 63 +++--- azalea-client/src/plugins/block_update.rs | 8 +- azalea-client/src/plugins/chunks.rs | 22 +-- azalea-client/src/plugins/disconnect.rs | 6 +- azalea-client/src/plugins/interact/mod.rs | 12 +- azalea-client/src/plugins/interact/pick.rs | 12 +- .../src/plugins/inventory/equipment_effects.rs | 14 +- azalea-client/src/plugins/inventory/mod.rs | 12 +- azalea-client/src/plugins/join.rs | 11 +- azalea-client/src/plugins/mining.rs | 42 ++-- azalea-client/src/plugins/movement.rs | 18 +- azalea-client/src/plugins/packet/config/mod.rs | 10 +- azalea-client/src/plugins/packet/game/events.rs | 17 +- azalea-client/src/plugins/packet/game/mod.rs | 217 ++++++++++----------- azalea-client/src/plugins/packet/mod.rs | 2 +- azalea-client/src/plugins/tick_counter.rs | 8 +- azalea-client/src/plugins/tick_end.rs | 4 +- azalea-client/src/test_utils/simulation.rs | 18 +- .../change_dimension_to_nether_and_back.rs | 22 +-- .../tests/simulation/client_disconnect.rs | 4 +- .../login_to_dimension_with_same_name.rs | 24 +-- ...receive_spawn_entity_and_start_config_packet.rs | 4 +- .../simulation/receive_start_config_packet.rs | 4 +- azalea-core/src/registry_holder/mod.rs | 2 +- azalea-entity/src/plugin/components.rs | 10 +- azalea-entity/src/plugin/indexing.rs | 76 ++++---- azalea-entity/src/plugin/mod.rs | 71 +++---- azalea-entity/src/plugin/relative_updates.rs | 6 +- azalea-physics/src/collision/entity_collisions.rs | 6 +- azalea-physics/src/collision/mod.rs | 10 +- azalea-physics/src/collision/world_collisions.rs | 12 +- azalea-physics/src/fluids.rs | 22 +-- azalea-physics/src/lib.rs | 36 ++-- azalea-physics/src/travel.rs | 14 +- azalea-physics/tests/physics.rs | 102 +++++----- azalea-protocol/Cargo.toml | 8 +- azalea-protocol/src/packets/game/c_add_entity.rs | 4 +- azalea-world/src/container.rs | 66 ++++--- azalea-world/src/find_blocks.rs | 20 +- azalea-world/src/lib.rs | 9 +- azalea-world/src/world.rs | 54 ++--- azalea/examples/testbot/commands/debug.rs | 22 +-- azalea/src/client_impl/entity_query.rs | 54 +++-- azalea/src/client_impl/mod.rs | 47 +++-- azalea/src/entity_ref/mod.rs | 4 +- azalea/src/entity_ref/shared_impls.rs | 24 ++- azalea/src/events.rs | 4 +- azalea/src/nearest_entity.rs | 46 ++--- azalea/src/pathfinder/debug.rs | 8 +- azalea/src/pathfinder/extras/utils.rs | 4 +- azalea/src/pathfinder/mod.rs | 79 ++++---- azalea/src/pathfinder/moves/mod.rs | 21 +- azalea/src/pathfinder/simulation.rs | 56 +++--- azalea/src/pathfinder/world.rs | 14 +- azalea/src/swarm/builder.rs | 6 +- azalea/src/swarm/chat.rs | 12 +- azalea/src/swarm/events.rs | 4 +- azalea/src/swarm/mod.rs | 4 +- 61 files changed, 748 insertions(+), 755 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0ac74dd..d95581e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ is breaking anyways, semantic versioning is not followed. ### Changed +- Rename `Instance` to `World` (and rename other related types). - Move the `Client` struct out of `azalea-client` into `azalea`. - `Client::ecs` is now an `RwLock` instead of a `Mutex`. - `Client::component` and `entity_component` now return a mapped RwLock guard instead of cloning the component. diff --git a/Cargo.lock b/Cargo.lock index f7f86db7..10ea58df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -536,6 +536,7 @@ dependencies = [ "azalea-inventory", "azalea-protocol-macros", "azalea-registry", + "azalea-world", "bevy_ecs", "flate2", "futures", diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index b7d01d58..90b1264c 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -11,7 +11,7 @@ use azalea_entity::{ EntityUpdateSystems, PlayerAbilities, indexing::EntityIdIndex, inventory::Inventory, }; use azalea_physics::local_player::PhysicsState; -use azalea_world::InstanceContainer; +use azalea_world::Worlds; use bevy_app::{App, AppExit, Plugin, PluginsState, SubApp, Update}; use bevy_ecs::{ message::MessageCursor, @@ -29,7 +29,7 @@ use crate::{ connection::RawConnection, cookies::ServerCookies, interact::BlockStatePredictionHandler, - local_player::{Hunger, InstanceHolder, PermissionLevel, TabList}, + local_player::{Hunger, PermissionLevel, TabList, WorldHolder}, mining, movement::LastSentLookDirection, player::retroactively_add_game_profile_component, @@ -43,7 +43,7 @@ use crate::{ #[derive(Bundle)] pub struct LocalPlayerBundle { pub raw_connection: RawConnection, - pub instance_holder: InstanceHolder, + pub world_holder: WorldHolder, pub metadata: azalea_entity::metadata::PlayerMetadataBundle, } @@ -56,7 +56,7 @@ pub struct LocalPlayerBundle { /// If you want to filter for this, use [`InGameState`]. #[derive(Bundle, Default)] pub struct JoinedClientBundle { - // note that InstanceHolder isn't here because it's set slightly before we fully join the world + // note that WorldHolder isn't here because it's set slightly before we fully join the world pub physics_state: PhysicsState, pub inventory: Inventory, pub tab_list: TabList, @@ -98,7 +98,7 @@ impl Plugin for AzaleaPlugin { .after(crate::join::handle_start_join_server_event), ), ) - .init_resource::() + .init_resource::() .init_resource::(); } } diff --git a/azalea-client/src/local_player.rs b/azalea-client/src/local_player.rs index 9e44913c..444b2fcc 100644 --- a/azalea-client/src/local_player.rs +++ b/azalea-client/src/local_player.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, sync::Arc}; use azalea_core::game_type::GameMode; -use azalea_world::{Instance, PartialInstance}; +use azalea_world::{PartialWorld, World}; use bevy_ecs::{component::Component, prelude::*}; use derive_more::{Deref, DerefMut}; use parking_lot::RwLock; @@ -9,28 +9,29 @@ use uuid::Uuid; use crate::{ClientInformation, player::PlayerInfo}; -/// A component that keeps strong references to our [`PartialInstance`] and -/// [`Instance`] for local players. +/// A component that keeps strong references to our [`PartialWorld`] and +/// [`World`] for local players. /// -/// This can also act as a convenience for accessing the player's Instance since -/// the alternative is to look up the player's [`InstanceName`] in the -/// [`InstanceContainer`]. +/// This can also act as a convenient way to access the player's `World`, since +/// the alternative is to look up the player's [`WorldName`] in the [`Worlds`] +/// resource. /// -/// [`InstanceContainer`]: azalea_world::InstanceContainer -/// [`InstanceName`]: azalea_world::InstanceName +/// [`Worlds`]: azalea_world::Worlds +/// [`WorldName`]: azalea_world::WorldName #[derive(Clone, Component)] -pub struct InstanceHolder { - /// The partial instance is the world this client currently has loaded. +pub struct WorldHolder { + /// The slice of the world that this client actually has loaded, based on + /// its render distance. + pub partial: Arc>, + /// The combined [`PartialWorld`]s of all clients in the same world. /// - /// It has a limited render distance. - pub partial_instance: Arc>, - /// The combined [`PartialInstance`]s of all clients in the same instance - /// (aka world/dimension). - /// - /// This is only relevant if you're using a shared world (i.e. a - /// swarm). - pub instance: Arc>, + /// The distinction between this and `partial` is mostly only relevant if + /// you're using a shared world (i.e. a swarm). If in doubt, prefer to use + /// the shared world. + pub shared: Arc>, } +#[deprecated = "renamed to `WorldHolder`."] +pub type InstanceHolder = WorldHolder; /// The gamemode of a local player. For a non-local player, you can look up the /// player in the [`TabList`]. @@ -103,18 +104,18 @@ impl Hunger { } } -impl InstanceHolder { - /// Create a new `InstanceHolder` for the given entity. +impl WorldHolder { + /// Create a new `WorldHolder` for the given entity. /// - /// The partial instance will be created for you. The render distance will + /// The partial world will be created for you. The render distance will /// be set to a default value, which you can change by creating a new - /// partial_instance. - pub fn new(entity: Entity, instance: Arc>) -> Self { + /// partial world. + pub fn new(entity: Entity, shared: Arc>) -> Self { let client_information = ClientInformation::default(); - InstanceHolder { - instance, - partial_instance: Arc::new(RwLock::new(PartialInstance::new( + WorldHolder { + shared, + partial: Arc::new(RwLock::new(PartialWorld::new( azalea_world::chunk_storage::calculate_chunk_storage_range( client_information.view_distance.into(), ), @@ -123,19 +124,19 @@ impl InstanceHolder { } } - /// Reset the `Instance` to a new reference to an empty instance, but with + /// Reset the [`World`] to be a reference to an empty world, but with /// the same registries as the current one. /// /// This is used by Azalea when entering the config state. pub fn reset(&mut self) { - let registries = self.instance.read().registries.clone(); + let registries = self.shared.read().registries.clone(); - let new_instance = Instance { + let new_world = World { registries, ..Default::default() }; - self.instance = Arc::new(RwLock::new(new_instance)); + self.shared = Arc::new(RwLock::new(new_world)); - self.partial_instance.write().reset(); + self.partial.write().reset(); } } diff --git a/azalea-client/src/plugins/block_update.rs b/azalea-client/src/plugins/block_update.rs index 46e6b409..51dba728 100644 --- a/azalea-client/src/plugins/block_update.rs +++ b/azalea-client/src/plugins/block_update.rs @@ -5,7 +5,7 @@ use bevy_ecs::prelude::*; use crate::{ chunks::handle_receive_chunk_event, interact::BlockStatePredictionHandler, - local_player::InstanceHolder, + local_player::WorldHolder, }; pub struct BlockUpdatePlugin; @@ -34,12 +34,12 @@ pub struct QueuedServerBlockUpdates { pub fn handle_block_update_event( mut query: Query<( &mut QueuedServerBlockUpdates, - &InstanceHolder, + &WorldHolder, &mut BlockStatePredictionHandler, )>, ) { - for (mut queued, instance_holder, mut prediction_handler) in query.iter_mut() { - let world = instance_holder.instance.read(); + for (mut queued, world_holder, mut prediction_handler) in query.iter_mut() { + let world = world_holder.shared.read(); for (pos, block_state) in queued.list.drain(..) { if !prediction_handler.update_known_server_state(pos, block_state) { world.chunks.set_block_state(pos, block_state); diff --git a/azalea-client/src/plugins/chunks.rs b/azalea-client/src/plugins/chunks.rs index d5014516..0937c2ef 100644 --- a/azalea-client/src/plugins/chunks.rs +++ b/azalea-client/src/plugins/chunks.rs @@ -17,7 +17,7 @@ use bevy_ecs::prelude::*; use tracing::{error, trace}; use crate::{ - inventory::InventorySystems, local_player::InstanceHolder, packet::game::SendGamePacketEvent, + inventory::InventorySystems, local_player::WorldHolder, packet::game::SendGamePacketEvent, respawn::perform_respawn, }; @@ -66,42 +66,40 @@ pub struct ChunkBatchFinishedEvent { pub fn handle_receive_chunk_event( mut events: MessageReader, - mut query: Query<&InstanceHolder>, + mut query: Query<&WorldHolder>, ) { for event in events.read() { let pos = ChunkPos::new(event.packet.x, event.packet.z); let local_player = query.get_mut(event.entity).unwrap(); - let mut instance = local_player.instance.write(); - let mut partial_instance = local_player.partial_instance.write(); + let mut world = local_player.shared.write(); + let mut partial_world = local_player.partial.write(); // OPTIMIZATION: if we already know about the chunk from the shared world (and // not ourselves), then we don't need to parse it again. This is only used when // we have a shared world, since we check that the chunk isn't currently owned // by this client. - let shared_chunk = instance.chunks.get(&pos); - let this_client_has_chunk = partial_instance.chunks.limited_get(&pos).is_some(); + let shared_chunk = world.chunks.get(&pos); + let this_client_has_chunk = partial_world.chunks.limited_get(&pos).is_some(); if !this_client_has_chunk && let Some(shared_chunk) = shared_chunk { trace!("Skipping parsing chunk {pos:?} because we already know about it"); - partial_instance - .chunks - .limited_set(&pos, Some(shared_chunk)); + partial_world.chunks.limited_set(&pos, Some(shared_chunk)); continue; } let heightmaps = &event.packet.chunk_data.heightmaps; - if let Err(e) = partial_instance.chunks.replace_with_packet_data( + if let Err(e) = partial_world.chunks.replace_with_packet_data( &pos, &mut Cursor::new(&event.packet.chunk_data.data), heightmaps, - &mut instance.chunks, + &mut world.chunks, ) { error!( "Couldn't set chunk data: {e}. World height: {}", - instance.chunks.height + world.chunks.height ); } } diff --git a/azalea-client/src/plugins/disconnect.rs b/azalea-client/src/plugins/disconnect.rs index 081c174e..be98383b 100644 --- a/azalea-client/src/plugins/disconnect.rs +++ b/azalea-client/src/plugins/disconnect.rs @@ -1,10 +1,10 @@ //! Disconnect a client from the server. use azalea_chat::FormattedText; +use azalea_core::entity_id::MinecraftEntityId; use azalea_entity::{ EntityBundle, HasClientLoaded, InLoadedChunk, LocalEntity, metadata::PlayerMetadataBundle, }; -use azalea_core::entity_id::MinecraftEntityId; use bevy_app::{App, Plugin, PostUpdate}; use bevy_ecs::prelude::*; use derive_more::Deref; @@ -14,7 +14,7 @@ use super::login::IsAuthenticated; #[cfg(feature = "online-mode")] use crate::chat_signing; use crate::{ - client::JoinedClientBundle, connection::RawConnection, local_player::InstanceHolder, + client::JoinedClientBundle, connection::RawConnection, local_player::WorldHolder, tick_counter::TicksConnected, }; @@ -63,7 +63,7 @@ pub struct RemoveOnDisconnectBundle { pub entity: EntityBundle, pub minecraft_entity_id: MinecraftEntityId, - pub instance_holder: InstanceHolder, + pub world_holder: WorldHolder, pub player_metadata: PlayerMetadataBundle, pub in_loaded_chunk: InLoadedChunk, //// This makes it close the TCP connection. diff --git a/azalea-client/src/plugins/interact/mod.rs b/azalea-client/src/plugins/interact/mod.rs index d8f8b8b4..04986de7 100644 --- a/azalea-client/src/plugins/interact/mod.rs +++ b/azalea-client/src/plugins/interact/mod.rs @@ -30,7 +30,7 @@ use azalea_protocol::packets::game::{ s_swing::ServerboundSwing, s_use_item_on::ServerboundUseItemOn, }; -use azalea_world::Instance; +use azalea_world::World; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; use tracing::warn; @@ -140,7 +140,7 @@ impl BlockStatePredictionHandler { } } - pub fn end_prediction_up_to(&mut self, seq: u32, world: &Instance) { + pub fn end_prediction_up_to(&mut self, seq: u32, world: &World) { let mut to_remove = Vec::new(); for (pos, state) in &self.server_state { if state.seq > seq { @@ -377,10 +377,10 @@ pub fn handle_entity_interact( /// /// If this is false, then we can interact with the block. /// -/// Passing the inventory, block position, and instance is necessary for the -/// adventure mode check. +/// The world, block position, and inventory are used for the adventure mode +/// check. pub fn check_is_interaction_restricted( - instance: &Instance, + world: &World, block_pos: BlockPos, game_mode: &GameMode, inventory: &Inventory, @@ -393,7 +393,7 @@ pub fn check_is_interaction_restricted( let held_item = inventory.held_item(); match &held_item { ItemStack::Present(item) => { - let block = instance.chunks.get_block_state(block_pos); + let block = world.chunks.get_block_state(block_pos); let Some(block) = block else { // block isn't loaded so just say that it is restricted return true; diff --git a/azalea-client/src/plugins/interact/pick.rs b/azalea-client/src/plugins/interact/pick.rs index 8ffe47e8..1fed584a 100644 --- a/azalea-client/src/plugins/interact/pick.rs +++ b/azalea-client/src/plugins/interact/pick.rs @@ -17,7 +17,7 @@ use azalea_physics::{ clip::{BlockShapeType, ClipContext, FluidPickType}, collision::entity_collisions::{AabbQuery, get_entities}, }; -use azalea_world::{Instance, InstanceContainer, InstanceName}; +use azalea_world::{World, WorldName, Worlds}; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; @@ -37,13 +37,13 @@ pub fn update_hit_result_component( &Position, &EntityDimensions, &LookDirection, - &InstanceName, + &WorldName, &Physics, &Attributes, ), With, >, - instance_container: Res, + worlds: Res, aabb_query: AabbQuery, pickable_query: MaybePickableEntityQuery, ) { @@ -63,7 +63,7 @@ pub fn update_hit_result_component( let eye_position = position.up(dimensions.eye_height.into()); - let Some(world_lock) = instance_container.get(world_name) else { + let Some(world_lock) = worlds.get(world_name) else { continue; }; let world = world_lock.read(); @@ -117,7 +117,7 @@ pub struct PickOpts<'world, 'state, 'a, 'b, 'c> { look_direction: LookDirection, eye_position: Vec3, aabb: &'a Aabb, - world: &'a Instance, + world: &'a World, entity_pick_range: f64, block_pick_range: f64, aabb_query: &'a AabbQuery<'world, 'state, 'b>, @@ -246,7 +246,7 @@ struct PickEntityOpts<'world, 'state, 'a, 'b> { source_entity: Entity, eye_position: Vec3, end_position: Vec3, - world: &'a azalea_world::Instance, + world: &'a azalea_world::World, pick_range_squared: f64, predicate: &'a dyn Fn(Entity) -> bool, aabb: &'a Aabb, diff --git a/azalea-client/src/plugins/inventory/equipment_effects.rs b/azalea-client/src/plugins/inventory/equipment_effects.rs index 47220bf2..d5897f48 100644 --- a/azalea-client/src/plugins/inventory/equipment_effects.rs +++ b/azalea-client/src/plugins/inventory/equipment_effects.rs @@ -19,7 +19,7 @@ use bevy_ecs::{ }; use tracing::{debug, error, warn}; -use crate::local_player::InstanceHolder; +use crate::local_player::WorldHolder; /// A component that contains the equipment slots that we had last tick. /// @@ -91,9 +91,9 @@ pub struct EquipmentChange { pub fn handle_equipment_changes( equipment_changes: On, - mut query: Query<(&InstanceHolder, &mut LastEquipmentItems, &mut Attributes)>, + mut query: Query<(&WorldHolder, &mut LastEquipmentItems, &mut Attributes)>, ) { - let Ok((instance_holder, mut last_equipment_items, mut attributes)) = + let Ok((world_holder, mut last_equipment_items, mut attributes)) = query.get_mut(equipment_changes.entity) else { error!( @@ -112,7 +112,7 @@ pub fn handle_equipment_changes( // stopLocationBasedEffects for (attribute, modifier) in - collect_attribute_modifiers_from_item(slot, &change.old, instance_holder) + collect_attribute_modifiers_from_item(slot, &change.old, world_holder) { if let Some(attribute) = attributes.get_mut(attribute) { attribute.remove(&modifier.id); @@ -126,7 +126,7 @@ pub fn handle_equipment_changes( // see ItemStack.forEachModifier in vanilla for (attribute, modifier) in - collect_attribute_modifiers_from_item(slot, &change.new, instance_holder) + collect_attribute_modifiers_from_item(slot, &change.new, world_holder) { if let Some(attribute) = attributes.get_mut(attribute) { attribute.remove(&modifier.id); @@ -144,7 +144,7 @@ pub fn handle_equipment_changes( fn collect_attribute_modifiers_from_item( slot: EquipmentSlot, item: &ItemStack, - instance_holder: &InstanceHolder, + world_holder: &WorldHolder, ) -> Vec<(azalea_registry::builtin::Attribute, AttributeModifier)> { let mut modifiers = Vec::new(); @@ -161,7 +161,7 @@ fn collect_attribute_modifiers_from_item( .get_component::() .unwrap_or_default(); if !enchants.levels.is_empty() { - let registry_holder = &instance_holder.instance.read().registries; + let registry_holder = &world_holder.shared.read().registries; for (enchant, &level) in &enchants.levels { let Some((_enchant_id, enchant_definition)) = enchant.resolve(registry_holder) else { warn!( diff --git a/azalea-client/src/plugins/inventory/mod.rs b/azalea-client/src/plugins/inventory/mod.rs index 740decb1..908ebe66 100644 --- a/azalea-client/src/plugins/inventory/mod.rs +++ b/azalea-client/src/plugins/inventory/mod.rs @@ -11,7 +11,7 @@ use azalea_protocol::packets::game::{ s_set_carried_item::ServerboundSetCarriedItem, }; use azalea_registry::builtin::MenuKind; -use azalea_world::{InstanceContainer, InstanceName}; +use azalea_world::{WorldName, Worlds}; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use indexmap::IndexMap; @@ -167,10 +167,10 @@ pub struct ContainerClickEvent { pub fn handle_container_click_event( container_click: On, mut commands: Commands, - mut query: Query<(Entity, &mut Inv, Option<&PlayerAbilities>, &InstanceName)>, - instance_container: Res, + mut query: Query<(Entity, &mut Inv, Option<&PlayerAbilities>, &WorldName)>, + worlds: Res, ) { - let (entity, mut inventory, player_abilities, instance_name) = + let (entity, mut inventory, player_abilities, world_name) = query.get_mut(container_click.entity).unwrap(); if inventory.id != container_click.window_id { error!( @@ -180,7 +180,7 @@ pub fn handle_container_click_event( return; } - let Some(instance) = instance_container.get(instance_name) else { + let Some(world) = worlds.get(world_name) else { return; }; @@ -191,7 +191,7 @@ pub fn handle_container_click_event( ); let new_slots = inventory.menu().slots(); - let registry_holder = &instance.read().registries; + let registry_holder = &world.read().registries; // see which slots changed after clicking and put them in the map the server // uses this to check if we desynced diff --git a/azalea-client/src/plugins/join.rs b/azalea-client/src/plugins/join.rs index c254bc26..a6c9c586 100644 --- a/azalea-client/src/plugins/join.rs +++ b/azalea-client/src/plugins/join.rs @@ -11,7 +11,7 @@ use azalea_protocol::{ login::{ClientboundLoginPacket, ServerboundHello, ServerboundLoginPacket}, }, }; -use azalea_world::Instance; +use azalea_world::World; use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_tasks::{IoTaskPool, Task, futures_lite::future}; @@ -23,6 +23,7 @@ use crate::{ LocalPlayerBundle, account::Account, connection::RawConnection, + local_player::WorldHolder, packet::login::{InLoginState, SendLoginPacketEvent}, }; @@ -204,12 +205,12 @@ pub fn poll_create_connection_task( let (read_conn, write_conn) = conn.into_split(); let (read_conn, write_conn) = (read_conn.raw, write_conn.raw); - let instance = Instance::default(); - let instance_holder = crate::local_player::InstanceHolder::new( + let world = World::default(); + let world_holder = WorldHolder::new( entity, // default to an empty world, it'll be set correctly later when we // get the login packet - Arc::new(RwLock::new(instance)), + Arc::new(RwLock::new(world)), ); entity_mut.insert(( @@ -220,7 +221,7 @@ pub fn poll_create_connection_task( write_conn, ConnectionProtocol::Login, ), - instance_holder, + world_holder, metadata: azalea_entity::metadata::PlayerMetadataBundle::default(), }, InLoginState, diff --git a/azalea-client/src/plugins/mining.rs b/azalea-client/src/plugins/mining.rs index e9dcbe59..35b01a6a 100644 --- a/azalea-client/src/plugins/mining.rs +++ b/azalea-client/src/plugins/mining.rs @@ -8,7 +8,7 @@ use azalea_inventory::ItemStack; use azalea_physics::{PhysicsSystems, collision::BlockWithShape}; use azalea_protocol::packets::game::s_player_action::{self, ServerboundPlayerAction}; use azalea_registry::builtin::{BlockKind, ItemKind}; -use azalea_world::{InstanceContainer, InstanceName}; +use azalea_world::{Worlds, WorldName}; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; @@ -20,7 +20,7 @@ use crate::{ check_is_interaction_restricted, pick::HitResultComponent, }, inventory::InventorySystems, - local_player::{InstanceHolder, LocalGameMode, PermissionLevel}, + local_player::{LocalGameMode, PermissionLevel, WorldHolder}, movement::MoveEventsSystems, packet::game::SendGamePacketEvent, }; @@ -219,7 +219,7 @@ pub fn handle_mining_queued( query: Query<( Entity, &MiningQueued, - &InstanceHolder, + &WorldHolder, &LocalGameMode, &Inventory, &ActiveEffects, @@ -240,7 +240,7 @@ pub fn handle_mining_queued( for ( entity, mining_queued, - instance_holder, + world_holder, game_mode, inventory, active_effects, @@ -261,9 +261,9 @@ pub fn handle_mining_queued( trace!("handle_mining_queued {mining_queued:?}"); commands.entity(entity).remove::(); - let instance = instance_holder.instance.read(); + let world = world_holder.shared.read(); if check_is_interaction_restricted( - &instance, + &world, mining_queued.position, &game_mode.current, inventory, @@ -320,7 +320,7 @@ pub fn handle_mining_queued( )); } - let target_block_state = instance + let target_block_state = world .get_block_state(mining_queued.position) .unwrap_or_default(); @@ -472,7 +472,7 @@ pub struct FinishMiningBlockEvent { pub fn handle_finish_mining_block_observer( finish_mining_block: On, mut query: Query<( - &InstanceName, + &WorldName, &LocalGameMode, &Inventory, &PlayerAbilities, @@ -480,12 +480,12 @@ pub fn handle_finish_mining_block_observer( &Position, &mut BlockStatePredictionHandler, )>, - instances: Res, + worlds: Res, ) { let event = finish_mining_block.event(); let ( - instance_name, + world_name, game_mode, inventory, abilities, @@ -493,9 +493,9 @@ pub fn handle_finish_mining_block_observer( player_pos, mut prediction_handler, ) = query.get_mut(finish_mining_block.entity).unwrap(); - let instance_lock = instances.get(instance_name).unwrap(); - let instance = instance_lock.read(); - if check_is_interaction_restricted(&instance, event.position, &game_mode.current, inventory) { + let world_lock = worlds.get(world_name).unwrap(); + let world = world_lock.read(); + if check_is_interaction_restricted(&world, event.position, &game_mode.current, inventory) { return; } @@ -508,7 +508,7 @@ pub fn handle_finish_mining_block_observer( } } - let Some(block_state) = instance.get_block_state(event.position) else { + let Some(block_state) = world.get_block_state(event.position) else { return; }; @@ -528,7 +528,7 @@ pub fn handle_finish_mining_block_observer( // when we break a waterlogged block we want to keep the water there let fluid_state = FluidState::from(block_state); let block_state_for_fluid = BlockState::from(fluid_state); - let old_state = instance + let old_state = world .set_block_state(event.position, block_state_for_fluid) .unwrap_or_default(); prediction_handler.retain_known_server_state(event.position, old_state, **player_pos); @@ -581,7 +581,7 @@ pub fn decrement_mine_delay(mut query: Query<&mut MineDelay>) { pub fn continue_mining_block( mut query: Query<( Entity, - &InstanceName, + &WorldName, &LocalGameMode, &Inventory, &MineBlockPos, @@ -598,11 +598,11 @@ pub fn continue_mining_block( )>, mut commands: Commands, mut mine_block_progress_events: MessageWriter, - instances: Res, + worlds: Res, ) { for ( entity, - instance_name, + world_name, game_mode, inventory, current_mining_pos, @@ -644,9 +644,9 @@ pub fn continue_mining_block( ) { trace!("continue mining block at {:?}", mining.pos); - let instance_lock = instances.get(instance_name).unwrap(); - let instance = instance_lock.read(); - let target_block_state = instance.get_block_state(mining.pos).unwrap_or_default(); + let world_lock = worlds.get(world_name).unwrap(); + let world = world_lock.read(); + let target_block_state = world.get_block_state(mining.pos).unwrap_or_default(); trace!("target_block_state: {target_block_state:?}"); diff --git a/azalea-client/src/plugins/movement.rs b/azalea-client/src/plugins/movement.rs index 40cc108e..94b996a0 100644 --- a/azalea-client/src/plugins/movement.rs +++ b/azalea-client/src/plugins/movement.rs @@ -31,12 +31,12 @@ use azalea_protocol::{ }, }; use azalea_registry::builtin::EntityKind; -use azalea_world::Instance; +use azalea_world::World; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; use crate::{ - local_player::{Hunger, InstanceHolder, LocalGameMode}, + local_player::{Hunger, LocalGameMode, WorldHolder}, packet::game::SendGamePacketEvent, }; @@ -296,7 +296,7 @@ pub fn local_player_ai_step( &PlayerAbilities, &metadata::Swimming, &metadata::SleepingPos, - &InstanceHolder, + &WorldHolder, &Position, Option<&Hunger>, Option<&LastSentInput>, @@ -316,7 +316,7 @@ pub fn local_player_ai_step( abilities, swimming, sleeping_pos, - instance_holder, + world_holder, position, hunger, last_sent_input, @@ -333,7 +333,7 @@ pub fn local_player_ai_step( let is_passenger = false; let is_sleeping = sleeping_pos.is_some(); - let world = instance_holder.instance.read(); + let world = world_holder.shared.read(); let ctx = CanPlayerFitCtx { world: &world, entity, @@ -587,16 +587,16 @@ pub fn update_pose( &Physics, &PhysicsState, &LocalGameMode, - &InstanceHolder, + &WorldHolder, &Position, )>, aabb_query: AabbQuery, collidable_entity_query: CollidableEntityQuery, ) { - for (entity, mut pose, physics, physics_state, game_mode, instance_holder, position) in + for (entity, mut pose, physics, physics_state, game_mode, world_holder, position) in query.iter_mut() { - let world = instance_holder.instance.read(); + let world = world_holder.shared.read(); let world = &*world; let ctx = CanPlayerFitCtx { world, @@ -642,7 +642,7 @@ pub fn update_pose( } struct CanPlayerFitCtx<'world, 'state, 'a, 'b> { - world: &'a Instance, + world: &'a World, entity: Entity, position: Position, aabb_query: &'a AabbQuery<'world, 'state, 'b>, diff --git a/azalea-client/src/plugins/packet/config/mod.rs b/azalea-client/src/plugins/packet/config/mod.rs index 27dae837..f59b8c23 100644 --- a/azalea-client/src/plugins/packet/config/mod.rs +++ b/azalea-client/src/plugins/packet/config/mod.rs @@ -17,7 +17,7 @@ use crate::{ connection::RawConnection, cookies::{RequestCookieEvent, StoreCookieEvent}, disconnect::DisconnectEvent, - local_player::InstanceHolder, + local_player::WorldHolder, packet::game::{KeepAliveEvent, ResourcePackEvent}, }; @@ -69,12 +69,12 @@ pub struct ConfigPacketHandler<'a> { } impl ConfigPacketHandler<'_> { pub fn registry_data(&mut self, p: &ClientboundRegistryData) { - as_system::>(self.ecs, |mut query| { - let instance_holder = query.get_mut(self.player).unwrap(); - let mut instance = instance_holder.instance.write(); + as_system::>(self.ecs, |mut query| { + let world_holder = query.get_mut(self.player).unwrap(); + let mut world = world_holder.shared.write(); // add the new registry data - instance + world .registries .append(p.registry_id.clone(), p.entries.clone()); }); diff --git a/azalea-client/src/plugins/packet/game/events.rs b/azalea-client/src/plugins/packet/game/events.rs index 535bd519..bc070ec8 100644 --- a/azalea-client/src/plugins/packet/game/events.rs +++ b/azalea-client/src/plugins/packet/game/events.rs @@ -5,8 +5,7 @@ use azalea_protocol::packets::{ Packet, game::{ClientboundGamePacket, ClientboundPlayerCombatKill, ServerboundGamePacket}, }; -use azalea_registry::identifier::Identifier; -use azalea_world::Instance; +use azalea_world::{World, WorldName}; use bevy_ecs::prelude::*; use parking_lot::RwLock; use tracing::{error, trace}; @@ -138,16 +137,18 @@ pub struct ResourcePackEvent { pub prompt: Option, } -/// An instance (aka world, dimension) was loaded by a client. +/// A world instance (aka dimension) was loaded by a client. /// -/// Since the instance is given to you as a weak reference, it won't be able to -/// be `upgrade`d if all local players leave it. +/// Since the world is given to you as a weak reference, it won't be able to be +/// `upgrade`d if all local players unload it. #[derive(Clone, Debug, Message)] -pub struct InstanceLoadedEvent { +pub struct WorldLoadedEvent { pub entity: Entity, - pub name: Identifier, - pub instance: Weak>, + pub name: WorldName, + pub world: Weak>, } +#[deprecated = "renamed to `WorldLoadedEvent`."] +pub type InstanceLoadedEvent = WorldLoadedEvent; /// A Bevy trigger that's sent when our client receives a [`ClientboundPing`] /// packet in the game state. diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs index f93a02ea..6489c899 100644 --- a/azalea-client/src/plugins/packet/game/mod.rs +++ b/azalea-client/src/plugins/packet/game/mod.rs @@ -19,7 +19,7 @@ use azalea_protocol::{ packets::{ConnectionProtocol, game::*}, }; use azalea_registry::builtin::EntityKind; -use azalea_world::{InstanceContainer, InstanceName, PartialInstance}; +use azalea_world::{PartialWorld, WorldName, Worlds}; use bevy_ecs::{prelude::*, system::SystemState}; pub use events::*; use tracing::{debug, error, trace, warn}; @@ -34,7 +34,7 @@ use crate::{ disconnect::DisconnectEvent, interact::BlockStatePredictionHandler, inventory::{ClientsideCloseContainerEvent, MenuOpenedEvent, SetContainerContentEvent}, - local_player::{Hunger, InstanceHolder, LocalGameMode, TabList}, + local_player::{Hunger, LocalGameMode, TabList, WorldHolder}, movement::{KnockbackData, KnockbackEvent}, packet::{as_system, declare_packet_handlers}, player::{GameProfileComponent, PlayerInfo}, @@ -207,15 +207,15 @@ impl GamePacketHandler<'_> { ( &GameProfileComponent, &ClientInformation, - Option<&mut InstanceName>, + Option<&mut WorldName>, Option<&mut LoadedBy>, &mut EntityIdIndex, - &mut InstanceHolder, + &mut WorldHolder, ), With, >, - MessageWriter, - ResMut, + MessageWriter, + ResMut, ResMut, Query<&mut LoadedBy, Without>, )>( @@ -223,33 +223,31 @@ impl GamePacketHandler<'_> { |( mut commands, mut query, - mut instance_loaded_events, - mut instance_container, + mut world_loaded_events, + mut worlds, mut entity_uuid_index, mut loaded_by_query, )| { let ( game_profile, client_information, - instance_name, + world_name, loaded_by, mut entity_id_index, - mut instance_holder, + mut world_holder, ) = query.get_mut(self.player).unwrap(); - let new_instance_name = p.common.dimension.clone(); + let new_world_name = WorldName(p.common.dimension.clone()); - if let Some(mut instance_name) = instance_name { - **instance_name = new_instance_name.clone(); + if let Some(mut world_name) = world_name { + *world_name = new_world_name.clone(); } else { - commands - .entity(self.player) - .insert(InstanceName(new_instance_name.clone())); + commands.entity(self.player).insert(new_world_name.clone()); } - let weak_instance; + let weak_world; { - let client_registries = &instance_holder.instance.read().registries; + let client_registries = &world_holder.shared.read().registries; let Some((_dimension_type, dimension_data)) = p.common.dimension_type(client_registries) @@ -257,46 +255,44 @@ impl GamePacketHandler<'_> { return; }; - // add this world to the instance_container (or don't if it's already - // there) - weak_instance = instance_container.get_or_insert( - new_instance_name.clone(), + // add this world to the `worlds` (or don't, if it's already there) + weak_world = worlds.get_or_insert( + new_world_name.clone(), dimension_data.height, dimension_data.min_y, client_registries, ); - instance_loaded_events.write(InstanceLoadedEvent { + world_loaded_events.write(WorldLoadedEvent { entity: self.player, - name: new_instance_name.clone(), - instance: Arc::downgrade(&weak_instance), + name: new_world_name.clone(), + world: Arc::downgrade(&weak_world), }); } - // set the partial_world to an empty world - // (when we add chunks or entities those will be in the - // instance_container) + // set the partial world to an empty world (when we add chunks or entities those + // will be in the `worlds`) - *instance_holder.partial_instance.write() = PartialInstance::new( + *world_holder.partial.write() = PartialWorld::new( azalea_world::chunk_storage::calculate_chunk_storage_range( client_information.view_distance.into(), ), - // this argument makes it so other clients don't update this player entity - // in a shared instance + // this argument makes it so other clients don't update this player entity in a + // shared world Some(self.player), ); { - let client_registries = instance_holder.instance.read().registries.clone(); - let shared_registries = &mut weak_instance.write().registries; - // add the registries from this instance to the weak instance + let client_registries = world_holder.shared.read().registries.clone(); + let shared_registries = &mut weak_world.write().registries; + // add the registries from this world to the weak world shared_registries.extend(client_registries); } - instance_holder.instance = weak_instance; + world_holder.shared = weak_world; let entity_bundle = EntityBundle::new( game_profile.uuid, Vec3::ZERO, EntityKind::Player, - new_instance_name, + new_world_name, ); let entity_id = p.player_id; // insert our components into the ecs :) @@ -316,7 +312,7 @@ impl GamePacketHandler<'_> { Some(game_profile.uuid), &mut entity_id_index, &mut entity_uuid_index, - &mut instance_holder.instance.write(), + &mut world_holder.shared.write(), ); // every entity is now unloaded by this player @@ -532,9 +528,9 @@ impl GamePacketHandler<'_> { pub fn set_chunk_cache_center(&mut self, p: &ClientboundSetChunkCacheCenter) { debug!("Got chunk cache center packet {p:?}"); - as_system::>(self.ecs, |mut query| { - let instance_holder = query.get_mut(self.player).unwrap(); - let mut partial_world = instance_holder.partial_instance.write(); + as_system::>(self.ecs, |mut query| { + let world_holder = query.get_mut(self.player).unwrap(); + let mut partial_world = world_holder.partial.write(); partial_world .chunks @@ -564,10 +560,10 @@ impl GamePacketHandler<'_> { as_system::<( Commands, - Query<(&mut EntityIdIndex, Option<&InstanceName>, Option<&TabList>)>, + Query<(&mut EntityIdIndex, Option<&WorldName>, Option<&TabList>)>, Query<&mut LoadedBy>, Query, - Res, + Res, ResMut, )>( self.ecs, @@ -576,22 +572,22 @@ impl GamePacketHandler<'_> { mut query, mut loaded_by_query, entity_query, - instance_container, + worlds, mut entity_uuid_index, )| { - let (mut entity_id_index, instance_name, tab_list) = + let (mut entity_id_index, world_name, tab_list) = query.get_mut(self.player).unwrap(); let entity_id = p.id; - let Some(instance_name) = instance_name else { + let Some(world_name) = world_name else { warn!("got add player packet but we haven't gotten a login packet yet"); return; }; // check if the entity already exists, and if it does then only add to LoadedBy - let instance = instance_container.get(instance_name).unwrap(); - if let Some(&ecs_entity) = instance.read().entity_by_id.get(&entity_id) { + let world = worlds.get(world_name).unwrap(); + if let Some(&ecs_entity) = world.read().entity_by_id.get(&entity_id) { // entity already exists let Ok(mut loaded_by) = loaded_by_query.get_mut(ecs_entity) else { // LoadedBy for this entity isn't in the ecs! figure out what went wrong @@ -621,7 +617,7 @@ impl GamePacketHandler<'_> { // entity doesn't exist in the global index! - let bundle = p.as_entity_bundle((**instance_name).clone()); + let bundle = p.as_entity_bundle(world_name.to_owned()); let mut spawned = commands.spawn((entity_id, LoadedBy(HashSet::from([self.player])), bundle)); let ecs_entity: Entity = spawned.id(); @@ -636,7 +632,7 @@ impl GamePacketHandler<'_> { Some(p.uuid), &mut entity_id_index, &mut entity_uuid_index, - &mut instance.write(), + &mut world.write(), ); // add the GameProfileComponent if the uuid is in the tab list @@ -659,12 +655,12 @@ impl GamePacketHandler<'_> { pub fn set_entity_data(&mut self, p: &ClientboundSetEntityData) { as_system::<( Commands, - Query<(&EntityIdIndex, &InstanceHolder)>, + Query<(&EntityIdIndex, &WorldHolder)>, // this is a separate query since it's applied on the entity id that's being updated // instead of the player that received the packet Query<&EntityKindComponent>, )>(self.ecs, |(mut commands, query, entity_kind_query)| { - let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get(self.player).unwrap(); let entity = entity_id_index.get_by_minecraft_entity(p.id); @@ -693,7 +689,7 @@ impl GamePacketHandler<'_> { // we use RelativeEntityUpdate because it makes sure changes aren't made // multiple times commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity| { let entity_id = entity.id(); entity.world_scope(|world| { @@ -720,10 +716,10 @@ impl GamePacketHandler<'_> { // vanilla servers use this packet for knockback, but note that the Explode // packet is also sometimes used by servers for knockback - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, query)| { - let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get(self.player).unwrap(); let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { // note that this log (and some other ones like the one in RemoveEntities) @@ -742,7 +738,7 @@ impl GamePacketHandler<'_> { let data = KnockbackData::Set(p.delta.to_vec3()); commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity_mut| { entity_mut .world_scope(|world| world.trigger(KnockbackEvent { entity, data })); @@ -790,10 +786,10 @@ impl GamePacketHandler<'_> { pub fn teleport_entity(&mut self, p: &ClientboundTeleportEntity) { debug!("Got teleport entity packet {p:?}"); - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get_mut(self.player).unwrap(); let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { warn!("Got teleport entity packet for unknown entity id {}", p.id); @@ -804,7 +800,7 @@ impl GamePacketHandler<'_> { let change = p.change.clone(); commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity| { let entity_id = entity.id(); entity.world_scope(move |world| { @@ -835,10 +831,10 @@ impl GamePacketHandler<'_> { pub fn rotate_head(&mut self, _p: &ClientboundRotateHead) {} pub fn move_entity_pos(&mut self, p: &ClientboundMoveEntityPos) { - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get_mut(self.player).unwrap(); debug!("Got move entity pos packet {p:?}"); @@ -851,7 +847,7 @@ impl GamePacketHandler<'_> { let new_delta = p.delta.clone(); let new_on_ground = p.on_ground; commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity_mut| { let mut physics = entity_mut.get_mut::().unwrap(); let new_pos = physics.vec_delta_codec.decode(&new_delta); @@ -874,10 +870,10 @@ impl GamePacketHandler<'_> { } pub fn move_entity_pos_rot(&mut self, p: &ClientboundMoveEntityPosRot) { - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get_mut(self.player).unwrap(); debug!("Got move entity pos rot packet {p:?}"); @@ -901,7 +897,7 @@ impl GamePacketHandler<'_> { let new_on_ground = p.on_ground; commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity_mut| { let mut physics = entity_mut.get_mut::().unwrap(); let new_position = physics.vec_delta_codec.decode(&new_delta); @@ -924,10 +920,10 @@ impl GamePacketHandler<'_> { } pub fn move_entity_rot(&mut self, p: &ClientboundMoveEntityRot) { - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get_mut(self.player).unwrap(); let entity = entity_id_index.get_by_minecraft_entity(p.entity_id); if let Some(entity) = entity { @@ -938,7 +934,7 @@ impl GamePacketHandler<'_> { let new_on_ground = p.on_ground; commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity_mut| { let mut physics = entity_mut.get_mut::().unwrap(); physics.set_on_ground(new_on_ground); @@ -1113,10 +1109,10 @@ impl GamePacketHandler<'_> { let mob_effect = p.mob_effect; let effect_data = &p.data; - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, query)| { - let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get(self.player).unwrap(); let Some(entity) = entity_id_index.get_by_minecraft_entity(p.entity_id) else { debug!( @@ -1126,10 +1122,10 @@ impl GamePacketHandler<'_> { return; }; - let partial_instance = instance_holder.partial_instance.clone(); + let partial_world = world_holder.partial.clone(); let effect_data = effect_data.clone(); commands.entity(entity).queue(RelativeEntityUpdate::new( - partial_instance, + partial_world, move |entity| { if let Some(mut active_effects) = entity.get_mut::() { active_effects.insert(mob_effect, effect_data.clone()); @@ -1147,11 +1143,11 @@ impl GamePacketHandler<'_> { pub fn award_stats(&mut self, _p: &ClientboundAwardStats) {} pub fn block_changed_ack(&mut self, p: &ClientboundBlockChangedAck) { - as_system::>( + as_system::>( self.ecs, |mut query| { let (local_player, mut prediction_handler) = query.get_mut(self.player).unwrap(); - let world = local_player.instance.read(); + let world = local_player.shared.read(); prediction_handler.end_prediction_up_to(p.seq, &world); }, ); @@ -1277,12 +1273,12 @@ impl GamePacketHandler<'_> { pub fn forget_level_chunk(&mut self, p: &ClientboundForgetLevelChunk) { debug!("Got forget level chunk packet {p:?}"); - as_system::>(self.ecs, |mut query| { + as_system::>(self.ecs, |mut query| { let local_player = query.get_mut(self.player).unwrap(); - let mut partial_instance = local_player.partial_instance.write(); + let mut partial_world = local_player.partial.write(); - partial_instance.chunks.limited_set(&p.pos, None); + partial_world.chunks.limited_set(&p.pos, None); }); } @@ -1355,10 +1351,10 @@ impl GamePacketHandler<'_> { let mob_effect = p.effect; - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, query)| { - let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get(self.player).unwrap(); let Some(entity) = entity_id_index.get_by_minecraft_entity(p.entity_id) else { debug!( @@ -1368,9 +1364,9 @@ impl GamePacketHandler<'_> { return; }; - let partial_instance = instance_holder.partial_instance.clone(); + let partial_world = world_holder.partial.clone(); commands.entity(entity).queue(RelativeEntityUpdate::new( - partial_instance, + partial_world, move |entity| { if let Some(mut active_effects) = entity.get_mut::() { active_effects.remove(mob_effect); @@ -1405,71 +1401,67 @@ impl GamePacketHandler<'_> { Commands, Query< ( - &mut InstanceHolder, + &mut WorldHolder, &GameProfileComponent, &ClientInformation, - Option<&mut InstanceName>, + Option<&mut WorldName>, ), With, >, MessageWriter<_>, - ResMut, + ResMut, Query<&mut LoadedBy, Without>, )>( self.ecs, - |(mut commands, mut query, mut events, mut instance_container, mut loaded_by_query)| { - let Ok((mut instance_holder, game_profile, client_information, instance_name)) = + |(mut commands, mut query, mut events, mut worlds, mut loaded_by_query)| { + let Ok((mut world_holder, game_profile, client_information, world_name)) = query.get_mut(self.player) else { warn!("Got respawn packet but player doesn't have the required components"); return; }; - let new_instance_name = p.common.dimension.clone(); + let new_world_name = WorldName(p.common.dimension.clone()); - if let Some(mut instance_name) = instance_name { - **instance_name = new_instance_name.clone(); + if let Some(mut world_name) = world_name { + *world_name = new_world_name.clone(); } else { - commands - .entity(self.player) - .insert(InstanceName(new_instance_name.clone())); + commands.entity(self.player).insert(new_world_name.clone()); } - let weak_instance; + let weak_world; { - let client_registries = &instance_holder.instance.read().registries; + let client_registries = &world_holder.shared.read().registries; let Some((_dimension_type, dimension_data)) = p.common.dimension_type(client_registries) else { return; }; - // add this world to the instance_container (or don't if it's already - // there) - weak_instance = instance_container.get_or_insert( - new_instance_name.clone(), + // add this world to the `worlds` (or don't if it's already there) + weak_world = worlds.get_or_insert( + new_world_name.clone(), dimension_data.height, dimension_data.min_y, client_registries, ); - events.write(InstanceLoadedEvent { + events.write(WorldLoadedEvent { entity: self.player, - name: new_instance_name.clone(), - instance: Arc::downgrade(&weak_instance), + name: new_world_name.clone(), + world: Arc::downgrade(&weak_world), }); } - // set the partial_world to an empty world - // (when we add chunks or entities those will be in the - // instance_container) + // set the partial world to an empty world (when we add chunks or entities, + // those will be in the `worlds`) - *instance_holder.partial_instance.write() = PartialInstance::new( + *world_holder.partial.write() = PartialWorld::new( azalea_world::chunk_storage::calculate_chunk_storage_range( client_information.view_distance.into(), ), Some(self.player), ); - instance_holder.instance = weak_instance; + world_holder.shared = weak_world; // every entity is now unloaded by this player for mut loaded_by in &mut loaded_by_query.iter_mut() { @@ -1481,7 +1473,7 @@ impl GamePacketHandler<'_> { game_profile.uuid, Vec3::ZERO, EntityKind::Player, - new_instance_name, + new_world_name, ); // update the local gamemode and metadata things commands.entity(self.player).insert(( @@ -1502,11 +1494,10 @@ impl GamePacketHandler<'_> { pub fn start_configuration(&mut self, _p: &ClientboundStartConfiguration) { debug!("Got start configuration packet"); - as_system::<(Commands, Query<(&mut RawConnection, &mut InstanceHolder)>)>( + as_system::<(Commands, Query<(&mut RawConnection, &mut WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let Some((mut raw_conn, mut instance_holder)) = query.get_mut(self.player).ok() - else { + let Some((mut raw_conn, mut world_holder)) = query.get_mut(self.player).ok() else { warn!("Got start configuration packet but player doesn't have a RawConnection"); return; }; @@ -1523,16 +1514,16 @@ impl GamePacketHandler<'_> { .remove::() .remove::(); - instance_holder.reset(); + world_holder.reset(); }, ); } pub fn entity_position_sync(&mut self, p: &ClientboundEntityPositionSync) { - as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( + as_system::<(Commands, Query<(&EntityIdIndex, &WorldHolder)>)>( self.ecs, |(mut commands, mut query)| { - let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); + let (entity_id_index, world_holder) = query.get_mut(self.player).unwrap(); let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { debug!("Got teleport entity packet for unknown entity id {}", p.id); @@ -1544,7 +1535,7 @@ impl GamePacketHandler<'_> { let new_look_direction = p.values.look_direction; commands.entity(entity).queue(RelativeEntityUpdate::new( - instance_holder.partial_instance.clone(), + world_holder.partial.clone(), move |entity_mut| { let is_local_entity = entity_mut.get::().is_some(); let mut physics = entity_mut.get_mut::().unwrap(); diff --git a/azalea-client/src/plugins/packet/mod.rs b/azalea-client/src/plugins/packet/mod.rs index 9d842dc6..63a94ee0 100644 --- a/azalea-client/src/plugins/packet/mod.rs +++ b/azalea-client/src/plugins/packet/mod.rs @@ -45,7 +45,7 @@ impl Plugin for PacketPlugin { .add_message::() .add_message::() .add_message::() - .add_message::() + .add_message::() .add_message::(); } } diff --git a/azalea-client/src/plugins/tick_counter.rs b/azalea-client/src/plugins/tick_counter.rs index e4b5f0a4..fba8bc1c 100644 --- a/azalea-client/src/plugins/tick_counter.rs +++ b/azalea-client/src/plugins/tick_counter.rs @@ -1,6 +1,6 @@ use azalea_core::tick::GameTick; use azalea_physics::PhysicsSystems; -use azalea_world::InstanceName; +use azalea_world::WorldName; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; @@ -27,9 +27,9 @@ impl Plugin for TickCounterPlugin { } } -/// Increment the [`TicksConnected`] component on every entity -/// that lives in an instance. -pub fn increment_counter(mut query: Query<&mut TicksConnected, With>) { +/// Increment the [`TicksConnected`] component for every entity that's in any +/// world. +pub fn increment_counter(mut query: Query<&mut TicksConnected, With>) { for mut counter in &mut query { counter.0 += 1; } diff --git a/azalea-client/src/plugins/tick_end.rs b/azalea-client/src/plugins/tick_end.rs index 15cd2e59..6df46c78 100644 --- a/azalea-client/src/plugins/tick_end.rs +++ b/azalea-client/src/plugins/tick_end.rs @@ -4,7 +4,7 @@ use azalea_core::tick::GameTick; use azalea_entity::LocalEntity; use azalea_physics::PhysicsSystems; use azalea_protocol::packets::game::ServerboundClientTickEnd; -use azalea_world::InstanceName; +use azalea_world::WorldName; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; @@ -27,7 +27,7 @@ impl Plugin for TickEndPlugin { } pub fn game_tick_packet( - query: Query, With)>, + query: Query, With)>, mut commands: Commands, ) { for entity in query.iter() { diff --git a/azalea-client/src/test_utils/simulation.rs b/azalea-client/src/test_utils/simulation.rs index 0e480b92..ce4c919d 100644 --- a/azalea-client/src/test_utils/simulation.rs +++ b/azalea-client/src/test_utils/simulation.rs @@ -31,7 +31,7 @@ use azalea_registry::{ data::{Biome, DimensionKind}, identifier::Identifier, }; -use azalea_world::{Chunk, Instance, Section, palette::PalettedContainer}; +use azalea_world::{Chunk, Section, World, palette::PalettedContainer}; use bevy_app::App; use bevy_ecs::{ component::Mutable, @@ -45,7 +45,7 @@ use uuid::Uuid; use crate::{ InConfigState, LocalPlayerBundle, connection::RawConnection, disconnect::DisconnectEvent, - local_player::InstanceHolder, packet::game::SendGamePacketEvent, player::GameProfileComponent, + local_player::WorldHolder, packet::game::SendGamePacketEvent, player::GameProfileComponent, }; /// A way to simulate a client in a server, used for some internal tests. @@ -175,15 +175,15 @@ impl Simulation { } pub fn chunk(&self, chunk_pos: ChunkPos) -> Option>> { - self.component::() - .instance + self.component::() + .shared .read() .chunks .get(&chunk_pos) } pub fn get_block_state(&self, pos: BlockPos) -> Option { - self.component::() - .instance + self.component::() + .shared .read() .get_block_state(pos) } @@ -287,12 +287,12 @@ fn create_local_player_bundle( let raw_connection = RawConnection::new_networkless(connection_protocol); - let instance = Instance::default(); - let instance_holder = InstanceHolder::new(entity, Arc::new(RwLock::new(instance))); + let world = World::default(); + let world_holder = WorldHolder::new(entity, Arc::new(RwLock::new(world))); let local_player_bundle = LocalPlayerBundle { raw_connection, - instance_holder, + world_holder, metadata: PlayerMetadataBundle::default(), }; diff --git a/azalea-client/tests/simulation/change_dimension_to_nether_and_back.rs b/azalea-client/tests/simulation/change_dimension_to_nether_and_back.rs index 2d4fb749..c23ef843 100644 --- a/azalea-client/tests/simulation/change_dimension_to_nether_and_back.rs +++ b/azalea-client/tests/simulation/change_dimension_to_nether_and_back.rs @@ -6,7 +6,7 @@ use azalea_protocol::packets::{ config::{ClientboundFinishConfiguration, ClientboundRegistryData}, }; use azalea_registry::{DataRegistry, data::DimensionKind, identifier::Identifier}; -use azalea_world::InstanceName; +use azalea_world::WorldName; use simdnbt::owned::{NbtCompound, NbtTag}; #[test] @@ -19,12 +19,12 @@ fn test_change_dimension_to_nether_and_back() { fn generic_test_change_dimension_to_nether_and_back(using_respawn: bool) { let make_basic_login_or_respawn_packet = if using_respawn { - |dimension: DimensionKind, instance_name: Identifier| { - make_basic_respawn_packet(dimension, instance_name).into_variant() + |dimension: DimensionKind, world_name: Identifier| { + make_basic_respawn_packet(dimension, world_name).into_variant() } } else { - |dimension: DimensionKind, instance_name: Identifier| { - make_basic_login_packet(dimension, instance_name).into_variant() + |dimension: DimensionKind, world_name: Identifier| { + make_basic_login_packet(dimension, world_name).into_variant() } }; @@ -81,9 +81,9 @@ fn generic_test_change_dimension_to_nether_and_back(using_respawn: bool) { simulation.tick(); assert_eq!( - *simulation.component::(), + *simulation.component::(), Identifier::new("azalea:a"), - "InstanceName should be azalea:a after setting dimension to that" + "WorldName should be azalea:a after setting dimension to that" ); simulation.receive_packet(make_basic_empty_chunk(ChunkPos::new(0, 0), (384 + 64) / 16)); @@ -108,9 +108,9 @@ fn generic_test_change_dimension_to_nether_and_back(using_respawn: bool) { "chunk should not exist immediately after changing dimensions" ); assert_eq!( - *simulation.component::(), + *simulation.component::(), Identifier::new("azalea:b"), - "InstanceName should be azalea:b after changing dimensions to that" + "WorldName should be azalea:b after changing dimensions to that" ); simulation.receive_packet(make_basic_empty_chunk(ChunkPos::new(0, 0), 256 / 16)); @@ -136,9 +136,9 @@ fn generic_test_change_dimension_to_nether_and_back(using_respawn: bool) { simulation.tick(); assert_eq!( - *simulation.component::(), + *simulation.component::(), Identifier::new("azalea:a"), - "InstanceName should be azalea:a after setting dimension back to that" + "WorldName should be azalea:a after setting dimension back to that" ); assert!( simulation.chunk(ChunkPos::new(0, 0)).is_none(), diff --git a/azalea-client/tests/simulation/client_disconnect.rs b/azalea-client/tests/simulation/client_disconnect.rs index 0956fbfa..60f112c2 100644 --- a/azalea-client/tests/simulation/client_disconnect.rs +++ b/azalea-client/tests/simulation/client_disconnect.rs @@ -1,6 +1,6 @@ use azalea_client::test_utils::prelude::*; use azalea_protocol::packets::ConnectionProtocol; -use azalea_world::InstanceName; +use azalea_world::WorldName; #[test] fn test_client_disconnect() { @@ -12,7 +12,7 @@ fn test_client_disconnect() { simulation.tick(); // make sure we're disconnected - let is_connected = simulation.has_component::(); + let is_connected = simulation.has_component::(); assert!(!is_connected); // tick again to make sure nothing goes wrong diff --git a/azalea-client/tests/simulation/login_to_dimension_with_same_name.rs b/azalea-client/tests/simulation/login_to_dimension_with_same_name.rs index 917c50bb..ef67130f 100644 --- a/azalea-client/tests/simulation/login_to_dimension_with_same_name.rs +++ b/azalea-client/tests/simulation/login_to_dimension_with_same_name.rs @@ -1,5 +1,5 @@ use azalea_client::{ - InConfigState, InGameState, local_player::InstanceHolder, test_utils::prelude::*, + InConfigState, InGameState, local_player::WorldHolder, test_utils::prelude::*, }; use azalea_core::position::ChunkPos; use azalea_entity::LocalEntity; @@ -9,7 +9,7 @@ use azalea_protocol::packets::{ game::ClientboundStartConfiguration, }; use azalea_registry::{DataRegistry, data::DimensionKind, identifier::Identifier}; -use azalea_world::InstanceName; +use azalea_world::WorldName; use simdnbt::owned::{NbtCompound, NbtTag}; #[test] @@ -22,12 +22,12 @@ fn test_login_to_dimension_with_same_name() { fn generic_test_login_to_dimension_with_same_name(using_respawn: bool) { let make_basic_login_or_respawn_packet = if using_respawn { - |dimension: DimensionKind, instance_name: Identifier| { - make_basic_respawn_packet(dimension, instance_name).into_variant() + |dimension: DimensionKind, world_name: Identifier| { + make_basic_respawn_packet(dimension, world_name).into_variant() } } else { - |dimension: DimensionKind, instance_name: Identifier| { - make_basic_login_packet(dimension, instance_name).into_variant() + |dimension: DimensionKind, world_name: Identifier| { + make_basic_login_packet(dimension, world_name).into_variant() } }; @@ -66,9 +66,9 @@ fn generic_test_login_to_dimension_with_same_name(using_respawn: bool) { simulation.tick(); assert_eq!( - *simulation.component::(), + *simulation.component::(), Identifier::new("azalea:overworld"), - "InstanceName should be azalea:overworld after setting dimension to that" + "WorldName should be azalea:overworld after setting dimension to that" ); simulation.receive_packet(make_basic_empty_chunk(ChunkPos::new(0, 0), (384 + 64) / 16)); @@ -107,14 +107,14 @@ fn generic_test_login_to_dimension_with_same_name(using_respawn: bool) { "chunk should not exist immediately after changing dimensions" ); assert_eq!( - *simulation.component::(), + *simulation.component::(), Identifier::new("azalea:overworld"), - "InstanceName should still be azalea:overworld after changing dimensions to that" + "WorldName should still be azalea:overworld after changing dimensions to that" ); assert_eq!( simulation - .component::() - .instance + .component::() + .shared .read() .chunks .height, diff --git a/azalea-client/tests/simulation/receive_spawn_entity_and_start_config_packet.rs b/azalea-client/tests/simulation/receive_spawn_entity_and_start_config_packet.rs index 13dd38fc..d6b228cb 100644 --- a/azalea-client/tests/simulation/receive_spawn_entity_and_start_config_packet.rs +++ b/azalea-client/tests/simulation/receive_spawn_entity_and_start_config_packet.rs @@ -5,7 +5,7 @@ use azalea_protocol::packets::{ game::{ClientboundAddEntity, ClientboundStartConfiguration}, }; use azalea_registry::builtin::EntityKind; -use azalea_world::InstanceName; +use azalea_world::WorldName; use uuid::Uuid; #[test] @@ -15,7 +15,7 @@ fn test_receive_spawn_entity_and_start_config_packet() { let mut simulation = Simulation::new(ConnectionProtocol::Game); simulation.receive_packet(default_login_packet()); simulation.tick(); - assert!(simulation.has_component::()); + assert!(simulation.has_component::()); simulation.tick(); simulation.receive_packet(ClientboundAddEntity { diff --git a/azalea-client/tests/simulation/receive_start_config_packet.rs b/azalea-client/tests/simulation/receive_start_config_packet.rs index f87d65da..a54abe5b 100644 --- a/azalea-client/tests/simulation/receive_start_config_packet.rs +++ b/azalea-client/tests/simulation/receive_start_config_packet.rs @@ -1,6 +1,6 @@ use azalea_client::{InConfigState, test_utils::prelude::*}; use azalea_protocol::packets::{ConnectionProtocol, game::ClientboundStartConfiguration}; -use azalea_world::InstanceName; +use azalea_world::WorldName; #[test] fn test_receive_start_config_packet() { @@ -10,7 +10,7 @@ fn test_receive_start_config_packet() { simulation.receive_packet(default_login_packet()); simulation.tick(); - assert!(simulation.has_component::()); + assert!(simulation.has_component::()); simulation.tick(); simulation.receive_packet(ClientboundStartConfiguration); diff --git a/azalea-core/src/registry_holder/mod.rs b/azalea-core/src/registry_holder/mod.rs index 90bad921..c83db40c 100644 --- a/azalea-core/src/registry_holder/mod.rs +++ b/azalea-core/src/registry_holder/mod.rs @@ -26,7 +26,7 @@ use tracing::error; /// /// This is the registry that is sent to the client upon login. /// -/// Note that `azalea-client` stores registries in `Instance` rather than +/// Note that `azalea-client` stores registries per-world rather than /// per-client like you might expect. This is an optimization for swarms to /// reduce memory usage, since registries are expected to be the same for every /// client in a world. diff --git a/azalea-entity/src/plugin/components.rs b/azalea-entity/src/plugin/components.rs index abeab160..4698a808 100644 --- a/azalea-entity/src/plugin/components.rs +++ b/azalea-entity/src/plugin/components.rs @@ -1,7 +1,7 @@ use azalea_block::fluid_state::FluidKind; use azalea_core::position::{BlockPos, ChunkPos, Vec3}; -use azalea_registry::{builtin::EntityKind, identifier::Identifier}; -use azalea_world::InstanceName; +use azalea_registry::builtin::EntityKind; +use azalea_world::WorldName; use bevy_ecs::{bundle::Bundle, component::Component}; use derive_more::{Deref, DerefMut}; use uuid::Uuid; @@ -18,7 +18,7 @@ use crate::{ pub struct EntityBundle { pub kind: EntityKindComponent, pub uuid: EntityUuid, - pub world_name: InstanceName, + pub world_name: WorldName, pub position: Position, pub last_sent_position: LastSentPosition, @@ -36,13 +36,13 @@ pub struct EntityBundle { } impl EntityBundle { - pub fn new(uuid: Uuid, pos: Vec3, kind: EntityKind, world_name: Identifier) -> Self { + pub fn new(uuid: Uuid, pos: Vec3, kind: EntityKind, world_name: WorldName) -> Self { let dimensions = EntityDimensions::from(kind); Self { kind: EntityKindComponent(kind), uuid: EntityUuid(uuid), - world_name: InstanceName(world_name), + world_name, position: Position(pos), chunk_pos: EntityChunkPos(ChunkPos::from(&pos)), last_sent_position: LastSentPosition(pos), diff --git a/azalea-entity/src/plugin/indexing.rs b/azalea-entity/src/plugin/indexing.rs index 3fba6b3c..9e539c23 100644 --- a/azalea-entity/src/plugin/indexing.rs +++ b/azalea-entity/src/plugin/indexing.rs @@ -6,7 +6,7 @@ use std::{ }; use azalea_core::{entity_id::MinecraftEntityId, position::ChunkPos}; -use azalea_world::{Instance, InstanceContainer, InstanceName}; +use azalea_world::{World, WorldName, Worlds}; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; use nohash_hasher::IntMap; @@ -48,10 +48,10 @@ impl EntityUuidIndex { /// An index of Minecraft entity IDs to Azalea ECS entities. /// /// This is a `Component` so local players can keep track of entity IDs -/// independently from the instance. +/// independently from the world. /// -/// If you need a per-instance instead of per-client version of this, you can -/// use [`Instance::entity_by_id`]. +/// If you need a per-world instead of per-client version of this, you can +/// use [`World::entity_by_id`]. #[derive(Component, Default)] pub struct EntityIdIndex { /// An index of entities by their MinecraftEntityId @@ -105,7 +105,7 @@ impl EntityIdIndex { } else { // this is expected to happen when despawning entities if it was already // despawned for another reason (like because the client received a - // remove_entities packet, or if we're in a shared instance where entity ids are + // remove_entities packet, or if we're in a shared world where entity ids are // different for each client) trace!( "Failed to remove {entity:?} from a client's EntityIdIndex (using EntityIdIndex::remove_by_ecs_entity). This may be expected behavior." @@ -125,30 +125,30 @@ impl Debug for EntityUuidIndex { #[derive(Component, Debug, Deref, DerefMut)] pub struct EntityChunkPos(pub ChunkPos); -/// Update the chunk position indexes in [`Instance::entities_by_chunk`]. +/// Update the chunk position indexes in [`World::entities_by_chunk`]. /// -/// [`Instance::entities_by_chunk`]: azalea_world::Instance::entities_by_chunk +/// [`World::entities_by_chunk`]: azalea_world::World::entities_by_chunk pub fn update_entity_chunk_positions( - mut query: Query<(Entity, &Position, &InstanceName, &mut EntityChunkPos), Changed>, - instance_container: Res, + mut query: Query<(Entity, &Position, &WorldName, &mut EntityChunkPos), Changed>, + worlds: Res, ) { - for (entity, pos, instance_name, mut entity_chunk_pos) in query.iter_mut() { + for (entity, pos, world_name, mut entity_chunk_pos) in query.iter_mut() { let old_chunk = **entity_chunk_pos; let new_chunk = ChunkPos::from(*pos); if old_chunk != new_chunk { **entity_chunk_pos = new_chunk; if old_chunk != new_chunk { - let Some(instance_lock) = instance_container.get(instance_name) else { + let Some(world_lock) = worlds.get(world_name) else { continue; }; - let mut instance = instance_lock.write(); + let mut world = world_lock.write(); // move the entity from the old chunk to the new one - if let Some(entities) = instance.entities_by_chunk.get_mut(&old_chunk) { + if let Some(entities) = world.entities_by_chunk.get_mut(&old_chunk) { entities.remove(&entity); } - instance + world .entities_by_chunk .entry(new_chunk) .or_default() @@ -159,20 +159,20 @@ pub fn update_entity_chunk_positions( } } -/// Insert new entities into [`Instance::entities_by_chunk`]. +/// Insert new entities into [`World::entities_by_chunk`]. pub fn insert_entity_chunk_position( - query: Query<(Entity, &Position, &InstanceName), Added>, - instance_container: Res, + query: Query<(Entity, &Position, &WorldName), Added>, + worlds: Res, ) { for (entity, pos, world_name) in query.iter() { - let Some(instance_lock) = instance_container.get(world_name) else { + let Some(world_lock) = worlds.get(world_name) else { // entity must've been despawned already continue; }; - let mut instance = instance_lock.write(); + let mut world = world_lock.write(); let chunk = ChunkPos::from(*pos); - instance + world .entities_by_chunk .entry(chunk) .or_default() @@ -185,26 +185,24 @@ pub fn insert_entity_chunk_position( pub fn remove_despawned_entities_from_indexes( mut commands: Commands, mut entity_uuid_index: ResMut, - instance_container: Res, + worlds: Res, query: Query< ( Entity, &EntityUuid, &MinecraftEntityId, &Position, - &InstanceName, + &WorldName, &LoadedBy, ), (Changed, Without), >, mut entity_id_index_query: Query<&mut EntityIdIndex>, ) { - for (entity, uuid, minecraft_id, position, instance_name, loaded_by) in &query { - let Some(instance_lock) = instance_container.get(instance_name) else { - // the instance isn't even loaded by us, so we can safely delete the entity - debug!( - "Despawned entity {entity:?} because it's in an instance that isn't loaded anymore" - ); + for (entity, uuid, minecraft_id, position, world_name, loaded_by) in &query { + let Some(world_lock) = worlds.get(world_name) else { + // the world isn't even loaded by us, so we can safely delete the entity + debug!("Despawned entity {entity:?} because it's in a world that isn't loaded anymore"); if entity_uuid_index.entity_by_uuid.remove(uuid).is_none() { warn!( "Tried to remove entity {entity:?} from the uuid index but it was not there." @@ -216,7 +214,7 @@ pub fn remove_despawned_entities_from_indexes( continue; }; - let mut instance = instance_lock.write(); + let mut world = world_lock.write(); // if the entity is being loaded by any of our clients, don't despawn it if !loaded_by.is_empty() { @@ -225,17 +223,17 @@ pub fn remove_despawned_entities_from_indexes( // remove the entity from the chunk index let chunk = ChunkPos::from(position); - match instance.entities_by_chunk.get_mut(&chunk) { + match world.entities_by_chunk.get_mut(&chunk) { Some(entities_in_chunk) => { if entities_in_chunk.remove(&entity) { // remove the chunk if there's no entities in it anymore if entities_in_chunk.is_empty() { - instance.entities_by_chunk.remove(&chunk); + world.entities_by_chunk.remove(&chunk); } } else { // search all the other chunks for it :( let mut found_in_other_chunks = HashSet::new(); - for (other_chunk, entities_in_other_chunk) in &mut instance.entities_by_chunk { + for (other_chunk, entities_in_other_chunk) in &mut world.entities_by_chunk { if entities_in_other_chunk.remove(&entity) { found_in_other_chunks.insert(other_chunk); } @@ -253,7 +251,7 @@ pub fn remove_despawned_entities_from_indexes( } _ => { let mut found_in_other_chunks = HashSet::new(); - for (other_chunk, entities_in_other_chunk) in &mut instance.entities_by_chunk { + for (other_chunk, entities_in_other_chunk) in &mut world.entities_by_chunk { if entities_in_other_chunk.remove(&entity) { found_in_other_chunks.insert(other_chunk); } @@ -273,9 +271,9 @@ pub fn remove_despawned_entities_from_indexes( if entity_uuid_index.entity_by_uuid.remove(uuid).is_none() { warn!("Tried to remove entity {entity:?} from the uuid index but it was not there."); } - if instance.entity_by_id.remove(minecraft_id).is_none() { + if world.entity_by_id.remove(minecraft_id).is_none() { debug!( - "Tried to remove entity {entity:?} from the per-instance entity id index but it was not there. This may be expected if you're in a shared instance." + "Tried to remove entity {entity:?} from the per-world entity id index but it was not there. This may be expected if you're in a shared world." ); } @@ -296,16 +294,16 @@ pub fn add_entity_to_indexes( entity_uuid: Option, entity_id_index: &mut EntityIdIndex, entity_uuid_index: &mut EntityUuidIndex, - instance: &mut Instance, + world: &mut World, ) { // per-client id index entity_id_index.insert(entity_id, ecs_entity); - // per-instance id index - instance.entity_by_id.insert(entity_id, ecs_entity); + // per-world id index + world.entity_by_id.insert(entity_id, ecs_entity); if let Some(uuid) = entity_uuid { - // per-instance uuid index + // per-world uuid index entity_uuid_index.insert(uuid, ecs_entity); } } diff --git a/azalea-entity/src/plugin/mod.rs b/azalea-entity/src/plugin/mod.rs index 03dda233..e40c24f2 100644 --- a/azalea-entity/src/plugin/mod.rs +++ b/azalea-entity/src/plugin/mod.rs @@ -11,7 +11,7 @@ use azalea_core::{ tick::GameTick, }; use azalea_registry::{builtin::BlockKind, tags}; -use azalea_world::{ChunkStorage, InstanceContainer, InstanceName}; +use azalea_world::{ChunkStorage, WorldName, Worlds}; use bevy_app::{App, Plugin, PostUpdate, Update}; use bevy_ecs::prelude::*; pub use components::*; @@ -97,22 +97,17 @@ pub fn add_dead(mut commands: Commands, query: Query<(Entity, &Health), Changed< } pub fn update_fluid_on_eyes( - mut query: Query<( - &mut FluidOnEyes, - &Position, - &EntityDimensions, - &InstanceName, - )>, - instance_container: Res, + mut query: Query<(&mut FluidOnEyes, &Position, &EntityDimensions, &WorldName)>, + worlds: Res, ) { - for (mut fluid_on_eyes, position, dimensions, instance_name) in query.iter_mut() { - let Some(instance) = instance_container.get(instance_name) else { + for (mut fluid_on_eyes, position, dimensions, world_name) in query.iter_mut() { + let Some(world) = worlds.get(world_name) else { continue; }; let adjusted_eye_y = position.y + (dimensions.eye_height as f64) - 0.1111111119389534; let eye_block_pos = BlockPos::from(position.with_y(adjusted_eye_y)); - let fluid_at_eye = instance + let fluid_at_eye = world .read() .get_fluid_state(eye_block_pos) .unwrap_or_default(); @@ -126,10 +121,10 @@ pub fn update_fluid_on_eyes( } pub fn update_on_climbable( - mut query: Query<(&mut OnClimbable, &Position, &InstanceName), With>, - instance_container: Res, + mut query: Query<(&mut OnClimbable, &Position, &WorldName), With>, + worlds: Res, ) { - for (mut on_climbable, position, instance_name) in query.iter_mut() { + for (mut on_climbable, position, world_name) in query.iter_mut() { // TODO: there's currently no gamemode component that can be accessed from here, // maybe LocalGameMode should be replaced with two components, maybe called // EntityGameMode and PreviousGameMode? @@ -138,27 +133,27 @@ pub fn update_on_climbable( // continue; // } - let Some(instance) = instance_container.get(instance_name) else { + let Some(world) = worlds.get(world_name) else { continue; }; - let instance = instance.read(); + let world = world.read(); let block_pos = BlockPos::from(position); - let block_state_at_feet = instance.get_block_state(block_pos).unwrap_or_default(); + let block_state_at_feet = world.get_block_state(block_pos).unwrap_or_default(); let block_at_feet = Box::::from(block_state_at_feet); let registry_block_at_feet = block_at_feet.as_registry_block(); **on_climbable = tags::blocks::CLIMBABLE.contains(®istry_block_at_feet) || (tags::blocks::TRAPDOORS.contains(®istry_block_at_feet) - && is_trapdoor_useable_as_ladder(block_state_at_feet, block_pos, &instance)); + && is_trapdoor_usable_as_ladder(block_state_at_feet, block_pos, &world)); } } -fn is_trapdoor_useable_as_ladder( +fn is_trapdoor_usable_as_ladder( block_state: BlockState, block_pos: BlockPos, - instance: &azalea_world::Instance, + world: &azalea_world::World, ) -> bool { // trapdoor must be open if !block_state @@ -169,9 +164,7 @@ fn is_trapdoor_useable_as_ladder( } // block below must be a ladder - let block_below = instance - .get_block_state(block_pos.down(1)) - .unwrap_or_default(); + let block_below = world.get_block_state(block_pos.down(1)).unwrap_or_default(); let registry_block_below = Box::::from(block_below).as_registry_block(); if registry_block_below != BlockKind::Ladder { return false; @@ -257,17 +250,17 @@ pub struct InLoadedChunk; /// Update the [`InLoadedChunk`] component for all entities in the world. pub fn update_in_loaded_chunk( mut commands: bevy_ecs::system::Commands, - query: Query<(Entity, &InstanceName, &Position)>, - instance_container: Res, + query: Query<(Entity, &WorldName, &Position)>, + worlds: Res, ) { - for (entity, instance_name, position) in &query { + for (entity, world_name, position) in &query { let player_chunk_pos = ChunkPos::from(position); - let Some(instance_lock) = instance_container.get(instance_name) else { + let Some(world_lock) = worlds.get(world_name) else { commands.entity(entity).remove::(); continue; }; - let in_loaded_chunk = instance_lock.read().chunks.get(&player_chunk_pos).is_some(); + let in_loaded_chunk = world_lock.read().chunks.get(&player_chunk_pos).is_some(); if in_loaded_chunk { commands.entity(entity).insert(InLoadedChunk); } else { @@ -326,20 +319,20 @@ mod tests { }; use azalea_core::position::{BlockPos, ChunkPos}; use azalea_registry::builtin::BlockKind; - use azalea_world::{Chunk, ChunkStorage, Instance, PartialInstance}; + use azalea_world::{Chunk, ChunkStorage, PartialWorld, World}; - use super::is_trapdoor_useable_as_ladder; + use super::is_trapdoor_usable_as_ladder; #[test] fn test_is_trapdoor_useable_as_ladder() { - let mut partial_instance = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); let mut chunks = ChunkStorage::default(); - partial_instance.chunks.set( + partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, Some(Chunk::default()), &mut chunks, ); - partial_instance.chunks.set_block_state( + partial_world.chunks.set_block_state( BlockPos::new(0, 0, 0), BlockKind::Stone.into(), &chunks, @@ -349,7 +342,7 @@ mod tests { facing: FacingCardinal::East, waterlogged: false, }; - partial_instance + partial_world .chunks .set_block_state(BlockPos::new(0, 0, 0), ladder.into(), &chunks); @@ -360,17 +353,17 @@ mod tests { powered: false, waterlogged: false, }; - partial_instance + partial_world .chunks .set_block_state(BlockPos::new(0, 1, 0), trapdoor.into(), &chunks); - let instance = Instance::from(chunks); - let trapdoor_matches_ladder = is_trapdoor_useable_as_ladder( - instance + let world = World::from(chunks); + let trapdoor_matches_ladder = is_trapdoor_usable_as_ladder( + world .get_block_state(BlockPos::new(0, 1, 0)) .unwrap_or_default(), BlockPos::new(0, 1, 0), - &instance, + &world, ); assert!(trapdoor_matches_ladder); diff --git a/azalea-entity/src/plugin/relative_updates.rs b/azalea-entity/src/plugin/relative_updates.rs index f80ccddc..53eb4c95 100644 --- a/azalea-entity/src/plugin/relative_updates.rs +++ b/azalea-entity/src/plugin/relative_updates.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use azalea_core::entity_id::MinecraftEntityId; -use azalea_world::PartialInstance; +use azalea_world::PartialWorld; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; use parking_lot::RwLock; @@ -38,13 +38,13 @@ use crate::LocalEntity; /// 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 partial_world: Arc>, + pub partial_world: Arc>, // a function that takes the entity and updates it pub update: Box, } impl RelativeEntityUpdate { pub fn new( - partial_world: Arc>, + partial_world: Arc>, update: impl FnOnce(&mut EntityWorldMut) + Send + Sync + 'static, ) -> Self { Self { diff --git a/azalea-physics/src/collision/entity_collisions.rs b/azalea-physics/src/collision/entity_collisions.rs index de70b2b9..5933f2d3 100644 --- a/azalea-physics/src/collision/entity_collisions.rs +++ b/azalea-physics/src/collision/entity_collisions.rs @@ -3,7 +3,7 @@ use azalea_entity::{ Physics, metadata::{AbstractBoat, Shulker}, }; -use azalea_world::Instance; +use azalea_world::World; use bevy_ecs::{ component::Component, entity::Entity, @@ -51,7 +51,7 @@ pub fn update_last_bounding_box( } pub fn get_entity_collisions( - world: &Instance, + world: &World, aabb: &Aabb, source_entity: Option, aabb_query: &AabbQuery, @@ -83,7 +83,7 @@ pub fn get_entity_collisions( /// `source_entity` is the entity that the bounding box belongs to, and won't be /// one of the returned entities. pub fn get_entities( - world: &Instance, + world: &World, source_entity: Option, aabb: &Aabb, predicate: &dyn Fn(Entity) -> bool, diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index f720fdba..430b91ad 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -19,7 +19,7 @@ use azalea_entity::{ metadata::Sprinting, }; use azalea_registry::builtin::BlockKind; -use azalea_world::{ChunkStorage, Instance}; +use azalea_world::{ChunkStorage, World}; use bevy_ecs::{entity::Entity, world::Mut}; pub use blocks::BlockWithShape; pub use discrete_voxel_shape::*; @@ -110,7 +110,7 @@ fn collide(ctx: &MoveCtx, movement: Vec3) -> Vec3 { pub struct MoveCtx<'world, 'state, 'a, 'b> { pub mover_type: MoverType, - pub world: &'a Instance, + pub world: &'a World, pub position: Mut<'a, Position>, pub physics: &'a mut Physics, pub source_entity: Entity, @@ -338,7 +338,7 @@ fn is_above_ground(ctx: &CanFallAtLeastCtx, max_up_step: f32) -> bool { pub struct CanFallAtLeastCtx<'world, 'state, 'a, 'b> { physics: &'a Physics, - world: &'a Instance, + world: &'a World, source_entity: Entity, aabb_query: &'a AabbQuery<'world, 'state, 'b>, collidable_entity_query: &'a CollidableEntityQuery<'world, 'state>, @@ -377,7 +377,7 @@ fn can_fall_at_least( fn collide_bounding_box( movement: Vec3, entity_bounding_box: &Aabb, - world: &Instance, + world: &World, entity_collisions: &[VoxelShape], ) -> Vec3 { let mut collision_boxes: Vec = Vec::with_capacity(entity_collisions.len() + 1); @@ -437,7 +437,7 @@ fn collide_with_shapes( /// Get the [`VoxelShape`] for the given fluid state. /// -/// The instance and position are required so it can check if the block above is +/// The world and position are required so it can check if the block above is /// also the same fluid type. pub fn fluid_shape(fluid: &FluidState, world: &ChunkStorage, pos: BlockPos) -> &'static VoxelShape { if fluid.amount == 9 { diff --git a/azalea-physics/src/collision/world_collisions.rs b/azalea-physics/src/collision/world_collisions.rs index cd883649..36a085de 100644 --- a/azalea-physics/src/collision/world_collisions.rs +++ b/azalea-physics/src/collision/world_collisions.rs @@ -7,14 +7,14 @@ use azalea_core::{ position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos, Vec3}, }; use azalea_inventory::ItemStack; -use azalea_world::{Chunk, Instance}; +use azalea_world::{Chunk, World}; use bevy_ecs::entity::Entity; use parking_lot::RwLock; use super::{BLOCK_SHAPE, Shapes}; use crate::collision::{Aabb, BlockWithShape, VoxelShape}; -pub fn get_block_collisions(world: &Instance, aabb: &Aabb) -> Vec { +pub fn get_block_collisions(world: &World, aabb: &Aabb) -> Vec { let mut state = BlockCollisionsState::new(world, aabb, EntityCollisionContext::of(None)); let mut block_collisions = Vec::new(); @@ -34,7 +34,7 @@ pub fn get_block_collisions(world: &Instance, aabb: &Aabb) -> Vec { block_collisions } -pub fn get_block_and_liquid_collisions(world: &Instance, aabb: &Aabb) -> Vec { +pub fn get_block_and_liquid_collisions(world: &World, aabb: &Aabb) -> Vec { let mut state = BlockCollisionsState::new( world, aabb, @@ -59,7 +59,7 @@ pub fn get_block_and_liquid_collisions(world: &Instance, aabb: &Aabb) -> Vec { - pub world: &'a Instance, + pub world: &'a World, pub aabb: &'a Aabb, pub entity_shape: VoxelShape, pub cursor: Cursor3d, @@ -126,7 +126,7 @@ impl<'a> BlockCollisionsState<'a> { block_collisions.push(block_shape); } - pub fn new(world: &'a Instance, aabb: &'a Aabb, context: EntityCollisionContext) -> Self { + pub fn new(world: &'a World, aabb: &'a Aabb, context: EntityCollisionContext) -> Self { let origin = BlockPos { x: (aabb.min.x - EPSILON).floor() as i32 - 1, y: (aabb.min.y - EPSILON).floor() as i32 - 1, @@ -283,7 +283,7 @@ impl CanStandOnFluidPredicate { /// a performance loss for Azalea. If this ever turns out to be a bottleneck, /// then maybe you should try having it do that instead. pub fn for_entities_in_chunks_colliding_with( - world: &Instance, + world: &World, aabb: &Aabb, mut consumer: impl FnMut(ChunkPos, &HashSet), ) { diff --git a/azalea-physics/src/fluids.rs b/azalea-physics/src/fluids.rs index fa6a1586..73ee7ddb 100644 --- a/azalea-physics/src/fluids.rs +++ b/azalea-physics/src/fluids.rs @@ -8,7 +8,7 @@ use azalea_core::{ }; use azalea_entity::{HasClientLoaded, LocalEntity, Physics, Position}; use azalea_registry::builtin::BlockKind; -use azalea_world::{Instance, InstanceContainer, InstanceName}; +use azalea_world::{World, WorldName, Worlds}; use bevy_ecs::prelude::*; use crate::collision::legacy_blocks_motion; @@ -16,13 +16,13 @@ use crate::collision::legacy_blocks_motion; #[allow(clippy::type_complexity)] pub fn update_in_water_state_and_do_fluid_pushing( mut query: Query< - (&mut Physics, &Position, &InstanceName), + (&mut Physics, &Position, &WorldName), (With, With), >, - instance_container: Res, + worlds: Res, ) { - for (mut physics, position, instance_name) in &mut query { - let Some(world_lock) = instance_container.get(instance_name) else { + for (mut physics, position, world_name) in &mut query { + let Some(world_lock) = worlds.get(world_name) else { continue; }; let world = world_lock.read(); @@ -41,7 +41,7 @@ pub fn update_in_water_state_and_do_fluid_pushing( .registries .dimension_type .map - .get(&**instance_name) + .get(&**world_name) .and_then(|i| i.ultrawarm) .unwrap_or_default(); let lava_push_factor = if is_ultrawarm { @@ -60,7 +60,7 @@ pub fn update_in_water_state_and_do_fluid_pushing( } fn update_in_water_state_and_do_water_current_pushing( physics: &mut Physics, - world: &Instance, + world: &World, _position: Position, ) { // TODO: implement vehicles and boats @@ -86,7 +86,7 @@ fn update_in_water_state_and_do_water_current_pushing( fn update_fluid_height_and_do_fluid_pushing( physics: &mut Physics, - world: &Instance, + world: &World, checking_fluid: FluidKind, fluid_push_factor: f64, ) -> bool { @@ -180,7 +180,7 @@ pub fn update_swimming() { } // FlowingFluid.getFlow -pub fn get_fluid_flow(fluid: &FluidState, world: &Instance, pos: BlockPos) -> Vec3 { +pub fn get_fluid_flow(fluid: &FluidState, world: &World, pos: BlockPos) -> Vec3 { let mut z_flow: f64 = 0.; let mut x_flow: f64 = 0.; @@ -244,7 +244,7 @@ pub fn get_fluid_flow(fluid: &FluidState, world: &Instance, pos: BlockPos) -> Ve // i don't really get what this is for fn is_solid_face( fluid: &FluidState, - world: &Instance, + world: &World, adjacent_pos: BlockPos, direction: Direction, ) -> bool { @@ -269,7 +269,7 @@ fn is_solid_face( fn is_face_sturdy( _block_state: BlockState, - _world: &Instance, + _world: &World, _pos: BlockPos, _direction: Direction, ) -> bool { diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 90c89b16..491bda0e 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -21,7 +21,7 @@ use azalea_entity::{ metadata::Sprinting, move_relative, }; use azalea_registry::builtin::{BlockKind, EntityKind, MobEffect}; -use azalea_world::{Instance, InstanceContainer, InstanceName}; +use azalea_world::{World, WorldName, Worlds}; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; use clip::box_traverse_blocks; @@ -71,12 +71,12 @@ pub fn ai_step( &LookDirection, &Sprinting, &ActiveEffects, - &InstanceName, + &WorldName, &EntityKindComponent, ), (With, With), >, - instance_container: Res, + worlds: Res, ) { for ( mut physics, @@ -85,7 +85,7 @@ pub fn ai_step( look_direction, sprinting, active_effects, - instance_name, + world_name, entity_kind, ) in &mut query { @@ -147,8 +147,8 @@ pub fn ai_step( *position, *look_direction, *sprinting, - instance_name, - &instance_container, + world_name, + &worlds, active_effects, ); physics.no_jump_delay = 10; @@ -176,13 +176,13 @@ fn jump_in_liquid(physics: &mut Physics) { #[allow(clippy::type_complexity)] pub fn apply_effects_from_blocks( mut query: Query< - (&mut Physics, &Position, &EntityDimensions, &InstanceName), + (&mut Physics, &Position, &EntityDimensions, &WorldName), (With, With), >, - instance_container: Res, + worlds: Res, ) { for (mut physics, position, dimensions, world_name) in &mut query { - let Some(world_lock) = instance_container.get(world_name) else { + let Some(world_lock) = worlds.get(world_name) else { continue; }; let world = world_lock.read(); @@ -211,7 +211,7 @@ pub fn apply_effects_from_blocks( fn check_inside_blocks( physics: &mut Physics, dimensions: &EntityDimensions, - world: &Instance, + world: &World, movements: &[EntityMovement], ) -> Vec { let mut blocks_inside = Vec::new(); @@ -291,7 +291,7 @@ fn collided_with_shape_moving_from( // BlockBehavior.entityInside fn handle_entity_inside_block( - world: &Instance, + world: &World, block: BlockState, block_pos: BlockPos, physics: &mut Physics, @@ -339,12 +339,12 @@ pub fn jump_from_ground( position: Position, look_direction: LookDirection, sprinting: Sprinting, - instance_name: &InstanceName, - instance_container: &InstanceContainer, + world_name: &WorldName, + worlds: &Worlds, active_effects: &ActiveEffects, ) { - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("All entities should be in a valid world"); let world = world_lock.read(); @@ -436,7 +436,7 @@ fn handle_on_climbable( velocity: Vec3, on_climbable: OnClimbable, position: Position, - world: &Instance, + world: &World, pose: Option, ) -> Vec3 { if !*on_climbable { @@ -488,7 +488,7 @@ fn get_friction_influenced_speed( /// Returns the what the entity's jump should be multiplied by based on the /// block they're standing on. -fn block_jump_factor(world: &Instance, position: Position) -> f32 { +fn block_jump_factor(world: &World, position: Position) -> f32 { let block_at_pos = world.chunks.get_block_state(position.into()); let block_below = world .chunks @@ -516,7 +516,7 @@ fn block_jump_factor(world: &Instance, 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: &Instance, position: Position) -> f32 { +fn jump_power(world: &World, position: Position) -> f32 { 0.42 * block_jump_factor(world, position) } diff --git a/azalea-physics/src/travel.rs b/azalea-physics/src/travel.rs index 0b980d5a..257e2924 100644 --- a/azalea-physics/src/travel.rs +++ b/azalea-physics/src/travel.rs @@ -7,7 +7,7 @@ use azalea_entity::{ Attributes, HasClientLoaded, Jumping, LocalEntity, LookDirection, OnClimbable, Physics, PlayerAbilities, Pose, Position, metadata::Sprinting, move_relative, }; -use azalea_world::{Instance, InstanceContainer, InstanceName}; +use azalea_world::{World, WorldName, Worlds}; use bevy_ecs::prelude::*; use crate::{ @@ -29,7 +29,7 @@ pub fn travel( ( Entity, &Attributes, - &InstanceName, + &WorldName, &OnClimbable, &Jumping, Option<&PhysicsState>, @@ -42,7 +42,7 @@ pub fn travel( ), (With, With), >, - instance_container: Res, + worlds: Res, aabb_query: AabbQuery, collidable_entity_query: CollidableEntityQuery, ) { @@ -61,7 +61,7 @@ pub fn travel( position, ) in &mut query { - let Some(world_lock) = instance_container.get(world_name) else { + let Some(world_lock) = worlds.get(world_name) else { continue; }; let world = world_lock.read(); @@ -252,7 +252,7 @@ fn get_fluid_falling_adjusted_movement( } fn is_free( - world: &Instance, + world: &World, source_entity: Entity, aabb_query: &AabbQuery, collidable_entity_query: &CollidableEntityQuery, @@ -274,7 +274,7 @@ fn is_free( } pub fn no_collision( - world: &Instance, + world: &World, source_entity: Option, aabb_query: &AabbQuery, collidable_entity_query: &CollidableEntityQuery, @@ -323,7 +323,7 @@ fn border_collision(_entity_physics: &Physics, _aabb: &Aabb) -> Option { None } -fn contains_any_liquid(world: &Instance, bounding_box: Aabb) -> bool { +fn contains_any_liquid(world: &World, bounding_box: Aabb) -> bool { let min = bounding_box.min.to_block_pos_floor(); let max = bounding_box.max.to_block_pos_ceil(); diff --git a/azalea-physics/tests/physics.rs b/azalea-physics/tests/physics.rs index 42dcf809..8359e05e 100644 --- a/azalea-physics/tests/physics.rs +++ b/azalea-physics/tests/physics.rs @@ -12,11 +12,8 @@ use azalea_core::{ }; use azalea_entity::{EntityBundle, EntityPlugin, HasClientLoaded, LocalEntity, Physics, Position}; use azalea_physics::PhysicsPlugin; -use azalea_registry::{ - builtin::{BlockKind, EntityKind}, - identifier::Identifier, -}; -use azalea_world::{Chunk, Instance, InstanceContainer, PartialInstance}; +use azalea_registry::builtin::{BlockKind, EntityKind}; +use azalea_world::{Chunk, PartialWorld, World, WorldName, Worlds}; use bevy_app::App; use parking_lot::RwLock; use uuid::Uuid; @@ -25,26 +22,24 @@ use uuid::Uuid; fn make_test_app() -> App { let mut app = App::new(); app.add_plugins((PhysicsPlugin, EntityPlugin)) - .init_resource::(); + .init_resource::(); app } -pub fn insert_overworld(app: &mut App) -> Arc> { - app.world_mut() - .resource_mut::() - .get_or_insert( - Identifier::new("minecraft:overworld"), - 384, - -64, - &RegistryHolder::default(), - ) +pub fn insert_overworld(app: &mut App) -> Arc> { + app.world_mut().resource_mut::().get_or_insert( + WorldName::new("minecraft:overworld"), + 384, + -64, + &RegistryHolder::default(), + ) } #[test] fn test_gravity() { let mut app = make_test_app(); let world_lock = insert_overworld(&mut app); - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); // the entity has to be in a loaded chunk for physics to work partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -63,7 +58,7 @@ fn test_gravity() { z: 0., }, EntityKind::Zombie, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -101,7 +96,7 @@ fn test_gravity() { fn test_collision() { let mut app = make_test_app(); let world_lock = insert_overworld(&mut app); - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -119,7 +114,7 @@ fn test_collision() { z: 0.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -158,7 +153,7 @@ fn test_collision() { fn test_slab_collision() { let mut app = make_test_app(); let world_lock = insert_overworld(&mut app); - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -176,7 +171,7 @@ fn test_slab_collision() { z: 0.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -209,7 +204,7 @@ fn test_slab_collision() { fn test_top_slab_collision() { let mut app = make_test_app(); let world_lock = insert_overworld(&mut app); - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -227,7 +222,7 @@ fn test_top_slab_collision() { z: 0.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -258,16 +253,13 @@ fn test_top_slab_collision() { #[test] fn test_weird_wall_collision() { let mut app = make_test_app(); - let world_lock = app - .world_mut() - .resource_mut::() - .get_or_insert( - Identifier::new("minecraft:overworld"), - 384, - -64, - &RegistryHolder::default(), - ); - let mut partial_world = PartialInstance::default(); + let world_lock = app.world_mut().resource_mut::().get_or_insert( + WorldName::new("minecraft:overworld"), + 384, + -64, + &RegistryHolder::default(), + ); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -285,7 +277,7 @@ fn test_weird_wall_collision() { z: 0.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -321,16 +313,13 @@ fn test_weird_wall_collision() { #[test] fn test_negative_coordinates_weird_wall_collision() { let mut app = make_test_app(); - let world_lock = app - .world_mut() - .resource_mut::() - .get_or_insert( - Identifier::new("minecraft:overworld"), - 384, - -64, - &RegistryHolder::default(), - ); - let mut partial_world = PartialInstance::default(); + let world_lock = app.world_mut().resource_mut::().get_or_insert( + WorldName::new("minecraft:overworld"), + 384, + -64, + &RegistryHolder::default(), + ); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: -1, z: -1 }, @@ -348,7 +337,7 @@ fn test_negative_coordinates_weird_wall_collision() { z: -7.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -388,16 +377,13 @@ fn test_negative_coordinates_weird_wall_collision() { #[test] fn spawn_and_unload_world() { let mut app = make_test_app(); - let world_lock = app - .world_mut() - .resource_mut::() - .get_or_insert( - Identifier::new("minecraft:overworld"), - 384, - -64, - &RegistryHolder::default(), - ); - let mut partial_world = PartialInstance::default(); + let world_lock = app.world_mut().resource_mut::().get_or_insert( + WorldName::new("minecraft:overworld"), + 384, + -64, + &RegistryHolder::default(), + ); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: -1, z: -1 }, @@ -415,7 +401,7 @@ fn spawn_and_unload_world() { z: -7.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, @@ -440,7 +426,7 @@ fn spawn_and_unload_world() { fn test_afk_pool() { let mut app = make_test_app(); let world_lock = insert_overworld(&mut app); - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); partial_world.chunks.set( &ChunkPos { x: 0, z: 0 }, @@ -531,7 +517,7 @@ fn test_afk_pool() { z: 1.5, }, EntityKind::Player, - Identifier::new("minecraft:overworld"), + WorldName::new("minecraft:overworld"), ), MinecraftEntityId(0), LocalEntity, diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml index c7b0fd57..193e153e 100644 --- a/azalea-protocol/Cargo.toml +++ b/azalea-protocol/Cargo.toml @@ -23,6 +23,7 @@ azalea-entity = { workspace = true } azalea-inventory.workspace = true azalea-protocol-macros.workspace = true azalea-registry.workspace = true +azalea-world = { workspace = true, optional = true } bevy_ecs = { workspace = true, optional = true } # byteorder.workspace = true flate2.workspace = true @@ -46,7 +47,12 @@ reqwest = { workspace = true, optional = true, features = ["socks"] } default = ["online-mode", "connecting"] connecting = [] online-mode = ["azalea-auth/online-mode", "dep:reqwest"] -bevy_ecs = ["dep:bevy_ecs", "azalea-entity/bevy_ecs", "azalea-core/bevy_ecs"] +bevy_ecs = [ + "dep:bevy_ecs", + "dep:azalea-world", + "azalea-entity/bevy_ecs", + "azalea-core/bevy_ecs", +] [lints] workspace = true diff --git a/azalea-protocol/src/packets/game/c_add_entity.rs b/azalea-protocol/src/packets/game/c_add_entity.rs index 19f229ee..1b94baef 100644 --- a/azalea-protocol/src/packets/game/c_add_entity.rs +++ b/azalea-protocol/src/packets/game/c_add_entity.rs @@ -3,7 +3,7 @@ use azalea_core::{delta::LpVec3, entity_id::MinecraftEntityId, position::Vec3}; use azalea_protocol_macros::ClientboundGamePacket; use azalea_registry::builtin::EntityKind; #[cfg(feature = "bevy_ecs")] -use azalea_registry::identifier::Identifier; +use azalea_world::WorldName; use uuid::Uuid; #[derive(AzBuf, ClientboundGamePacket, Clone, Debug, PartialEq)] @@ -36,7 +36,7 @@ impl ClientboundAddEntity { /// You must apply the metadata after inserting the bundle with /// [`Self::apply_metadata`]. #[cfg(feature = "bevy_ecs")] - pub fn as_entity_bundle(&self, world_name: Identifier) -> azalea_entity::EntityBundle { + pub fn as_entity_bundle(&self, world_name: WorldName) -> azalea_entity::EntityBundle { azalea_entity::EntityBundle::new(self.uuid, self.position, self.entity_type, world_name) } diff --git a/azalea-world/src/container.rs b/azalea-world/src/container.rs index 97bc2a1f..af344dc0 100644 --- a/azalea-world/src/container.rs +++ b/azalea-world/src/container.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + fmt::{self, Display}, sync::{Arc, Weak}, }; @@ -12,14 +13,14 @@ use parking_lot::RwLock; use rustc_hash::FxHashMap; use tracing::{debug, error}; -use crate::{ChunkStorage, Instance}; +use crate::{ChunkStorage, World}; -/// A container of [`Instance`]s (aka worlds). +/// A container of [`World`] instances. /// -/// Instances are stored as a Weak pointer here, so if no clients are using an -/// instance it will be forgotten. +/// Worlds are stored as a `Weak` pointer here, so if no clients are using a +/// world then it will be forgotten. #[derive(Default, Resource)] -pub struct InstanceContainer { +pub struct Worlds { // We just refer to the chunks here and don't include entities because there's not that many // cases where we'd want to get every entity in the world (just getting the entities in chunks // should work fine). @@ -29,22 +30,21 @@ pub struct InstanceContainer { // If it looks like we're relying on the server giving us unique world names, that's because we // are. An evil server could give us two worlds with the same name and then we'd have no way of - // 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 instances: FxHashMap>>, + // telling them apart. We hope most servers are nice and don't do that. Perhaps this should be + // changed in the future to be configurable. + pub map: FxHashMap>>, } -impl InstanceContainer { +impl Worlds { pub fn new() -> Self { - InstanceContainer::default() + Worlds::default() } - /// Get an instance (aka world) from the container. + /// Get a world instance from the container. /// - /// Returns `None` if none of the clients are in this instance. - pub fn get(&self, name: &InstanceName) -> Option>> { - self.instances.get(name).and_then(|world| world.upgrade()) + /// Returns `None` if none of the clients are in the requested world. + pub fn get(&self, name: &WorldName) -> Option>> { + self.map.get(name).and_then(|world| world.upgrade()) } /// Add an empty world to the container (unless it already exists) and @@ -52,12 +52,12 @@ impl InstanceContainer { #[must_use = "the world will be immediately forgotten if unused"] pub fn get_or_insert( &mut self, - name: Identifier, + name: WorldName, height: u32, min_y: i32, default_registries: &RegistryHolder, - ) -> Arc> { - match self.instances.get(&name).and_then(|world| world.upgrade()) { + ) -> Arc> { + match self.map.get(&name).and_then(|world| world.upgrade()) { Some(existing_lock) => { let existing = existing_lock.read(); if existing.chunks.height != height { @@ -75,24 +75,40 @@ impl InstanceContainer { existing_lock.clone() } _ => { - let world = Arc::new(RwLock::new(Instance { + let world = Arc::new(RwLock::new(World { chunks: ChunkStorage::new(height, min_y), entities_by_chunk: HashMap::new(), entity_by_id: IntMap::default(), registries: default_registries.clone(), })); - debug!("Added new instance {name}"); - self.instances.insert(name, Arc::downgrade(&world)); + debug!("Added new world {name:?}"); + self.map.insert(name, Arc::downgrade(&world)); world } } } } -/// The name of the [`Instance`] (aka world/dimension) that the entity is in. +/// The name of the [`World`] (aka dimension) that an entity is in. /// -/// If two entities share the same instance name, we assume they're in the -/// same instance. +/// If two entities share the same world name, then Azalea assumes that they're +/// in the same world. #[derive(Clone, Component, Debug, Deref, DerefMut, Eq, Hash, PartialEq)] #[doc(alias("worldname", "world name", "dimension"))] -pub struct InstanceName(pub Identifier); +pub struct WorldName(pub Identifier); +impl WorldName { + /// Create a new `WorldName` with the given name. + pub fn new(name: &str) -> Self { + Self(Identifier::new(name)) + } +} +impl Display for WorldName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} +impl From for WorldName { + fn from(ident: Identifier) -> Self { + Self(ident) + } +} diff --git a/azalea-world/src/find_blocks.rs b/azalea-world/src/find_blocks.rs index bd4ec09a..f8f1fd91 100644 --- a/azalea-world/src/find_blocks.rs +++ b/azalea-world/src/find_blocks.rs @@ -1,9 +1,9 @@ use azalea_block::{BlockState, BlockStates}; use azalea_core::position::{BlockPos, ChunkPos}; -use crate::{Chunk, ChunkStorage, Instance, iterators::ChunkIterator, palette::Palette}; +use crate::{Chunk, ChunkStorage, World, iterators::ChunkIterator, palette::Palette}; -impl Instance { +impl World { /// Find the coordinates of a block in the world. /// /// Note that this is sorted by `x+y+z` and not `x^2+y^2+z^2` for @@ -206,8 +206,8 @@ impl Iterator for FindBlocks<'_> { /// An optimized function for finding the block positions in a chunk that match /// the given block states. /// -/// This is used internally by [`Instance::find_block`] and -/// [`Instance::find_blocks`]. +/// This is used internally by [`World::find_block`] and +/// [`World::find_blocks`]. pub fn find_blocks_in_chunk( block_states: &BlockStates, chunk_pos: ChunkPos, @@ -257,9 +257,9 @@ mod tests { #[test] fn find_block() { - let mut instance = Instance::default(); + let mut world = World::default(); - let chunk_storage = &mut instance.chunks; + let chunk_storage = &mut world.chunks; let mut partial_chunk_storage = PartialChunkStorage::default(); // block at (17, 0, 0) and (0, 18, 0) @@ -278,15 +278,15 @@ mod tests { chunk_storage.set_block_state(BlockPos { x: 17, y: 0, z: 0 }, BlockKind::Stone.into()); chunk_storage.set_block_state(BlockPos { x: 0, y: 18, z: 0 }, BlockKind::Stone.into()); - let pos = instance.find_block(BlockPos { x: 0, y: 0, z: 0 }, &BlockKind::Stone.into()); + let pos = world.find_block(BlockPos { x: 0, y: 0, z: 0 }, &BlockKind::Stone.into()); assert_eq!(pos, Some(BlockPos { x: 17, y: 0, z: 0 })); } #[test] fn find_block_next_to_chunk_border() { - let mut instance = Instance::default(); + let mut world = World::default(); - let chunk_storage = &mut instance.chunks; + let chunk_storage = &mut world.chunks; let mut partial_chunk_storage = PartialChunkStorage::default(); // block at (-1, 0, 0) and (15, 0, 0) @@ -305,7 +305,7 @@ mod tests { chunk_storage.set_block_state(BlockPos { x: -1, y: 0, z: 0 }, BlockKind::Stone.into()); chunk_storage.set_block_state(BlockPos { x: 15, y: 0, z: 0 }, BlockKind::Stone.into()); - let pos = instance.find_block(BlockPos { x: 0, y: 0, z: 0 }, &BlockKind::Stone.into()); + let pos = world.find_block(BlockPos { x: 0, y: 0, z: 0 }, &BlockKind::Stone.into()); assert_eq!(pos, Some(BlockPos { x: -1, y: 0, z: 0 })); } } diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs index 7212c519..325d3b43 100644 --- a/azalea-world/src/lib.rs +++ b/azalea-world/src/lib.rs @@ -12,5 +12,12 @@ mod world; pub use bit_storage::BitStorage; pub use chunk_storage::{Chunk, ChunkStorage, PartialChunkStorage, Section}; -pub use container::{InstanceContainer, InstanceName}; +pub use container::{Worlds, WorldName}; pub use world::*; + +#[deprecated = "renamed to `WorldName`."] +pub type InstanceName = WorldName; +#[deprecated = "renamed to `WorldContainer`."] +pub type InstanceContainer = Worlds; +#[deprecated = "renamed to `PartialWorld`."] +pub type PartialInstance = PartialWorld; diff --git a/azalea-world/src/world.rs b/azalea-world/src/world.rs index a6ee1a63..74390ee4 100644 --- a/azalea-world/src/world.rs +++ b/azalea-world/src/world.rs @@ -14,30 +14,30 @@ use nohash_hasher::IntMap; use crate::{ChunkStorage, PartialChunkStorage}; -/// PartialInstances are usually owned by clients, and hold strong references to -/// chunks and entities in [`Instance`]s. +/// A reference to a slice of the world, as seen by an individual client. /// -/// Basically, they hold the chunks and entities that are within render -/// distance but can still access chunks and entities owned by other -/// `PartialInstance`s that have the same `Instance`. +/// A `PartialWorld` will typically be owned by a client, and it holds strong +/// references to chunks and entities in a [`World`]s. /// -/// This is primarily useful for having multiple clients in the same Instance. -pub struct PartialInstance { +/// In other words, this type holds the chunks and entities that are within +/// render distance for a client. The same chunk/entity may be referenced by +/// more than one `PartialWorld`. +pub struct PartialWorld { pub chunks: PartialChunkStorage, /// Some metadata about entities, like what entities are in certain chunks. /// This does not contain the entity data itself, that's in the ECS. pub entity_infos: PartialEntityInfos, } -impl PartialInstance { +impl PartialWorld { pub fn new(chunk_radius: u32, owner_entity: Option) -> Self { - PartialInstance { + PartialWorld { chunks: PartialChunkStorage::new(chunk_radius), entity_infos: PartialEntityInfos::new(owner_entity), } } - /// Clears the internal references to chunks in the PartialInstance and + /// Clears the internal references to chunks in the [`PartialWorld`] and /// resets the view center. pub fn reset(&mut self) { self.chunks = PartialChunkStorage::new(self.chunks.chunk_radius); @@ -75,16 +75,21 @@ impl PartialEntityInfos { } } -/// A world where the chunks are stored as weak pointers. This is used for -/// shared worlds. +/// A Minecraft world, sometimes referred to as a dimension. /// -/// Also see [`PartialInstance`]. +/// This is the most commonly used type to interact with the world that a client +/// is in. In here, all chunks are stored as weak pointers, which means that +/// clients in different areas of the same world can share the same `World` +/// instance. /// -/// This is sometimes interchangeably called a "world". However, this type is -/// called `Instance` to avoid colliding with the `World` type from Bevy ECS. +/// Also see [`PartialWorld`]. +/// +/// Note that this is distinct from Bevy's `World` type, which contains all of +/// the data for every client. When referring to the Bevy `World` within Azalea, +/// the term "ECS" is generally used instead. #[derive(Debug, Default)] -#[doc(alias("world", "dimension"))] -pub struct Instance { +#[doc(alias("instance", "dimension", "level"))] +pub struct World { pub chunks: ChunkStorage, /// An index of all the entities we know are in the chunks of the world @@ -101,7 +106,10 @@ pub struct Instance { pub registries: RegistryHolder, } -impl Instance { +#[deprecated = "renamed to `World`."] +pub type Instance = World; + +impl World { /// Get the block at the given position, or `None` if it's outside of the /// world that we have loaded. pub fn get_block_state(&self, pos: BlockPos) -> Option { @@ -131,17 +139,17 @@ impl Instance { } } -impl Debug for PartialInstance { +impl Debug for PartialWorld { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PartialInstance") + f.debug_struct("PartialWorld") .field("chunks", &self.chunks) .field("entity_infos", &self.entity_infos) .finish() } } -impl Default for PartialInstance { - /// Creates a completely self-contained `PartialInstance`. This is only for +impl Default for PartialWorld { + /// Creates a completely self-contained [`PartialWorld`]. This is only for /// testing and shouldn't be used in actual code! fn default() -> Self { let chunk_storage = PartialChunkStorage::default(); @@ -153,7 +161,7 @@ impl Default for PartialInstance { } } -impl From for Instance { +impl From for World { /// 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/examples/testbot/commands/debug.rs b/azalea/examples/testbot/commands/debug.rs index 1f9d5e5d..57d9ff1f 100644 --- a/azalea/examples/testbot/commands/debug.rs +++ b/azalea/examples/testbot/commands/debug.rs @@ -15,7 +15,7 @@ use azalea::{ use azalea_core::hit_result::HitResult; use azalea_entity::{EntityKindComponent, metadata}; use azalea_inventory::components::MaxStackSize; -use azalea_world::InstanceContainer; +use azalea_world::Worlds; use bevy_app::AppExit; use bevy_ecs::{message::Messages, query::With, world::EntityRef}; use parking_lot::Mutex; @@ -331,16 +331,16 @@ pub fn register(commands: &mut CommandDispatcher>) { // info.layout().size()).unwrap(); match name.as_ref() { - "azalea_world::container::InstanceContainer" => { - let instance_container = ecs.resource::(); + "azalea_world::container::Worlds" => { + let worlds = ecs.resource::(); - for (instance_name, instance) in &instance_container.instances { - writeln!(report, "- Name: {instance_name}").unwrap(); - writeln!(report, "- Reference count: {}", instance.strong_count()) + for (world_name, world) in &worlds.map { + writeln!(report, "- Name: {world_name}").unwrap(); + writeln!(report, "- Reference count: {}", world.strong_count()) .unwrap(); - if let Some(instance) = instance.upgrade() { - let instance = instance.read(); - let strong_chunks = instance + if let Some(world) = world.upgrade() { + let world = world.read(); + let strong_chunks = world .chunks .map .iter() @@ -350,13 +350,13 @@ pub fn register(commands: &mut CommandDispatcher>) { report, "- Chunks: {} strongly referenced, {} in map", strong_chunks, - instance.chunks.map.len() + world.chunks.map.len() ) .unwrap(); writeln!( report, "- Entities: {}", - instance.entities_by_chunk.len() + world.entities_by_chunk.len() ) .unwrap(); } diff --git a/azalea/src/client_impl/entity_query.rs b/azalea/src/client_impl/entity_query.rs index 44fbe9e8..27c3aa9a 100644 --- a/azalea/src/client_impl/entity_query.rs +++ b/azalea/src/client_impl/entity_query.rs @@ -2,7 +2,7 @@ use std::{any, sync::Arc}; use azalea_core::position::Vec3; use azalea_entity::Position; -use azalea_world::InstanceName; +use azalea_world::WorldName; use bevy_ecs::{ component::Component, entity::Entity, @@ -44,9 +44,9 @@ impl Client { /// # Examples /// /// ``` - /// # use azalea_world::InstanceName; + /// # use azalea_world::WorldName; /// # fn example(client: &azalea::Client) { - /// let world_name = client.component::(); + /// let world_name = client.component::(); /// # } pub fn component(&self) -> MappedRwLockReadGuard<'_, T> { self.get_component::().unwrap_or_else(|| { @@ -150,9 +150,9 @@ impl Client { /// Quickly returns an [`EntityRef`] for an arbitrary entity that /// matches the given predicate function that is in the same - /// [`Instance`] as the client. + /// [`World`] as the client. /// - /// [`Instance`]: azalea_world::Instance + /// [`World`]: azalea_world::World pub fn any_entity_by( &self, predicate: impl EntityPredicate, @@ -162,7 +162,7 @@ impl Client { } /// Quickly returns a lightweight [`Entity`] for an arbitrary entity that /// matches the given predicate function that is in the same - /// [`Instance`] as the client. + /// [`World`] as the client. /// /// To get an [`EntityRef`], consider using [`Self::any_entity_by`] /// instead. @@ -184,13 +184,13 @@ impl Client { /// # } /// ``` /// - /// [`Instance`]: azalea_world::Instance + /// [`World`]: azalea_world::World pub fn any_entity_id_by( &self, predicate: impl EntityPredicate, ) -> Option { - let instance_name = self.get_component::()?.clone(); - predicate.find_any(self.ecs.clone(), &instance_name) + let world_name = self.get_component::()?.clone(); + predicate.find_any(self.ecs.clone(), &world_name) } /// Return an [`EntityRef`] for the nearest entity that matches the @@ -225,7 +225,7 @@ impl Client { self.nearest_entity_ids_by(predicate).first().copied() } - /// Returns an array of all [`EntityRef`]s in the instance that match the + /// Returns an array of all [`EntityRef`]s in the world that match the /// predicate, sorted by nearest first. /// /// To only get the nearest entity, consider using @@ -240,7 +240,7 @@ impl Client { .map(|e| self.entity_ref_for(e)) .collect() } - /// Returns an array of all [`Entity`]s in the instance that match the + /// Returns an array of all [`Entity`]s in the world that match the /// predicate, sorted by nearest first. /// /// To only get the nearest entity, consider using @@ -259,18 +259,18 @@ impl Client { &self, predicate: impl EntityPredicate, ) -> Box<[Entity]> { - let (instance_name, position) = { - let Some(instance_name) = self.get_component::() else { + let (world_name, position) = { + let Some(world_name) = self.get_component::() else { return Box::new([]); }; let Some(position) = self.get_component::() else { return Box::new([]); }; - (instance_name.clone(), **position) + (world_name.clone(), **position) }; - predicate.find_all_sorted(self.ecs.clone(), &instance_name, position) + predicate.find_all_sorted(self.ecs.clone(), &world_name, position) } /// Get a component from an entity. @@ -316,15 +316,11 @@ impl Client { } pub trait EntityPredicate { - fn find_any( - &self, - ecs_lock: Arc>, - instance_name: &InstanceName, - ) -> Option; + fn find_any(&self, ecs_lock: Arc>, world_name: &WorldName) -> Option; fn find_all_sorted( &self, ecs_lock: Arc>, - instance_name: &InstanceName, + world_name: &WorldName, nearest_to: Vec3, ) -> Box<[Entity]>; } @@ -333,30 +329,26 @@ where F: Fn(ROQueryItem) -> bool, for<'w, 's> <::ReadOnly as QueryData>::Item<'w, 's>: Copy, { - fn find_any( - &self, - ecs_lock: Arc>, - instance_name: &InstanceName, - ) -> Option { + fn find_any(&self, ecs_lock: Arc>, world_name: &WorldName) -> Option { let mut ecs = ecs_lock.write(); - let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>(); + let mut query = ecs.query_filtered::<(Entity, &WorldName, Q), Filter>(); query .iter(&ecs) - .find(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(*q)) + .find(|(_, e_world_name, q)| *e_world_name == world_name && (self)(*q)) .map(|(e, _, _)| e) } fn find_all_sorted( &self, ecs_lock: Arc>, - instance_name: &InstanceName, + world_name: &WorldName, nearest_to: Vec3, ) -> Box<[Entity]> { let mut ecs = ecs_lock.write(); - let mut query = ecs.query_filtered::<(Entity, &InstanceName, &Position, Q), Filter>(); + let mut query = ecs.query_filtered::<(Entity, &WorldName, &Position, Q), Filter>(); let mut entities = query .iter(&ecs) - .filter(|(_, e_instance_name, _, q)| *e_instance_name == instance_name && (self)(*q)) + .filter(|(_, e_world_name, _, q)| *e_world_name == world_name && (self)(*q)) .map(|(e, _, position, _)| (e, Vec3::from(position))) .collect::>(); diff --git a/azalea/src/client_impl/mod.rs b/azalea/src/client_impl/mod.rs index f884898f..d55e5a38 100644 --- a/azalea/src/client_impl/mod.rs +++ b/azalea/src/client_impl/mod.rs @@ -7,7 +7,7 @@ use azalea_client::{ connection::RawConnection, disconnect::DisconnectEvent, join::{ConnectOpts, StartJoinServerEvent}, - local_player::{Hunger, InstanceHolder, TabList}, + local_player::{Hunger, TabList, WorldHolder}, packet::game::SendGamePacketEvent, player::{GameProfileComponent, PlayerInfo}, start_ecs_runner, @@ -25,13 +25,9 @@ use azalea_protocol::{ resolve::ResolveError, }; use azalea_registry::{DataRegistryKeyRef, identifier::Identifier}; -use azalea_world::{Instance, InstanceName, PartialInstance}; +use azalea_world::{PartialWorld, World, WorldName}; use bevy_app::App; -use bevy_ecs::{ - entity::Entity, - resource::Resource, - world::{Mut, World}, -}; +use bevy_ecs::{entity::Entity, resource::Resource, world::Mut}; use parking_lot::RwLock; use tokio::sync::mpsc; use uuid::Uuid; @@ -67,17 +63,17 @@ pub struct Client { /// A mutually exclusive reference to the entity component system (ECS). /// /// You probably don't need to access this directly. Note that if you're - /// using a shared world (i.e. a swarm), the ECS will contain all entities - /// in all instances/dimensions. + /// using a shared world (i.e. a swarm), the ECS will also contain all + /// entities in all worlds. /// /// You can nearly always use [`Self::component`], [`Self::query_self`], /// [`Self::query_entity`], or another one of those related functions to /// access the ECS instead. - pub ecs: Arc>, + pub ecs: Arc>, } pub struct StartClientOpts { - pub ecs_lock: Arc>, + pub ecs_lock: Arc>, pub account: Account, pub connect_opts: ConnectOpts, pub event_sender: Option>, @@ -144,7 +140,7 @@ impl Client { /// World, and schedule runner function. /// You should only use this if you want to change these fields from the /// defaults, otherwise use [`Client::join`]. - pub fn new(entity: Entity, ecs: Arc>) -> Self { + pub fn new(entity: Entity, ecs: Arc>) -> Self { Self { // default our id to 0, it'll be set later entity, @@ -278,15 +274,16 @@ impl Client { f(value) } - /// Get an `RwLock` with a reference to our (potentially shared) world. + /// Get an `RwLock` with a reference to our (potentially shared) Minecraft + /// world. /// - /// This gets the [`Instance`] from the client's [`InstanceHolder`] + /// This gets the [`World`] from the client's [`WorldHolder`] /// component. If it's a normal client, then it'll be the same as the /// world the client has loaded. If the client is using a shared world, /// then the shared world will be a superset of the client's world. - pub fn world(&self) -> Arc> { - let instance_holder = self.component::(); - instance_holder.instance.clone() + pub fn world(&self) -> Arc> { + let world_holder = self.component::(); + world_holder.shared.clone() } /// Get an `RwLock` with a reference to the world that this client has @@ -298,15 +295,15 @@ impl Client { /// let world = client.partial_world(); /// let is_0_0_loaded = world.read().chunks.limited_get(&ChunkPos::new(0, 0)).is_some(); /// # } - pub fn partial_world(&self) -> Arc> { - let instance_holder = self.component::(); - instance_holder.partial_instance.clone() + pub fn partial_world(&self) -> Arc> { + let world_holder = self.component::(); + world_holder.partial.clone() } /// Returns whether we have a received the login packet yet. pub fn logged_in(&self) -> bool { // the login packet tells us the world name - self.query_self::, _>(|ins| ins.is_some()) + self.query_self::, _>(|ins| ins.is_some()) } /// Returns the client as an [`EntityRef`], allowing you to treat it as any @@ -409,8 +406,8 @@ impl Client { /// Call the given function with the client's [`RegistryHolder`]. /// - /// The player's instance (aka world) will be locked during this time, which - /// may result in a deadlock if you try to access the instance again while + /// Note that the player's world will be locked during this time, which may + /// result in a deadlock if you try to access the world again while /// in the function. /// /// [`RegistryHolder`]: azalea_core::registry_holder::RegistryHolder @@ -418,8 +415,8 @@ impl Client { &self, f: impl FnOnce(&azalea_core::registry_holder::RegistryHolder) -> R, ) -> R { - let instance = self.world(); - let registries = &instance.read().registries; + let world = self.world(); + let registries = &world.read().registries; f(registries) } diff --git a/azalea/src/entity_ref/mod.rs b/azalea/src/entity_ref/mod.rs index d604fe00..e09852c1 100644 --- a/azalea/src/entity_ref/mod.rs +++ b/azalea/src/entity_ref/mod.rs @@ -57,9 +57,9 @@ impl EntityRef { /// # Examples /// /// ``` - /// # use azalea_world::InstanceName; + /// # use azalea_world::WorldName; /// # fn example(client: &azalea::Client) { - /// let world_name = client.component::(); + /// let world_name = client.component::(); /// # } pub fn component(&self) -> MappedRwLockReadGuard<'_, T> { self.client.entity_component(self.entity) diff --git a/azalea/src/entity_ref/shared_impls.rs b/azalea/src/entity_ref/shared_impls.rs index f6aa332e..79396f56 100644 --- a/azalea/src/entity_ref/shared_impls.rs +++ b/azalea/src/entity_ref/shared_impls.rs @@ -2,7 +2,7 @@ use azalea_core::{entity_id::MinecraftEntityId, position::Vec3}; use azalea_entity::{ Attributes, Dead, EntityUuid, Physics, Position, dimensions::EntityDimensions, metadata::Health, }; -use azalea_world::InstanceName; +use azalea_world::WorldName; use uuid::Uuid; use super::EntityRef; @@ -141,21 +141,29 @@ impl_entity_functions! { } Client: - /// Get the name of the instance (world) that the bot is in. + #[deprecated = "renamed to `world_name`."] + EntityRef: + #[deprecated = "renamed to `world_name`."] + pub fn instance_name(&self) -> WorldName { + self.world_name() + } + + Client: + /// Get the name of the world that the bot is in. /// /// This can be used to check if the client is in the same world as another /// entity. - #[doc(alias("world_name", "dimension_name"))] + #[doc(alias("dimension_name"))] EntityRef: - /// Get the name of the instance (world) that the entity is in. + /// Get the name of the world that the entity is in. /// /// This can be used to check if the entity is in the same world as another /// entity. /// - /// Also see [`Client::instance_name`], - #[doc(alias("world_name", "dimension_name"))] - pub fn instance_name(&self) -> InstanceName { - (*self.component::()).clone() + /// Also see [`Client::world_name`], + #[doc(alias("dimension_name"))] + pub fn world_name(&self) -> WorldName { + (*self.component::()).clone() } Client: diff --git a/azalea/src/events.rs b/azalea/src/events.rs index 18d24773..b0bc8cd1 100644 --- a/azalea/src/events.rs +++ b/azalea/src/events.rs @@ -7,7 +7,7 @@ use azalea_chat::FormattedText; use azalea_core::{entity_id::MinecraftEntityId, position::ChunkPos, tick::GameTick}; use azalea_entity::{Dead, InLoadedChunk}; use azalea_protocol::packets::game::c_player_combat_kill::ClientboundPlayerCombatKill; -use azalea_world::InstanceName; +use azalea_world::WorldName; use bevy_app::{App, Plugin, PreUpdate, Update}; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; @@ -211,7 +211,7 @@ pub fn chat_listener( } // only tick if we're in a world -pub fn tick_listener(query: Query<&LocalPlayerEvents, With>) { +pub fn tick_listener(query: Query<&LocalPlayerEvents, With>) { for local_player_events in &query { let _ = local_player_events.send(Event::Tick); } diff --git a/azalea/src/nearest_entity.rs b/azalea/src/nearest_entity.rs index bf3f2fdb..3dc32adc 100644 --- a/azalea/src/nearest_entity.rs +++ b/azalea/src/nearest_entity.rs @@ -1,6 +1,6 @@ use azalea_core::entity_id::MinecraftEntityId; use azalea_entity::Position; -use azalea_world::InstanceName; +use azalea_world::WorldName; use bevy_ecs::{ prelude::Entity, query::{QueryFilter, With}, @@ -11,8 +11,8 @@ use bevy_ecs::{ /// entity, (or several) close to a given position. /// /// This system parameter allows for additional filtering of entities based off -/// of ECS marker components, such as `With<>`, `Without<>`, or `Added<>`, etc. -/// All functions used by this system parameter instance will respect the +/// of ECS marker components, such as `With`, `Without`, or `Added`, +/// etc. All functions used by this system parameter instance will respect the /// applied filter. /// /// ``` @@ -50,13 +50,12 @@ pub struct EntityFinder<'w, 's, F = ()> where F: QueryFilter + 'static, { - all_entities: - Query<'w, 's, (&'static Position, &'static InstanceName), With>, + all_entities: Query<'w, 's, (&'static Position, &'static WorldName), With>, filtered_entities: Query< 'w, 's, - (Entity, &'static InstanceName, &'static Position), + (Entity, &'static WorldName, &'static Position), (With, F), >, } @@ -65,21 +64,22 @@ impl<'a, F> EntityFinder<'_, '_, F> where F: QueryFilter + 'static, { - /// Gets the nearest entity to the given position and world instance name. + /// Gets the nearest entity to the given position and with the given world + /// name. /// /// This method will return `None` if there are no entities within range. If /// multiple entities are within range, only the closest one is returned. pub fn nearest_to_position( &'a self, position: Position, - instance_name: &InstanceName, + world_name: &WorldName, max_distance: f64, ) -> Option { let mut nearest_entity = None; let mut min_distance = max_distance; - for (target_entity, e_instance, e_pos) in self.filtered_entities.iter() { - if e_instance != instance_name { + for (target_entity, e_world, e_pos) in self.filtered_entities.iter() { + if e_world != world_name { continue; } @@ -99,19 +99,19 @@ where /// multiple entities are within range, only the closest one is /// returned. pub fn nearest_to_entity(&'a self, entity: Entity, max_distance: f64) -> Option { - let Ok((position, instance_name)) = self.all_entities.get(entity) else { + let Ok((position, world_name)) = self.all_entities.get(entity) else { return None; }; let mut nearest_entity = None; let mut min_distance = max_distance; - for (target_entity, e_instance, e_pos) in self.filtered_entities.iter() { + for (target_entity, e_world, e_pos) in self.filtered_entities.iter() { if entity == target_entity { continue; }; - if e_instance != instance_name { + if e_world != world_name { continue; } @@ -135,13 +135,13 @@ where pub fn nearby_entities_to_position( &'a self, position: &'a Position, - instance_name: &'a InstanceName, + world_name: &'a WorldName, max_distance: f64, ) -> impl Iterator + 'a { self.filtered_entities .iter() - .filter_map(move |(target_entity, e_instance, e_pos)| { - if e_instance != instance_name { + .filter_map(move |(target_entity, e_world, e_pos)| { + if e_world != world_name { return None; } @@ -167,23 +167,23 @@ where max_distance: f64, ) -> impl Iterator + 'a { let position; - let instance_name; - if let Ok((pos, instance)) = self.all_entities.get(entity) { - position = *pos; - instance_name = Some(instance); + let world_name; + if let Ok((p, w)) = self.all_entities.get(entity) { + position = *p; + world_name = Some(w); } else { position = Position::default(); - instance_name = None; + world_name = None; }; self.filtered_entities .iter() - .filter_map(move |(target_entity, e_instance, e_pos)| { + .filter_map(move |(target_entity, e_world, e_pos)| { if entity == target_entity { return None; } - if Some(e_instance) != instance_name { + if Some(e_world) != world_name { return None; } diff --git a/azalea/src/pathfinder/debug.rs b/azalea/src/pathfinder/debug.rs index 25f82946..7fe44919 100644 --- a/azalea/src/pathfinder/debug.rs +++ b/azalea/src/pathfinder/debug.rs @@ -1,4 +1,4 @@ -use azalea_client::{chat::SendChatEvent, local_player::InstanceHolder}; +use azalea_client::{chat::SendChatEvent, local_player::WorldHolder}; use azalea_core::position::Vec3; use bevy_ecs::prelude::*; @@ -35,7 +35,7 @@ use super::ExecutingPath; pub struct PathfinderDebugParticles; pub fn debug_render_path_with_particles( - mut query: Query<(Entity, &ExecutingPath, &InstanceHolder), With>, + mut query: Query<(Entity, &ExecutingPath, &WorldHolder), With>, // chat_events is Option because the tests don't have SendChatEvent // and we have to use ResMut because bevy doesn't support Option chat_events: Option>>, @@ -50,12 +50,12 @@ pub fn debug_render_path_with_particles( *tick_count += 1; return; } - for (entity, executing_path, instance_holder) in &mut query { + for (entity, executing_path, world_holder) in &mut query { if executing_path.path.is_empty() { continue; } - let chunks = &instance_holder.instance.read().chunks; + let chunks = &world_holder.shared.read().chunks; let mut start = executing_path.last_reached_node; for (i, edge) in executing_path.path.iter().enumerate() { diff --git a/azalea/src/pathfinder/extras/utils.rs b/azalea/src/pathfinder/extras/utils.rs index 3ae0b457..53345139 100644 --- a/azalea/src/pathfinder/extras/utils.rs +++ b/azalea/src/pathfinder/extras/utils.rs @@ -115,13 +115,13 @@ pub fn get_hit_result_while_looking_at_with_eye_position( #[cfg(test)] mod tests { use azalea_core::position::ChunkPos; - use azalea_world::{Chunk, PartialInstance}; + use azalea_world::{Chunk, PartialWorld}; use super::*; #[test] fn test_cannot_reach_block_through_wall_when_y_is_negative() { - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); let mut world = ChunkStorage::default(); partial_world .chunks diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index fe94e42d..96de98da 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -36,7 +36,7 @@ use azalea_block::{BlockState, BlockTrait}; use azalea_client::{ StartSprintEvent, StartWalkEvent, inventory::InventorySystems, - local_player::InstanceHolder, + local_player::WorldHolder, mining::{Mining, MiningSystems, StartMiningBlockEvent}, movement::MoveEventsSystems, }; @@ -46,7 +46,7 @@ use azalea_core::{ }; use azalea_entity::{LocalEntity, Physics, Position, inventory::Inventory, metadata::Player}; use azalea_physics::{PhysicsSystems, get_block_pos_below_that_affects_movement}; -use azalea_world::{InstanceContainer, InstanceName}; +use azalea_world::{WorldName, Worlds}; use bevy_app::{PreUpdate, Update}; use bevy_ecs::prelude::*; use bevy_tasks::{AsyncComputeTaskPool, Task}; @@ -109,7 +109,7 @@ impl Plugin for PathfinderPlugin { ( goto_listener, handle_tasks, - stop_pathfinding_on_instance_change, + stop_pathfinding_on_world_change, path_found_listener, handle_stop_pathfinding_event, ) @@ -307,16 +307,16 @@ pub fn goto_listener( &mut Pathfinder, Option<&mut ExecutingPath>, &Position, - &InstanceName, + &WorldName, &Inventory, Option<&CustomPathfinderState>, )>, - instance_container: Res, + worlds: Res, ) { let thread_pool = AsyncComputeTaskPool::get(); for event in events.read() { - let Ok((mut pathfinder, executing_path, position, instance_name, inventory, custom_state)) = + let Ok((mut pathfinder, executing_path, position, world_name, inventory, custom_state)) = query.get_mut(event.entity) else { warn!("got goto event for an entity that can't pathfind"); @@ -367,8 +367,8 @@ pub fn goto_listener( ); } - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); let goal = event.goal.clone(); @@ -417,7 +417,7 @@ pub struct CalculatePathCtx { pub entity: Entity, pub start: BlockPos, pub goal: Arc, - pub world_lock: Arc>, + pub world_lock: Arc>, pub goto_id_atomic: Arc, pub mining_cache: MiningCache, pub custom_state: CustomPathfinderState, @@ -559,15 +559,15 @@ pub fn path_found_listener( mut query: Query<( &mut Pathfinder, Option<&mut ExecutingPath>, - &InstanceName, + &WorldName, &Inventory, Option<&CustomPathfinderState>, )>, - instance_container: Res, + worlds: Res, mut commands: Commands, ) { for event in events.read() { - let Ok((mut pathfinder, executing_path, instance_name, inventory, custom_state)) = + let Ok((mut pathfinder, executing_path, world_name, inventory, custom_state)) = query.get_mut(event.entity) else { debug!("got path found event for an entity that can't pathfind"); @@ -580,8 +580,8 @@ pub fn path_found_listener( // combine the old and new paths if the first node of the new path is a // successor of the last node of the old path if let Some(last_node_of_current_path) = executing_path.path.back() { - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); let origin = event.start; let successors_fn: moves::SuccessorsFn = event.successors_fn; @@ -676,11 +676,11 @@ pub fn timeout_movement( &mut ExecutingPath, &Position, Option<&Mining>, - &InstanceName, + &WorldName, &Inventory, Option<&CustomPathfinderState>, )>, - instance_container: Res, + worlds: Res, ) { for ( entity, @@ -688,7 +688,7 @@ pub fn timeout_movement( mut executing_path, position, mining, - instance_name, + world_name, inventory, custom_state, ) in &mut query @@ -713,8 +713,8 @@ pub fn timeout_movement( let cur_pos = player_pos_to_block_pos(**position); executing_path.last_reached_node = cur_pos; - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); let Some(opts) = pathfinder.opts.clone() else { warn!( @@ -751,15 +751,14 @@ pub fn check_node_reached( &mut ExecutingPath, &Position, &Physics, - &InstanceName, + &WorldName, )>, mut walk_events: MessageWriter, mut commands: Commands, - instance_container: Res, + worlds: Res, ) { - for (entity, mut pathfinder, mut executing_path, position, physics, instance_name) in &mut query - { - let Some(instance) = instance_container.get(instance_name) else { + for (entity, mut pathfinder, mut executing_path, position, physics, world_name) in &mut query { + let Some(world) = worlds.get(world_name) else { warn!("entity is pathfinding but not in a valid world"); continue; }; @@ -794,8 +793,8 @@ pub fn check_node_reached( let block_pos_below = get_block_pos_below_that_affects_movement(*position); let block_state_below = { - let instance = instance.read(); - instance + let world = world.read(); + world .chunks .get_block_state(block_pos_below) .unwrap_or(BlockState::AIR) @@ -879,21 +878,21 @@ pub fn check_for_path_obstruction( Entity, &mut Pathfinder, &mut ExecutingPath, - &InstanceName, + &WorldName, &Inventory, Option<&CustomPathfinderState>, )>, - instance_container: Res, + worlds: Res, ) { - for (entity, mut pathfinder, mut executing_path, instance_name, inventory, custom_state) in + for (entity, mut pathfinder, mut executing_path, world_name, inventory, custom_state) in &mut query { let Some(opts) = pathfinder.opts.clone() else { continue; }; - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); // obstruction check (the path we're executing isn't possible anymore) @@ -948,8 +947,8 @@ pub fn check_for_path_obstruction( continue; }; - let world_lock = instance_container - .get(instance_name) + let world_lock = worlds + .get(world_name) .expect("Entity tried to pathfind but the entity isn't in a valid world"); // patch up to 20 nodes @@ -980,7 +979,7 @@ fn patch_path( pathfinder: &mut Pathfinder, inventory: &Inventory, entity: Entity, - world_lock: Arc>, + world_lock: Arc>, custom_state: CustomPathfinderState, opts: PathfinderOpts, ) { @@ -1145,7 +1144,7 @@ pub fn tick_execute_path( &Position, &Physics, Option<&Mining>, - &InstanceHolder, + &WorldHolder, &Inventory, )>, mut look_at_events: MessageWriter, @@ -1154,7 +1153,7 @@ pub fn tick_execute_path( mut jump_events: MessageWriter, mut start_mining_events: MessageWriter, ) { - for (entity, executing_path, position, physics, mining, instance_holder, inventory_component) in + for (entity, executing_path, position, physics, mining, world_holder, inventory_component) in &mut query { if let Some(edge) = executing_path.path.front() { @@ -1165,7 +1164,7 @@ pub fn tick_execute_path( start: executing_path.last_reached_node, physics, is_currently_mining: mining.is_some(), - instance: instance_holder.instance.clone(), + world: world_holder.shared.clone(), menu: inventory_component.inventory_menu.clone(), commands: &mut commands, @@ -1246,13 +1245,13 @@ pub fn handle_stop_pathfinding_event( } } -pub fn stop_pathfinding_on_instance_change( - mut query: Query<(Entity, &mut ExecutingPath), Changed>, +pub fn stop_pathfinding_on_world_change( + mut query: Query<(Entity, &mut ExecutingPath), Changed>, mut stop_pathfinding_events: MessageWriter, ) { for (entity, mut executing_path) in &mut query { if !executing_path.path.is_empty() { - debug!("instance changed, clearing path"); + debug!("world changed, clearing path"); executing_path.path.clear(); stop_pathfinding_events.write(StopPathfindingEvent { entity, diff --git a/azalea/src/pathfinder/moves/mod.rs b/azalea/src/pathfinder/moves/mod.rs index 33c34c3b..d575c01a 100644 --- a/azalea/src/pathfinder/moves/mod.rs +++ b/azalea/src/pathfinder/moves/mod.rs @@ -13,7 +13,7 @@ use azalea_client::{ }; use azalea_core::position::{BlockPos, Vec3}; use azalea_inventory::Menu; -use azalea_world::Instance; +use azalea_world::World; use bevy_ecs::{entity::Entity, message::MessageWriter, system::Commands}; use parking_lot::RwLock; use tracing::debug; @@ -65,7 +65,7 @@ pub struct ExecuteCtx<'s, 'w1, 'w2, 'w3, 'w4, 'w5, 'w6, 'a> { pub position: Vec3, pub physics: &'a azalea_entity::Physics, pub is_currently_mining: bool, - pub instance: Arc>, + pub world: Arc>, pub menu: Menu, pub commands: &'a mut Commands<'w1, 's>, @@ -124,11 +124,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_, '_> { /// Returns whether this block could be mined. pub fn should_mine(&mut self, block: BlockPos) -> bool { - let block_state = self - .instance - .read() - .get_block_state(block) - .unwrap_or_default(); + let block_state = self.world.read().get_block_state(block).unwrap_or_default(); if is_block_state_passable(block_state) { // block is already passable, no need to mine it return false; @@ -141,11 +137,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_, '_> { /// /// Returns whether the block is being mined. pub fn mine(&mut self, block: BlockPos) -> bool { - let block_state = self - .instance - .read() - .get_block_state(block) - .unwrap_or_default(); + let block_state = self.world.read().get_block_state(block).unwrap_or_default(); if is_block_state_passable(block_state) { // block is already passable, no need to mine it return false; @@ -196,10 +188,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_, '_> { } pub fn get_block_state(&self, block: BlockPos) -> BlockState { - self.instance - .read() - .get_block_state(block) - .unwrap_or_default() + self.world.read().get_block_state(block).unwrap_or_default() } } diff --git a/azalea/src/pathfinder/simulation.rs b/azalea/src/pathfinder/simulation.rs index ca5e4f36..94837f9e 100644 --- a/azalea/src/pathfinder/simulation.rs +++ b/azalea/src/pathfinder/simulation.rs @@ -13,8 +13,8 @@ use azalea_entity::{ Attributes, LookDirection, Physics, Position, dimensions::EntityDimensions, inventory::Inventory, }; -use azalea_registry::{builtin::EntityKind, identifier::Identifier}; -use azalea_world::{ChunkStorage, Instance, InstanceContainer, PartialInstance}; +use azalea_registry::builtin::EntityKind; +use azalea_world::{ChunkStorage, PartialWorld, World, WorldName, Worlds}; use bevy_app::App; use bevy_ecs::prelude::*; use parking_lot::RwLock; @@ -45,14 +45,14 @@ impl SimulatedPlayerBundle { } } -fn simulation_instance_name() -> Identifier { - Identifier::new("azalea:simulation") +fn simulation_world_name() -> WorldName { + WorldName::new("azalea:simulation") } -fn create_simulation_instance(chunks: ChunkStorage) -> (App, Arc>) { - let instance_name = simulation_instance_name(); +fn create_simulation_world(chunks: ChunkStorage) -> (App, Arc>) { + let world_name = simulation_world_name(); - let instance = Arc::new(RwLock::new(Instance { + let world = Arc::new(RwLock::new(World { chunks, ..Default::default() })); @@ -72,8 +72,8 @@ fn create_simulation_instance(chunks: ChunkStorage) -> (App, Arc (App, Arc>, + world: Arc>, player: &SimulatedPlayerBundle, ) -> impl Bundle { - let instance_name = simulation_instance_name(); + let world_name = simulation_world_name(); ( MinecraftEntityId(0), @@ -100,12 +100,12 @@ fn create_simulation_player_complete_bundle( Uuid::nil(), *player.position, EntityKind::Player, - instance_name, + world_name, ), - azalea_client::local_player::InstanceHolder { - // partial_instance is never actually used by the pathfinder so - partial_instance: Arc::new(RwLock::new(PartialInstance::default())), - instance: instance.clone(), + azalea_client::local_player::WorldHolder { + // the partial world is never actually used by the pathfinder, so we can leave it empty + partial: Arc::new(RwLock::new(PartialWorld::default())), + shared: world.clone(), }, Inventory::default(), LocalGameMode::from(GameMode::Survival), @@ -117,11 +117,11 @@ fn create_simulation_player_complete_bundle( } fn create_simulation_player( - ecs: &mut World, - instance: Arc>, + ecs: &mut bevy_ecs::world::World, + world: Arc>, player: SimulatedPlayerBundle, ) -> Entity { - let mut entity = ecs.spawn(create_simulation_player_complete_bundle(instance, &player)); + let mut entity = ecs.spawn(create_simulation_player_complete_bundle(world, &player)); entity.insert(player); entity.id() } @@ -130,17 +130,17 @@ fn create_simulation_player( pub struct Simulation { pub app: App, pub entity: Entity, - _instance: Arc>, + _world: Arc>, } impl Simulation { pub fn new(chunks: ChunkStorage, player: SimulatedPlayerBundle) -> Self { - let (mut app, instance) = create_simulation_instance(chunks); - let entity = create_simulation_player(app.world_mut(), instance.clone(), player); + let (mut app, world) = create_simulation_world(chunks); + let entity = create_simulation_player(app.world_mut(), world.clone(), player); Self { app, entity, - _instance: instance, + _world: world, } } @@ -168,12 +168,12 @@ impl Simulation { /// A set of simulations, useful for efficiently doing multiple simulations. pub struct SimulationSet { pub app: App, - instance: Arc>, + world: Arc>, } impl SimulationSet { pub fn new(chunks: ChunkStorage) -> Self { - let (app, instance) = create_simulation_instance(chunks); - Self { app, instance } + let (app, world) = create_simulation_world(chunks); + Self { app, world } } pub fn tick(&mut self) { self.app.update(); @@ -181,7 +181,7 @@ impl SimulationSet { } pub fn spawn(&mut self, player: SimulatedPlayerBundle) -> Entity { - create_simulation_player(self.app.world_mut(), self.instance.clone(), player) + create_simulation_player(self.app.world_mut(), self.world.clone(), player) } pub fn despawn(&mut self, entity: Entity) { self.app.world_mut().despawn(entity); diff --git a/azalea/src/pathfinder/world.rs b/azalea/src/pathfinder/world.rs index 13d60162..fdeb0b2f 100644 --- a/azalea/src/pathfinder/world.rs +++ b/azalea/src/pathfinder/world.rs @@ -11,7 +11,7 @@ use azalea_core::{ }; use azalea_physics::collision::BlockWithShape; use azalea_registry::{builtin::BlockKind, tags}; -use azalea_world::{Instance, palette::PalettedContainer}; +use azalea_world::{World, palette::PalettedContainer}; use parking_lot::RwLock; use super::{mining::MiningCache, rel_block_pos::RelBlockPos}; @@ -25,7 +25,7 @@ pub struct CachedWorld { origin: BlockPos, min_y: i32, - world_lock: Arc>, + world_lock: Arc>, // we store `PalettedContainer`s instead of `Chunk`s or `Section`s because it doesn't contain // any unnecessary data like heightmaps or biomes. @@ -99,7 +99,7 @@ pub struct CachedSection { } impl CachedWorld { - pub fn new(world_lock: Arc>, origin: BlockPos) -> Self { + pub fn new(world_lock: Arc>, origin: BlockPos) -> Self { let min_y = world_lock.read().chunks.min_y; Self { origin, @@ -675,13 +675,13 @@ pub fn is_block_state_water(block_state: BlockState) -> bool { #[cfg(test)] mod tests { - use azalea_world::{Chunk, ChunkStorage, PartialInstance}; + use azalea_world::{Chunk, ChunkStorage, PartialWorld}; use super::*; #[test] fn test_is_passable() { - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); let mut world = ChunkStorage::default(); partial_world @@ -703,7 +703,7 @@ mod tests { #[test] fn test_is_solid() { - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); let mut world = ChunkStorage::default(); partial_world .chunks @@ -724,7 +724,7 @@ mod tests { #[test] fn test_is_standable() { - let mut partial_world = PartialInstance::default(); + let mut partial_world = PartialWorld::default(); let mut world = ChunkStorage::default(); partial_world .chunks diff --git a/azalea/src/swarm/builder.rs b/azalea/src/swarm/builder.rs index 14c9c290..560be3d8 100644 --- a/azalea/src/swarm/builder.rs +++ b/azalea/src/swarm/builder.rs @@ -10,7 +10,7 @@ use std::{ use azalea_client::{DefaultPlugins, account::Account, start_ecs_runner}; use azalea_protocol::address::{ResolvableAddr, ResolvedAddr}; -use azalea_world::InstanceContainer; +use azalea_world::Worlds; use bevy_app::{App, AppExit, Plugins, SubApp}; use bevy_ecs::{component::Component, resource::Resource}; use futures::future::join_all; @@ -431,7 +431,7 @@ where addr }; - let instance_container = Arc::new(RwLock::new(InstanceContainer::default())); + let worlds = Arc::new(RwLock::new(Worlds::default())); // we can't modify the swarm plugins after this let (bots_tx, mut bots_rx) = mpsc::unbounded_channel(); @@ -451,7 +451,7 @@ where ecs: ecs_lock.clone(), address: Arc::new(RwLock::new(address)), - instance_container, + worlds, bots_tx, diff --git a/azalea/src/swarm/chat.rs b/azalea/src/swarm/chat.rs index 0bad69c1..c5e3eba3 100644 --- a/azalea/src/swarm/chat.rs +++ b/azalea/src/swarm/chat.rs @@ -2,12 +2,12 @@ // How the chat event works (to avoid firing the event multiple times): // --- -// There's a shared queue of all the chat messages -// Each bot contains an index of the farthest message we've seen -// When a bot receives a chat messages, it looks into the queue to find the -// earliest instance of the message content that's after the bot's chat index. -// If it finds it, then its personal index is simply updated. Otherwise, fire -// the event and add to the queue. +// There's a shared queue of all the chat messages. Each bot contains an index +// of the farthest message that it has seen. When a bot receives a chat +// message, it looks into the shared queue to find the earliest instance of the +// message content, that's after the bot's current chat index. If it finds it, +// then its personal index is simply updated. Otherwise, it fires the event and +// adds to the shared queue. // // To make sure the queue doesn't grow too large, we keep a `chat_min_index` // in Swarm that's set to the smallest index of all the bots, and we remove all diff --git a/azalea/src/swarm/events.rs b/azalea/src/swarm/events.rs index ee5859ca..83817c86 100644 --- a/azalea/src/swarm/events.rs +++ b/azalea/src/swarm/events.rs @@ -1,4 +1,4 @@ -use azalea_client::local_player::InstanceHolder; +use azalea_client::local_player::WorldHolder; use azalea_core::entity_id::MinecraftEntityId; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; @@ -21,7 +21,7 @@ pub struct SwarmReadyEvent; struct IsSwarmReady(bool); fn check_ready( - query: Query, With>, + query: Query, With>, mut is_swarm_ready: ResMut, mut ready_events: MessageWriter, ) { diff --git a/azalea/src/swarm/mod.rs b/azalea/src/swarm/mod.rs index b1061346..4ecb0726 100644 --- a/azalea/src/swarm/mod.rs +++ b/azalea/src/swarm/mod.rs @@ -15,7 +15,7 @@ use std::sync::{ use azalea_client::{account::Account, chat::ChatPacket, join::ConnectOpts}; use azalea_entity::LocalEntity; use azalea_protocol::address::ResolvedAddr; -use azalea_world::InstanceContainer; +use azalea_world::Worlds; use bevy_app::{PluginGroup, PluginGroupBuilder}; use bevy_ecs::prelude::*; pub use builder::SwarmBuilder; @@ -47,7 +47,7 @@ pub struct Swarm { // the address is public and mutable so plugins can change it pub address: Arc>, - pub instance_container: Arc>, + pub worlds: Arc>, /// This is used internally to make the client handler function work. pub(crate) bots_tx: mpsc::UnboundedSender<(Option, Client)>, -- cgit v1.2.3