mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
Merge branch 'main' into 1.19.3
This commit is contained in:
commit
2db0847ed0
290 changed files with 3039 additions and 767 deletions
0
.cargo/config.toml
Normal file → Executable file
0
.cargo/config.toml
Normal file → Executable file
0
.github/workflows/check.yml
vendored
Normal file → Executable file
0
.github/workflows/check.yml
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
570
Cargo.lock
generated
Executable file → Normal file
570
Cargo.lock
generated
Executable file → Normal file
File diff suppressed because it is too large
Load diff
0
Cargo.toml
Normal file → Executable file
0
Cargo.toml
Normal file → Executable file
0
README.md
Normal file → Executable file
0
README.md
Normal file → Executable file
0
azalea-auth/Cargo.toml
Normal file → Executable file
0
azalea-auth/Cargo.toml
Normal file → Executable file
0
azalea-auth/README.md
Normal file → Executable file
0
azalea-auth/README.md
Normal file → Executable file
0
azalea-auth/examples/auth.rs
Normal file → Executable file
0
azalea-auth/examples/auth.rs
Normal file → Executable file
0
azalea-auth/src/auth.rs
Normal file → Executable file
0
azalea-auth/src/auth.rs
Normal file → Executable file
0
azalea-auth/src/cache.rs
Normal file → Executable file
0
azalea-auth/src/cache.rs
Normal file → Executable file
0
azalea-auth/src/sessionserver.rs
Normal file → Executable file
0
azalea-auth/src/sessionserver.rs
Normal file → Executable file
0
azalea-block/Cargo.toml
Normal file → Executable file
0
azalea-block/Cargo.toml
Normal file → Executable file
0
azalea-block/README.md
Normal file → Executable file
0
azalea-block/README.md
Normal file → Executable file
0
azalea-block/azalea-block-macros/Cargo.toml
Normal file → Executable file
0
azalea-block/azalea-block-macros/Cargo.toml
Normal file → Executable file
0
azalea-block/azalea-block-macros/src/lib.rs
Normal file → Executable file
0
azalea-block/azalea-block-macros/src/lib.rs
Normal file → Executable file
0
azalea-block/azalea-block-macros/src/utils.rs
Normal file → Executable file
0
azalea-block/azalea-block-macros/src/utils.rs
Normal file → Executable file
0
azalea-block/src/behavior.rs
Normal file → Executable file
0
azalea-block/src/behavior.rs
Normal file → Executable file
0
azalea-block/src/blocks.rs
Normal file → Executable file
0
azalea-block/src/blocks.rs
Normal file → Executable file
0
azalea-block/src/lib.rs
Normal file → Executable file
0
azalea-block/src/lib.rs
Normal file → Executable file
0
azalea-brigadier/Cargo.toml
Normal file → Executable file
0
azalea-brigadier/Cargo.toml
Normal file → Executable file
0
azalea-brigadier/src/suggestion/mod.rs
Normal file → Executable file
0
azalea-brigadier/src/suggestion/mod.rs
Normal file → Executable file
0
azalea-brigadier/src/suggestion/suggestions.rs
Normal file → Executable file
0
azalea-brigadier/src/suggestion/suggestions.rs
Normal file → Executable file
0
azalea-buf/Cargo.toml
Normal file → Executable file
0
azalea-buf/Cargo.toml
Normal file → Executable file
0
azalea-buf/README.md
Normal file → Executable file
0
azalea-buf/README.md
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/Cargo.toml
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/Cargo.toml
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/README.md
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/README.md
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/src/lib.rs
Normal file → Executable file
0
azalea-buf/azalea-buf-macros/src/lib.rs
Normal file → Executable file
0
azalea-buf/src/definitions.rs
Normal file → Executable file
0
azalea-buf/src/definitions.rs
Normal file → Executable file
0
azalea-buf/src/lib.rs
Normal file → Executable file
0
azalea-buf/src/lib.rs
Normal file → Executable file
0
azalea-buf/src/read.rs
Normal file → Executable file
0
azalea-buf/src/read.rs
Normal file → Executable file
0
azalea-buf/src/serializable_uuid.rs
Normal file → Executable file
0
azalea-buf/src/serializable_uuid.rs
Normal file → Executable file
0
azalea-buf/src/write.rs
Normal file → Executable file
0
azalea-buf/src/write.rs
Normal file → Executable file
0
azalea-chat/Cargo.toml
Normal file → Executable file
0
azalea-chat/Cargo.toml
Normal file → Executable file
0
azalea-chat/src/text_component.rs
Normal file → Executable file
0
azalea-chat/src/text_component.rs
Normal file → Executable file
0
azalea-chat/src/translatable_component.rs
Normal file → Executable file
0
azalea-chat/src/translatable_component.rs
Normal file → Executable file
|
@ -19,7 +19,9 @@ azalea-physics = {path = "../azalea-physics", version = "0.3.0"}
|
|||
azalea-protocol = {path = "../azalea-protocol", version = "0.3.0"}
|
||||
azalea-world = {path = "../azalea-world", version = "0.3.0"}
|
||||
log = "0.4.17"
|
||||
parking_lot = "0.12.1"
|
||||
thiserror = "1.0.37"
|
||||
nohash-hasher = "0.2.0"
|
||||
parking_lot = {version = "^0.12.1", features = ["deadlock_detection"]}
|
||||
thiserror = "^1.0.34"
|
||||
tokio = {version = "^1.21.2", features = ["sync"]}
|
||||
typemap_rev = "0.2.0"
|
||||
uuid = "^1.1.2"
|
||||
|
|
0
azalea-client/src/account.rs
Normal file → Executable file
0
azalea-client/src/account.rs
Normal file → Executable file
2
azalea-client/src/chat.rs
Normal file → Executable file
2
azalea-client/src/chat.rs
Normal file → Executable file
|
@ -67,7 +67,7 @@ impl Client {
|
|||
/// # account,
|
||||
/// # address: "localhost",
|
||||
/// # state: State::default(),
|
||||
/// # plugins: vec![],
|
||||
/// # plugins: plugins![],
|
||||
/// # handle,
|
||||
/// # })
|
||||
/// # .await
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{movement::MoveDirection, Account, Player};
|
||||
use crate::{movement::WalkDirection, plugins::Plugins, Account, Player};
|
||||
use azalea_auth::game_profile::GameProfile;
|
||||
use azalea_chat::Component;
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
|
@ -27,11 +27,11 @@ use azalea_protocol::{
|
|||
resolver, ServerAddress,
|
||||
};
|
||||
use azalea_world::{
|
||||
entity::{metadata, EntityData, EntityMetadata, EntityMut, EntityRef},
|
||||
entity::{metadata, Entity, EntityData, EntityMetadata},
|
||||
Dimension,
|
||||
};
|
||||
use log::{debug, error, info, warn};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::{
|
||||
any,
|
||||
backtrace::Backtrace,
|
||||
|
@ -91,10 +91,14 @@ pub struct Client {
|
|||
game_profile: GameProfile,
|
||||
pub read_conn: Arc<tokio::sync::Mutex<ReadConnection<ClientboundGamePacket>>>,
|
||||
pub write_conn: Arc<tokio::sync::Mutex<WriteConnection<ServerboundGamePacket>>>,
|
||||
pub player: Arc<Mutex<Player>>,
|
||||
pub dimension: Arc<Mutex<Dimension>>,
|
||||
pub player: Arc<RwLock<Player>>,
|
||||
pub dimension: Arc<RwLock<Dimension>>,
|
||||
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
|
||||
/// client and keep state. If you're not making a plugin and you're using
|
||||
/// the `azalea` crate. you can ignore this field.
|
||||
pub plugins: Arc<Plugins>,
|
||||
tasks: Arc<Mutex<Vec<JoinHandle<()>>>>,
|
||||
}
|
||||
|
||||
|
@ -102,8 +106,12 @@ pub struct Client {
|
|||
pub struct PhysicsState {
|
||||
/// Minecraft only sends a movement packet either after 20 ticks or if the player moved enough. This is that tick counter.
|
||||
pub position_remainder: u32,
|
||||
pub was_sprinting: bool,
|
||||
// Whether we're going to try to start sprinting this tick. Equivalent to
|
||||
// holding down ctrl for a tick.
|
||||
pub trying_to_sprint: bool,
|
||||
|
||||
pub move_direction: MoveDirection,
|
||||
pub move_direction: WalkDirection,
|
||||
pub forward_impulse: f32,
|
||||
pub left_impulse: f32,
|
||||
}
|
||||
|
@ -258,11 +266,14 @@ impl Client {
|
|||
game_profile,
|
||||
read_conn,
|
||||
write_conn,
|
||||
player: Arc::new(Mutex::new(Player::default())),
|
||||
dimension: Arc::new(Mutex::new(Dimension::default())),
|
||||
player: Arc::new(RwLock::new(Player::default())),
|
||||
dimension: Arc::new(RwLock::new(Dimension::default())),
|
||||
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
|
||||
tasks: Arc::new(Mutex::new(Vec::new())),
|
||||
client_information: Arc::new(RwLock::new(ClientInformation::default())),
|
||||
// The plugins can be modified by the user by replacing the plugins
|
||||
// field right after this. No Mutex so the user doesn't need to .lock().
|
||||
plugins: Arc::new(Plugins::new()),
|
||||
tasks: Arc::new(Mutex::new(Vec::new())),
|
||||
};
|
||||
|
||||
tx.send(Event::Initialize).unwrap();
|
||||
|
@ -413,7 +424,7 @@ impl Client {
|
|||
.as_int()
|
||||
.expect("min_y tag is not an int");
|
||||
|
||||
let mut dimension_lock = client.dimension.lock();
|
||||
let mut dimension_lock = client.dimension.write();
|
||||
// the 16 here is our render distance
|
||||
// i'll make this an actual setting later
|
||||
*dimension_lock = Dimension::new(16, height, min_y);
|
||||
|
@ -425,7 +436,7 @@ impl Client {
|
|||
);
|
||||
dimension_lock.add_entity(p.player_id, entity);
|
||||
|
||||
let mut player_lock = client.player.lock();
|
||||
let mut player_lock = client.player.write();
|
||||
|
||||
player_lock.set_entity_id(p.player_id);
|
||||
}
|
||||
|
@ -492,11 +503,11 @@ impl Client {
|
|||
|
||||
let (new_pos, y_rot, x_rot) = {
|
||||
let player_entity_id = {
|
||||
let player_lock = client.player.lock();
|
||||
let player_lock = client.player.write();
|
||||
player_lock.entity_id
|
||||
};
|
||||
|
||||
let mut dimension_lock = client.dimension.lock();
|
||||
let mut dimension_lock = client.dimension.write();
|
||||
|
||||
let mut player_entity = dimension_lock
|
||||
.entity_mut(player_entity_id)
|
||||
|
@ -584,7 +595,7 @@ impl Client {
|
|||
debug!("Got chunk cache center packet {:?}", p);
|
||||
client
|
||||
.dimension
|
||||
.lock()
|
||||
.write()
|
||||
.update_view_center(&ChunkPos::new(p.x, p.z));
|
||||
}
|
||||
ClientboundGamePacket::LevelChunkWithLight(p) => {
|
||||
|
@ -594,7 +605,7 @@ impl Client {
|
|||
// debug("chunk {:?}")
|
||||
if let Err(e) = client
|
||||
.dimension
|
||||
.lock()
|
||||
.write()
|
||||
.replace_with_packet_data(&pos, &mut Cursor::new(&p.chunk_data.data))
|
||||
{
|
||||
error!("Couldn't set chunk data: {}", e);
|
||||
|
@ -606,11 +617,11 @@ impl Client {
|
|||
ClientboundGamePacket::AddEntity(p) => {
|
||||
debug!("Got add entity packet {:?}", p);
|
||||
let entity = EntityData::from(p);
|
||||
client.dimension.lock().add_entity(p.id, entity);
|
||||
client.dimension.write().add_entity(p.id, entity);
|
||||
}
|
||||
ClientboundGamePacket::SetEntityData(p) => {
|
||||
debug!("Got set entity data packet {:?}", p);
|
||||
let mut dimension = client.dimension.lock();
|
||||
let mut dimension = client.dimension.write();
|
||||
if let Some(mut entity) = dimension.entity_mut(p.id) {
|
||||
entity.apply_metadata(&p.packed_items.0);
|
||||
} else {
|
||||
|
@ -629,7 +640,7 @@ impl Client {
|
|||
ClientboundGamePacket::AddPlayer(p) => {
|
||||
debug!("Got add player packet {:?}", p);
|
||||
let entity = EntityData::from(p);
|
||||
client.dimension.lock().add_entity(p.id, entity);
|
||||
client.dimension.write().add_entity(p.id, entity);
|
||||
}
|
||||
ClientboundGamePacket::InitializeBorder(p) => {
|
||||
debug!("Got initialize border packet {:?}", p);
|
||||
|
@ -650,7 +661,7 @@ impl Client {
|
|||
debug!("Got set experience packet {:?}", p);
|
||||
}
|
||||
ClientboundGamePacket::TeleportEntity(p) => {
|
||||
let mut dimension_lock = client.dimension.lock();
|
||||
let mut dimension_lock = client.dimension.write();
|
||||
|
||||
dimension_lock
|
||||
.set_entity_pos(
|
||||
|
@ -670,14 +681,14 @@ impl Client {
|
|||
// debug!("Got rotate head packet {:?}", p);
|
||||
}
|
||||
ClientboundGamePacket::MoveEntityPos(p) => {
|
||||
let mut dimension_lock = client.dimension.lock();
|
||||
let mut dimension_lock = client.dimension.write();
|
||||
|
||||
dimension_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.lock();
|
||||
let mut dimension_lock = client.dimension.write();
|
||||
|
||||
dimension_lock
|
||||
.move_entity_with_delta(p.entity_id, &p.delta)
|
||||
|
@ -712,7 +723,7 @@ impl Client {
|
|||
}
|
||||
ClientboundGamePacket::BlockUpdate(p) => {
|
||||
debug!("Got block update packet {:?}", p);
|
||||
let mut dimension = client.dimension.lock();
|
||||
let mut dimension = client.dimension.write();
|
||||
dimension.set_block_state(&p.pos, p.block_state);
|
||||
}
|
||||
ClientboundGamePacket::Animate(p) => {
|
||||
|
@ -720,7 +731,7 @@ impl Client {
|
|||
}
|
||||
ClientboundGamePacket::SectionBlocksUpdate(p) => {
|
||||
debug!("Got section blocks update packet {:?}", p);
|
||||
let mut dimension = client.dimension.lock();
|
||||
let mut dimension = client.dimension.write();
|
||||
for state in &p.states {
|
||||
dimension.set_block_state(&(p.section_pos + state.pos.clone()), state.state);
|
||||
}
|
||||
|
@ -818,8 +829,8 @@ 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.lock();
|
||||
let player_lock = client.player.lock();
|
||||
let dimension_lock = client.dimension.write();
|
||||
let player_lock = client.player.write();
|
||||
let player_entity = player_lock.entity(&dimension_lock);
|
||||
let player_entity = if let Some(player_entity) = player_entity {
|
||||
player_entity
|
||||
|
@ -845,30 +856,42 @@ impl Client {
|
|||
}
|
||||
|
||||
/// Returns the entity associated to the player.
|
||||
pub fn entity_mut<'d>(&self, dimension: &'d mut Dimension) -> EntityMut<'d> {
|
||||
pub fn entity_mut(&self) -> Entity<RwLockWriteGuard<Dimension>> {
|
||||
let entity_id = {
|
||||
let player_lock = self.player.lock();
|
||||
let player_lock = self.player.write();
|
||||
player_lock.entity_id
|
||||
};
|
||||
dimension
|
||||
.entity_mut(entity_id)
|
||||
.expect("Player entity should be in the given dimension")
|
||||
|
||||
let mut dimension = self.dimension.write();
|
||||
|
||||
let entity_data = dimension
|
||||
.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)
|
||||
}
|
||||
/// Returns the entity associated to the player.
|
||||
pub fn entity<'d>(&self, dimension: &'d Dimension) -> EntityRef<'d> {
|
||||
pub fn entity(&self) -> Entity<RwLockReadGuard<Dimension>> {
|
||||
let entity_id = {
|
||||
let player_lock = self.player.lock();
|
||||
let player_lock = self.player.read();
|
||||
player_lock.entity_id
|
||||
};
|
||||
dimension
|
||||
.entity(entity_id)
|
||||
.expect("Player entity should be in the given dimension")
|
||||
|
||||
let dimension = self.dimension.read();
|
||||
|
||||
let entity_data = dimension
|
||||
.entity_storage
|
||||
.get_by_id(entity_id)
|
||||
.expect("Player entity should be in the given dimension");
|
||||
let entity_ptr = unsafe { entity_data.as_const_ptr() };
|
||||
Entity::new(dimension, entity_id, entity_ptr)
|
||||
}
|
||||
|
||||
/// Returns whether we have a received the login packet yet.
|
||||
pub fn logged_in(&self) -> bool {
|
||||
let dimension = self.dimension.lock();
|
||||
let player = self.player.lock();
|
||||
let dimension = self.dimension.read();
|
||||
let player = self.player.write();
|
||||
player.entity(&dimension).is_some()
|
||||
}
|
||||
|
||||
|
|
0
azalea-client/src/get_mc_dir.rs
Normal file → Executable file
0
azalea-client/src/get_mc_dir.rs
Normal file → Executable file
|
@ -7,6 +7,9 @@
|
|||
|
||||
#![feature(provide_any)]
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(trait_upcasting)]
|
||||
|
||||
mod account;
|
||||
mod chat;
|
||||
mod client;
|
||||
|
@ -14,11 +17,13 @@ mod get_mc_dir;
|
|||
mod movement;
|
||||
pub mod ping;
|
||||
mod player;
|
||||
mod plugins;
|
||||
|
||||
pub use account::Account;
|
||||
pub use client::{ChatPacket, Client, ClientInformation, Event, JoinError};
|
||||
pub use movement::MoveDirection;
|
||||
pub use movement::{SprintDirection, WalkDirection};
|
||||
pub use player::Player;
|
||||
pub use plugins::{Plugin, Plugins};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
198
azalea-client/src/movement.rs
Normal file → Executable file
198
azalea-client/src/movement.rs
Normal file → Executable file
|
@ -2,6 +2,7 @@ use crate::Client;
|
|||
use azalea_core::Vec3;
|
||||
use azalea_physics::collision::{MovableEntity, MoverType};
|
||||
use azalea_physics::HasPhysics;
|
||||
use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket;
|
||||
use azalea_protocol::packets::game::{
|
||||
serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket,
|
||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
|
@ -28,24 +29,19 @@ impl From<MoveEntityError> for MovePlayerError {
|
|||
}
|
||||
|
||||
impl Client {
|
||||
/// This gets called every tick.
|
||||
pub async fn send_position(&mut self) -> Result<(), MovePlayerError> {
|
||||
/// This gets called automatically every tick.
|
||||
pub(crate) async fn send_position(&mut self) -> Result<(), MovePlayerError> {
|
||||
let packet = {
|
||||
let player_lock = self.player.lock();
|
||||
let mut physics_state = self.physics_state.lock();
|
||||
let mut dimension_lock = self.dimension.lock();
|
||||
|
||||
let mut player_entity = player_lock
|
||||
.entity_mut(&mut dimension_lock)
|
||||
.expect("Player must exist");
|
||||
let player_pos = player_entity.pos();
|
||||
let player_old_pos = player_entity.last_pos;
|
||||
|
||||
// TODO: send sprinting and sneaking packets here if they changed
|
||||
|
||||
self.send_sprinting_if_needed().await?;
|
||||
// TODO: the camera being able to be controlled by other entities isn't implemented yet
|
||||
// if !self.is_controlled_camera() { return };
|
||||
|
||||
let mut physics_state = self.physics_state.lock();
|
||||
|
||||
let player_entity = self.entity();
|
||||
let player_pos = player_entity.pos();
|
||||
let player_old_pos = player_entity.last_pos;
|
||||
|
||||
let x_delta = player_pos.x - player_old_pos.x;
|
||||
let y_delta = player_pos.y - player_old_pos.y;
|
||||
let z_delta = player_pos.z - player_old_pos.z;
|
||||
|
@ -105,6 +101,9 @@ impl Client {
|
|||
None
|
||||
};
|
||||
|
||||
drop(player_entity);
|
||||
let mut player_entity = self.entity_mut();
|
||||
|
||||
if sending_position {
|
||||
player_entity.last_pos = *player_entity.pos();
|
||||
physics_state.position_remainder = 0;
|
||||
|
@ -127,10 +126,35 @@ impl Client {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_sprinting_if_needed(&mut self) -> Result<(), MovePlayerError> {
|
||||
let is_sprinting = self.entity().metadata.sprinting;
|
||||
let was_sprinting = self.physics_state.lock().was_sprinting;
|
||||
if is_sprinting != was_sprinting {
|
||||
let sprinting_action = if is_sprinting {
|
||||
azalea_protocol::packets::game::serverbound_player_command_packet::Action::StartSprinting
|
||||
} else {
|
||||
azalea_protocol::packets::game::serverbound_player_command_packet::Action::StopSprinting
|
||||
};
|
||||
let player_entity_id = self.entity().id;
|
||||
self.write_packet(
|
||||
ServerboundPlayerCommandPacket {
|
||||
id: player_entity_id,
|
||||
action: sprinting_action,
|
||||
data: 0,
|
||||
}
|
||||
.get(),
|
||||
)
|
||||
.await?;
|
||||
self.physics_state.lock().was_sprinting = is_sprinting;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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.lock();
|
||||
let mut dimension_lock = self.dimension.lock();
|
||||
let player_lock = self.player.write();
|
||||
let mut dimension_lock = self.dimension.write();
|
||||
|
||||
dimension_lock.set_entity_pos(player_lock.entity_id, new_pos)?;
|
||||
|
||||
|
@ -138,8 +162,8 @@ impl Client {
|
|||
}
|
||||
|
||||
pub async fn move_entity(&mut self, movement: &Vec3) -> Result<(), MovePlayerError> {
|
||||
let mut dimension_lock = self.dimension.lock();
|
||||
let player = self.player.lock();
|
||||
let mut dimension_lock = self.dimension.write();
|
||||
let player = self.player.write();
|
||||
|
||||
let mut entity = player
|
||||
.entity_mut(&mut dimension_lock)
|
||||
|
@ -160,19 +184,38 @@ impl Client {
|
|||
pub fn ai_step(&mut self) {
|
||||
self.tick_controls(None);
|
||||
|
||||
let player_lock = self.player.lock();
|
||||
let mut dimension_lock = self.dimension.lock();
|
||||
let mut player_entity = player_lock
|
||||
.entity_mut(&mut dimension_lock)
|
||||
.expect("Player must exist");
|
||||
|
||||
// server ai step
|
||||
{
|
||||
let mut player_entity = self.entity_mut();
|
||||
|
||||
let physics_state = self.physics_state.lock();
|
||||
player_entity.xxa = physics_state.left_impulse;
|
||||
player_entity.zza = physics_state.forward_impulse;
|
||||
}
|
||||
|
||||
// TODO: food data and abilities
|
||||
// let has_enough_food_to_sprint = self.food_data().food_level || self.abilities().may_fly;
|
||||
let has_enough_food_to_sprint = true;
|
||||
|
||||
// TODO: double tapping w to sprint i think
|
||||
|
||||
let trying_to_sprint = self.physics_state.lock().trying_to_sprint;
|
||||
|
||||
if !self.sprinting()
|
||||
&& (
|
||||
// !self.is_in_water()
|
||||
// || self.is_underwater() &&
|
||||
self.has_enough_impulse_to_start_sprinting()
|
||||
&& has_enough_food_to_sprint
|
||||
// && !self.using_item()
|
||||
// && !self.has_effect(MobEffects.BLINDNESS)
|
||||
&& trying_to_sprint
|
||||
)
|
||||
{
|
||||
self.set_sprinting(true);
|
||||
}
|
||||
|
||||
let mut player_entity = self.entity_mut();
|
||||
player_entity.ai_step();
|
||||
}
|
||||
|
||||
|
@ -184,21 +227,21 @@ impl Client {
|
|||
let mut left_impulse: f32 = 0.;
|
||||
let move_direction = physics_state.move_direction;
|
||||
match move_direction {
|
||||
MoveDirection::Forward | MoveDirection::ForwardRight | MoveDirection::ForwardLeft => {
|
||||
WalkDirection::Forward | WalkDirection::ForwardRight | WalkDirection::ForwardLeft => {
|
||||
forward_impulse += 1.;
|
||||
}
|
||||
MoveDirection::Backward
|
||||
| MoveDirection::BackwardRight
|
||||
| MoveDirection::BackwardLeft => {
|
||||
WalkDirection::Backward
|
||||
| WalkDirection::BackwardRight
|
||||
| WalkDirection::BackwardLeft => {
|
||||
forward_impulse -= 1.;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
match move_direction {
|
||||
MoveDirection::Right | MoveDirection::ForwardRight | MoveDirection::BackwardRight => {
|
||||
WalkDirection::Right | WalkDirection::ForwardRight | WalkDirection::BackwardRight => {
|
||||
left_impulse += 1.;
|
||||
}
|
||||
MoveDirection::Left | MoveDirection::ForwardLeft | MoveDirection::BackwardLeft => {
|
||||
WalkDirection::Left | WalkDirection::ForwardLeft | WalkDirection::BackwardLeft => {
|
||||
left_impulse -= 1.;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -212,35 +255,90 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
/// Start walking in the given direction.
|
||||
pub fn walk(&mut self, direction: MoveDirection) {
|
||||
let mut physics_state = self.physics_state.lock();
|
||||
physics_state.move_direction = direction;
|
||||
/// Start walking in the given direction. To sprint, use
|
||||
/// [`Client::sprint`]. To stop walking, call walk with
|
||||
/// `WalkDirection::None`.
|
||||
pub fn walk(&mut self, direction: WalkDirection) {
|
||||
{
|
||||
let mut physics_state = self.physics_state.lock();
|
||||
physics_state.move_direction = direction;
|
||||
}
|
||||
|
||||
self.set_sprinting(false);
|
||||
}
|
||||
|
||||
/// Toggle whether we're jumping. This acts as if you held space in
|
||||
/// Start sprinting in the given direction. To stop moving, call
|
||||
/// [`Client::walk(WalkDirection::None)`]
|
||||
pub fn sprint(&mut self, direction: SprintDirection) {
|
||||
let mut physics_state = self.physics_state.lock();
|
||||
physics_state.move_direction = WalkDirection::from(direction);
|
||||
physics_state.trying_to_sprint = true;
|
||||
}
|
||||
|
||||
// Whether we're currently sprinting.
|
||||
pub fn sprinting(&self) -> bool {
|
||||
self.entity().metadata.sprinting
|
||||
}
|
||||
|
||||
/// Change whether we're sprinting by adding an attribute modifier to the
|
||||
/// player. You should use the [`walk`] and [`sprint`] methods instead.
|
||||
/// Returns if the operation was successful.
|
||||
fn set_sprinting(&mut self, sprinting: bool) -> bool {
|
||||
let mut player_entity = self.entity_mut();
|
||||
player_entity.metadata.sprinting = sprinting;
|
||||
if sprinting {
|
||||
player_entity
|
||||
.attributes
|
||||
.speed
|
||||
.insert(azalea_world::entity::attributes::sprinting_modifier())
|
||||
.is_ok()
|
||||
} else {
|
||||
player_entity
|
||||
.attributes
|
||||
.speed
|
||||
.remove(&azalea_world::entity::attributes::sprinting_modifier().uuid)
|
||||
.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Set whether we're jumping. This acts as if you held space in
|
||||
/// vanilla. If you want to jump once, use the `jump` function.
|
||||
///
|
||||
/// If you're making a realistic client, calling this function every tick is
|
||||
/// recommended.
|
||||
pub fn set_jumping(&mut self, jumping: bool) {
|
||||
let mut dimension = self.dimension.lock();
|
||||
let mut player_entity = self.entity_mut(&mut dimension);
|
||||
|
||||
let mut player_entity = self.entity_mut();
|
||||
player_entity.jumping = jumping;
|
||||
}
|
||||
|
||||
/// Returns whether the player will try to jump next tick.
|
||||
pub fn jumping(&self) -> bool {
|
||||
let dimension = self.dimension.lock();
|
||||
let player_entity = self.entity(&dimension);
|
||||
let player_entity = self.entity();
|
||||
|
||||
player_entity.jumping
|
||||
}
|
||||
|
||||
/// Sets your rotation. `y_rot` is yaw (looking to the side), `x_rot` is
|
||||
/// pitch (looking up and down). You can get these numbers from the vanilla
|
||||
/// f3 screen.
|
||||
pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) {
|
||||
let mut player_entity = self.entity_mut();
|
||||
player_entity.set_rotation(y_rot, x_rot);
|
||||
}
|
||||
|
||||
// Whether the player is moving fast enough to be able to start sprinting.
|
||||
fn has_enough_impulse_to_start_sprinting(&self) -> bool {
|
||||
// if self.underwater() {
|
||||
// self.has_forward_impulse()
|
||||
// } else {
|
||||
let physics_state = self.physics_state.lock();
|
||||
physics_state.forward_impulse > 0.8
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum MoveDirection {
|
||||
pub enum WalkDirection {
|
||||
#[default]
|
||||
None,
|
||||
Forward,
|
||||
|
@ -252,3 +350,21 @@ pub enum MoveDirection {
|
|||
BackwardRight,
|
||||
BackwardLeft,
|
||||
}
|
||||
|
||||
/// The directions that we can sprint in. It's a subset of [`WalkDirection`].
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum SprintDirection {
|
||||
Forward,
|
||||
ForwardRight,
|
||||
ForwardLeft,
|
||||
}
|
||||
|
||||
impl From<SprintDirection> for WalkDirection {
|
||||
fn from(d: SprintDirection) -> Self {
|
||||
match d {
|
||||
SprintDirection::Forward => WalkDirection::Forward,
|
||||
SprintDirection::ForwardRight => WalkDirection::ForwardRight,
|
||||
SprintDirection::ForwardLeft => WalkDirection::ForwardLeft,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6
azalea-client/src/player.rs
Normal file → Executable file
6
azalea-client/src/player.rs
Normal file → Executable file
|
@ -1,4 +1,4 @@
|
|||
use azalea_world::entity::{EntityMut, EntityRef};
|
||||
use azalea_world::entity::Entity;
|
||||
use azalea_world::Dimension;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -18,12 +18,12 @@ 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<EntityRef> {
|
||||
pub fn entity<'d>(&'d self, dimension: &'d Dimension) -> Option<Entity<&Dimension>> {
|
||||
dimension.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<EntityMut> {
|
||||
pub fn entity_mut<'d>(&'d self, dimension: &'d mut Dimension) -> Option<Entity> {
|
||||
dimension.entity_mut(self.entity_id)
|
||||
}
|
||||
|
||||
|
|
78
azalea-client/src/plugins.rs
Normal file
78
azalea-client/src/plugins.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::{Client, Event};
|
||||
use async_trait::async_trait;
|
||||
use nohash_hasher::NoHashHasher;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
collections::HashMap,
|
||||
hash::BuildHasherDefault,
|
||||
};
|
||||
|
||||
// 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)]
|
||||
pub struct Plugins {
|
||||
map: Option<HashMap<TypeId, Box<dyn Plugin>, BuildHasherDefault<NoHashHasher<u64>>>>,
|
||||
}
|
||||
|
||||
impl Plugins {
|
||||
pub fn new() -> Self {
|
||||
Self { map: None }
|
||||
}
|
||||
|
||||
pub fn add<T: Plugin>(&mut self, plugin: T) {
|
||||
if self.map.is_none() {
|
||||
self.map = Some(HashMap::with_hasher(BuildHasherDefault::default()));
|
||||
}
|
||||
self.map
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.insert(TypeId::of::<T>(), Box::new(plugin));
|
||||
}
|
||||
|
||||
pub fn get<T: Plugin>(&self) -> Option<&T> {
|
||||
self.map
|
||||
.as_ref()
|
||||
.and_then(|map| map.get(&TypeId::of::<T>()))
|
||||
.and_then(|boxed| (boxed.as_ref() as &dyn Any).downcast_ref::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Plugins {
|
||||
type Item = Box<dyn Plugin>;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.map
|
||||
.map(|map| map.into_iter().map(|(_, v)| v).collect::<Vec<_>>())
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugins can keep their own personal state, listen to events, and add new functions to Client.
|
||||
#[async_trait]
|
||||
pub trait Plugin: Send + Sync + PluginClone + Any + 'static {
|
||||
async fn handle(self: Box<Self>, event: Event, bot: Client);
|
||||
}
|
||||
|
||||
/// An internal trait that allows Plugin to be cloned.
|
||||
#[doc(hidden)]
|
||||
pub trait PluginClone {
|
||||
fn clone_box(&self) -> Box<dyn Plugin>;
|
||||
}
|
||||
impl<T> PluginClone for T
|
||||
where
|
||||
T: 'static + Plugin + Clone,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn Plugin> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
impl Clone for Box<dyn Plugin> {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
0
azalea-core/Cargo.toml
Normal file → Executable file
0
azalea-core/Cargo.toml
Normal file → Executable file
0
azalea-core/README.md
Normal file → Executable file
0
azalea-core/README.md
Normal file → Executable file
42
azalea-core/src/aabb.rs
Normal file → Executable file
42
azalea-core/src/aabb.rs
Normal file → Executable file
|
@ -1,4 +1,4 @@
|
|||
use crate::{Axis, BlockHitResult, BlockPos, Direction, PositionXYZ, Vec3};
|
||||
use crate::{Axis, BlockHitResult, BlockPos, Direction, Vec3};
|
||||
|
||||
pub const EPSILON: f64 = 1.0E-7;
|
||||
|
||||
|
@ -15,7 +15,7 @@ pub struct AABB {
|
|||
}
|
||||
|
||||
pub struct ClipPointOpts<'a> {
|
||||
pub t: &'a mut [f64],
|
||||
pub t: &'a mut f64,
|
||||
pub approach_dir: Option<Direction>,
|
||||
pub delta: &'a Vec3,
|
||||
pub begin: f64,
|
||||
|
@ -225,13 +225,10 @@ impl AABB {
|
|||
}
|
||||
|
||||
pub fn clip(&self, min: &Vec3, max: &Vec3) -> Option<Vec3> {
|
||||
let mut t = [1.0];
|
||||
let x = max.x - min.x;
|
||||
let y = max.y - min.y;
|
||||
let z = max.z - min.z;
|
||||
let _dir = self.get_direction(self, min, &mut t, None, &Vec3 { x, y, z })?;
|
||||
let t = t[0];
|
||||
Some(min.add(t * x, t * y, t * z))
|
||||
let mut t = 1.0;
|
||||
let delta = max - min;
|
||||
let _dir = self.get_direction(self, min, &mut t, None, &delta)?;
|
||||
Some(min + &(delta * t))
|
||||
}
|
||||
|
||||
pub fn clip_iterable(
|
||||
|
@ -241,19 +238,16 @@ impl AABB {
|
|||
to: &Vec3,
|
||||
pos: &BlockPos,
|
||||
) -> Option<BlockHitResult> {
|
||||
let mut t = [1.0];
|
||||
let mut t = 1.0;
|
||||
let mut dir = None;
|
||||
let x = to.x - from.x;
|
||||
let y = to.y - from.y;
|
||||
let z = to.z - from.z;
|
||||
let delta = to - from;
|
||||
|
||||
for aabb in boxes {
|
||||
dir = self.get_direction(aabb, from, &mut t, dir, &Vec3 { x, y, z });
|
||||
dir = self.get_direction(aabb, from, &mut t, dir, &delta);
|
||||
}
|
||||
let dir = dir?;
|
||||
let t = t[0];
|
||||
Some(BlockHitResult {
|
||||
location: from.add(t * x, t * y, t * z),
|
||||
location: from + &(delta * t),
|
||||
direction: dir,
|
||||
block_pos: *pos,
|
||||
inside: false,
|
||||
|
@ -265,7 +259,7 @@ impl AABB {
|
|||
&self,
|
||||
aabb: &AABB,
|
||||
from: &Vec3,
|
||||
t: &mut [f64],
|
||||
t: &mut f64,
|
||||
dir: Option<Direction>,
|
||||
delta: &Vec3,
|
||||
) -> Option<Direction> {
|
||||
|
@ -393,13 +387,13 @@ impl AABB {
|
|||
let t_y = (opts.start.y + t_x) / opts.delta.y;
|
||||
let t_z = (opts.start.z + t_x) / opts.delta.z;
|
||||
if 0.0 < t_x
|
||||
&& t_x < opts.t[0]
|
||||
&& t_x < *opts.t
|
||||
&& opts.min_x - EPSILON < t_y
|
||||
&& t_y < opts.max_x + EPSILON
|
||||
&& opts.min_z - EPSILON < t_z
|
||||
&& t_z < opts.max_z + EPSILON
|
||||
{
|
||||
opts.t[0] = t_x;
|
||||
*opts.t = t_x;
|
||||
Some(opts.result_dir)
|
||||
} else {
|
||||
opts.approach_dir
|
||||
|
@ -416,11 +410,11 @@ impl AABB {
|
|||
}
|
||||
|
||||
pub fn get_center(&self) -> Vec3 {
|
||||
Vec3 {
|
||||
x: (self.min_x + self.max_x) / 2.0,
|
||||
y: (self.min_y + self.max_y) / 2.0,
|
||||
z: (self.min_z + self.max_z) / 2.0,
|
||||
}
|
||||
Vec3::new(
|
||||
(self.min_x + self.max_x) / 2.0,
|
||||
(self.min_y + self.max_y) / 2.0,
|
||||
(self.min_z + self.max_z) / 2.0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn of_size(center: Vec3, dx: f64, dy: f64, dz: f64) -> AABB {
|
||||
|
|
0
azalea-core/src/bitset.rs
Normal file → Executable file
0
azalea-core/src/bitset.rs
Normal file → Executable file
0
azalea-core/src/block_hit_result.rs
Normal file → Executable file
0
azalea-core/src/block_hit_result.rs
Normal file → Executable file
0
azalea-core/src/cursor3d.rs
Normal file → Executable file
0
azalea-core/src/cursor3d.rs
Normal file → Executable file
23
azalea-core/src/delta.rs
Normal file → Executable file
23
azalea-core/src/delta.rs
Normal file → Executable file
|
@ -1,5 +1,3 @@
|
|||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use crate::Vec3;
|
||||
pub use azalea_buf::McBuf;
|
||||
|
||||
|
@ -76,24 +74,3 @@ impl Vec3 {
|
|||
self.multiply(amount, amount, amount)
|
||||
}
|
||||
}
|
||||
|
||||
// impl + and +=
|
||||
impl Add for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn add(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x + other.x,
|
||||
y: self.y + other.y,
|
||||
z: self.z + other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Vec3 {
|
||||
fn add_assign(&mut self, other: Vec3) {
|
||||
self.x += other.x;
|
||||
self.y += other.y;
|
||||
self.z += other.z;
|
||||
}
|
||||
}
|
||||
|
|
58
azalea-core/src/direction.rs
Normal file → Executable file
58
azalea-core/src/direction.rs
Normal file → Executable file
|
@ -13,6 +13,15 @@ pub enum Direction {
|
|||
East,
|
||||
}
|
||||
|
||||
// TODO: make azalea_block use this instead of FacingCardinal
|
||||
#[derive(Clone, Copy, Debug, McBuf)]
|
||||
pub enum CardinalDirection {
|
||||
North,
|
||||
South,
|
||||
West,
|
||||
East,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Axis {
|
||||
X = 0,
|
||||
|
@ -27,6 +36,55 @@ pub enum AxisCycle {
|
|||
Backward = 2,
|
||||
}
|
||||
|
||||
impl CardinalDirection {
|
||||
#[inline]
|
||||
pub fn x(self) -> i32 {
|
||||
match self {
|
||||
CardinalDirection::East => 1,
|
||||
CardinalDirection::West => -1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn z(self) -> i32 {
|
||||
match self {
|
||||
CardinalDirection::South => 1,
|
||||
CardinalDirection::North => -1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter() -> impl Iterator<Item = CardinalDirection> {
|
||||
[
|
||||
CardinalDirection::North,
|
||||
CardinalDirection::South,
|
||||
CardinalDirection::West,
|
||||
CardinalDirection::East,
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn right(self) -> CardinalDirection {
|
||||
match self {
|
||||
CardinalDirection::North => CardinalDirection::East,
|
||||
CardinalDirection::South => CardinalDirection::West,
|
||||
CardinalDirection::West => CardinalDirection::North,
|
||||
CardinalDirection::East => CardinalDirection::South,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn left(self) -> CardinalDirection {
|
||||
match self {
|
||||
CardinalDirection::North => CardinalDirection::West,
|
||||
CardinalDirection::South => CardinalDirection::East,
|
||||
CardinalDirection::West => CardinalDirection::South,
|
||||
CardinalDirection::East => CardinalDirection::North,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
/// Pick x, y, or z from the arguments depending on the axis.
|
||||
#[inline]
|
||||
|
|
0
azalea-core/src/particle/mod.rs
Normal file → Executable file
0
azalea-core/src/particle/mod.rs
Normal file → Executable file
301
azalea-core/src/position.rs
Normal file → Executable file
301
azalea-core/src/position.rs
Normal file → Executable file
|
@ -2,114 +2,136 @@ use crate::ResourceLocation;
|
|||
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
|
||||
use std::{
|
||||
io::{Cursor, Write},
|
||||
ops::{Add, Mul, Rem},
|
||||
ops::{Add, AddAssign, Mul, Rem, Sub},
|
||||
};
|
||||
|
||||
pub trait PositionXYZ<T>
|
||||
where
|
||||
T: Add<T, Output = T> + Mul<T, Output = T>,
|
||||
{
|
||||
fn x(&self) -> T;
|
||||
fn y(&self) -> T;
|
||||
fn z(&self) -> T;
|
||||
macro_rules! vec3_impl {
|
||||
($name:ident, $type:ty) => {
|
||||
impl $name {
|
||||
pub fn new(x: $type, y: $type, z: $type) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
fn set_x(&self, n: T) -> Self;
|
||||
fn set_y(&self, n: T) -> Self;
|
||||
fn set_z(&self, n: T) -> Self;
|
||||
pub fn length_sqr(&self) -> $type {
|
||||
self.x * self.x + self.y * self.y + self.z * self.z
|
||||
}
|
||||
|
||||
// hopefully these get optimized
|
||||
fn add_x(&self, n: T) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_x(self.x() + n)
|
||||
}
|
||||
fn add_y(&self, n: T) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_y(self.y() + n)
|
||||
}
|
||||
fn add_z(&self, n: T) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_z(self.z() + n)
|
||||
}
|
||||
/// Return a new instance of this position with the y coordinate
|
||||
/// decreased by the given number.
|
||||
pub fn down(&self, y: $type) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y - y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
/// Return a new instance of this position with the y coordinate
|
||||
/// increased by the given number.
|
||||
pub fn up(&self, y: $type) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y + y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&self, x: T, y: T, z: T) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.add_x(x).add_y(y).add_z(z)
|
||||
}
|
||||
impl Add for &$name {
|
||||
type Output = $name;
|
||||
|
||||
fn length_sqr(&self) -> T
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.x() * self.x() + self.y() * self.y() + self.z() * self.z()
|
||||
}
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
$name {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
(&self).add(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for $name {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.x += rhs.x;
|
||||
self.y += rhs.y;
|
||||
self.z += rhs.z;
|
||||
}
|
||||
}
|
||||
impl Rem<$type> for $name {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, rhs: $type) -> Self::Output {
|
||||
Self {
|
||||
x: self.x % rhs,
|
||||
y: self.y % rhs,
|
||||
z: self.z % rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for &$name {
|
||||
type Output = $name;
|
||||
|
||||
/// Find the difference between two positions.
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self::Output {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
z: self.z - other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sub for $name {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
(&self).sub(&other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<$type> for $name {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, multiplier: $type) -> Self::Output {
|
||||
Self {
|
||||
x: self.x * multiplier,
|
||||
y: self.y * multiplier,
|
||||
z: self.z * multiplier,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct Vec3 {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
vec3_impl!(Vec3, f64);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct BlockPos {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub z: i32,
|
||||
}
|
||||
vec3_impl!(BlockPos, i32);
|
||||
|
||||
impl BlockPos {
|
||||
pub fn new(x: i32, y: i32, z: i32) -> Self {
|
||||
BlockPos { x, y, z }
|
||||
}
|
||||
|
||||
pub fn below(&self) -> Self {
|
||||
self.add(0, -1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<i32> for BlockPos {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, rhs: i32) -> Self {
|
||||
BlockPos {
|
||||
x: self.x % rhs,
|
||||
y: self.y % rhs,
|
||||
z: self.z % rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PositionXYZ<i32> for BlockPos {
|
||||
fn x(&self) -> i32 {
|
||||
self.x
|
||||
}
|
||||
fn y(&self) -> i32 {
|
||||
self.y
|
||||
}
|
||||
fn z(&self) -> i32 {
|
||||
self.z
|
||||
}
|
||||
fn set_x(&self, n: i32) -> Self {
|
||||
BlockPos {
|
||||
x: n,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
fn set_y(&self, n: i32) -> Self {
|
||||
BlockPos {
|
||||
x: self.x,
|
||||
y: n,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
fn set_z(&self, n: i32) -> Self {
|
||||
BlockPos {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: n,
|
||||
/// Get the absolute center of a block position by adding 0.5 to each coordinate.
|
||||
pub fn center(&self) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x as f64 + 0.5,
|
||||
y: self.y as f64 + 0.5,
|
||||
z: self.z as f64 + 0.5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,17 +149,15 @@ impl ChunkPos {
|
|||
}
|
||||
|
||||
/// The coordinates of a chunk section in the world.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ChunkSectionPos {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub z: i32,
|
||||
}
|
||||
vec3_impl!(ChunkSectionPos, i32);
|
||||
|
||||
impl ChunkSectionPos {
|
||||
pub fn new(x: i32, y: i32, z: i32) -> Self {
|
||||
ChunkSectionPos { x, y, z }
|
||||
}
|
||||
pub fn block_to_section_coord(block: i32) -> i32 {
|
||||
block >> 4
|
||||
}
|
||||
|
@ -155,32 +175,25 @@ impl ChunkBlockPos {
|
|||
ChunkBlockPos { x, y, z }
|
||||
}
|
||||
}
|
||||
/// The coordinates of a block inside a chunk section.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
||||
/// The coordinates of a block inside a chunk section. Each coordinate must be in the range [0, 15].
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ChunkSectionBlockPos {
|
||||
/// A number between 0 and 16.
|
||||
pub x: u8,
|
||||
/// A number between 0 and 16.
|
||||
pub y: u8,
|
||||
/// A number between 0 and 16.
|
||||
pub z: u8,
|
||||
}
|
||||
|
||||
impl ChunkSectionBlockPos {
|
||||
pub fn new(x: u8, y: u8, z: u8) -> Self {
|
||||
ChunkSectionBlockPos { x, y, z }
|
||||
}
|
||||
}
|
||||
vec3_impl!(ChunkSectionBlockPos, u8);
|
||||
|
||||
impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
|
||||
type Output = BlockPos;
|
||||
|
||||
fn add(self, rhs: ChunkSectionBlockPos) -> Self::Output {
|
||||
BlockPos {
|
||||
x: self.x * 16 + rhs.x as i32,
|
||||
y: self.y * 16 + rhs.y as i32,
|
||||
z: self.z * 16 + rhs.z as i32,
|
||||
}
|
||||
BlockPos::new(
|
||||
self.x * 16 + rhs.x as i32,
|
||||
self.y * 16 + rhs.y as i32,
|
||||
self.z * 16 + rhs.z as i32,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,47 +205,6 @@ pub struct GlobalPos {
|
|||
pub dimension: ResourceLocation,
|
||||
}
|
||||
|
||||
/// An exact point in the world.
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
||||
pub struct Vec3 {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
impl PositionXYZ<f64> for Vec3 {
|
||||
fn x(&self) -> f64 {
|
||||
self.x
|
||||
}
|
||||
fn y(&self) -> f64 {
|
||||
self.y
|
||||
}
|
||||
fn z(&self) -> f64 {
|
||||
self.z
|
||||
}
|
||||
fn set_x(&self, n: f64) -> Self {
|
||||
Vec3 {
|
||||
x: n,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
fn set_y(&self, n: f64) -> Self {
|
||||
Vec3 {
|
||||
x: self.x,
|
||||
y: n,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
fn set_z(&self, n: f64) -> Self {
|
||||
Vec3 {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockPos> for ChunkPos {
|
||||
fn from(pos: &BlockPos) -> Self {
|
||||
ChunkPos {
|
||||
|
@ -261,9 +233,9 @@ impl From<ChunkSectionPos> for ChunkPos {
|
|||
impl From<&BlockPos> for ChunkBlockPos {
|
||||
fn from(pos: &BlockPos) -> Self {
|
||||
ChunkBlockPos {
|
||||
x: pos.x.rem_euclid(16).unsigned_abs() as u8,
|
||||
x: pos.x.rem_euclid(16) as u8,
|
||||
y: pos.y,
|
||||
z: pos.z.rem_euclid(16).unsigned_abs() as u8,
|
||||
z: pos.z.rem_euclid(16) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -271,9 +243,9 @@ impl From<&BlockPos> for ChunkBlockPos {
|
|||
impl From<&BlockPos> for ChunkSectionBlockPos {
|
||||
fn from(pos: &BlockPos) -> Self {
|
||||
ChunkSectionBlockPos {
|
||||
x: pos.x.rem(16).unsigned_abs() as u8,
|
||||
y: pos.y.rem(16).unsigned_abs() as u8,
|
||||
z: pos.z.rem(16).unsigned_abs() as u8,
|
||||
x: pos.x.rem_euclid(16) as u8,
|
||||
y: pos.y.rem_euclid(16) as u8,
|
||||
z: pos.z.rem_euclid(16) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +254,7 @@ impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
|
|||
fn from(pos: &ChunkBlockPos) -> Self {
|
||||
ChunkSectionBlockPos {
|
||||
x: pos.x,
|
||||
y: pos.y.rem(16).unsigned_abs() as u8,
|
||||
y: pos.y.rem_euclid(16) as u8,
|
||||
z: pos.z,
|
||||
}
|
||||
}
|
||||
|
@ -419,4 +391,13 @@ mod tests {
|
|||
let block_pos = BlockPos::read_from(&mut buf).unwrap();
|
||||
assert_eq!(block_pos, BlockPos::new(49, -43, -3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_chunk_section_block_pos() {
|
||||
let block_pos = BlockPos::new(0, -60, 0);
|
||||
assert_eq!(
|
||||
ChunkSectionBlockPos::from(&block_pos),
|
||||
ChunkSectionBlockPos::new(0, 4, 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
0
azalea-core/src/slot.rs
Normal file → Executable file
0
azalea-core/src/slot.rs
Normal file → Executable file
0
azalea-crypto/Cargo.toml
Normal file → Executable file
0
azalea-crypto/Cargo.toml
Normal file → Executable file
0
azalea-crypto/README.md
Normal file → Executable file
0
azalea-crypto/README.md
Normal file → Executable file
0
azalea-crypto/benches/my_benchmark.rs
Normal file → Executable file
0
azalea-crypto/benches/my_benchmark.rs
Normal file → Executable file
0
azalea-crypto/src/lib.rs
Normal file → Executable file
0
azalea-crypto/src/lib.rs
Normal file → Executable file
0
azalea-crypto/src/signing.rs
Normal file → Executable file
0
azalea-crypto/src/signing.rs
Normal file → Executable file
0
azalea-language/Cargo.toml
Normal file → Executable file
0
azalea-language/Cargo.toml
Normal file → Executable file
0
azalea-language/README.md
Normal file → Executable file
0
azalea-language/README.md
Normal file → Executable file
0
azalea-language/src/en_us.json
Normal file → Executable file
0
azalea-language/src/en_us.json
Normal file → Executable file
0
azalea-language/src/lib.rs
Normal file → Executable file
0
azalea-language/src/lib.rs
Normal file → Executable file
0
azalea-nbt/Cargo.toml
Normal file → Executable file
0
azalea-nbt/Cargo.toml
Normal file → Executable file
9
azalea-physics/Cargo.toml
Normal file → Executable file
9
azalea-physics/Cargo.toml
Normal file → Executable file
|
@ -3,16 +3,17 @@ description = "Physics for Minecraft entities."
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "azalea-physics"
|
||||
version = "0.3.0"
|
||||
repository = "https://github.com/mat-1/azalea/tree/main/azalea-physics"
|
||||
version = "0.3.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
azalea-block = { path = "../azalea-block", version = "^0.3.0" }
|
||||
azalea-core = { path = "../azalea-core", version = "^0.3.0" }
|
||||
azalea-world = { path = "../azalea-world", version = "^0.3.0" }
|
||||
azalea-block = {path = "../azalea-block", version = "^0.3.0"}
|
||||
azalea-core = {path = "../azalea-core", version = "^0.3.0"}
|
||||
azalea-world = {path = "../azalea-world", version = "^0.3.0"}
|
||||
lazy_static = "1.4.0"
|
||||
parking_lot = "^0.12.1"
|
||||
|
||||
[dev-dependencies]
|
||||
uuid = "^1.1.2"
|
||||
|
|
0
azalea-physics/README.md
Normal file → Executable file
0
azalea-physics/README.md
Normal file → Executable file
0
azalea-physics/src/collision/blocks.rs
Normal file → Executable file
0
azalea-physics/src/collision/blocks.rs
Normal file → Executable file
7
azalea-physics/src/collision/dimension_collisions.rs
Normal file → Executable file
7
azalea-physics/src/collision/dimension_collisions.rs
Normal file → Executable file
|
@ -3,7 +3,8 @@ use azalea_block::BlockState;
|
|||
use azalea_core::{ChunkPos, ChunkSectionPos, Cursor3d, CursorIterationType, EPSILON};
|
||||
use azalea_world::entity::EntityData;
|
||||
use azalea_world::{Chunk, Dimension};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::Shapes;
|
||||
|
||||
|
@ -92,10 +93,10 @@ impl<'a> Iterator for BlockCollisions<'a> {
|
|||
Some(chunk) => chunk,
|
||||
None => continue,
|
||||
};
|
||||
let chunk_lock = chunk.lock().unwrap();
|
||||
|
||||
let pos = item.pos;
|
||||
let block_state: BlockState = chunk_lock
|
||||
let block_state: BlockState = chunk
|
||||
.lock()
|
||||
.get(&(&pos).into(), self.dimension.min_y())
|
||||
.unwrap_or(BlockState::Air);
|
||||
|
||||
|
|
0
azalea-physics/src/collision/discrete_voxel_shape.rs
Normal file → Executable file
0
azalea-physics/src/collision/discrete_voxel_shape.rs
Normal file → Executable file
0
azalea-physics/src/collision/mergers.rs
Normal file → Executable file
0
azalea-physics/src/collision/mergers.rs
Normal file → Executable file
10
azalea-physics/src/collision/mod.rs
Normal file → Executable file
10
azalea-physics/src/collision/mod.rs
Normal file → Executable file
|
@ -4,8 +4,10 @@ mod discrete_voxel_shape;
|
|||
mod mergers;
|
||||
mod shape;
|
||||
|
||||
use azalea_core::{Axis, PositionXYZ, Vec3, AABB, EPSILON};
|
||||
use azalea_world::entity::{EntityData, EntityMut};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use azalea_core::{Axis, Vec3, AABB, EPSILON};
|
||||
use azalea_world::entity::{Entity, EntityData};
|
||||
use azalea_world::{Dimension, MoveEntityError};
|
||||
pub use blocks::BlockWithShape;
|
||||
use dimension_collisions::CollisionGetter;
|
||||
|
@ -81,7 +83,7 @@ impl HasCollision for Dimension {
|
|||
}
|
||||
}
|
||||
|
||||
impl MovableEntity for EntityMut<'_> {
|
||||
impl<D: DerefMut<Target = Dimension>> MovableEntity for Entity<'_, D> {
|
||||
/// Move an entity by a given delta, checking for collisions.
|
||||
fn move_colliding(
|
||||
&mut self,
|
||||
|
@ -158,6 +160,8 @@ impl MovableEntity for EntityMut<'_> {
|
|||
|
||||
if vertical_collision {
|
||||
// blockBelow.updateEntityAfterFallOn(this.level, this);
|
||||
// the default implementation of updateEntityAfterFallOn sets the y movement to 0
|
||||
self.delta.y = 0.;
|
||||
}
|
||||
|
||||
if on_ground {
|
||||
|
|
0
azalea-physics/src/collision/shape.rs
Normal file → Executable file
0
azalea-physics/src/collision/shape.rs
Normal file → Executable file
49
azalea-physics/src/lib.rs
Normal file → Executable file
49
azalea-physics/src/lib.rs
Normal file → Executable file
|
@ -2,9 +2,14 @@
|
|||
|
||||
pub mod collision;
|
||||
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use azalea_block::{Block, BlockState};
|
||||
use azalea_core::{BlockPos, Vec3};
|
||||
use azalea_world::entity::{EntityData, EntityMut};
|
||||
use azalea_world::{
|
||||
entity::{Entity, EntityData},
|
||||
Dimension,
|
||||
};
|
||||
use collision::{MovableEntity, MoverType};
|
||||
|
||||
pub trait HasPhysics {
|
||||
|
@ -14,7 +19,7 @@ pub trait HasPhysics {
|
|||
fn jump_from_ground(&mut self);
|
||||
}
|
||||
|
||||
impl HasPhysics for EntityMut<'_> {
|
||||
impl<D: DerefMut<Target = Dimension>> 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) {
|
||||
|
@ -115,17 +120,17 @@ impl HasPhysics for EntityMut<'_> {
|
|||
y: jump_power,
|
||||
z: old_delta_movement.z,
|
||||
};
|
||||
// if self.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,
|
||||
// };
|
||||
// }
|
||||
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.has_impulse = true;
|
||||
self.has_impulse = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,17 +143,21 @@ fn get_block_pos_below_that_affects_movement(entity: &EntityData) -> BlockPos {
|
|||
)
|
||||
}
|
||||
|
||||
fn handle_relative_friction_and_calculate_movement(
|
||||
entity: &mut EntityMut,
|
||||
fn handle_relative_friction_and_calculate_movement<D: DerefMut<Target = Dimension>>(
|
||||
entity: &mut Entity<D>,
|
||||
acceleration: &Vec3,
|
||||
block_friction: f32,
|
||||
) -> Vec3 {
|
||||
entity.move_relative(get_speed(&*entity, block_friction), acceleration);
|
||||
entity.move_relative(
|
||||
get_friction_influenced_speed(&*entity, block_friction),
|
||||
acceleration,
|
||||
);
|
||||
// entity.delta = entity.handle_on_climbable(entity.delta);
|
||||
entity
|
||||
.move_colliding(&MoverType::Own, &entity.delta.clone())
|
||||
.expect("Entity should exist.");
|
||||
// let delta_movement = entity.delta;
|
||||
// ladders
|
||||
// if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable() || entity.getFeetBlockState().is(Blocks.POWDER_SNOW) && PowderSnowBlock.canEntityWalkOnPowderSnow(entity))) {
|
||||
// var3 = new Vec3(var3.x, 0.2D, var3.z);
|
||||
// }
|
||||
|
@ -160,10 +169,10 @@ fn handle_relative_friction_and_calculate_movement(
|
|||
// private float getFrictionInfluencedSpeed(float friction) {
|
||||
// return this.onGround ? this.getSpeed() * (0.21600002F / (friction * friction * friction)) : this.flyingSpeed;
|
||||
// }
|
||||
fn get_speed(entity: &EntityData, friction: f32) -> f32 {
|
||||
fn get_friction_influenced_speed(entity: &EntityData, friction: f32) -> f32 {
|
||||
// TODO: have speed & flying_speed fields in entity
|
||||
if entity.on_ground {
|
||||
let speed: f32 = 0.7;
|
||||
let speed: f32 = entity.attributes.speed.calculate() as f32;
|
||||
speed * (0.216f32 / (friction * friction * friction))
|
||||
} else {
|
||||
// entity.flying_speed
|
||||
|
@ -173,7 +182,7 @@ fn get_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(entity: &EntityMut) -> f32 {
|
||||
fn block_jump_factor<D: DerefMut<Target = Dimension>>(entity: &Entity<D>) -> f32 {
|
||||
let block_at_pos = entity.dimension.get_block_state(&entity.pos().into());
|
||||
let block_below = entity
|
||||
.dimension
|
||||
|
@ -201,11 +210,11 @@ fn block_jump_factor(entity: &EntityMut) -> f32 {
|
|||
// public double getJumpBoostPower() {
|
||||
// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F * (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
|
||||
// }
|
||||
fn jump_power(entity: &EntityMut) -> f32 {
|
||||
fn jump_power<D: DerefMut<Target = Dimension>>(entity: &Entity<D>) -> f32 {
|
||||
0.42 * block_jump_factor(entity)
|
||||
}
|
||||
|
||||
fn jump_boost_power(_entity: &EntityMut) -> f64 {
|
||||
fn jump_boost_power<D: DerefMut<Target = Dimension>>(_entity: &Entity<D>) -> f64 {
|
||||
// TODO: potion effects
|
||||
// if let Some(effects) = entity.effects() {
|
||||
// if let Some(jump_effect) = effects.get(&Effect::Jump) {
|
||||
|
|
0
azalea-protocol/Cargo.toml
Normal file → Executable file
0
azalea-protocol/Cargo.toml
Normal file → Executable file
0
azalea-protocol/README.md
Normal file → Executable file
0
azalea-protocol/README.md
Normal file → Executable file
0
azalea-protocol/azalea-protocol-macros/Cargo.toml
Normal file → Executable file
0
azalea-protocol/azalea-protocol-macros/Cargo.toml
Normal file → Executable file
0
azalea-protocol/azalea-protocol-macros/src/lib.rs
Normal file → Executable file
0
azalea-protocol/azalea-protocol-macros/src/lib.rs
Normal file → Executable file
0
azalea-protocol/src/connect.rs
Normal file → Executable file
0
azalea-protocol/src/connect.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_animate_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_animate_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_changed_ack_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_changed_ack_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_event_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_event_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_update_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_block_update_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_chat_preview_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_chat_preview_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_commands_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_commands_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs
Normal file → Executable file
0
azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue