mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
merge
This commit is contained in:
commit
8397fc8445
23 changed files with 295 additions and 254 deletions
|
@ -1,13 +1,32 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
//! Implementations of chat-related features.
|
||||
|
||||
use crate::Client;
|
||||
use azalea_chat::Component;
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol::packets::game::{
|
||||
clientbound_player_chat_packet::LastSeenMessagesUpdate,
|
||||
clientbound_player_chat_packet::{ClientboundPlayerChatPacket, LastSeenMessagesUpdate},
|
||||
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
serverbound_chat_command_packet::ServerboundChatCommandPacket,
|
||||
serverbound_chat_packet::ServerboundChatPacket,
|
||||
};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::Client;
|
||||
/// A chat packet, either a system message or a chat message.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ChatPacket {
|
||||
System(ClientboundSystemChatPacket),
|
||||
Player(Box<ClientboundPlayerChatPacket>),
|
||||
}
|
||||
|
||||
impl ChatPacket {
|
||||
/// Get the message shown in chat for this packet.
|
||||
pub fn message(&self) -> Component {
|
||||
match self {
|
||||
ChatPacket::System(p) => p.content.clone(),
|
||||
ChatPacket::Player(p) => p.message(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Sends chat message to the server. This only sends the chat packet and
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
pub use crate::chat::ChatPacket;
|
||||
use crate::{movement::WalkDirection, plugins::Plugins, Account, Player};
|
||||
use azalea_auth::game_profile::GameProfile;
|
||||
use azalea_chat::Component;
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
use azalea_protocol::{
|
||||
connect::{Connection, ConnectionError, ReadConnection, WriteConnection},
|
||||
packets::{
|
||||
game::{
|
||||
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket,
|
||||
serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
|
@ -32,7 +30,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};
|
||||
|
@ -66,23 +64,6 @@ pub enum Event {
|
|||
Packet(Box<ClientboundGamePacket>),
|
||||
}
|
||||
|
||||
/// A chat packet, either a system message or a chat message.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ChatPacket {
|
||||
System(ClientboundSystemChatPacket),
|
||||
Player(Box<ClientboundPlayerChatPacket>),
|
||||
}
|
||||
|
||||
impl ChatPacket {
|
||||
/// Get the message shown in chat for this packet.
|
||||
pub fn message(&self) -> Component {
|
||||
match self {
|
||||
ChatPacket::System(p) => p.content.clone(),
|
||||
ChatPacket::Player(p) => p.message(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A player that you control that is currently in a Minecraft server.
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
|
@ -90,9 +71,9 @@ 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>>,
|
||||
/// Whether there's multiple clients sharing the same dimension.
|
||||
pub dimension_shared: Arc<RwLock<bool>>,
|
||||
pub world: Arc<RwLock<World>>,
|
||||
/// Whether there's multiple clients sharing the same world.
|
||||
pub world_shared: Arc<RwLock<bool>>,
|
||||
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
|
||||
|
@ -146,13 +127,13 @@ pub enum HandleError {
|
|||
}
|
||||
|
||||
impl Client {
|
||||
/// Create a new client from the given game profile, conn in the game
|
||||
/// state, and dimension. You should only use this if you want to change
|
||||
/// these fields from the defaults, otherwise use `Client::join`.
|
||||
/// Create a new client from the given GameProfile, Connection, and World.
|
||||
/// You should only use this if you want to change these fields from the
|
||||
/// defaults, otherwise use [`Client::join`].
|
||||
pub fn new(
|
||||
game_profile: GameProfile,
|
||||
conn: Connection<ClientboundGamePacket, ServerboundGamePacket>,
|
||||
dimension: Option<Arc<RwLock<Dimension>>>,
|
||||
world: Option<Arc<RwLock<World>>>,
|
||||
) -> Self {
|
||||
let (read_conn, write_conn) = conn.into_split();
|
||||
let (read_conn, write_conn) = (
|
||||
|
@ -165,8 +146,8 @@ impl Client {
|
|||
read_conn,
|
||||
write_conn,
|
||||
player: Arc::new(RwLock::new(Player::default())),
|
||||
dimension_shared: Arc::new(RwLock::new(dimension.is_some())),
|
||||
dimension: dimension.unwrap_or_else(|| Arc::new(RwLock::new(Dimension::default()))),
|
||||
world_shared: Arc::new(RwLock::new(world.is_some())),
|
||||
world: world.unwrap_or_else(|| Arc::new(RwLock::new(World::default()))),
|
||||
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
|
||||
client_information: Arc::new(
|
||||
RwLock::new(ServerboundClientInformationPacket::default()),
|
||||
|
@ -450,27 +431,27 @@ 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();
|
||||
|
||||
if *client.dimension_shared.read() {
|
||||
if *client.world_shared.read() {
|
||||
// we can't clear the dimension if it's shared, so just
|
||||
// make sure the height and stuff is correct
|
||||
if dimension_lock.height() != height {
|
||||
if world_lock.height() != height {
|
||||
error!(
|
||||
"Shared dimension height mismatch: {} != {}",
|
||||
dimension_lock.height(),
|
||||
world_lock.height(),
|
||||
height
|
||||
);
|
||||
}
|
||||
if dimension_lock.min_y() != min_y {
|
||||
if world_lock.min_y() != min_y {
|
||||
error!(
|
||||
"Shared dimension min_y mismatch: {} != {}",
|
||||
dimension_lock.min_y(),
|
||||
"Shared world min_y mismatch: {} != {}",
|
||||
world_lock.min_y(),
|
||||
min_y
|
||||
);
|
||||
}
|
||||
} else {
|
||||
*dimension_lock = Dimension::new(
|
||||
*world_lock = World::new(
|
||||
client.client_information.read().view_distance.into(),
|
||||
height,
|
||||
min_y,
|
||||
|
@ -482,7 +463,7 @@ impl Client {
|
|||
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();
|
||||
|
||||
|
@ -555,9 +536,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");
|
||||
|
||||
|
@ -611,7 +592,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");
|
||||
|
||||
|
@ -642,7 +623,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));
|
||||
}
|
||||
|
@ -652,7 +633,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))
|
||||
{
|
||||
|
@ -665,12 +646,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);
|
||||
|
@ -688,7 +669,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);
|
||||
|
@ -709,9 +690,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 {
|
||||
|
@ -729,16 +710,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()))?;
|
||||
}
|
||||
|
@ -771,17 +752,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) => {
|
||||
|
@ -877,16 +858,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;
|
||||
}
|
||||
}
|
||||
|
@ -904,43 +885,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).
|
||||
|
@ -968,6 +949,12 @@ impl Client {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get your player entity's metadata. You can use this to get your health,
|
||||
/// xp score, and other useful information.
|
||||
pub fn metadata(&self) -> metadata::Player {
|
||||
self.entity().metadata.clone().into_player().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<std::sync::PoisonError<T>> for HandleError {
|
||||
|
|
|
@ -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: {} {:?}",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -7,19 +7,21 @@ use std::{
|
|||
hash::BuildHasherDefault,
|
||||
};
|
||||
|
||||
type U64Hasher = BuildHasherDefault<NoHashHasher<u64>>;
|
||||
|
||||
// kind of based on https://docs.rs/http/latest/src/http/extensions.rs.html
|
||||
/// A map of plugin ids to Plugin trait objects. The client stores this so we
|
||||
/// can keep the state for our plugins.
|
||||
///
|
||||
/// If you're using azalea, you should generate this from the `plugins!` macro.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Plugins {
|
||||
map: Option<HashMap<TypeId, Box<dyn Plugin>, BuildHasherDefault<NoHashHasher<u64>>>>,
|
||||
map: Option<HashMap<TypeId, Box<dyn Plugin>, U64Hasher>>,
|
||||
}
|
||||
|
||||
impl Plugins {
|
||||
pub fn new() -> Self {
|
||||
Self { map: None }
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn add<T: Plugin>(&mut self, plugin: T) {
|
||||
|
@ -46,7 +48,7 @@ impl IntoIterator for Plugins {
|
|||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.map
|
||||
.map(|map| map.into_iter().map(|(_, v)| v).collect::<Vec<_>>())
|
||||
.map(|map| map.into_values().collect::<Vec<_>>())
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
mod blocks;
|
||||
mod dimension_collisions;
|
||||
mod discrete_voxel_shape;
|
||||
mod mergers;
|
||||
mod shape;
|
||||
mod world_collisions;
|
||||
|
||||
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 std::ops::DerefMut;
|
||||
use world_collisions::CollisionGetter;
|
||||
|
||||
pub enum MoverType {
|
||||
Own,
|
||||
|
@ -33,7 +33,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));
|
||||
|
@ -62,7 +62,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
|
||||
|
@ -82,7 +82,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,
|
||||
|
@ -110,7 +110,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();
|
||||
|
||||
|
@ -126,7 +126,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;
|
||||
|
@ -140,7 +140,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");
|
||||
|
||||
|
@ -197,7 +197,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);
|
||||
|
@ -209,7 +209,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)
|
||||
|
|
14
azalea-physics/src/collision/dimension_collisions.rs → azalea-physics/src/collision/world_collisions.rs
Executable file → Normal file
14
azalea-physics/src/collision/dimension_collisions.rs → azalea-physics/src/collision/world_collisions.rs
Executable file → Normal 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
|
|
@ -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();
|
||||
|
@ -122,12 +122,11 @@ impl<D: DerefMut<Target = Dimension>> HasPhysics for Entity<'_, D> {
|
|||
};
|
||||
if self.metadata.sprinting {
|
||||
let y_rot = self.y_rot * 0.017453292;
|
||||
self.delta = self.delta
|
||||
+ Vec3 {
|
||||
x: (-f32::sin(y_rot) * 0.2) as f64,
|
||||
y: 0.,
|
||||
z: (f32::cos(y_rot) * 0.2) as f64,
|
||||
};
|
||||
self.delta += Vec3 {
|
||||
x: (-f32::sin(y_rot) * 0.2) as f64,
|
||||
y: 0.,
|
||||
z: (f32::cos(y_rot) * 0.2) as f64,
|
||||
};
|
||||
}
|
||||
|
||||
self.has_impulse = true;
|
||||
|
@ -143,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,
|
||||
|
@ -182,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 {
|
||||
|
@ -210,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) {
|
||||
|
@ -232,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),
|
||||
|
@ -250,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();
|
||||
|
@ -267,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),
|
||||
|
@ -281,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.);
|
||||
|
@ -298,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),
|
||||
|
@ -312,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,
|
||||
);
|
||||
|
@ -320,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();
|
||||
|
@ -330,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),
|
||||
|
@ -344,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,
|
||||
);
|
||||
|
@ -352,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();
|
||||
|
@ -362,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),
|
||||
|
@ -376,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,
|
||||
);
|
||||
|
@ -384,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();
|
||||
|
|
|
@ -302,7 +302,8 @@ where
|
|||
R1: ProtocolPacket + Debug,
|
||||
W1: ProtocolPacket + Debug,
|
||||
{
|
||||
fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
||||
/// Creates a `Connection` of a type from a `Connection` of another type. Useful for servers or custom packets.
|
||||
pub fn from<R2, W2>(connection: Connection<R1, W1>) -> Connection<R2, W2>
|
||||
where
|
||||
R2: ProtocolPacket + Debug,
|
||||
W2: ProtocolPacket + Debug,
|
||||
|
@ -323,4 +324,25 @@ where
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an existing `TcpStream` into a `Connection`. Useful for servers.
|
||||
pub fn wrap(stream: TcpStream) -> Connection<R1, W1> {
|
||||
let (read_stream, write_stream) = stream.into_split();
|
||||
|
||||
Connection {
|
||||
reader: ReadConnection {
|
||||
read_stream,
|
||||
buffer: BytesMut::new(),
|
||||
compression_threshold: None,
|
||||
dec_cipher: None,
|
||||
_reading: PhantomData,
|
||||
},
|
||||
writer: WriteConnection {
|
||||
write_stream,
|
||||
compression_threshold: None,
|
||||
enc_cipher: None,
|
||||
_writing: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -40,9 +40,8 @@ impl AttributeInstance {
|
|||
AttributeModifierOperation::MultiplyBase => total += self.base * modifier.amount,
|
||||
_ => {}
|
||||
}
|
||||
match modifier.operation {
|
||||
AttributeModifierOperation::MultiplyTotal => total *= 1.0 + modifier.amount,
|
||||
_ => {}
|
||||
if let AttributeModifierOperation::MultiplyTotal = modifier.operation {
|
||||
total *= 1.0 + modifier.amount
|
||||
}
|
||||
}
|
||||
total
|
||||
|
|
|
@ -6,6 +6,7 @@ use super::{EntityDataValue, Pose, Rotations, VillagerData};
|
|||
use azalea_block::BlockState;
|
||||
use azalea_chat::Component;
|
||||
use azalea_core::{BlockPos, Direction, Particle, Slot};
|
||||
use enum_as_inner::EnumAsInner;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
ops::{Deref, DerefMut},
|
||||
|
@ -7908,7 +7909,7 @@ impl DerefMut for AbstractTameable {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, EnumAsInner)]
|
||||
pub enum EntityMetadata {
|
||||
Allay(Allay),
|
||||
AreaEffectCloud(AreaEffectCloud),
|
||||
|
|
|
@ -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,16 +264,25 @@ 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
|
||||
}
|
||||
|
||||
/// Convert this &mut self into a (mutable) pointer.
|
||||
///
|
||||
/// # Safety
|
||||
/// The entity MUST exist while this pointer exists.
|
||||
pub unsafe fn as_ptr(&mut self) -> NonNull<EntityData> {
|
||||
NonNull::new_unchecked(self as *mut EntityData)
|
||||
}
|
||||
|
||||
/// Convert this &self into a (mutable) pointer.
|
||||
///
|
||||
/// # Safety
|
||||
/// The entity MUST exist while this pointer exists. You also must not
|
||||
/// modify the data inside the pointer.
|
||||
pub unsafe fn as_const_ptr(&self) -> NonNull<EntityData> {
|
||||
// this is cursed
|
||||
NonNull::new_unchecked(self as *const EntityData as *mut EntityData)
|
||||
|
@ -286,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,
|
||||
|
@ -296,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);
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -38,11 +38,9 @@ impl BotTrait for azalea_client::Client {
|
|||
impl crate::Plugin for Plugin {
|
||||
async fn handle(self: Box<Self>, event: Event, mut bot: Client) {
|
||||
if let Event::Tick = event {
|
||||
if *self.state.jumping_once.lock() {
|
||||
if bot.jumping() {
|
||||
*self.state.jumping_once.lock() = false;
|
||||
bot.set_jumping(false);
|
||||
}
|
||||
if *self.state.jumping_once.lock() && bot.jumping() {
|
||||
*self.state.jumping_once.lock() = false;
|
||||
bot.set_jumping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
target: possible_move.next_node(node),
|
||||
cost: possible_move.cost(&world, node),
|
||||
});
|
||||
}
|
||||
edges
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ impl<
|
|||
for n in &known_nodes {
|
||||
*pf.state_mut(n) = NodeState::default();
|
||||
}
|
||||
(*pf.state_mut(&start)).rhs = W::default();
|
||||
pf.state_mut(&start).rhs = W::default();
|
||||
pf.open.push(start, pf.calculate_key(&start));
|
||||
|
||||
pf
|
||||
|
|
|
@ -11,7 +11,7 @@ use azalea_protocol::{
|
|||
resolver::{self, ResolverError},
|
||||
ServerAddress,
|
||||
};
|
||||
use azalea_world::Dimension;
|
||||
use azalea_world::World;
|
||||
use futures::{
|
||||
future::{select_all, try_join_all},
|
||||
FutureExt,
|
||||
|
@ -121,8 +121,8 @@ pub async fn start_swarm<
|
|||
let resolved_address = resolver::resolve_address(&address).await?;
|
||||
let address_borrow = &address;
|
||||
|
||||
let shared_dimension = Arc::new(RwLock::new(Dimension::default()));
|
||||
let shared_dimension_borrow = &shared_dimension;
|
||||
let shared_world = Arc::new(RwLock::new(World::default()));
|
||||
let shared_world_borrow = &shared_world;
|
||||
|
||||
let bots: Vec<(Client, UnboundedReceiver<Event>)> = try_join_all(options.accounts.iter().map(
|
||||
async move |account| -> Result<(Client, UnboundedReceiver<Event>), JoinError> {
|
||||
|
@ -132,7 +132,7 @@ pub async fn start_swarm<
|
|||
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let client = Client::new(game_profile, conn, Some(shared_dimension_borrow.clone()));
|
||||
let client = Client::new(game_profile, conn, Some(shared_world_borrow.clone()));
|
||||
|
||||
tx.send(Event::Initialize).unwrap();
|
||||
|
||||
|
|
|
@ -73,7 +73,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()
|
||||
|
|
Loading…
Add table
Reference in a new issue