1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

instanceloadedevent and a few fixes

This commit is contained in:
mat 2023-09-18 19:29:14 -05:00
parent 856a3252f6
commit e6941b6a24
7 changed files with 100 additions and 26 deletions

View file

@ -1,4 +1,8 @@
use std::{collections::HashSet, io::Cursor, sync::Arc}; use std::{
collections::HashSet,
io::Cursor,
sync::{Arc, Weak},
};
use azalea_buf::McBufWritable; use azalea_buf::McBufWritable;
use azalea_chat::FormattedText; use azalea_chat::FormattedText;
@ -23,7 +27,7 @@ use azalea_protocol::{
}, },
read::ReadPacketError, read::ReadPacketError,
}; };
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance}; use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
use bevy_app::{App, First, Plugin, PreUpdate, Update}; use bevy_app::{App, First, Plugin, PreUpdate, Update};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component,
@ -36,7 +40,7 @@ use bevy_ecs::{
world::World, world::World,
}; };
use log::{debug, error, trace, warn}; use log::{debug, error, trace, warn};
use parking_lot::Mutex; use parking_lot::{Mutex, RwLock};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::{ use crate::{
@ -100,7 +104,8 @@ impl Plugin for PacketHandlerPlugin {
.add_event::<ChatReceivedEvent>() .add_event::<ChatReceivedEvent>()
.add_event::<DeathEvent>() .add_event::<DeathEvent>()
.add_event::<KeepAliveEvent>() .add_event::<KeepAliveEvent>()
.add_event::<ResourcePackEvent>(); .add_event::<ResourcePackEvent>()
.add_event::<InstanceLoadedEvent>();
} }
} }
@ -171,6 +176,17 @@ pub struct ResourcePackEvent {
pub prompt: Option<FormattedText>, pub prompt: Option<FormattedText>,
} }
/// An instance (aka world, 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.
#[derive(Event, Debug, Clone)]
pub struct InstanceLoadedEvent {
pub entity: Entity,
pub name: ResourceLocation,
pub instance: Weak<RwLock<Instance>>,
}
/// Something that receives packets from the server. /// Something that receives packets from the server.
#[derive(Event, Component, Clone)] #[derive(Event, Component, Clone)]
pub struct PacketReceiver { pub struct PacketReceiver {
@ -227,9 +243,11 @@ pub fn process_packet_events(ecs: &mut World) {
&GameProfileComponent, &GameProfileComponent,
&ClientInformation, &ClientInformation,
)>, )>,
EventWriter<InstanceLoadedEvent>,
ResMut<InstanceContainer>, ResMut<InstanceContainer>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query, mut instance_container) = system_state.get_mut(ecs); let (mut commands, mut query, mut instance_loaded_events, mut instance_container) =
system_state.get_mut(ecs);
let (mut local_player, mut entity_id_index, game_profile, client_information) = let (mut local_player, mut entity_id_index, game_profile, client_information) =
query.get_mut(player_entity).unwrap(); query.get_mut(player_entity).unwrap();
@ -246,15 +264,21 @@ pub fn process_packet_events(ecs: &mut World) {
}) })
.element; .element;
let new_world_name = p.dimension.clone(); let new_instance_name = p.dimension.clone();
// add this world to the instance_container (or don't if it's already // add this world to the instance_container (or don't if it's already
// there) // there)
let weak_world = instance_container.insert( let instance = instance_container.insert(
new_world_name.clone(), new_instance_name.clone(),
dimension.height, dimension.height,
dimension.min_y, dimension.min_y,
); );
instance_loaded_events.send(InstanceLoadedEvent {
entity: player_entity,
name: new_instance_name.clone(),
instance: Arc::downgrade(&instance),
});
// set the partial_world to an empty world // set the partial_world to an empty world
// (when we add chunks or entities those will be in the // (when we add chunks or entities those will be in the
// instance_container) // instance_container)
@ -267,14 +291,14 @@ pub fn process_packet_events(ecs: &mut World) {
// in a shared world // in a shared world
Some(player_entity), Some(player_entity),
); );
local_player.world = weak_world; local_player.world = instance;
let player_bundle = PlayerBundle { let player_bundle = PlayerBundle {
entity: EntityBundle::new( entity: EntityBundle::new(
game_profile.uuid, game_profile.uuid,
Vec3::default(), Vec3::default(),
azalea_registry::EntityKind::Player, azalea_registry::EntityKind::Player,
new_world_name, new_instance_name,
), ),
metadata: PlayerMetadataBundle::default(), metadata: PlayerMetadataBundle::default(),
}; };
@ -1161,9 +1185,11 @@ pub fn process_packet_events(ecs: &mut World) {
&ClientInformation, &ClientInformation,
&ReceivedRegistries, &ReceivedRegistries,
)>, )>,
EventWriter<InstanceLoadedEvent>,
ResMut<InstanceContainer>, ResMut<InstanceContainer>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query, mut instance_container) = system_state.get_mut(ecs); let (mut commands, mut query, mut instance_loaded_events, mut instance_container) =
system_state.get_mut(ecs);
let (mut local_player, game_profile, client_information, received_registries) = let (mut local_player, game_profile, client_information, received_registries) =
query.get_mut(player_entity).unwrap(); query.get_mut(player_entity).unwrap();
@ -1178,15 +1204,20 @@ pub fn process_packet_events(ecs: &mut World) {
}) })
.element; .element;
let new_world_name = p.dimension.clone(); let new_instance_name = p.dimension.clone();
// add this world to the instance_container (or don't if it's already // add this world to the instance_container (or don't if it's already
// there) // there)
let weak_world = instance_container.insert( let instance = instance_container.insert(
new_world_name.clone(), new_instance_name.clone(),
dimension.height, dimension.height,
dimension.min_y, dimension.min_y,
); );
instance_loaded_events.send(InstanceLoadedEvent {
entity: player_entity,
name: new_instance_name.clone(),
instance: Arc::downgrade(&instance),
});
// set the partial_world to an empty world // set the partial_world to an empty world
// (when we add chunks or entities those will be in the // (when we add chunks or entities those will be in the
@ -1197,7 +1228,7 @@ pub fn process_packet_events(ecs: &mut World) {
), ),
Some(player_entity), Some(player_entity),
); );
local_player.world = weak_world; local_player.world = instance;
// this resets a bunch of our components like physics and stuff // this resets a bunch of our components like physics and stuff
let player_bundle = PlayerBundle { let player_bundle = PlayerBundle {
@ -1205,7 +1236,7 @@ pub fn process_packet_events(ecs: &mut World) {
game_profile.uuid, game_profile.uuid,
Vec3::default(), Vec3::default(),
azalea_registry::EntityKind::Player, azalea_registry::EntityKind::Player,
new_world_name, new_instance_name,
), ),
metadata: PlayerMetadataBundle::default(), metadata: PlayerMetadataBundle::default(),
}; };

View file

@ -218,6 +218,32 @@ impl BitStorage {
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
self.size self.size
} }
pub fn iter(&self) -> BitStorageIter {
BitStorageIter {
storage: self,
index: 0,
}
}
}
pub struct BitStorageIter<'a> {
storage: &'a BitStorage,
index: usize,
}
impl<'a> Iterator for BitStorageIter<'a> {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.storage.size {
return None;
}
let value = self.storage.get(self.index);
self.index += 1;
Some(value)
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -27,20 +27,18 @@ pub struct InstanceContainer {
// telling them apart. We hope most servers are nice and don't do that though. It's only an // 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 // issue when there's multiple clients with the same WorldContainer in different worlds
// anyways. // anyways.
pub worlds: HashMap<ResourceLocation, Weak<RwLock<Instance>>>, pub instances: HashMap<ResourceLocation, Weak<RwLock<Instance>>>,
} }
impl InstanceContainer { impl InstanceContainer {
pub fn new() -> Self { pub fn new() -> Self {
InstanceContainer { InstanceContainer::default()
worlds: HashMap::new(),
}
} }
/// Get a world from the container. Returns `None` if none of the clients /// Get a world from the container. Returns `None` if none of the clients
/// are in this world. /// are in this world.
pub fn get(&self, name: &InstanceName) -> Option<Arc<RwLock<Instance>>> { pub fn get(&self, name: &InstanceName) -> Option<Arc<RwLock<Instance>>> {
self.worlds.get(name).and_then(|world| world.upgrade()) self.instances.get(name).and_then(|world| world.upgrade())
} }
/// Add an empty world to the container (or not if it already exists) and /// Add an empty world to the container (or not if it already exists) and
@ -52,7 +50,7 @@ impl InstanceContainer {
height: u32, height: u32,
min_y: i32, min_y: i32,
) -> Arc<RwLock<Instance>> { ) -> Arc<RwLock<Instance>> {
if let Some(existing_lock) = self.worlds.get(&name).and_then(|world| world.upgrade()) { if let Some(existing_lock) = self.instances.get(&name).and_then(|world| world.upgrade()) {
let existing = existing_lock.read(); let existing = existing_lock.read();
if existing.chunks.height != height { if existing.chunks.height != height {
error!( error!(
@ -73,7 +71,7 @@ impl InstanceContainer {
entities_by_chunk: HashMap::new(), entities_by_chunk: HashMap::new(),
entity_by_id: IntMap::default(), entity_by_id: IntMap::default(),
})); }));
self.worlds.insert(name, Arc::downgrade(&world)); self.instances.insert(name, Arc::downgrade(&world));
world world
} }
} }

View file

@ -119,6 +119,25 @@ impl Heightmap {
false false
} }
/// Get an iterator over the top available block positions in this
/// heightmap.
pub fn iter_first_available<'a>(&'a self) -> impl Iterator<Item = ChunkBlockPos> + 'a {
self.data.iter().enumerate().map(move |(index, height)| {
let x = (index % 16) as u8;
let z = (index / 16) as u8;
ChunkBlockPos::new(x, height as i32 + self.min_y, z)
})
}
/// Get an iterator over the top block positions in this heightmap.
pub fn iter_highest_taken<'a>(&'a self) -> impl Iterator<Item = ChunkBlockPos> + 'a {
self.data.iter().enumerate().map(move |(index, height)| {
let x = (index % 16) as u8;
let z = (index / 16) as u8;
ChunkBlockPos::new(x, height as i32 + self.min_y - 1, z)
})
}
} }
impl FromStr for HeightmapKind { impl FromStr for HeightmapKind {

View file

@ -339,7 +339,7 @@ async fn swarm_handle(
SwarmEvent::Chat(m) => { SwarmEvent::Chat(m) => {
println!("swarm chat message: {}", m.message().to_ansi()); println!("swarm chat message: {}", m.message().to_ansi());
if m.message().to_string() == "<py5> world" { if m.message().to_string() == "<py5> world" {
for (name, world) in &swarm.instance_container.read().worlds { for (name, world) in &swarm.instance_container.read().instances {
println!("world name: {name}"); println!("world name: {name}");
if let Some(w) = world.upgrade() { if let Some(w) = world.upgrade() {
for chunk_pos in w.read().chunks.map.values() { for chunk_pos in w.read().chunks.map.values() {

View file

@ -20,7 +20,7 @@ pub use azalea_block as blocks;
pub use azalea_brigadier as brigadier; pub use azalea_brigadier as brigadier;
pub use azalea_chat::FormattedText; pub use azalea_chat::FormattedText;
pub use azalea_client::*; pub use azalea_client::*;
pub use azalea_core::{BlockPos, ChunkPos, Vec3}; pub use azalea_core::{BlockPos, ChunkPos, ResourceLocation, Vec3};
pub use azalea_entity as entity; pub use azalea_entity as entity;
pub use azalea_protocol as protocol; pub use azalea_protocol as protocol;
pub use azalea_registry::{Block, EntityKind, Item}; pub use azalea_registry::{Block, EntityKind, Item};

View file

@ -70,7 +70,7 @@ impl Simulation {
// make sure it doesn't do fixed ticks without us telling it to // make sure it doesn't do fixed ticks without us telling it to
.insert_resource(FixedTime::new(Duration::from_secs(60))) .insert_resource(FixedTime::new(Duration::from_secs(60)))
.insert_resource(InstanceContainer { .insert_resource(InstanceContainer {
worlds: [(instance_name.clone(), Arc::downgrade(&instance.clone()))] instances: [(instance_name.clone(), Arc::downgrade(&instance.clone()))]
.iter() .iter()
.cloned() .cloned()
.collect(), .collect(),