mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
some ecs stuff in az-client
This commit is contained in:
parent
13fc403484
commit
8a93a2c158
7 changed files with 113 additions and 63 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -276,6 +276,7 @@ dependencies = [
|
|||
"azalea-crypto",
|
||||
"azalea-physics",
|
||||
"azalea-protocol",
|
||||
"azalea-registry",
|
||||
"azalea-world",
|
||||
"log",
|
||||
"nohash-hasher",
|
||||
|
|
|
@ -11,14 +11,15 @@ version = "0.5.0"
|
|||
[dependencies]
|
||||
anyhow = "1.0.59"
|
||||
async-trait = "0.1.58"
|
||||
azalea-auth = {path = "../azalea-auth", version = "0.5.0" }
|
||||
azalea-block = {path = "../azalea-block", version = "0.5.0" }
|
||||
azalea-chat = {path = "../azalea-chat", version = "0.5.0" }
|
||||
azalea-core = {path = "../azalea-core", version = "0.5.0" }
|
||||
azalea-crypto = {path = "../azalea-crypto", version = "0.5.0" }
|
||||
azalea-physics = {path = "../azalea-physics", version = "0.5.0" }
|
||||
azalea-protocol = {path = "../azalea-protocol", version = "0.5.0" }
|
||||
azalea-world = {path = "../azalea-world", version = "0.5.0" }
|
||||
azalea-auth = {path = "../azalea-auth", version = "0.5.0"}
|
||||
azalea-block = {path = "../azalea-block", version = "0.5.0"}
|
||||
azalea-chat = {path = "../azalea-chat", version = "0.5.0"}
|
||||
azalea-core = {path = "../azalea-core", version = "0.5.0"}
|
||||
azalea-crypto = {path = "../azalea-crypto", version = "0.5.0"}
|
||||
azalea-physics = {path = "../azalea-physics", version = "0.5.0"}
|
||||
azalea-protocol = {path = "../azalea-protocol", version = "0.5.0"}
|
||||
azalea-registry = {path = "../azalea-registry", version = "0.5.0"}
|
||||
azalea-world = {path = "../azalea-world", version = "0.5.0"}
|
||||
log = "0.4.17"
|
||||
nohash-hasher = "0.2.0"
|
||||
once_cell = "1.16.0"
|
||||
|
|
|
@ -29,7 +29,11 @@ use azalea_protocol::{
|
|||
resolver, ServerAddress,
|
||||
};
|
||||
use azalea_world::{
|
||||
entity::{metadata, Entity, EntityData, EntityMetadata},
|
||||
entity::{
|
||||
self,
|
||||
metadata::{self, PlayerMetadataBundle},
|
||||
EntityId,
|
||||
},
|
||||
PartialWorld, WeakWorld, WeakWorldContainer,
|
||||
};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
@ -40,6 +44,7 @@ use std::{
|
|||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
io::{self, Cursor},
|
||||
ops::DerefMut,
|
||||
sync::Arc,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
@ -90,7 +95,7 @@ pub struct Client {
|
|||
pub profile: GameProfile,
|
||||
pub read_conn: Arc<tokio::sync::Mutex<ReadConnection<ClientboundGamePacket>>>,
|
||||
pub write_conn: Arc<tokio::sync::Mutex<WriteConnection<ServerboundGamePacket>>>,
|
||||
pub entity_id: Arc<RwLock<u32>>,
|
||||
pub entity_id: Arc<RwLock<EntityId>>,
|
||||
/// The world that this client has access to. This supports shared worlds.
|
||||
pub world: Arc<RwLock<PartialWorld>>,
|
||||
/// A container of world names to worlds. If we're not using a shared world
|
||||
|
@ -179,7 +184,7 @@ impl Client {
|
|||
read_conn,
|
||||
write_conn,
|
||||
// default our id to 0, it'll be set later
|
||||
entity_id: Arc::new(RwLock::new(0)),
|
||||
entity_id: Arc::new(RwLock::new(EntityId(0))),
|
||||
world: Arc::new(RwLock::new(PartialWorld::default())),
|
||||
world_container: world_container
|
||||
.unwrap_or_else(|| Arc::new(RwLock::new(WeakWorldContainer::new()))),
|
||||
|
@ -523,18 +528,27 @@ impl Client {
|
|||
*world_lock = PartialWorld::new(
|
||||
client.client_information.read().view_distance.into(),
|
||||
weak_world,
|
||||
Some(p.player_id),
|
||||
Some(EntityId(p.player_id)),
|
||||
);
|
||||
|
||||
let entity = EntityData::new(
|
||||
client.profile.uuid,
|
||||
Vec3::default(),
|
||||
EntityMetadata::Player(metadata::Player::default()),
|
||||
);
|
||||
// make it so other entities don't update this entity in a shared world
|
||||
world_lock.add_entity(p.player_id, entity);
|
||||
let player_bundle = entity::PlayerBundle {
|
||||
entity: entity::EntityBundle::new(
|
||||
client.profile.uuid,
|
||||
Vec3::default(),
|
||||
azalea_registry::EntityKind::Player,
|
||||
),
|
||||
metadata: PlayerMetadataBundle::default(),
|
||||
};
|
||||
// let entity = EntityData::new(
|
||||
// client.profile.uuid,
|
||||
// Vec3::default(),
|
||||
// EntityMetadata::Player(metadata::Player::default()),
|
||||
// );
|
||||
// the first argument makes it so other entities don't update this entity in a
|
||||
// shared world
|
||||
world_lock.add_entity(EntityId(p.player_id), player_bundle);
|
||||
|
||||
*client.entity_id.write() = p.player_id;
|
||||
*client.entity_id.write() = EntityId(p.player_id);
|
||||
}
|
||||
|
||||
// send the client information that we have set
|
||||
|
@ -600,54 +614,59 @@ impl Client {
|
|||
|
||||
let (new_pos, y_rot, x_rot) = {
|
||||
let player_entity_id = *client.entity_id.read();
|
||||
let mut world_lock = client.world();
|
||||
// let mut player_entity = world_lock.entity_mut(player_entity_id).unwrap();
|
||||
let (physics, position) =
|
||||
world_lock
|
||||
.entity_storage
|
||||
.read()
|
||||
.query_entity_mut::<(&mut entity::Physics, &entity::Position)>(
|
||||
player_entity_id,
|
||||
);
|
||||
|
||||
let mut world_lock = client.world.write();
|
||||
|
||||
let mut player_entity = world_lock.entity_mut(player_entity_id).unwrap();
|
||||
|
||||
let delta_movement = player_entity.delta;
|
||||
let delta_movement = physics.delta;
|
||||
|
||||
let is_x_relative = p.relative_arguments.x;
|
||||
let is_y_relative = p.relative_arguments.y;
|
||||
let is_z_relative = p.relative_arguments.z;
|
||||
|
||||
let (delta_x, new_pos_x) = if is_x_relative {
|
||||
player_entity.last_pos.x += p.x;
|
||||
(delta_movement.x, player_entity.pos().x + p.x)
|
||||
physics.last_pos.x += p.x;
|
||||
(delta_movement.x, position.x + p.x)
|
||||
} else {
|
||||
player_entity.last_pos.x = p.x;
|
||||
physics.last_pos.x = p.x;
|
||||
(0.0, p.x)
|
||||
};
|
||||
let (delta_y, new_pos_y) = if is_y_relative {
|
||||
player_entity.last_pos.y += p.y;
|
||||
(delta_movement.y, player_entity.pos().y + p.y)
|
||||
physics.last_pos.y += p.y;
|
||||
(delta_movement.y, position.y + p.y)
|
||||
} else {
|
||||
player_entity.last_pos.y = p.y;
|
||||
physics.last_pos.y = p.y;
|
||||
(0.0, p.y)
|
||||
};
|
||||
let (delta_z, new_pos_z) = if is_z_relative {
|
||||
player_entity.last_pos.z += p.z;
|
||||
(delta_movement.z, player_entity.pos().z + p.z)
|
||||
physics.last_pos.z += p.z;
|
||||
(delta_movement.z, position.z + p.z)
|
||||
} else {
|
||||
player_entity.last_pos.z = p.z;
|
||||
physics.last_pos.z = p.z;
|
||||
(0.0, p.z)
|
||||
};
|
||||
|
||||
let mut y_rot = p.y_rot;
|
||||
let mut x_rot = p.x_rot;
|
||||
if p.relative_arguments.x_rot {
|
||||
x_rot += player_entity.x_rot;
|
||||
x_rot += physics.x_rot;
|
||||
}
|
||||
if p.relative_arguments.y_rot {
|
||||
y_rot += player_entity.y_rot;
|
||||
y_rot += physics.y_rot;
|
||||
}
|
||||
|
||||
player_entity.delta = Vec3 {
|
||||
physics.delta = Vec3 {
|
||||
x: delta_x,
|
||||
y: delta_y,
|
||||
z: delta_z,
|
||||
};
|
||||
player_entity.set_rotation(y_rot, x_rot);
|
||||
entity::set_rotation(physics.deref_mut(), y_rot, x_rot);
|
||||
// TODO: minecraft sets "xo", "yo", and "zo" here but idk what that means
|
||||
// so investigate that ig
|
||||
let new_pos = Vec3 {
|
||||
|
@ -783,8 +802,12 @@ impl Client {
|
|||
}
|
||||
ClientboundGamePacket::AddEntity(p) => {
|
||||
debug!("Got add entity packet {:?}", p);
|
||||
let entity = EntityData::from(p);
|
||||
client.world.write().add_entity(p.id, entity);
|
||||
// let entity = EntityData::from(p);
|
||||
let bundle = p.as_entity_bundle();
|
||||
let world = client.world();
|
||||
world.add_entity(p.id, bundle);
|
||||
let entity = world.entity_storage.write().ecs_entity(p.id);
|
||||
p.apply_metadata(entity);
|
||||
}
|
||||
ClientboundGamePacket::SetEntityData(p) => {
|
||||
debug!("Got set entity data packet {:?}", p);
|
||||
|
@ -1049,19 +1072,19 @@ impl Client {
|
|||
self.world.read().shared.clone()
|
||||
}
|
||||
|
||||
/// Returns the entity associated to the player.
|
||||
pub fn entity(&self) -> Entity<Arc<WeakWorld>> {
|
||||
let entity_id = *self.entity_id.read();
|
||||
// /// Returns the entity associated to the player.
|
||||
// pub fn entity(&self) -> Entity<Arc<WeakWorld>> {
|
||||
// let entity_id = *self.entity_id.read();
|
||||
|
||||
let world = self.world();
|
||||
let entity_data = world
|
||||
.entity_storage
|
||||
.read()
|
||||
.get_by_id(entity_id)
|
||||
.expect("Player entity should be in the given world");
|
||||
let entity_ptr = unsafe { entity_data.as_ptr() };
|
||||
Entity::new(world, entity_id, entity_ptr)
|
||||
}
|
||||
// let world = self.world();
|
||||
// let entity_data = world
|
||||
// .entity_storage
|
||||
// .read()
|
||||
// .get_by_id(entity_id)
|
||||
// .expect("Player entity should be in the given world");
|
||||
// let entity_ptr = unsafe { entity_data.as_ptr() };
|
||||
// Entity::new(world, entity_id, entity_ptr)
|
||||
// }
|
||||
|
||||
/// Returns whether we have a received the login packet yet.
|
||||
pub fn logged_in(&self) -> bool {
|
||||
|
|
|
@ -41,12 +41,11 @@ pub struct ClientboundAddEntityPacket {
|
|||
// }
|
||||
|
||||
impl ClientboundAddEntityPacket {
|
||||
fn as_bundle(&self) -> EntityBundle {
|
||||
pub fn as_entity_bundle(&self) -> EntityBundle {
|
||||
EntityBundle::new(self.uuid, self.position, self.entity_type)
|
||||
}
|
||||
|
||||
pub fn apply_to_entity(&self, entity: &mut bevy_ecs::world::EntityMut) {
|
||||
pub fn apply_metadata(&self, entity: &mut bevy_ecs::world::EntityMut) {
|
||||
apply_default_metadata(entity, self.entity_type);
|
||||
entity.insert(self.as_bundle());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,6 +254,9 @@ pub struct Physics {
|
|||
}
|
||||
|
||||
/// A component NewType for [`azalea_registry::EntityKind`].
|
||||
///
|
||||
/// Most of the time, you should be using `azalea_registry::EntityKind`
|
||||
/// instead.
|
||||
#[derive(Component, Clone, Copy, Debug, PartialEq, Deref)]
|
||||
pub struct EntityKind(azalea_registry::EntityKind);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ impl PartialEntityStorage {
|
|||
if self.loaded_entity_ids.remove(&id) {
|
||||
let mut shared = self.shared.write();
|
||||
|
||||
let mut query = shared.query::<(&Position, &EntityUuid)>();
|
||||
let mut query = shared.query_to_state::<(&Position, &EntityUuid)>();
|
||||
let (pos, uuid) = query.get(&mut shared.ecs, id.into()).expect(
|
||||
"If the entity was being loaded by this storage, it must be in the shared
|
||||
storage.",
|
||||
|
@ -210,7 +210,7 @@ impl PartialEntityStorage {
|
|||
/// shared storage, unless there are no other references to them.
|
||||
pub fn clear_chunk(&mut self, chunk: &ChunkPos) {
|
||||
let mut shared = self.shared.write();
|
||||
let mut query = shared.query::<&EntityUuid>();
|
||||
let mut query = shared.query_to_state::<&EntityUuid>();
|
||||
|
||||
if let Some(entities) = shared.ids_by_chunk.get(chunk).cloned() {
|
||||
for &id in entities.iter() {
|
||||
|
@ -296,7 +296,9 @@ impl WeakEntityStorage {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
|
||||
/// Query the ecs to get a [`QueryState`]. You should probably use
|
||||
/// [`Self::query_entity`] or [`Self::query_entity_mut`] instead.
|
||||
pub fn query_to_state<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
|
||||
self.ecs.query::<Q>()
|
||||
}
|
||||
|
||||
|
@ -333,6 +335,29 @@ impl WeakEntityStorage {
|
|||
.or_default()
|
||||
.insert(entity_id);
|
||||
}
|
||||
|
||||
/// This can only be called for read-only queries, see
|
||||
/// [`Self::query_entity_mut`] for write-queries.
|
||||
pub fn query_entity<'w, Q: WorldQuery>(
|
||||
&'w mut self,
|
||||
entity_id: EntityId,
|
||||
) -> bevy_ecs::query::ROQueryItem<'w, Q> {
|
||||
let mut query = self.query_to_state::<Q>();
|
||||
query.get(&self.ecs, entity_id.into()).unwrap()
|
||||
}
|
||||
|
||||
pub fn query_entity_mut<'w, Q: WorldQuery>(&'w mut self, entity_id: EntityId) -> Q::Item<'w> {
|
||||
let mut query = self.query_to_state::<Q>();
|
||||
query.get_mut(&mut self.ecs, entity_id.into()).unwrap()
|
||||
}
|
||||
|
||||
/// Returns an [`EntityMut`] for the given entity ID.
|
||||
///
|
||||
/// You only need this if you're going to be adding new components to the
|
||||
/// entity. Otherwise, use [`Self::query_entity_mut`].
|
||||
pub fn ecs_entity_mut(&mut self, entity_id: EntityId) -> EntityMut {
|
||||
self.ecs.get_entity_mut(entity_id.into()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for WeakEntityStorage {
|
||||
|
|
|
@ -165,7 +165,7 @@ impl WeakWorld {
|
|||
}
|
||||
|
||||
pub fn query_entities<Q: WorldQuery>(&self) -> QueryState<Q, ()> {
|
||||
self.entity_storage.write().query::<Q>()
|
||||
self.entity_storage.write().query_to_state::<Q>()
|
||||
}
|
||||
|
||||
/// Set an entity's position in the world.
|
||||
|
@ -179,10 +179,8 @@ impl WeakWorld {
|
|||
new_pos: Vec3,
|
||||
) -> Result<(), MoveEntityError> {
|
||||
let mut entity_storage = self.entity_storage.write();
|
||||
let mut query = entity_storage.query::<(&mut Position, &mut Physics)>();
|
||||
let (pos, physics) = query
|
||||
.get_mut(&mut entity_storage.ecs, entity_id.into())
|
||||
.unwrap();
|
||||
let (pos, physics) =
|
||||
entity_storage.query_entity_mut::<(&mut Position, &mut Physics)>(entity_id);
|
||||
|
||||
self.set_entity_pos_from_refs(entity_id, new_pos, pos.into_inner(), physics.into_inner())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue