Skip to content

Commit 7d92a7e

Browse files
committed
Initial implementation of fluid pushing
1 parent 56e0f61 commit 7d92a7e

File tree

20 files changed

+366
-120
lines changed

20 files changed

+366
-120
lines changed

azalea-block/src/behavior.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub struct BlockBehavior {
44
pub destroy_time: f32,
55
pub explosion_resistance: f32,
66
pub requires_correct_tool_for_drops: bool,
7+
8+
pub force_solid: Option<bool>,
79
}
810

911
impl Default for BlockBehavior {
@@ -14,6 +16,7 @@ impl Default for BlockBehavior {
1416
destroy_time: 0.,
1517
explosion_resistance: 0.,
1618
requires_correct_tool_for_drops: false,
19+
force_solid: None,
1720
}
1821
}
1922
}
@@ -52,4 +55,10 @@ impl BlockBehavior {
5255
self.requires_correct_tool_for_drops = true;
5356
self
5457
}
58+
59+
// TODO: currently unused
60+
pub fn force_solid(mut self, force_solid: bool) -> Self {
61+
self.force_solid = Some(force_solid);
62+
self
63+
}
5564
}

azalea-block/src/block_state.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ pub struct BlockState {
3131
}
3232

3333
impl BlockState {
34+
/// A shortcut for getting the air block state, since it always has an ID of
35+
/// 0.
3436
pub const AIR: BlockState = BlockState { id: 0 };
3537

38+
/// Whether the block state is possible to exist in vanilla Minecraft.
39+
///
40+
/// It's equivalent to checking that the state ID is not greater than
41+
/// [`Self::MAX_STATE`].
3642
#[inline]
3743
pub fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool {
3844
state_id <= Self::MAX_STATE

azalea-block/src/fluid_state.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::block_state::{BlockState, BlockStateIntegerRepr};
1+
use crate::{
2+
block_state::{BlockState, BlockStateIntegerRepr},
3+
Block,
4+
};
25

36
#[derive(Clone, Debug)]
47
pub struct FluidState {
@@ -12,6 +15,13 @@ pub struct FluidState {
1215
/// basically the opposite (0 = full, 8 = empty). You can convert between
1316
/// the two representations with [`to_or_from_legacy_fluid_level`].
1417
pub amount: u8,
18+
19+
/// Whether this fluid is at the max level and there's another fluid of the
20+
/// same type above it.
21+
///
22+
/// TODO: this is currently unused (always false), make this actually get
23+
/// set (see FlowingFluid.getFlowing)
24+
pub falling: bool,
1525
}
1626
impl FluidState {
1727
/// A floating point number in between 0 and 1 representing the height (as a
@@ -20,9 +30,28 @@ impl FluidState {
2030
self.amount as f32 / 9.
2131
}
2232

23-
pub fn get_flow(world: &Instance, pos: BlockPos) {
24-
let _ = world;
25-
let _ = pos;
33+
pub fn affects_flow(&self, other: &FluidState) -> bool {
34+
other.amount == 0 || self.is_same_kind(other)
35+
}
36+
37+
pub fn is_same_kind(&self, other: &FluidState) -> bool {
38+
(other.is_water() && self.is_water())
39+
|| (other.is_lava() && self.is_lava())
40+
|| (self.amount == 0 && other.amount == 0)
41+
}
42+
43+
pub fn is_water(&self) -> bool {
44+
matches!(
45+
self.fluid,
46+
azalea_registry::Fluid::Water | azalea_registry::Fluid::FlowingWater
47+
)
48+
}
49+
50+
pub fn is_lava(&self) -> bool {
51+
matches!(
52+
self.fluid,
53+
azalea_registry::Fluid::Lava | azalea_registry::Fluid::FlowingLava
54+
)
2655
}
2756
}
2857

@@ -31,6 +60,7 @@ impl Default for FluidState {
3160
Self {
3261
fluid: azalea_registry::Fluid::Empty,
3362
amount: 0,
63+
falling: false,
3464
}
3565
}
3666
}
@@ -47,23 +77,27 @@ impl From<BlockState> for FluidState {
4777
Self {
4878
fluid: azalea_registry::Fluid::Water,
4979
amount: 8,
80+
falling: false,
5081
}
5182
} else {
5283
let block = Box::<dyn Block>::from(state);
5384
if let Some(water) = block.downcast_ref::<crate::blocks::Water>() {
5485
Self {
5586
fluid: azalea_registry::Fluid::Water,
5687
amount: to_or_from_legacy_fluid_level(water.level as u8),
88+
falling: false,
5789
}
5890
} else if let Some(lava) = block.downcast_ref::<crate::blocks::Lava>() {
5991
Self {
6092
fluid: azalea_registry::Fluid::Lava,
6193
amount: to_or_from_legacy_fluid_level(lava.level as u8),
94+
falling: false,
6295
}
6396
} else {
6497
Self {
6598
fluid: azalea_registry::Fluid::Empty,
6699
amount: 0,
100+
falling: false,
67101
}
68102
}
69103
}

azalea-block/src/lib.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@ mod generated;
88
mod range;
99

1010
use core::fmt::Debug;
11-
use std::{
12-
any::Any,
13-
fmt,
14-
io::{self, Cursor, Write},
15-
};
11+
use std::any::Any;
1612

17-
use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
1813
pub use behavior::BlockBehavior;
19-
use block_state::BlockState;
14+
// re-exported for convenience
15+
pub use block_state::BlockState;
2016
pub use generated::{blocks, properties};
2117
pub use range::BlockStates;
2218

azalea-client/src/mining.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use azalea_block::{Block, BlockState, FluidState};
1+
use azalea_block::{fluid_state::FluidState, Block, BlockState};
22
use azalea_core::{direction::Direction, game_type::GameMode, position::BlockPos, tick::GameTick};
33
use azalea_entity::{mining::get_mine_progress, FluidOnEyes, Physics};
44
use azalea_inventory::ItemStack;

azalea-client/src/movement.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ impl Plugin for PlayerMovePlugin {
6565
(tick_controls, local_player_ai_step)
6666
.chain()
6767
.in_set(PhysicsSet)
68-
.before(ai_step),
68+
.before(ai_step)
69+
.before(azalea_physics::fluids::update_in_water_state_and_do_fluid_pushing),
6970
send_sprinting_if_needed.after(azalea_entity::update_in_loaded_chunk),
7071
send_position.after(PhysicsSet),
7172
)

azalea-core/src/direction.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use azalea_buf::AzBuf;
22

3-
use crate::position::Vec3;
3+
use crate::position::{BlockPos, Vec3};
44

55
#[derive(Clone, Copy, Debug, AzBuf, Default, Eq, PartialEq)]
66
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@@ -15,6 +15,14 @@ pub enum Direction {
1515
}
1616

1717
impl Direction {
18+
pub const HORIZONTAL: [Direction; 4] = [
19+
Direction::North,
20+
Direction::South,
21+
Direction::West,
22+
Direction::East,
23+
];
24+
pub const VERTICAL: [Direction; 2] = [Direction::Down, Direction::Up];
25+
1826
pub fn nearest(vec: Vec3) -> Direction {
1927
let mut best_direction = Direction::North;
2028
let mut best_direction_amount = 0.0;
@@ -29,7 +37,7 @@ impl Direction {
2937
]
3038
.iter()
3139
{
32-
let amount = dir.normal().dot(vec);
40+
let amount = dir.normal_vec3().dot(vec);
3341
if amount > best_direction_amount {
3442
best_direction = *dir;
3543
best_direction_amount = amount;
@@ -39,17 +47,23 @@ impl Direction {
3947
best_direction
4048
}
4149

42-
pub fn normal(self) -> Vec3 {
50+
#[inline]
51+
pub fn normal(self) -> BlockPos {
4352
match self {
44-
Direction::Down => Vec3::new(0.0, -1.0, 0.0),
45-
Direction::Up => Vec3::new(0.0, 1.0, 0.0),
46-
Direction::North => Vec3::new(0.0, 0.0, -1.0),
47-
Direction::South => Vec3::new(0.0, 0.0, 1.0),
48-
Direction::West => Vec3::new(-1.0, 0.0, 0.0),
49-
Direction::East => Vec3::new(1.0, 0.0, 0.0),
53+
Direction::Down => BlockPos::new(0, -1, 0),
54+
Direction::Up => BlockPos::new(0, 1, 0),
55+
Direction::North => BlockPos::new(0, 0, -1),
56+
Direction::South => BlockPos::new(0, 0, 1),
57+
Direction::West => BlockPos::new(-1, 0, 0),
58+
Direction::East => BlockPos::new(1, 0, 0),
5059
}
5160
}
5261

62+
#[inline]
63+
pub fn normal_vec3(self) -> Vec3 {
64+
self.normal().to_vec3_floored()
65+
}
66+
5367
pub fn opposite(self) -> Direction {
5468
match self {
5569
Direction::Down => Direction::Up,
@@ -60,6 +74,16 @@ impl Direction {
6074
Direction::East => Direction::West,
6175
}
6276
}
77+
78+
pub fn x(self) -> i32 {
79+
self.normal().x
80+
}
81+
pub fn y(self) -> i32 {
82+
self.normal().y
83+
}
84+
pub fn z(self) -> i32 {
85+
self.normal().z
86+
}
6387
}
6488

6589
/// The four cardinal directions.

azalea-core/src/position.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ use std::{
88
fmt,
99
hash::Hash,
1010
io::{Cursor, Write},
11-
ops::{Add, AddAssign, Mul, Rem, Sub},
11+
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub},
1212
};
1313

1414
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
1515

16+
use crate::direction::Direction;
1617
use crate::math;
1718
use crate::resource_location::ResourceLocation;
1819

@@ -138,7 +139,6 @@ macro_rules! vec3_impl {
138139
}
139140
}
140141
}
141-
142142
impl Add for $name {
143143
type Output = $name;
144144

@@ -147,6 +147,18 @@ macro_rules! vec3_impl {
147147
(&self).add(&rhs)
148148
}
149149
}
150+
impl Add<$type> for $name {
151+
type Output = Self;
152+
153+
#[inline]
154+
fn add(self, rhs: $type) -> Self::Output {
155+
Self {
156+
x: self.x + rhs,
157+
y: self.y + rhs,
158+
z: self.z + rhs,
159+
}
160+
}
161+
}
150162

151163
impl AddAssign for $name {
152164
#[inline]
@@ -203,6 +215,35 @@ macro_rules! vec3_impl {
203215
}
204216
}
205217
}
218+
impl MulAssign<$type> for $name {
219+
#[inline]
220+
fn mul_assign(&mut self, multiplier: $type) {
221+
self.x *= multiplier;
222+
self.y *= multiplier;
223+
self.z *= multiplier;
224+
}
225+
}
226+
227+
impl Div<$type> for $name {
228+
type Output = Self;
229+
230+
#[inline]
231+
fn div(self, divisor: $type) -> Self::Output {
232+
Self {
233+
x: self.x / divisor,
234+
y: self.y / divisor,
235+
z: self.z / divisor,
236+
}
237+
}
238+
}
239+
impl DivAssign<$type> for $name {
240+
#[inline]
241+
fn div_assign(&mut self, divisor: $type) {
242+
self.x /= divisor;
243+
self.y /= divisor;
244+
self.z /= divisor;
245+
}
246+
}
206247

207248
impl From<($type, $type, $type)> for $name {
208249
#[inline]
@@ -345,6 +386,10 @@ impl BlockPos {
345386
z: self.z.max(other.z),
346387
}
347388
}
389+
390+
pub fn offset_with_direction(self, direction: Direction) -> Self {
391+
self + direction.normal()
392+
}
348393
}
349394

350395
/// Chunk coordinates are used to represent where a chunk is in the world. You

azalea-physics/src/clip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use azalea_block::{BlockState, FluidState};
1+
use azalea_block::{fluid_state::FluidState, BlockState};
22
use azalea_core::{
33
block_hit_result::BlockHitResult,
44
direction::Direction,

azalea-physics/src/collision/discrete_voxel_shape.rs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -238,39 +238,33 @@ impl BitSetDiscreteVoxelShape {
238238
var2: bool,
239239
) {
240240
let mut var3 = BitSetDiscreteVoxelShape::from(var0);
241-
for var4 in 0..var3.y_size {
242-
for var5 in 0..var3.x_size {
241+
for y in 0..var3.y_size {
242+
for x in 0..var3.x_size {
243243
let mut var6 = None;
244-
for var7 in 0..=var3.z_size {
245-
if var3.is_full_wide(var5, var4, var7) {
244+
for z in 0..=var3.z_size {
245+
if var3.is_full_wide(x, y, z) {
246246
if var2 {
247247
if var6.is_none() {
248-
var6 = Some(var7);
248+
var6 = Some(z);
249249
}
250250
} else {
251-
consumer(var5, var4, var7, var5 + 1, var4 + 1, var7 + 1);
251+
consumer(x, y, z, x + 1, y + 1, z + 1);
252252
}
253253
} else if var6.is_some() {
254-
let mut var8 = var5;
255-
let mut var9 = var4;
256-
var3.clear_z_strip(var6.unwrap(), var7, var5, var4);
257-
while var3.is_z_strip_full(var6.unwrap(), var7, var8 + 1, var4) {
258-
var3.clear_z_strip(var6.unwrap(), var7, var8 + 1, var4);
254+
let mut var8 = x;
255+
let mut var9 = y;
256+
var3.clear_z_strip(var6.unwrap(), z, x, y);
257+
while var3.is_z_strip_full(var6.unwrap(), z, var8 + 1, y) {
258+
var3.clear_z_strip(var6.unwrap(), z, var8 + 1, y);
259259
var8 += 1;
260260
}
261-
while var3.is_xz_rectangle_full(
262-
var5,
263-
var8 + 1,
264-
var6.unwrap(),
265-
var7,
266-
var9 + 1,
267-
) {
268-
for var10 in var5..=var8 {
269-
var3.clear_z_strip(var6.unwrap(), var7, var10, var9 + 1);
261+
while var3.is_xz_rectangle_full(x, var8 + 1, var6.unwrap(), z, var9 + 1) {
262+
for var10 in x..=var8 {
263+
var3.clear_z_strip(var6.unwrap(), z, var10, var9 + 1);
270264
}
271265
var9 += 1;
272266
}
273-
consumer(var5, var4, var6.unwrap(), var8 + 1, var9 + 1, var7);
267+
consumer(x, y, var6.unwrap(), var8 + 1, var9 + 1, z);
274268
var6 = None;
275269
}
276270
}

0 commit comments

Comments
 (0)