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

Rename "dimension" to "world" (#39)

* rename "dimension" to "world"

* Update mod.rs
This commit is contained in:
mat 2022-11-15 14:52:26 -06:00 committed by GitHub
parent b9da6f7475
commit 0d004b72ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 197 additions and 192 deletions

View file

@ -29,7 +29,7 @@ use azalea_protocol::{
};
use azalea_world::{
entity::{metadata, Entity, EntityData, EntityMetadata},
Dimension,
World,
};
use log::{debug, error, info, warn};
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
@ -87,7 +87,7 @@ pub struct Client {
pub read_conn: Arc<tokio::sync::Mutex<ReadConnection<ClientboundGamePacket>>>,
pub write_conn: Arc<tokio::sync::Mutex<WriteConnection<ServerboundGamePacket>>>,
pub player: Arc<RwLock<Player>>,
pub dimension: Arc<RwLock<Dimension>>,
pub world: Arc<RwLock<World>>,
pub physics_state: Arc<Mutex<PhysicsState>>,
pub client_information: Arc<RwLock<ClientInformation>>,
/// Plugins are a way for other crates to add custom functionality to the
@ -262,7 +262,7 @@ impl Client {
read_conn,
write_conn,
player: Arc::new(RwLock::new(Player::default())),
dimension: Arc::new(RwLock::new(Dimension::default())),
world: Arc::new(RwLock::new(World::default())),
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
client_information: Arc::new(RwLock::new(ClientInformation::default())),
// The plugins can be modified by the user by replacing the plugins
@ -414,17 +414,17 @@ impl Client {
.as_int()
.expect("min_y tag is not an int");
let mut dimension_lock = client.dimension.write();
let mut world_lock = client.world.write();
// the 16 here is our render distance
// i'll make this an actual setting later
*dimension_lock = Dimension::new(16, height, min_y);
*world_lock = World::new(16, height, min_y);
let entity = EntityData::new(
client.game_profile.uuid,
Vec3::default(),
EntityMetadata::Player(metadata::Player::default()),
);
dimension_lock.add_entity(p.player_id, entity);
world_lock.add_entity(p.player_id, entity);
let mut player_lock = client.player.write();
@ -497,9 +497,9 @@ impl Client {
player_lock.entity_id
};
let mut dimension_lock = client.dimension.write();
let mut world_lock = client.world.write();
let mut player_entity = dimension_lock
let mut player_entity = world_lock
.entity_mut(player_entity_id)
.expect("Player entity doesn't exist");
@ -553,7 +553,7 @@ impl Client {
y: new_pos_y,
z: new_pos_z,
};
dimension_lock
world_lock
.set_entity_pos(player_entity_id, new_pos)
.expect("The player entity should always exist");
@ -584,7 +584,7 @@ impl Client {
ClientboundGamePacket::SetChunkCacheCenter(p) => {
debug!("Got chunk cache center packet {:?}", p);
client
.dimension
.world
.write()
.update_view_center(&ChunkPos::new(p.x, p.z));
}
@ -594,7 +594,7 @@ impl Client {
// let chunk = Chunk::read_with_world_height(&mut p.chunk_data);
// debug("chunk {:?}")
if let Err(e) = client
.dimension
.world
.write()
.replace_with_packet_data(&pos, &mut Cursor::new(&p.chunk_data.data))
{
@ -607,12 +607,12 @@ impl Client {
ClientboundGamePacket::AddEntity(p) => {
debug!("Got add entity packet {:?}", p);
let entity = EntityData::from(p);
client.dimension.write().add_entity(p.id, entity);
client.world.write().add_entity(p.id, entity);
}
ClientboundGamePacket::SetEntityData(p) => {
debug!("Got set entity data packet {:?}", p);
let mut dimension = client.dimension.write();
if let Some(mut entity) = dimension.entity_mut(p.id) {
let mut world = client.world.write();
if let Some(mut entity) = world.entity_mut(p.id) {
entity.apply_metadata(&p.packed_items.0);
} else {
warn!("Server sent an entity data packet for an entity id ({}) that we don't know about", p.id);
@ -630,7 +630,7 @@ impl Client {
ClientboundGamePacket::AddPlayer(p) => {
debug!("Got add player packet {:?}", p);
let entity = EntityData::from(p);
client.dimension.write().add_entity(p.id, entity);
client.world.write().add_entity(p.id, entity);
}
ClientboundGamePacket::InitializeBorder(p) => {
debug!("Got initialize border packet {:?}", p);
@ -651,9 +651,9 @@ impl Client {
debug!("Got set experience packet {:?}", p);
}
ClientboundGamePacket::TeleportEntity(p) => {
let mut dimension_lock = client.dimension.write();
let mut world_lock = client.world.write();
dimension_lock
world_lock
.set_entity_pos(
p.id,
Vec3 {
@ -671,16 +671,16 @@ impl Client {
// debug!("Got rotate head packet {:?}", p);
}
ClientboundGamePacket::MoveEntityPos(p) => {
let mut dimension_lock = client.dimension.write();
let mut world_lock = client.world.write();
dimension_lock
world_lock
.move_entity_with_delta(p.entity_id, &p.delta)
.map_err(|e| HandleError::Other(e.into()))?;
}
ClientboundGamePacket::MoveEntityPosRot(p) => {
let mut dimension_lock = client.dimension.write();
let mut world_lock = client.world.write();
dimension_lock
world_lock
.move_entity_with_delta(p.entity_id, &p.delta)
.map_err(|e| HandleError::Other(e.into()))?;
}
@ -713,17 +713,17 @@ impl Client {
}
ClientboundGamePacket::BlockUpdate(p) => {
debug!("Got block update packet {:?}", p);
let mut dimension = client.dimension.write();
dimension.set_block_state(&p.pos, p.block_state);
let mut world = client.world.write();
world.set_block_state(&p.pos, p.block_state);
}
ClientboundGamePacket::Animate(p) => {
debug!("Got animate packet {:?}", p);
}
ClientboundGamePacket::SectionBlocksUpdate(p) => {
debug!("Got section blocks update packet {:?}", p);
let mut dimension = client.dimension.write();
let mut world = client.world.write();
for state in &p.states {
dimension.set_block_state(&(p.section_pos + state.pos.clone()), state.state);
world.set_block_state(&(p.section_pos + state.pos.clone()), state.state);
}
}
ClientboundGamePacket::GameEvent(p) => {
@ -819,16 +819,16 @@ impl Client {
async fn game_tick(client: &mut Client, tx: &UnboundedSender<Event>) {
// return if there's no chunk at the player's position
{
let dimension_lock = client.dimension.write();
let world_lock = client.world.write();
let player_lock = client.player.write();
let player_entity = player_lock.entity(&dimension_lock);
let player_entity = player_lock.entity(&world_lock);
let player_entity = if let Some(player_entity) = player_entity {
player_entity
} else {
return;
};
let player_chunk_pos: ChunkPos = player_entity.pos().into();
if dimension_lock[&player_chunk_pos].is_none() {
if world_lock[&player_chunk_pos].is_none() {
return;
}
}
@ -846,43 +846,43 @@ impl Client {
}
/// Returns the entity associated to the player.
pub fn entity_mut(&self) -> Entity<RwLockWriteGuard<Dimension>> {
pub fn entity_mut(&self) -> Entity<RwLockWriteGuard<World>> {
let entity_id = {
let player_lock = self.player.write();
player_lock.entity_id
};
let mut dimension = self.dimension.write();
let mut world = self.world.write();
let entity_data = dimension
let entity_data = world
.entity_storage
.get_mut_by_id(entity_id)
.expect("Player entity should exist");
let entity_ptr = unsafe { entity_data.as_ptr() };
Entity::new(dimension, entity_id, entity_ptr)
Entity::new(world, entity_id, entity_ptr)
}
/// Returns the entity associated to the player.
pub fn entity(&self) -> Entity<RwLockReadGuard<Dimension>> {
pub fn entity(&self) -> Entity<RwLockReadGuard<World>> {
let entity_id = {
let player_lock = self.player.read();
player_lock.entity_id
};
let dimension = self.dimension.read();
let world = self.world.read();
let entity_data = dimension
let entity_data = world
.entity_storage
.get_by_id(entity_id)
.expect("Player entity should be in the given dimension");
.expect("Player entity should be in the given world");
let entity_ptr = unsafe { entity_data.as_const_ptr() };
Entity::new(dimension, entity_id, entity_ptr)
Entity::new(world, entity_id, entity_ptr)
}
/// Returns whether we have a received the login packet yet.
pub fn logged_in(&self) -> bool {
let dimension = self.dimension.read();
let world = self.world.read();
let player = self.player.write();
player.entity(&dimension).is_some()
player.entity(&world).is_some()
}
/// Tell the server we changed our game options (i.e. render distance, main hand).

View file

@ -154,19 +154,19 @@ impl Client {
// Set our current position to the provided Vec3, potentially clipping through blocks.
pub async fn set_pos(&mut self, new_pos: Vec3) -> Result<(), MovePlayerError> {
let player_lock = self.player.write();
let mut dimension_lock = self.dimension.write();
let mut world_lock = self.world.write();
dimension_lock.set_entity_pos(player_lock.entity_id, new_pos)?;
world_lock.set_entity_pos(player_lock.entity_id, new_pos)?;
Ok(())
}
pub async fn move_entity(&mut self, movement: &Vec3) -> Result<(), MovePlayerError> {
let mut dimension_lock = self.dimension.write();
let mut world_lock = self.world.write();
let player = self.player.write();
let mut entity = player
.entity_mut(&mut dimension_lock)
.entity_mut(&mut world_lock)
.ok_or(MovePlayerError::PlayerNotInWorld)?;
log::trace!(
"move entity bounding box: {} {:?}",

View file

@ -1,13 +1,13 @@
use azalea_world::entity::Entity;
use azalea_world::Dimension;
use azalea_world::World;
use uuid::Uuid;
/// Something that has a dimension associated to it. Usually, this is a `Client`.
pub trait DimensionHaver {
fn dimension(&self) -> &Dimension;
/// Something that has a world associated to it. Usually, this is a `Client`.
pub trait WorldHaver {
fn world(&self) -> &World;
}
/// A player in the dimension or tab list.
/// A player in the world or tab list.
#[derive(Default, Debug)]
pub struct Player {
/// The player's uuid.
@ -18,13 +18,13 @@ pub struct Player {
impl Player {
/// Get a reference to the entity of the player in the world.
pub fn entity<'d>(&'d self, dimension: &'d Dimension) -> Option<Entity<&Dimension>> {
dimension.entity(self.entity_id)
pub fn entity<'d>(&'d self, world: &'d World) -> Option<Entity<&World>> {
world.entity(self.entity_id)
}
/// Get a mutable reference to the entity of the player in the world.
pub fn entity_mut<'d>(&'d self, dimension: &'d mut Dimension) -> Option<Entity> {
dimension.entity_mut(self.entity_id)
pub fn entity_mut<'d>(&'d self, world: &'d mut World) -> Option<Entity> {
world.entity_mut(self.entity_id)
}
pub fn set_uuid(&mut self, uuid: Uuid) {

View file

@ -197,12 +197,12 @@ impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
}
}
/// A block pos with an attached dimension
/// A block pos with an attached world
#[derive(Debug, Clone)]
pub struct GlobalPos {
pub pos: BlockPos,
// this is actually a ResourceKey in Minecraft, but i don't think it matters?
pub dimension: ResourceLocation,
pub world: ResourceLocation,
}
impl From<&BlockPos> for ChunkPos {
@ -297,7 +297,7 @@ impl McBufReadable for BlockPos {
impl McBufReadable for GlobalPos {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(GlobalPos {
dimension: ResourceLocation::read_from(buf)?,
world: ResourceLocation::read_from(buf)?,
pos: BlockPos::read_from(buf)?,
})
}
@ -326,7 +326,7 @@ impl McBufWritable for BlockPos {
impl McBufWritable for GlobalPos {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
ResourceLocation::write_into(&self.dimension, buf)?;
ResourceLocation::write_into(&self.world, buf)?;
BlockPos::write_into(&self.pos, buf)?;
Ok(())

View file

@ -1,18 +1,18 @@
mod blocks;
mod dimension_collisions;
mod discrete_voxel_shape;
mod mergers;
mod shape;
mod world_collisions;
use std::ops::DerefMut;
use azalea_core::{Axis, Vec3, AABB, EPSILON};
use azalea_world::entity::{Entity, EntityData};
use azalea_world::{Dimension, MoveEntityError};
use azalea_world::{MoveEntityError, World};
pub use blocks::BlockWithShape;
use dimension_collisions::CollisionGetter;
pub use discrete_voxel_shape::*;
pub use shape::*;
use world_collisions::CollisionGetter;
pub enum MoverType {
Own,
@ -34,7 +34,7 @@ pub trait MovableEntity {
) -> Result<(), MoveEntityError>;
}
impl HasCollision for Dimension {
impl HasCollision for World {
// private Vec3 collide(Vec3 var1) {
// AABB var2 = this.getBoundingBox();
// List var3 = this.level.getEntityCollisions(this, var2.expandTowards(var1));
@ -63,7 +63,7 @@ impl HasCollision for Dimension {
fn collide(&self, movement: &Vec3, entity: &EntityData) -> Vec3 {
let entity_bounding_box = entity.bounding_box;
// TODO: get_entity_collisions
// let entity_collisions = dimension.get_entity_collisions(self, entity_bounding_box.expand_towards(movement));
// let entity_collisions = world.get_entity_collisions(self, entity_bounding_box.expand_towards(movement));
let entity_collisions = Vec::new();
if movement.length_sqr() == 0.0 {
*movement
@ -83,7 +83,7 @@ impl HasCollision for Dimension {
}
}
impl<D: DerefMut<Target = Dimension>> MovableEntity for Entity<'_, D> {
impl<D: DerefMut<Target = World>> MovableEntity for Entity<'_, D> {
/// Move an entity by a given delta, checking for collisions.
fn move_colliding(
&mut self,
@ -111,7 +111,7 @@ impl<D: DerefMut<Target = Dimension>> MovableEntity for Entity<'_, D> {
// movement = this.maybeBackOffFromEdge(movement, moverType);
let collide_result = { self.dimension.collide(movement, self) };
let collide_result = { self.world.collide(movement, self) };
let move_distance = collide_result.length_sqr();
@ -127,7 +127,7 @@ impl<D: DerefMut<Target = Dimension>> MovableEntity for Entity<'_, D> {
}
};
self.dimension.set_entity_pos(self.id, new_pos)?;
self.world.set_entity_pos(self.id, new_pos)?;
}
let x_collision = movement.x != collide_result.x;
@ -141,7 +141,7 @@ impl<D: DerefMut<Target = Dimension>> MovableEntity for Entity<'_, D> {
let _block_pos_below = self.on_pos_legacy();
// let _block_state_below = self
// .dimension
// .world
// .get_block_state(&block_pos_below)
// .expect("Couldn't get block state below");
@ -198,7 +198,7 @@ fn collide_bounding_box(
entity: Option<&EntityData>,
movement: &Vec3,
entity_bounding_box: &AABB,
dimension: &Dimension,
world: &World,
entity_collisions: Vec<VoxelShape>,
) -> Vec3 {
let mut collision_boxes: Vec<VoxelShape> = Vec::with_capacity(entity_collisions.len() + 1);
@ -210,7 +210,7 @@ fn collide_bounding_box(
// TODO: world border
let block_collisions =
dimension.get_block_collisions(entity, entity_bounding_box.expand_towards(movement));
world.get_block_collisions(entity, entity_bounding_box.expand_towards(movement));
let block_collisions = block_collisions.collect::<Vec<_>>();
collision_boxes.extend(block_collisions);
collide_with_shapes(movement, *entity_bounding_box, &collision_boxes)

View file

@ -2,7 +2,7 @@ use crate::collision::{BlockWithShape, VoxelShape, AABB};
use azalea_block::BlockState;
use azalea_core::{ChunkPos, ChunkSectionPos, Cursor3d, CursorIterationType, EPSILON};
use azalea_world::entity::EntityData;
use azalea_world::{Chunk, Dimension};
use azalea_world::{Chunk, World};
use parking_lot::Mutex;
use std::sync::Arc;
@ -16,7 +16,7 @@ pub trait CollisionGetter {
) -> BlockCollisions<'a>;
}
impl CollisionGetter for Dimension {
impl CollisionGetter for World {
fn get_block_collisions<'a>(
&'a self,
entity: Option<&EntityData>,
@ -27,7 +27,7 @@ impl CollisionGetter for Dimension {
}
pub struct BlockCollisions<'a> {
pub dimension: &'a Dimension,
pub world: &'a World,
// context: CollisionContext,
pub aabb: AABB,
pub entity_shape: VoxelShape,
@ -37,7 +37,7 @@ pub struct BlockCollisions<'a> {
impl<'a> BlockCollisions<'a> {
// TODO: the entity is stored in the context
pub fn new(dimension: &'a Dimension, _entity: Option<&EntityData>, aabb: AABB) -> Self {
pub fn new(world: &'a World, _entity: Option<&EntityData>, aabb: AABB) -> Self {
let origin_x = (aabb.min_x - EPSILON) as i32 - 1;
let origin_y = (aabb.min_y - EPSILON) as i32 - 1;
let origin_z = (aabb.min_z - EPSILON) as i32 - 1;
@ -49,7 +49,7 @@ impl<'a> BlockCollisions<'a> {
let cursor = Cursor3d::new(origin_x, origin_y, origin_z, end_x, end_y, end_z);
Self {
dimension,
world,
aabb,
entity_shape: VoxelShape::from(aabb),
cursor,
@ -75,7 +75,7 @@ impl<'a> BlockCollisions<'a> {
// return var7;
// }
self.dimension[&chunk_pos].as_ref()
self.world[&chunk_pos].as_ref()
}
}
@ -97,7 +97,7 @@ impl<'a> Iterator for BlockCollisions<'a> {
let pos = item.pos;
let block_state: BlockState = chunk
.lock()
.get(&(&pos).into(), self.dimension.min_y())
.get(&(&pos).into(), self.world.min_y())
.unwrap_or(BlockState::Air);
// TODO: continue if self.only_suffocating_blocks and the block is not suffocating

View file

@ -8,7 +8,7 @@ use azalea_block::{Block, BlockState};
use azalea_core::{BlockPos, Vec3};
use azalea_world::{
entity::{Entity, EntityData},
Dimension,
World,
};
use collision::{MovableEntity, MoverType};
@ -19,7 +19,7 @@ pub trait HasPhysics {
fn jump_from_ground(&mut self);
}
impl<D: DerefMut<Target = Dimension>> HasPhysics for Entity<'_, D> {
impl<D: DerefMut<Target = World>> HasPhysics for Entity<'_, D> {
/// Move the entity with the given acceleration while handling friction,
/// gravity, collisions, and some other stuff.
fn travel(&mut self, acceleration: &Vec3) {
@ -40,7 +40,7 @@ impl<D: DerefMut<Target = Dimension>> HasPhysics for Entity<'_, D> {
let block_pos_below = get_block_pos_below_that_affects_movement(self);
let block_state_below = self
.dimension
.world
.get_block_state(&block_pos_below)
.unwrap_or(BlockState::Air);
let block_below: Box<dyn Block> = block_state_below.into();
@ -142,7 +142,7 @@ fn get_block_pos_below_that_affects_movement(entity: &EntityData) -> BlockPos {
)
}
fn handle_relative_friction_and_calculate_movement<D: DerefMut<Target = Dimension>>(
fn handle_relative_friction_and_calculate_movement<D: DerefMut<Target = World>>(
entity: &mut Entity<D>,
acceleration: &Vec3,
block_friction: f32,
@ -181,10 +181,10 @@ fn get_friction_influenced_speed(entity: &EntityData, friction: f32) -> f32 {
/// Returns the what the entity's jump should be multiplied by based on the
/// block they're standing on.
fn block_jump_factor<D: DerefMut<Target = Dimension>>(entity: &Entity<D>) -> f32 {
let block_at_pos = entity.dimension.get_block_state(&entity.pos().into());
fn block_jump_factor<D: DerefMut<Target = World>>(entity: &Entity<D>) -> f32 {
let block_at_pos = entity.world.get_block_state(&entity.pos().into());
let block_below = entity
.dimension
.world
.get_block_state(&get_block_pos_below_that_affects_movement(entity));
let block_at_pos_jump_factor = if let Some(block) = block_at_pos {
@ -209,11 +209,11 @@ fn block_jump_factor<D: DerefMut<Target = Dimension>>(entity: &Entity<D>) -> f32
// public double getJumpBoostPower() {
// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F * (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
// }
fn jump_power<D: DerefMut<Target = Dimension>>(entity: &Entity<D>) -> f32 {
fn jump_power<D: DerefMut<Target = World>>(entity: &Entity<D>) -> f32 {
0.42 * block_jump_factor(entity)
}
fn jump_boost_power<D: DerefMut<Target = Dimension>>(_entity: &Entity<D>) -> f64 {
fn jump_boost_power<D: DerefMut<Target = World>>(_entity: &Entity<D>) -> f64 {
// TODO: potion effects
// if let Some(effects) = entity.effects() {
// if let Some(jump_effect) = effects.get(&Effect::Jump) {
@ -231,14 +231,14 @@ fn jump_boost_power<D: DerefMut<Target = Dimension>>(_entity: &Entity<D>) -> f64
mod tests {
use super::*;
use azalea_core::ChunkPos;
use azalea_world::{Chunk, Dimension};
use azalea_world::{Chunk, World};
use uuid::Uuid;
#[test]
fn test_gravity() {
let mut dim = Dimension::default();
let mut world = World::default();
dim.add_entity(
world.add_entity(
0,
EntityData::new(
Uuid::from_u128(0),
@ -249,7 +249,7 @@ mod tests {
},
),
);
let mut entity = dim.entity_mut(0).unwrap();
let mut entity = world.entity_mut(0).unwrap();
// y should start at 70
assert_eq!(entity.pos().y, 70.);
entity.ai_step();
@ -266,10 +266,11 @@ mod tests {
}
#[test]
fn test_collision() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.add_entity(
world.add_entity(
0,
EntityData::new(
Uuid::from_u128(0),
@ -280,12 +281,12 @@ mod tests {
},
),
);
let block_state = dim.set_block_state(&BlockPos { x: 0, y: 69, z: 0 }, BlockState::Stone);
let block_state = world.set_block_state(&BlockPos { x: 0, y: 69, z: 0 }, BlockState::Stone);
assert!(
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = dim.entity_mut(0).unwrap();
let mut entity = world.entity_mut(0).unwrap();
entity.ai_step();
// delta will change, but it won't move until next tick
assert_eq!(entity.pos().y, 70.);
@ -297,10 +298,11 @@ mod tests {
#[test]
fn test_slab_collision() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.add_entity(
world.add_entity(
0,
EntityData::new(
Uuid::from_u128(0),
@ -311,7 +313,7 @@ mod tests {
},
),
);
let block_state = dim.set_block_state(
let block_state = world.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::StoneSlab_BottomFalse,
);
@ -319,7 +321,7 @@ mod tests {
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = dim.entity_mut(0).unwrap();
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();
@ -329,10 +331,11 @@ mod tests {
#[test]
fn test_top_slab_collision() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.add_entity(
world.add_entity(
0,
EntityData::new(
Uuid::from_u128(0),
@ -343,7 +346,7 @@ mod tests {
},
),
);
let block_state = dim.set_block_state(
let block_state = world.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::StoneSlab_TopFalse,
);
@ -351,7 +354,7 @@ mod tests {
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = dim.entity_mut(0).unwrap();
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();
@ -361,10 +364,11 @@ mod tests {
#[test]
fn test_weird_wall_collision() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.add_entity(
world.add_entity(
0,
EntityData::new(
Uuid::from_u128(0),
@ -375,7 +379,7 @@ mod tests {
},
),
);
let block_state = dim.set_block_state(
let block_state = world.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::CobblestoneWall_LowLowLowFalseFalseLow,
);
@ -383,7 +387,7 @@ mod tests {
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = dim.entity_mut(0).unwrap();
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();

View file

@ -1,6 +1,6 @@
use crate::palette::PalettedContainer;
use crate::palette::PalettedContainerType;
use crate::Dimension;
use crate::World;
use azalea_block::BlockState;
use azalea_buf::BufReadError;
use azalea_buf::{McBufReadable, McBufWritable};
@ -143,7 +143,7 @@ impl IndexMut<&ChunkPos> for ChunkStorage {
impl Chunk {
pub fn read_with_dimension(
buf: &mut Cursor<&[u8]>,
data: &Dimension,
data: &World,
) -> Result<Self, BufReadError> {
Self::read_with_dimension_height(buf, data.height())
}

View file

@ -5,7 +5,7 @@ pub mod metadata;
use self::attributes::{AttributeInstance, AttributeModifiers};
pub use self::metadata::EntityMetadata;
use crate::Dimension;
use crate::World;
use azalea_block::BlockState;
use azalea_core::{BlockPos, Vec3, AABB};
pub use data::*;
@ -15,22 +15,22 @@ use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use uuid::Uuid;
/// A reference to an entity in a dimension.
/// A reference to an entity in a world.
#[derive(Debug)]
pub struct Entity<'d, D = &'d mut Dimension> {
/// The dimension this entity is in.
pub dimension: D,
pub struct Entity<'d, D = &'d mut World> {
/// The world this entity is in.
pub world: D,
/// The incrementing numerical id of the entity.
pub id: u32,
pub data: NonNull<EntityData>,
_marker: PhantomData<&'d ()>,
}
impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
pub fn new(dimension: D, id: u32, data: NonNull<EntityData>) -> Self {
impl<'d, D: Deref<Target = World>> Entity<'d, D> {
pub fn new(world: D, id: u32, data: NonNull<EntityData>) -> Self {
// TODO: have this be based on the entity type
Self {
dimension,
world,
id,
data,
_marker: PhantomData,
@ -38,12 +38,12 @@ impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
}
}
impl<'d, D: DerefMut<Target = Dimension>> Entity<'d, D> {
impl<'d, D: DerefMut<Target = World>> Entity<'d, D> {
/// Sets the position of the entity. This doesn't update the cache in
/// azalea-world, and should only be used within azalea-world!
///
/// # Safety
/// Cached position in the dimension must be updated.
/// Cached position in the world must be updated.
pub unsafe fn move_unchecked(&mut self, new_pos: Vec3) {
self.pos = new_pos;
let bounding_box = self.make_bounding_box();
@ -94,7 +94,7 @@ impl<'d, D: DerefMut<Target = Dimension>> Entity<'d, D> {
}
}
impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
impl<'d, D: Deref<Target = World>> Entity<'d, D> {
#[inline]
pub fn pos(&self) -> &Vec3 {
&self.pos
@ -129,10 +129,10 @@ impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
// TODO: check if block below is a fence, wall, or fence gate
let block_pos = pos.down(1);
let block_state = self.dimension.get_block_state(&block_pos);
let block_state = self.world.get_block_state(&block_pos);
if block_state == Some(BlockState::Air) {
let block_pos_below = block_pos.down(1);
let block_state_below = self.dimension.get_block_state(&block_pos_below);
let block_state_below = self.world.get_block_state(&block_pos_below);
if let Some(_block_state_below) = block_state_below {
// if block_state_below.is_fence()
// || block_state_below.is_wall()
@ -149,13 +149,13 @@ impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
// impl<
// 'd,
// D: DerefMut<Target = Dimension> + Deref<Target = Dimension>,
// D2: Deref<Target = Dimension>,
// D: DerefMut<Target = World> + Deref<Target = World>,
// D2: Deref<Target = World>,
// > From<Entity<'d, D>> for Entity<'d, D2>
// {
// fn from(entity: Entity<'d, D>) -> Entity<'d, D> {
// Entity {
// dimension: entity.dimension,
// world: entity.world,
// id: entity.id,
// data: entity.data,
// _marker: PhantomData,
@ -163,13 +163,13 @@ impl<'d, D: Deref<Target = Dimension>> Entity<'d, D> {
// }
// }
impl<D: DerefMut<Target = Dimension>> DerefMut for Entity<'_, D> {
impl<D: DerefMut<Target = World>> DerefMut for Entity<'_, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.data.as_mut() }
}
}
impl<D: Deref<Target = Dimension>> Deref for Entity<'_, D> {
impl<D: Deref<Target = World>> Deref for Entity<'_, D> {
type Target = EntityData;
fn deref(&self) -> &Self::Target {
@ -181,7 +181,7 @@ impl<D: Deref<Target = Dimension>> Deref for Entity<'_, D> {
pub struct EntityData {
pub uuid: Uuid,
/// The position of the entity right now.
/// This can be changde with unsafe_move, but the correct way is with dimension.move_entity
/// This can be changde with unsafe_move, but the correct way is with world.move_entity
pos: Vec3,
/// The position of the entity last tick.
pub last_pos: Vec3,
@ -264,7 +264,7 @@ impl EntityData {
}
}
/// Get the position of the entity in the dimension.
/// Get the position of the entity in the world.
#[inline]
pub fn pos(&self) -> &Vec3 {
&self.pos
@ -295,9 +295,9 @@ mod tests {
#[test]
fn from_mut_entity_to_ref_entity() {
let mut dim = Dimension::default();
let mut world = World::default();
let uuid = Uuid::from_u128(100);
dim.add_entity(
world.add_entity(
0,
EntityData::new(
uuid,
@ -305,7 +305,7 @@ mod tests {
EntityMetadata::Player(metadata::Player::default()),
),
);
let entity: Entity = dim.entity_mut(0).unwrap();
let entity: Entity = world.entity_mut(0).unwrap();
let entity_ref = Entity::from(entity);
assert_eq!(entity_ref.uuid, uuid);
}

View file

@ -22,10 +22,9 @@ use std::{
use thiserror::Error;
use uuid::Uuid;
/// A dimension is a collection of chunks and entities.
/// Minecraft calls these "Levels", Fabric calls them "Worlds", Minestom calls them "Instances".
/// A world is a collection of chunks and entities. They're called "levels" in Minecraft's source code.
#[derive(Debug, Default)]
pub struct Dimension {
pub struct World {
pub chunk_storage: ChunkStorage,
pub entity_storage: EntityStorage,
}
@ -36,9 +35,9 @@ pub enum MoveEntityError {
EntityDoesNotExist,
}
impl Dimension {
impl World {
pub fn new(chunk_radius: u32, height: u32, min_y: i32) -> Self {
Dimension {
World {
chunk_storage: ChunkStorage::new(chunk_radius, height, min_y),
entity_storage: EntityStorage::new(),
}
@ -127,13 +126,13 @@ impl Dimension {
self.entity_storage.get_mut_by_id(id)
}
pub fn entity(&self, id: u32) -> Option<Entity<&Dimension>> {
pub fn entity(&self, id: u32) -> Option<Entity<&World>> {
let entity_data = self.entity_storage.get_by_id(id)?;
let entity_ptr = unsafe { entity_data.as_const_ptr() };
Some(Entity::new(self, id, entity_ptr))
}
pub fn entity_mut(&mut self, id: u32) -> Option<Entity<'_, &mut Dimension>> {
pub fn entity_mut(&mut self, id: u32) -> Option<Entity<'_, &mut World>> {
let entity_data = self.entity_storage.get_mut_by_id(id)?;
let entity_ptr = unsafe { entity_data.as_ptr() };
Some(Entity::new(self, id, entity_ptr))
@ -157,14 +156,14 @@ impl Dimension {
}
}
impl Index<&ChunkPos> for Dimension {
impl Index<&ChunkPos> for World {
type Output = Option<Arc<Mutex<Chunk>>>;
fn index(&self, pos: &ChunkPos) -> &Self::Output {
&self.chunk_storage[pos]
}
}
impl IndexMut<&ChunkPos> for Dimension {
impl IndexMut<&ChunkPos> for World {
fn index_mut<'a>(&'a mut self, pos: &ChunkPos) -> &'a mut Self::Output {
&mut self.chunk_storage[pos]
}

View file

@ -49,7 +49,7 @@ async fn deposit(bot: &mut Client, state: State) -> anyhow::Result<()> {
bot.goto(Vec3::new(0, 70, 0)).await?;
let chest = bot
.open_container(&bot.dimension.block_at(BlockPos::new(0, 70, 0)))
.open_container(&bot.world.block_at(BlockPos::new(0, 70, 0)))
.await
.unwrap();

View file

@ -36,10 +36,7 @@ async fn swarm_handle(swarm: Swarm, event: Event, state: State) {
match event {
Event::Tick => {
// choose an arbitrary player within render distance to target
if let Some(target) = swarm
.dimension
.find_one_entity(|e| e.id == "minecraft:player")
{
if let Some(target) = swarm.world.find_one_entity(|e| e.id == "minecraft:player") {
for bot in swarm {
bot.tick_goto_goal(pathfinder::Goals::Reach(target.bounding_box));
// if target.bounding_box.distance(bot.eyes) < bot.reach_distance() {

View file

@ -74,11 +74,11 @@ impl Trait for azalea_client::Client {
let successors = |node: &Node| {
let mut edges = Vec::new();
let dimension = self.dimension.read();
let world = self.world.read();
for possible_move in possible_moves.iter() {
edges.push(Edge {
target: possible_move.next_node(node),
cost: possible_move.cost(&dimension, node),
cost: possible_move.cost(&world, node),
});
}
edges

View file

@ -1,11 +1,11 @@
use super::{Node, VerticalVel};
use azalea_core::{BlockPos, CardinalDirection};
use azalea_physics::collision::{self, BlockWithShape};
use azalea_world::Dimension;
use azalea_world::World;
/// whether this block is passable
fn is_block_passable(pos: &BlockPos, dim: &Dimension) -> bool {
if let Some(block) = dim.get_block_state(pos) {
fn is_block_passable(pos: &BlockPos, world: &World) -> bool {
if let Some(block) = world.get_block_state(pos) {
block.shape() == &collision::empty_shape()
} else {
false
@ -13,8 +13,8 @@ fn is_block_passable(pos: &BlockPos, dim: &Dimension) -> bool {
}
/// whether this block has a solid hitbox (i.e. we can stand on it)
fn is_block_solid(pos: &BlockPos, dim: &Dimension) -> bool {
if let Some(block) = dim.get_block_state(pos) {
fn is_block_solid(pos: &BlockPos, world: &World) -> bool {
if let Some(block) = world.get_block_state(pos) {
block.shape() == &collision::block_shape()
} else {
false
@ -22,21 +22,22 @@ fn is_block_solid(pos: &BlockPos, dim: &Dimension) -> bool {
}
/// Whether this block and the block above are passable
fn is_passable(pos: &BlockPos, dim: &Dimension) -> bool {
is_block_passable(pos, dim) && is_block_passable(&pos.up(1), dim)
fn is_passable(pos: &BlockPos, world: &World) -> bool {
is_block_passable(pos, world) && is_block_passable(&pos.up(1), world)
}
/// Whether we can stand in this position. Checks if the block below is solid,
/// and that the two blocks above that are passable.
fn is_standable(pos: &BlockPos, dim: &Dimension) -> bool {
is_block_solid(&pos.down(1), dim) && is_passable(pos, dim)
fn is_standable(pos: &BlockPos, world: &World) -> bool {
is_block_solid(&pos.down(1), world) && is_passable(pos, world)
}
const JUMP_COST: f32 = 0.5;
const WALK_ONE_BLOCK_COST: f32 = 1.0;
pub trait Move {
fn cost(&self, dim: &Dimension, node: &Node) -> f32;
fn cost(&self, world: &World, node: &Node) -> f32;
/// Returns by how much the entity's position should be changed when this move is executed.
fn offset(&self) -> BlockPos;
fn next_node(&self, node: &Node) -> Node {
@ -49,8 +50,9 @@ pub trait Move {
pub struct ForwardMove(pub CardinalDirection);
impl Move for ForwardMove {
fn cost(&self, dim: &Dimension, node: &Node) -> f32 {
if is_standable(&(node.pos + self.offset()), dim) && node.vertical_vel == VerticalVel::None
fn cost(&self, world: &World, node: &Node) -> f32 {
if is_standable(&(node.pos + self.offset()), world)
&& node.vertical_vel == VerticalVel::None
{
WALK_ONE_BLOCK_COST
} else {
@ -64,10 +66,10 @@ impl Move for ForwardMove {
pub struct AscendMove(pub CardinalDirection);
impl Move for AscendMove {
fn cost(&self, dim: &Dimension, node: &Node) -> f32 {
fn cost(&self, world: &World, node: &Node) -> f32 {
if node.vertical_vel == VerticalVel::None
&& is_block_passable(&node.pos.up(2), dim)
&& is_standable(&(node.pos + self.offset()), dim)
&& is_block_passable(&node.pos.up(2), world)
&& is_standable(&(node.pos + self.offset()), world)
{
WALK_ONE_BLOCK_COST + JUMP_COST
} else {
@ -86,11 +88,11 @@ impl Move for AscendMove {
}
pub struct DescendMove(pub CardinalDirection);
impl Move for DescendMove {
fn cost(&self, dim: &Dimension, node: &Node) -> f32 {
fn cost(&self, world: &World, node: &Node) -> f32 {
// check whether 3 blocks vertically forward are passable
if node.vertical_vel == VerticalVel::None
&& is_standable(&(node.pos + self.offset()), dim)
&& is_block_passable(&(node.pos + self.offset().up(2)), dim)
&& is_standable(&(node.pos + self.offset()), world)
&& is_block_passable(&(node.pos + self.offset().up(2)), world)
{
WALK_ONE_BLOCK_COST
} else {
@ -109,24 +111,24 @@ impl Move for DescendMove {
}
pub struct DiagonalMove(pub CardinalDirection);
impl Move for DiagonalMove {
fn cost(&self, dim: &Dimension, node: &Node) -> f32 {
fn cost(&self, world: &World, node: &Node) -> f32 {
if node.vertical_vel != VerticalVel::None {
return f32::INFINITY;
}
if !is_passable(
&BlockPos::new(node.pos.x + self.0.x(), node.pos.y, node.pos.z + self.0.z()),
dim,
world,
) && !is_passable(
&BlockPos::new(
node.pos.x + self.0.right().x(),
node.pos.y,
node.pos.z + self.0.right().z(),
),
dim,
world,
) {
return f32::INFINITY;
}
if !is_standable(&(node.pos + self.offset()), dim) {
if !is_standable(&(node.pos + self.offset()), world) {
return f32::INFINITY;
}
WALK_ONE_BLOCK_COST * 1.4
@ -152,40 +154,43 @@ mod tests {
#[test]
fn test_is_passable() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
dim.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
world.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
world.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
assert_eq!(is_block_passable(&BlockPos::new(0, 0, 0), &dim), false);
assert_eq!(is_block_passable(&BlockPos::new(0, 1, 0), &dim), true);
assert_eq!(is_block_passable(&BlockPos::new(0, 0, 0), &world), false);
assert_eq!(is_block_passable(&BlockPos::new(0, 1, 0), &world), true);
}
#[test]
fn test_is_solid() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
dim.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
world.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
world.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
assert_eq!(is_block_solid(&BlockPos::new(0, 0, 0), &dim), true);
assert_eq!(is_block_solid(&BlockPos::new(0, 1, 0), &dim), false);
assert_eq!(is_block_solid(&BlockPos::new(0, 0, 0), &world), true);
assert_eq!(is_block_solid(&BlockPos::new(0, 1, 0), &world), false);
}
#[test]
fn test_is_standable() {
let mut dim = Dimension::default();
dim.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
let mut world = World::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
dim.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
dim.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
dim.set_block_state(&BlockPos::new(0, 2, 0), BlockState::Air);
dim.set_block_state(&BlockPos::new(0, 3, 0), BlockState::Air);
world.set_block_state(&BlockPos::new(0, 0, 0), BlockState::Stone);
world.set_block_state(&BlockPos::new(0, 1, 0), BlockState::Air);
world.set_block_state(&BlockPos::new(0, 2, 0), BlockState::Air);
world.set_block_state(&BlockPos::new(0, 3, 0), BlockState::Air);
assert!(is_standable(&BlockPos::new(0, 1, 0), &dim));
assert!(!is_standable(&BlockPos::new(0, 0, 0), &dim));
assert!(!is_standable(&BlockPos::new(0, 2, 0), &dim));
assert!(is_standable(&BlockPos::new(0, 1, 0), &world));
assert!(!is_standable(&BlockPos::new(0, 0, 0), &world));
assert!(!is_standable(&BlockPos::new(0, 2, 0), &world));
}
}

View file

@ -59,7 +59,7 @@ async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()>
println!("{}", m.message().to_ansi(None));
if m.message().to_string() == "<py5> goto" {
let target_pos_vec3 = *(bot
.dimension
.world
.read()
.entity_by_uuid(&uuid::uuid!("6536bfed869548fd83a1ecd24cf2a0fd"))
.unwrap()