mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
Initial implementation of fluid pushing
This commit is contained in:
parent
56e0f61a51
commit
7d92a7e125
20 changed files with 366 additions and 120 deletions
|
@ -4,6 +4,8 @@ pub struct BlockBehavior {
|
|||
pub destroy_time: f32,
|
||||
pub explosion_resistance: f32,
|
||||
pub requires_correct_tool_for_drops: bool,
|
||||
|
||||
pub force_solid: Option<bool>,
|
||||
}
|
||||
|
||||
impl Default for BlockBehavior {
|
||||
|
@ -14,6 +16,7 @@ impl Default for BlockBehavior {
|
|||
destroy_time: 0.,
|
||||
explosion_resistance: 0.,
|
||||
requires_correct_tool_for_drops: false,
|
||||
force_solid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,4 +55,10 @@ impl BlockBehavior {
|
|||
self.requires_correct_tool_for_drops = true;
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: currently unused
|
||||
pub fn force_solid(mut self, force_solid: bool) -> Self {
|
||||
self.force_solid = Some(force_solid);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,14 @@ pub struct BlockState {
|
|||
}
|
||||
|
||||
impl BlockState {
|
||||
/// A shortcut for getting the air block state, since it always has an ID of
|
||||
/// 0.
|
||||
pub const AIR: BlockState = BlockState { id: 0 };
|
||||
|
||||
/// Whether the block state is possible to exist in vanilla Minecraft.
|
||||
///
|
||||
/// It's equivalent to checking that the state ID is not greater than
|
||||
/// [`Self::MAX_STATE`].
|
||||
#[inline]
|
||||
pub fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool {
|
||||
state_id <= Self::MAX_STATE
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::block_state::{BlockState, BlockStateIntegerRepr};
|
||||
use crate::{
|
||||
block_state::{BlockState, BlockStateIntegerRepr},
|
||||
Block,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FluidState {
|
||||
|
@ -12,6 +15,13 @@ pub struct FluidState {
|
|||
/// basically the opposite (0 = full, 8 = empty). You can convert between
|
||||
/// the two representations with [`to_or_from_legacy_fluid_level`].
|
||||
pub amount: u8,
|
||||
|
||||
/// Whether this fluid is at the max level and there's another fluid of the
|
||||
/// same type above it.
|
||||
///
|
||||
/// TODO: this is currently unused (always false), make this actually get
|
||||
/// set (see FlowingFluid.getFlowing)
|
||||
pub falling: bool,
|
||||
}
|
||||
impl FluidState {
|
||||
/// A floating point number in between 0 and 1 representing the height (as a
|
||||
|
@ -20,9 +30,28 @@ impl FluidState {
|
|||
self.amount as f32 / 9.
|
||||
}
|
||||
|
||||
pub fn get_flow(world: &Instance, pos: BlockPos) {
|
||||
let _ = world;
|
||||
let _ = pos;
|
||||
pub fn affects_flow(&self, other: &FluidState) -> bool {
|
||||
other.amount == 0 || self.is_same_kind(other)
|
||||
}
|
||||
|
||||
pub fn is_same_kind(&self, other: &FluidState) -> bool {
|
||||
(other.is_water() && self.is_water())
|
||||
|| (other.is_lava() && self.is_lava())
|
||||
|| (self.amount == 0 && other.amount == 0)
|
||||
}
|
||||
|
||||
pub fn is_water(&self) -> bool {
|
||||
matches!(
|
||||
self.fluid,
|
||||
azalea_registry::Fluid::Water | azalea_registry::Fluid::FlowingWater
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_lava(&self) -> bool {
|
||||
matches!(
|
||||
self.fluid,
|
||||
azalea_registry::Fluid::Lava | azalea_registry::Fluid::FlowingLava
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +60,7 @@ impl Default for FluidState {
|
|||
Self {
|
||||
fluid: azalea_registry::Fluid::Empty,
|
||||
amount: 0,
|
||||
falling: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +77,7 @@ impl From<BlockState> for FluidState {
|
|||
Self {
|
||||
fluid: azalea_registry::Fluid::Water,
|
||||
amount: 8,
|
||||
falling: false,
|
||||
}
|
||||
} else {
|
||||
let block = Box::<dyn Block>::from(state);
|
||||
|
@ -54,16 +85,19 @@ impl From<BlockState> for FluidState {
|
|||
Self {
|
||||
fluid: azalea_registry::Fluid::Water,
|
||||
amount: to_or_from_legacy_fluid_level(water.level as u8),
|
||||
falling: false,
|
||||
}
|
||||
} else if let Some(lava) = block.downcast_ref::<crate::blocks::Lava>() {
|
||||
Self {
|
||||
fluid: azalea_registry::Fluid::Lava,
|
||||
amount: to_or_from_legacy_fluid_level(lava.level as u8),
|
||||
falling: false,
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
fluid: azalea_registry::Fluid::Empty,
|
||||
amount: 0,
|
||||
falling: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,11 @@ mod generated;
|
|||
mod range;
|
||||
|
||||
use core::fmt::Debug;
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt,
|
||||
io::{self, Cursor, Write},
|
||||
};
|
||||
use std::any::Any;
|
||||
|
||||
use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
|
||||
pub use behavior::BlockBehavior;
|
||||
use block_state::BlockState;
|
||||
// re-exported for convenience
|
||||
pub use block_state::BlockState;
|
||||
pub use generated::{blocks, properties};
|
||||
pub use range::BlockStates;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use azalea_block::{Block, BlockState, FluidState};
|
||||
use azalea_block::{fluid_state::FluidState, Block, BlockState};
|
||||
use azalea_core::{direction::Direction, game_type::GameMode, position::BlockPos, tick::GameTick};
|
||||
use azalea_entity::{mining::get_mine_progress, FluidOnEyes, Physics};
|
||||
use azalea_inventory::ItemStack;
|
||||
|
|
|
@ -65,7 +65,8 @@ impl Plugin for PlayerMovePlugin {
|
|||
(tick_controls, local_player_ai_step)
|
||||
.chain()
|
||||
.in_set(PhysicsSet)
|
||||
.before(ai_step),
|
||||
.before(ai_step)
|
||||
.before(azalea_physics::fluids::update_in_water_state_and_do_fluid_pushing),
|
||||
send_sprinting_if_needed.after(azalea_entity::update_in_loaded_chunk),
|
||||
send_position.after(PhysicsSet),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use azalea_buf::AzBuf;
|
||||
|
||||
use crate::position::Vec3;
|
||||
use crate::position::{BlockPos, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Debug, AzBuf, Default, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
@ -15,6 +15,14 @@ pub enum Direction {
|
|||
}
|
||||
|
||||
impl Direction {
|
||||
pub const HORIZONTAL: [Direction; 4] = [
|
||||
Direction::North,
|
||||
Direction::South,
|
||||
Direction::West,
|
||||
Direction::East,
|
||||
];
|
||||
pub const VERTICAL: [Direction; 2] = [Direction::Down, Direction::Up];
|
||||
|
||||
pub fn nearest(vec: Vec3) -> Direction {
|
||||
let mut best_direction = Direction::North;
|
||||
let mut best_direction_amount = 0.0;
|
||||
|
@ -29,7 +37,7 @@ impl Direction {
|
|||
]
|
||||
.iter()
|
||||
{
|
||||
let amount = dir.normal().dot(vec);
|
||||
let amount = dir.normal_vec3().dot(vec);
|
||||
if amount > best_direction_amount {
|
||||
best_direction = *dir;
|
||||
best_direction_amount = amount;
|
||||
|
@ -39,17 +47,23 @@ impl Direction {
|
|||
best_direction
|
||||
}
|
||||
|
||||
pub fn normal(self) -> Vec3 {
|
||||
#[inline]
|
||||
pub fn normal(self) -> BlockPos {
|
||||
match self {
|
||||
Direction::Down => Vec3::new(0.0, -1.0, 0.0),
|
||||
Direction::Up => Vec3::new(0.0, 1.0, 0.0),
|
||||
Direction::North => Vec3::new(0.0, 0.0, -1.0),
|
||||
Direction::South => Vec3::new(0.0, 0.0, 1.0),
|
||||
Direction::West => Vec3::new(-1.0, 0.0, 0.0),
|
||||
Direction::East => Vec3::new(1.0, 0.0, 0.0),
|
||||
Direction::Down => BlockPos::new(0, -1, 0),
|
||||
Direction::Up => BlockPos::new(0, 1, 0),
|
||||
Direction::North => BlockPos::new(0, 0, -1),
|
||||
Direction::South => BlockPos::new(0, 0, 1),
|
||||
Direction::West => BlockPos::new(-1, 0, 0),
|
||||
Direction::East => BlockPos::new(1, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn normal_vec3(self) -> Vec3 {
|
||||
self.normal().to_vec3_floored()
|
||||
}
|
||||
|
||||
pub fn opposite(self) -> Direction {
|
||||
match self {
|
||||
Direction::Down => Direction::Up,
|
||||
|
@ -60,6 +74,16 @@ impl Direction {
|
|||
Direction::East => Direction::West,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn x(self) -> i32 {
|
||||
self.normal().x
|
||||
}
|
||||
pub fn y(self) -> i32 {
|
||||
self.normal().y
|
||||
}
|
||||
pub fn z(self) -> i32 {
|
||||
self.normal().z
|
||||
}
|
||||
}
|
||||
|
||||
/// The four cardinal directions.
|
||||
|
|
|
@ -8,11 +8,12 @@ use std::{
|
|||
fmt,
|
||||
hash::Hash,
|
||||
io::{Cursor, Write},
|
||||
ops::{Add, AddAssign, Mul, Rem, Sub},
|
||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub},
|
||||
};
|
||||
|
||||
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
|
||||
|
||||
use crate::direction::Direction;
|
||||
use crate::math;
|
||||
use crate::resource_location::ResourceLocation;
|
||||
|
||||
|
@ -138,7 +139,6 @@ macro_rules! vec3_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for $name {
|
||||
type Output = $name;
|
||||
|
||||
|
@ -147,6 +147,18 @@ macro_rules! vec3_impl {
|
|||
(&self).add(&rhs)
|
||||
}
|
||||
}
|
||||
impl Add<$type> for $name {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: $type) -> Self::Output {
|
||||
Self {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
z: self.z + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for $name {
|
||||
#[inline]
|
||||
|
@ -203,6 +215,35 @@ macro_rules! vec3_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl MulAssign<$type> for $name {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, multiplier: $type) {
|
||||
self.x *= multiplier;
|
||||
self.y *= multiplier;
|
||||
self.z *= multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<$type> for $name {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn div(self, divisor: $type) -> Self::Output {
|
||||
Self {
|
||||
x: self.x / divisor,
|
||||
y: self.y / divisor,
|
||||
z: self.z / divisor,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DivAssign<$type> for $name {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, divisor: $type) {
|
||||
self.x /= divisor;
|
||||
self.y /= divisor;
|
||||
self.z /= divisor;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<($type, $type, $type)> for $name {
|
||||
#[inline]
|
||||
|
@ -345,6 +386,10 @@ impl BlockPos {
|
|||
z: self.z.max(other.z),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset_with_direction(self, direction: Direction) -> Self {
|
||||
self + direction.normal()
|
||||
}
|
||||
}
|
||||
|
||||
/// Chunk coordinates are used to represent where a chunk is in the world. You
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use azalea_block::{BlockState, FluidState};
|
||||
use azalea_block::{fluid_state::FluidState, BlockState};
|
||||
use azalea_core::{
|
||||
block_hit_result::BlockHitResult,
|
||||
direction::Direction,
|
||||
|
|
|
@ -238,39 +238,33 @@ impl BitSetDiscreteVoxelShape {
|
|||
var2: bool,
|
||||
) {
|
||||
let mut var3 = BitSetDiscreteVoxelShape::from(var0);
|
||||
for var4 in 0..var3.y_size {
|
||||
for var5 in 0..var3.x_size {
|
||||
for y in 0..var3.y_size {
|
||||
for x in 0..var3.x_size {
|
||||
let mut var6 = None;
|
||||
for var7 in 0..=var3.z_size {
|
||||
if var3.is_full_wide(var5, var4, var7) {
|
||||
for z in 0..=var3.z_size {
|
||||
if var3.is_full_wide(x, y, z) {
|
||||
if var2 {
|
||||
if var6.is_none() {
|
||||
var6 = Some(var7);
|
||||
var6 = Some(z);
|
||||
}
|
||||
} else {
|
||||
consumer(var5, var4, var7, var5 + 1, var4 + 1, var7 + 1);
|
||||
consumer(x, y, z, x + 1, y + 1, z + 1);
|
||||
}
|
||||
} else if var6.is_some() {
|
||||
let mut var8 = var5;
|
||||
let mut var9 = var4;
|
||||
var3.clear_z_strip(var6.unwrap(), var7, var5, var4);
|
||||
while var3.is_z_strip_full(var6.unwrap(), var7, var8 + 1, var4) {
|
||||
var3.clear_z_strip(var6.unwrap(), var7, var8 + 1, var4);
|
||||
let mut var8 = x;
|
||||
let mut var9 = y;
|
||||
var3.clear_z_strip(var6.unwrap(), z, x, y);
|
||||
while var3.is_z_strip_full(var6.unwrap(), z, var8 + 1, y) {
|
||||
var3.clear_z_strip(var6.unwrap(), z, var8 + 1, y);
|
||||
var8 += 1;
|
||||
}
|
||||
while var3.is_xz_rectangle_full(
|
||||
var5,
|
||||
var8 + 1,
|
||||
var6.unwrap(),
|
||||
var7,
|
||||
var9 + 1,
|
||||
) {
|
||||
for var10 in var5..=var8 {
|
||||
var3.clear_z_strip(var6.unwrap(), var7, var10, var9 + 1);
|
||||
while var3.is_xz_rectangle_full(x, var8 + 1, var6.unwrap(), z, var9 + 1) {
|
||||
for var10 in x..=var8 {
|
||||
var3.clear_z_strip(var6.unwrap(), z, var10, var9 + 1);
|
||||
}
|
||||
var9 += 1;
|
||||
}
|
||||
consumer(var5, var4, var6.unwrap(), var8 + 1, var9 + 1, var7);
|
||||
consumer(x, y, var6.unwrap(), var8 + 1, var9 + 1, z);
|
||||
var6 = None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ mod world_collisions;
|
|||
|
||||
use std::{ops::Add, sync::LazyLock};
|
||||
|
||||
use azalea_block::FluidState;
|
||||
use azalea_block::{fluid_state::FluidState, BlockState};
|
||||
use azalea_core::{
|
||||
aabb::AABB,
|
||||
direction::Axis,
|
||||
|
@ -111,7 +111,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
|
|||
y: 0.,
|
||||
z: movement.z,
|
||||
},
|
||||
&entity_bounding_box.move_relative(&directly_up_delta),
|
||||
&entity_bounding_box.move_relative(directly_up_delta),
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
)
|
||||
|
@ -132,7 +132,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
|
|||
y: -step_to_delta.y + movement.y,
|
||||
z: 0.,
|
||||
},
|
||||
&entity_bounding_box.move_relative(&step_to_delta),
|
||||
&entity_bounding_box.move_relative(step_to_delta),
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
));
|
||||
|
@ -296,7 +296,7 @@ fn collide_with_shapes(
|
|||
if y_movement != 0. {
|
||||
y_movement = Shapes::collide(&Axis::Y, &entity_box, collision_boxes, y_movement);
|
||||
if y_movement != 0. {
|
||||
entity_box = entity_box.move_relative(&Vec3 {
|
||||
entity_box = entity_box.move_relative(Vec3 {
|
||||
x: 0.,
|
||||
y: y_movement,
|
||||
z: 0.,
|
||||
|
@ -311,7 +311,7 @@ fn collide_with_shapes(
|
|||
if more_z_movement && z_movement != 0. {
|
||||
z_movement = Shapes::collide(&Axis::Z, &entity_box, collision_boxes, z_movement);
|
||||
if z_movement != 0. {
|
||||
entity_box = entity_box.move_relative(&Vec3 {
|
||||
entity_box = entity_box.move_relative(Vec3 {
|
||||
x: 0.,
|
||||
y: 0.,
|
||||
z: z_movement,
|
||||
|
@ -322,7 +322,7 @@ fn collide_with_shapes(
|
|||
if x_movement != 0. {
|
||||
x_movement = Shapes::collide(&Axis::X, &entity_box, collision_boxes, x_movement);
|
||||
if x_movement != 0. {
|
||||
entity_box = entity_box.move_relative(&Vec3 {
|
||||
entity_box = entity_box.move_relative(Vec3 {
|
||||
x: x_movement,
|
||||
y: 0.,
|
||||
z: 0.,
|
||||
|
@ -384,3 +384,28 @@ pub fn fluid_shape(
|
|||
fn calculate_shape_for_fluid(amount: u8) -> VoxelShape {
|
||||
box_shape(0.0, 0.0, 0.0, 1.0, (f32::from(amount) / 9.0) as f64, 1.0)
|
||||
}
|
||||
|
||||
/// Whether the block is treated as "motion blocking".
|
||||
///
|
||||
/// This is marked as deprecated in Minecraft.
|
||||
pub fn legacy_blocks_motion(block: BlockState) -> bool {
|
||||
let registry_block = azalea_registry::Block::from(block);
|
||||
legacy_calculate_solid(block)
|
||||
&& registry_block != azalea_registry::Block::Cobweb
|
||||
&& registry_block != azalea_registry::Block::BambooSapling
|
||||
}
|
||||
|
||||
pub fn legacy_calculate_solid(block: BlockState) -> bool {
|
||||
// force_solid has to be checked before anything else
|
||||
let block_trait = Box::<dyn azalea_block::Block>::from(block);
|
||||
if let Some(solid) = block_trait.behavior().force_solid {
|
||||
return solid;
|
||||
}
|
||||
|
||||
let shape = block.collision_shape();
|
||||
if shape.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let bounds = shape.bounds();
|
||||
bounds.size() >= 0.7291666666666666 || bounds.get_size(Axis::Y) >= 1.0
|
||||
}
|
||||
|
|
|
@ -526,13 +526,6 @@ impl VoxelShape {
|
|||
movement
|
||||
}
|
||||
|
||||
// public VoxelShape optimize() {
|
||||
// VoxelShape[] var1 = new VoxelShape[]{Shapes.empty()};
|
||||
// this.forAllBoxes((var1x, var3, var5, var7, var9, var11) -> {
|
||||
// var1[0] = Shapes.joinUnoptimized(var1[0], Shapes.box(var1x, var3,
|
||||
// var5, var7, var9, var11), BooleanOp.OR); });
|
||||
// return var1[0];
|
||||
// }
|
||||
fn optimize(&self) -> VoxelShape {
|
||||
let mut shape = EMPTY_SHAPE.clone();
|
||||
self.for_all_boxes(|var1x, var3, var5, var7, var9, var11| {
|
||||
|
@ -545,35 +538,10 @@ impl VoxelShape {
|
|||
shape
|
||||
}
|
||||
|
||||
// public void forAllBoxes(Shapes.DoubleLineConsumer var1) {
|
||||
// DoubleList var2 = this.getCoords(Direction.Axis.X);
|
||||
// DoubleList var3 = this.getCoords(Direction.Axis.Y);
|
||||
// DoubleList var4 = this.getCoords(Direction.Axis.Z);
|
||||
// this.shape.forAllBoxes((var4x, var5, var6, var7, var8, var9) -> {
|
||||
// var1.consume(var2.getDouble(var4x), var3.getDouble(var5),
|
||||
// var4.getDouble(var6), var2.getDouble(var7), var3.getDouble(var8),
|
||||
// var4.getDouble(var9)); }, true);
|
||||
// }
|
||||
pub fn for_all_boxes(&self, mut consumer: impl FnMut(f64, f64, f64, f64, f64, f64))
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// let x_coords = self.get_coords(Axis::X);
|
||||
// let y_coords = self.get_coords(Axis::Y);
|
||||
// let z_coords = self.get_coords(Axis::Z);
|
||||
// self.shape().for_all_boxes(
|
||||
// |var4x, var5, var6, var7, var8, var9| {
|
||||
// consumer(
|
||||
// x_coords[var4x as usize],
|
||||
// y_coords[var5 as usize],
|
||||
// z_coords[var6 as usize],
|
||||
// x_coords[var7 as usize],
|
||||
// y_coords[var8 as usize],
|
||||
// z_coords[var9 as usize],
|
||||
// )
|
||||
// },
|
||||
// true,
|
||||
// );
|
||||
let x_coords = self.get_coords(Axis::X);
|
||||
let y_coords = self.get_coords(Axis::Y);
|
||||
let z_coords = self.get_coords(Axis::Z);
|
||||
|
@ -596,22 +564,26 @@ impl VoxelShape {
|
|||
let mut aabbs = Vec::new();
|
||||
self.for_all_boxes(|min_x, min_y, min_z, max_x, max_y, max_z| {
|
||||
aabbs.push(AABB {
|
||||
min_x,
|
||||
min_y,
|
||||
min_z,
|
||||
max_x,
|
||||
max_y,
|
||||
max_z,
|
||||
min: Vec3::new(min_x, min_y, min_z),
|
||||
max: Vec3::new(max_x, max_y, max_z),
|
||||
});
|
||||
});
|
||||
aabbs
|
||||
}
|
||||
|
||||
pub fn bounds(&self) -> AABB {
|
||||
assert!(!self.is_empty(), "Can't get bounds for empty shape");
|
||||
AABB {
|
||||
min: Vec3::new(self.min(Axis::X), self.min(Axis::Y), self.min(Axis::Z)),
|
||||
max: Vec3::new(self.max(Axis::X), self.max(Axis::Y), self.max(Axis::Z)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AABB> for VoxelShape {
|
||||
fn from(aabb: AABB) -> Self {
|
||||
box_shape_unchecked(
|
||||
aabb.min_x, aabb.min_y, aabb.min_z, aabb.max_x, aabb.max_y, aabb.max_z,
|
||||
aabb.min.x, aabb.min.y, aabb.min.z, aabb.max.x, aabb.max.y, aabb.max.z,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,12 +49,8 @@ pub fn get_block_collisions(world: &Instance, aabb: AABB) -> Vec<VoxelShape> {
|
|||
// if it's a full block do a faster collision check
|
||||
if block_state.is_collision_shape_full() {
|
||||
if !state.aabb.intersects_aabb(&AABB {
|
||||
min_x: item.pos.x as f64,
|
||||
min_y: item.pos.y as f64,
|
||||
min_z: item.pos.z as f64,
|
||||
max_x: (item.pos.x + 1) as f64,
|
||||
max_y: (item.pos.y + 1) as f64,
|
||||
max_z: (item.pos.z + 1) as f64,
|
||||
min: item.pos.to_vec3_floored(),
|
||||
max: (item.pos + 1).to_vec3_floored(),
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
@ -95,15 +91,15 @@ pub struct BlockCollisionsState<'a> {
|
|||
impl<'a> BlockCollisionsState<'a> {
|
||||
pub fn new(world: &'a Instance, aabb: AABB) -> Self {
|
||||
let origin = BlockPos {
|
||||
x: (aabb.min_x - EPSILON).floor() as i32 - 1,
|
||||
y: (aabb.min_y - EPSILON).floor() as i32 - 1,
|
||||
z: (aabb.min_z - EPSILON).floor() as i32 - 1,
|
||||
x: (aabb.min.x - EPSILON).floor() as i32 - 1,
|
||||
y: (aabb.min.y - EPSILON).floor() as i32 - 1,
|
||||
z: (aabb.min.z - EPSILON).floor() as i32 - 1,
|
||||
};
|
||||
|
||||
let end = BlockPos {
|
||||
x: (aabb.max_x + EPSILON).floor() as i32 + 1,
|
||||
y: (aabb.max_y + EPSILON).floor() as i32 + 1,
|
||||
z: (aabb.max_z + EPSILON).floor() as i32 + 1,
|
||||
x: (aabb.max.x + EPSILON).floor() as i32 + 1,
|
||||
y: (aabb.max.y + EPSILON).floor() as i32 + 1,
|
||||
z: (aabb.max.z + EPSILON).floor() as i32 + 1,
|
||||
};
|
||||
|
||||
let cursor = Cursor3d::new(origin, end);
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
use std::cmp;
|
||||
|
||||
use azalea_core::position::{BlockPos, Vec3};
|
||||
use azalea_block::{fluid_state::FluidState, BlockState};
|
||||
use azalea_core::{
|
||||
direction::Direction,
|
||||
position::{BlockPos, Vec3},
|
||||
};
|
||||
use azalea_entity::{metadata::AbstractBoat, InLoadedChunk, LocalEntity, Physics, Position};
|
||||
use azalea_registry::{EntityKind, Fluid};
|
||||
use azalea_world::{Instance, InstanceContainer, InstanceName};
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
use crate::collision::legacy_blocks_motion;
|
||||
|
||||
pub fn update_in_water_state_and_do_fluid_pushing(
|
||||
mut query: Query<
|
||||
(&mut Physics, &Position, &InstanceName),
|
||||
|
@ -19,14 +25,20 @@ pub fn update_in_water_state_and_do_fluid_pushing(
|
|||
.expect("All entities should be in a valid world");
|
||||
let world = world_lock.read();
|
||||
|
||||
println!("update_in_water_state_and_do_fluid_pushing");
|
||||
|
||||
physics.water_fluid_height = 0.;
|
||||
physics.lava_fluid_height = 0.;
|
||||
|
||||
update_in_water_state_and_do_water_current_pushing(&mut physics, &world, &position);
|
||||
let lava_push_factor = world
|
||||
.registries
|
||||
.dimension_type()
|
||||
.map(|d| d.lava_push_factor);
|
||||
|
||||
println!("physics.water_fluid_height: {}", physics.water_fluid_height);
|
||||
|
||||
// let lava_push_factor = world
|
||||
// .registries
|
||||
// .dimension_type()
|
||||
// .map(|d| d.lava_push_factor);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
fn update_in_water_state_and_do_water_current_pushing(
|
||||
|
@ -59,18 +71,20 @@ fn update_fluid_height_and_do_fluid_pushing(
|
|||
physics: &mut Physics,
|
||||
world: &Instance,
|
||||
checking_fluid: Fluid,
|
||||
fluid_push_factor: f32,
|
||||
fluid_push_factor: f64,
|
||||
) -> bool {
|
||||
// if touching_unloaded_chunk() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
let checking_liquids_aabb = physics.bounding_box.deflate_all(0.001);
|
||||
|
||||
let min_x = checking_liquids_aabb.min.x.floor() as i32;
|
||||
let max_x = checking_liquids_aabb.max.x.ceil() as i32;
|
||||
let min_y = checking_liquids_aabb.min.y.floor() as i32;
|
||||
let max_y = checking_liquids_aabb.max.y.ceil() as i32;
|
||||
let min_z = checking_liquids_aabb.min.z.floor() as i32;
|
||||
|
||||
let max_x = checking_liquids_aabb.max.x.ceil() as i32;
|
||||
let max_y = checking_liquids_aabb.max.y.ceil() as i32;
|
||||
let max_z = checking_liquids_aabb.max.z.ceil() as i32;
|
||||
|
||||
let mut min_height_touching = 0.;
|
||||
|
@ -94,14 +108,19 @@ fn update_fluid_height_and_do_fluid_pushing(
|
|||
continue;
|
||||
}
|
||||
touching_fluid = true;
|
||||
min_height_touching = f64::min(
|
||||
min_height_touching = f64::max(
|
||||
fluid_max_y - checking_liquids_aabb.min.y,
|
||||
min_height_touching,
|
||||
);
|
||||
if !is_entity_pushable_by_fluid {
|
||||
continue;
|
||||
}
|
||||
let mut additional_player_delta_for_fluid = fluid_at_cur_pos.flow();
|
||||
let mut additional_player_delta_for_fluid =
|
||||
get_fluid_flow(&fluid_at_cur_pos, world, cur_pos);
|
||||
println!(
|
||||
"additional_player_delta_for_fluid: {}",
|
||||
additional_player_delta_for_fluid
|
||||
);
|
||||
if min_height_touching < 0.4 {
|
||||
additional_player_delta_for_fluid *= min_height_touching;
|
||||
};
|
||||
|
@ -112,6 +131,9 @@ fn update_fluid_height_and_do_fluid_pushing(
|
|||
}
|
||||
}
|
||||
|
||||
println!("num_fluids_being_touched: {}", num_fluids_being_touched);
|
||||
println!("additional_player_delta: {}", additional_player_delta);
|
||||
|
||||
if additional_player_delta.length() > 0. {
|
||||
additional_player_delta /= num_fluids_being_touched as f64;
|
||||
|
||||
|
@ -120,7 +142,7 @@ fn update_fluid_height_and_do_fluid_pushing(
|
|||
// }
|
||||
|
||||
let player_delta = physics.velocity;
|
||||
additionalPlayerDelta *= fluid_push_factor;
|
||||
additional_player_delta *= fluid_push_factor;
|
||||
const MIN_PUSH: f64 = 0.003;
|
||||
const MIN_PUSH_LENGTH: f64 = MIN_PUSH * 1.5;
|
||||
|
||||
|
@ -146,3 +168,108 @@ fn update_fluid_height_and_do_fluid_pushing(
|
|||
pub fn update_swimming() {
|
||||
// TODO: swimming
|
||||
}
|
||||
|
||||
// FlowingFluid.getFlow
|
||||
pub fn get_fluid_flow(fluid: &FluidState, world: &Instance, pos: BlockPos) -> Vec3 {
|
||||
let mut z_flow: f64 = 0.;
|
||||
let mut x_flow: f64 = 0.;
|
||||
|
||||
for direction in Direction::HORIZONTAL {
|
||||
let adjacent_block_pos = pos.offset_with_direction(direction);
|
||||
let adjacent_fluid_state = world
|
||||
.get_fluid_state(&adjacent_block_pos)
|
||||
.unwrap_or_default();
|
||||
if fluid.affects_flow(&adjacent_fluid_state) {
|
||||
println!(
|
||||
"affects flow {adjacent_block_pos} {:?}",
|
||||
adjacent_fluid_state
|
||||
);
|
||||
let mut adjacent_fluid_height = adjacent_fluid_state.height();
|
||||
let mut adjacent_height_difference: f32 = 0.;
|
||||
|
||||
if adjacent_fluid_height == 0. {
|
||||
if !legacy_blocks_motion(
|
||||
world
|
||||
.get_block_state(&adjacent_block_pos)
|
||||
.unwrap_or_default(),
|
||||
) {
|
||||
let block_pos_below_adjacent = adjacent_block_pos.down(1);
|
||||
let fluid_below_adjacent = world
|
||||
.get_fluid_state(&block_pos_below_adjacent)
|
||||
.unwrap_or_default();
|
||||
|
||||
if fluid.affects_flow(&fluid_below_adjacent) {
|
||||
adjacent_fluid_height = fluid_below_adjacent.height();
|
||||
if adjacent_fluid_height > 0. {
|
||||
adjacent_height_difference =
|
||||
fluid.height() - (adjacent_fluid_height - 0.8888889);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if adjacent_fluid_height > 0. {
|
||||
adjacent_height_difference = fluid.height() - adjacent_fluid_height;
|
||||
}
|
||||
|
||||
if adjacent_height_difference != 0. {
|
||||
x_flow += (direction.x() as f32 * adjacent_height_difference) as f64;
|
||||
z_flow += (direction.z() as f32 * adjacent_height_difference) as f64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut flow = Vec3::new(x_flow, 0., z_flow);
|
||||
if fluid.falling {
|
||||
for direction in Direction::HORIZONTAL {
|
||||
let adjacent_block_pos = pos.offset_with_direction(direction);
|
||||
if is_solid_face(fluid, world, adjacent_block_pos, direction)
|
||||
|| is_solid_face(fluid, world, adjacent_block_pos.up(1), direction)
|
||||
{
|
||||
flow = flow.normalize() + Vec3::new(0., -6., 0.);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flow.normalize()
|
||||
}
|
||||
|
||||
// i don't really get what this is for
|
||||
fn is_solid_face(
|
||||
fluid: &FluidState,
|
||||
world: &Instance,
|
||||
adjacent_pos: BlockPos,
|
||||
direction: Direction,
|
||||
) -> bool {
|
||||
let block_state = world.get_block_state(&adjacent_pos).unwrap_or_default();
|
||||
let fluid_state = world.get_fluid_state(&adjacent_pos).unwrap_or_default();
|
||||
if fluid_state.is_same_kind(fluid) {
|
||||
return false;
|
||||
}
|
||||
if direction == Direction::Up {
|
||||
return true;
|
||||
}
|
||||
let registry_block = azalea_registry::Block::from(block_state);
|
||||
if matches!(
|
||||
registry_block,
|
||||
azalea_registry::Block::Ice | azalea_registry::Block::FrostedIce
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
is_face_sturdy(block_state, world, adjacent_pos, direction)
|
||||
}
|
||||
|
||||
fn is_face_sturdy(
|
||||
block_state: BlockState,
|
||||
world: &Instance,
|
||||
pos: BlockPos,
|
||||
direction: Direction,
|
||||
) -> bool {
|
||||
// TODO: this does a whole bunch of physics shape checks for waterlogged blocks
|
||||
// that i honestly cannot be bothered to implement right now
|
||||
|
||||
// see BlockBehavior.isFaceSturdy in the decompiled minecraft source
|
||||
|
||||
// also, this probably should be in a module other than fluids.rs
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ use std::{
|
|||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use azalea_block::{BlockState, BlockStateIntegerRepr, FluidState};
|
||||
use azalea_block::block_state::{BlockState, BlockStateIntegerRepr};
|
||||
use azalea_block::fluid_state::FluidState;
|
||||
use azalea_buf::{AzaleaRead, AzaleaWrite, BufReadError};
|
||||
use azalea_core::position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
|
||||
use nohash_hasher::IntMap;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use azalea_block::{BlockState, BlockStates};
|
||||
use azalea_block::{block_state::BlockState, BlockStates};
|
||||
use azalea_core::position::{BlockPos, ChunkPos};
|
||||
|
||||
use crate::{iterators::ChunkIterator, palette::Palette, ChunkStorage, Instance};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::io::{Cursor, Write};
|
||||
|
||||
use azalea_block::BlockStateIntegerRepr;
|
||||
use azalea_block::block_state::BlockStateIntegerRepr;
|
||||
use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
|
||||
use azalea_core::math;
|
||||
use tracing::warn;
|
||||
|
|
|
@ -5,7 +5,8 @@ use std::{
|
|||
fmt::Debug,
|
||||
};
|
||||
|
||||
use azalea_block::{BlockState, FluidState};
|
||||
use azalea_block::fluid_state::FluidState;
|
||||
use azalea_block::BlockState;
|
||||
use azalea_core::position::{BlockPos, ChunkPos};
|
||||
use azalea_core::registry_holder::RegistryHolder;
|
||||
use bevy_ecs::{component::Component, entity::Entity};
|
||||
|
|
|
@ -114,7 +114,20 @@ pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
|
|||
println!("getblock xyz {x} {y} {z}");
|
||||
let block_pos = BlockPos::new(x, y, z);
|
||||
let block = source.bot.world().read().get_block_state(&block_pos);
|
||||
source.reply(&format!("Block at {block_pos:?} is {block:?}"));
|
||||
source.reply(&format!("Block at {block_pos} is {block:?}"));
|
||||
1
|
||||
})),
|
||||
)));
|
||||
commands.register(literal("getfluid").then(argument("x", integer()).then(
|
||||
argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
|
||||
let source = ctx.source.lock();
|
||||
let x = get_integer(ctx, "x").unwrap();
|
||||
let y = get_integer(ctx, "y").unwrap();
|
||||
let z = get_integer(ctx, "z").unwrap();
|
||||
println!("getfluid xyz {x} {y} {z}");
|
||||
let block_pos = BlockPos::new(x, y, z);
|
||||
let block = source.bot.world().read().get_fluid_state(&block_pos);
|
||||
source.reply(&format!("Fluid at {block_pos} is {block:?}"));
|
||||
1
|
||||
})),
|
||||
)));
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::{cell::UnsafeCell, ops::RangeInclusive};
|
||||
|
||||
use azalea_block::{properties::Waterlogged, BlockState, BlockStateIntegerRepr, BlockStates};
|
||||
use azalea_block::{
|
||||
block_state::BlockStateIntegerRepr, properties::Waterlogged, BlockState, BlockStates,
|
||||
};
|
||||
use azalea_inventory::Menu;
|
||||
use nohash_hasher::IntMap;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue