chore: made tnt explosion bit faster
This commit is contained in:
parent
39596c1b9f
commit
322b7af6ae
@ -1367,7 +1367,22 @@ pub fn build() -> TokenStream {
|
|||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn to_axis(&self) -> HorizontalAxis {
|
||||||
|
match self {
|
||||||
|
Self::North | Self::South => HorizontalAxis::Z,
|
||||||
|
Self::West | Self::East => HorizontalAxis::X,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn to_facing(&self) -> HorizontalFacing {
|
||||||
|
match self {
|
||||||
|
Self::North => HorizontalFacing::North,
|
||||||
|
Self::South => HorizontalFacing::South,
|
||||||
|
Self::West => HorizontalFacing::West,
|
||||||
|
Self::East => HorizontalFacing::East,
|
||||||
|
}
|
||||||
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn opposite(&self) -> Self {
|
pub const fn opposite(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@ -84,7 +84,7 @@ impl BlockDirection {
|
|||||||
Self::all()[random.next_bounded_i32(Self::all().len() as i32 - 1) as usize]
|
Self::all()[random.next_bounded_i32(Self::all().len() as i32 - 1) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn random_horizontal(random: &mut RandomGenerator) -> Self {
|
pub fn random_horizontal(random: &mut RandomGenerator) -> HorizontalFacing {
|
||||||
Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize]
|
Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +159,13 @@ impl BlockDirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn horizontal() -> [Self; 4] {
|
pub const fn horizontal() -> [HorizontalFacing; 4] {
|
||||||
[Self::North, Self::South, Self::West, Self::East]
|
[
|
||||||
|
HorizontalFacing::North,
|
||||||
|
HorizontalFacing::South,
|
||||||
|
HorizontalFacing::West,
|
||||||
|
HorizontalFacing::East,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -261,6 +266,7 @@ impl BlockDirection {
|
|||||||
|
|
||||||
pub trait FacingExt {
|
pub trait FacingExt {
|
||||||
fn to_block_direction(&self) -> BlockDirection;
|
fn to_block_direction(&self) -> BlockDirection;
|
||||||
|
fn to_horizontal_facing(&self) -> Option<HorizontalFacing>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FacingExt for Facing {
|
impl FacingExt for Facing {
|
||||||
@ -274,6 +280,15 @@ impl FacingExt for Facing {
|
|||||||
Self::Down => BlockDirection::Down,
|
Self::Down => BlockDirection::Down,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn to_horizontal_facing(&self) -> Option<HorizontalFacing> {
|
||||||
|
match self {
|
||||||
|
Self::North => Some(HorizontalFacing::North),
|
||||||
|
Self::South => Some(HorizontalFacing::South),
|
||||||
|
Self::West => Some(HorizontalFacing::West),
|
||||||
|
Self::East => Some(HorizontalFacing::East),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HorizontalFacingExt {
|
pub trait HorizontalFacingExt {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ impl BlockState {
|
|||||||
self.state_flags & HAS_RANDOM_TICKS != 0
|
self.state_flags & HAS_RANDOM_TICKS != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
///`isSideSolidFullSquare()` in Java!
|
///`isFaceSturdy()` in Java!
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_side_solid(&self, side: BlockDirection) -> bool {
|
pub const fn is_side_solid(&self, side: BlockDirection) -> bool {
|
||||||
match side {
|
match side {
|
||||||
|
|||||||
@ -560796,6 +560796,22 @@ impl HorizontalFacing {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
pub const fn to_axis(&self) -> HorizontalAxis {
|
||||||
|
match self {
|
||||||
|
Self::North | Self::South => HorizontalAxis::Z,
|
||||||
|
Self::West | Self::East => HorizontalAxis::X,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn to_facing(&self) -> HorizontalFacing {
|
||||||
|
match self {
|
||||||
|
Self::North => HorizontalFacing::North,
|
||||||
|
Self::South => HorizontalFacing::South,
|
||||||
|
Self::West => HorizontalFacing::West,
|
||||||
|
Self::East => HorizontalFacing::East,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn opposite(&self) -> Self {
|
pub const fn opposite(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::North => Self::South,
|
Self::North => Self::South,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use pumpkin_data::{
|
|||||||
Block, BlockDirection,
|
Block, BlockDirection,
|
||||||
block_properties::{
|
block_properties::{
|
||||||
BlockProperties, BrownMushroomBlockLikeProperties, ChorusFlowerLikeProperties,
|
BlockProperties, BrownMushroomBlockLikeProperties, ChorusFlowerLikeProperties,
|
||||||
|
HorizontalFacing,
|
||||||
},
|
},
|
||||||
tag,
|
tag,
|
||||||
};
|
};
|
||||||
@ -51,7 +52,7 @@ impl ChorusPlantFeature {
|
|||||||
fn all_neighbors_empty<T: GenerationCache>(
|
fn all_neighbors_empty<T: GenerationCache>(
|
||||||
chunk: &T,
|
chunk: &T,
|
||||||
pos: &BlockPos,
|
pos: &BlockPos,
|
||||||
ignore: Option<BlockDirection>,
|
ignore: Option<HorizontalFacing>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
if Some(dir) == ignore {
|
if Some(dir) == ignore {
|
||||||
@ -139,12 +140,9 @@ fn grow_tree_recursive<T: GenerationCache>(
|
|||||||
stems += 1;
|
stems += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The 4 horizontal directions
|
|
||||||
const HORIZ: [BlockDirection; 4] = BlockDirection::horizontal();
|
|
||||||
|
|
||||||
for _ in 0..stems {
|
for _ in 0..stems {
|
||||||
// Pick a random horizontal direction
|
// Pick a random horizontal direction
|
||||||
let dir = HORIZ[random.next_bounded_i32(4) as usize];
|
let dir = BlockDirection::horizontal()[random.next_bounded_i32(4) as usize];
|
||||||
let target = top.offset(dir.to_offset());
|
let target = top.offset(dir.to_offset());
|
||||||
let target_below = target.down();
|
let target_below = target.down();
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ impl CoralClawFeature {
|
|||||||
k = random.next_bounded_i32(3) + 2;
|
k = random.next_bounded_i32(3) + 2;
|
||||||
} else {
|
} else {
|
||||||
pos = pos.up();
|
pos = pos.up();
|
||||||
let _directions = [direction2, BlockDirection::Up];
|
//let _directions = [direction2, BlockDirection::Up];
|
||||||
direction3 = direction2; // TODO: make this random
|
direction3 = direction2; // TODO: make this random
|
||||||
k = random.next_bounded_i32(3) + 5;
|
k = random.next_bounded_i32(3) + 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,13 +68,12 @@ impl CoralFeature {
|
|||||||
.properties(wall_coral.default_state.id)
|
.properties(wall_coral.default_state.id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_props();
|
.to_props();
|
||||||
let facing = dir.to_facing();
|
|
||||||
// Set the right Axis
|
// Set the right Axis
|
||||||
let props: Vec<(&str, &str)> = original_props
|
let props: Vec<(&str, &str)> = original_props
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
if *key == "facing" {
|
if *key == "facing" {
|
||||||
(*key, facing.to_value())
|
(*key, dir.to_value())
|
||||||
} else {
|
} else {
|
||||||
(*key, *value)
|
(*key, *value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,7 +148,7 @@ impl DungeonFeature {
|
|||||||
BlockProperties, ChestLikeProperties,
|
BlockProperties, ChestLikeProperties,
|
||||||
};
|
};
|
||||||
let mut props = ChestLikeProperties::default(&Block::CHEST);
|
let mut props = ChestLikeProperties::default(&Block::CHEST);
|
||||||
props.facing = dir.opposite().to_cardinal_direction();
|
props.facing = dir.opposite();
|
||||||
let state_id = props.to_state_id(&Block::CHEST);
|
let state_id = props.to_state_id(&Block::CHEST);
|
||||||
pumpkin_data::BlockState::from_id(state_id)
|
pumpkin_data::BlockState::from_id(state_id)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use pumpkin_data::{BlockDirection, BlockState, fluid::Fluid};
|
use pumpkin_data::{BlockDirection, BlockState, block_properties::HorizontalFacing, fluid::Fluid};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{int_provider::IntProvider, position::BlockPos},
|
math::{int_provider::IntProvider, position::BlockPos},
|
||||||
random::{RandomGenerator, RandomImpl},
|
random::{RandomGenerator, RandomImpl},
|
||||||
@ -78,7 +78,7 @@ impl MangroveRootPlacer {
|
|||||||
chunk: &mut T,
|
chunk: &mut T,
|
||||||
random: &mut RandomGenerator,
|
random: &mut RandomGenerator,
|
||||||
pos: BlockPos,
|
pos: BlockPos,
|
||||||
direction: BlockDirection,
|
direction: HorizontalFacing,
|
||||||
origin: BlockPos,
|
origin: BlockPos,
|
||||||
offshoots: &mut Vec<BlockPos>,
|
offshoots: &mut Vec<BlockPos>,
|
||||||
root_length: i32,
|
root_length: i32,
|
||||||
@ -109,7 +109,7 @@ impl MangroveRootPlacer {
|
|||||||
fn get_offshoot_positions(
|
fn get_offshoot_positions(
|
||||||
&self,
|
&self,
|
||||||
pos: BlockPos,
|
pos: BlockPos,
|
||||||
direction: BlockDirection,
|
direction: HorizontalFacing,
|
||||||
random: &mut RandomGenerator,
|
random: &mut RandomGenerator,
|
||||||
origin: BlockPos,
|
origin: BlockPos,
|
||||||
) -> Vec<BlockPos> {
|
) -> Vec<BlockPos> {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use pumpkin_data::BlockState;
|
use pumpkin_data::BlockState;
|
||||||
|
use pumpkin_data::block_properties::HorizontalFacing;
|
||||||
use pumpkin_util::math::int_provider::IntProvider;
|
use pumpkin_util::math::int_provider::IntProvider;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
||||||
@ -85,7 +86,7 @@ impl UpwardsBranchingTrunkPlacer {
|
|||||||
nodes: &mut Vec<TreeNode>,
|
nodes: &mut Vec<TreeNode>,
|
||||||
logs: &mut Vec<BlockPos>,
|
logs: &mut Vec<BlockPos>,
|
||||||
current_pos: BlockPos,
|
current_pos: BlockPos,
|
||||||
branch_dir: BlockDirection,
|
branch_dir: HorizontalFacing,
|
||||||
branch_pos: i32,
|
branch_pos: i32,
|
||||||
mut branch_steps: i32,
|
mut branch_steps: i32,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -9,7 +9,8 @@ use crate::{
|
|||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
Block, BlockDirection, FacingExt, HorizontalFacingExt,
|
Block, BlockDirection, FacingExt, HorizontalFacingExt,
|
||||||
block_properties::{
|
block_properties::{
|
||||||
BlockProperties, Facing, LadderLikeProperties, MangroveRootsLikeProperties,
|
BlockProperties, Facing, HorizontalFacing, LadderLikeProperties,
|
||||||
|
MangroveRootsLikeProperties,
|
||||||
},
|
},
|
||||||
tag::{self, Taggable},
|
tag::{self, Taggable},
|
||||||
};
|
};
|
||||||
@ -18,7 +19,9 @@ use pumpkin_world::{
|
|||||||
BlockStateId,
|
BlockStateId,
|
||||||
world::{BlockAccessor, BlockFlags},
|
world::{BlockAccessor, BlockFlags},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CoralFanBlock;
|
pub struct CoralFanBlock;
|
||||||
|
|
||||||
impl BlockMetadata for CoralFanBlock {
|
impl BlockMetadata for CoralFanBlock {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
let alive_wall_fans = tag::Block::MINECRAFT_WALL_CORALS.1;
|
let alive_wall_fans = tag::Block::MINECRAFT_WALL_CORALS.1;
|
||||||
@ -81,18 +84,18 @@ impl BlockBehaviour for CoralFanBlock {
|
|||||||
for dir in directions {
|
for dir in directions {
|
||||||
if dir != Facing::Up
|
if dir != Facing::Up
|
||||||
&& dir != Facing::Down
|
&& dir != Facing::Down
|
||||||
&& can_place_at(args.world, args.position, dir.to_block_direction())
|
&& can_place_at(
|
||||||
|
args.world,
|
||||||
|
args.position,
|
||||||
|
dir.to_horizontal_facing().unwrap(),
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let Some(wall_block) = get_corresponding_wall_fan_type(args.block) else {
|
let Some(wall_block) = get_corresponding_wall_fan_type(args.block) else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
let mut coral_wall_fan_props = CoralWallFanLikeProperties::default(&wall_block);
|
let mut coral_wall_fan_props = CoralWallFanLikeProperties::default(&wall_block);
|
||||||
coral_wall_fan_props.waterlogged = args.replacing.water_source();
|
coral_wall_fan_props.waterlogged = args.replacing.water_source();
|
||||||
coral_wall_fan_props.facing = dir
|
coral_wall_fan_props.facing = dir.opposite().to_horizontal_facing().unwrap();
|
||||||
.opposite()
|
|
||||||
.to_block_direction()
|
|
||||||
.to_horizontal_facing()
|
|
||||||
.unwrap();
|
|
||||||
return coral_wall_fan_props.to_state_id(&wall_block);
|
return coral_wall_fan_props.to_state_id(&wall_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,6 +107,7 @@ impl BlockBehaviour for CoralFanBlock {
|
|||||||
0
|
0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if !scan_for_water(args.world, args.position).await {
|
if !scan_for_water(args.world, args.position).await {
|
||||||
@ -111,24 +115,32 @@ impl BlockBehaviour for CoralFanBlock {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if !scan_for_water(args.world, args.position).await && !is_dead_coral(args.block) {
|
if !scan_for_water(args.world, args.position).await && !is_dead_coral(args.block) {
|
||||||
let current_state = args.world.get_block_state(args.position);
|
let current_state = args.world.get_block_state(args.position);
|
||||||
|
|
||||||
|
// VANILLA FIX: Explicitly set waterlogged to false when dying
|
||||||
let dead_block_state_id = if is_wall_fan(args.block) {
|
let dead_block_state_id = if is_wall_fan(args.block) {
|
||||||
let props =
|
let mut props =
|
||||||
CoralWallFanLikeProperties::from_state_id(current_state.id, args.block);
|
CoralWallFanLikeProperties::from_state_id(current_state.id, args.block);
|
||||||
|
props.waterlogged = false;
|
||||||
props.to_state_id(&get_dead_type(args.block))
|
props.to_state_id(&get_dead_type(args.block))
|
||||||
} else {
|
} else {
|
||||||
let props = CoralFanLikeProperties::from_state_id(current_state.id, args.block);
|
let mut props =
|
||||||
|
CoralFanLikeProperties::from_state_id(current_state.id, args.block);
|
||||||
|
props.waterlogged = false;
|
||||||
props.to_state_id(&get_dead_type(args.block))
|
props.to_state_id(&get_dead_type(args.block))
|
||||||
};
|
};
|
||||||
|
|
||||||
args.world
|
args.world
|
||||||
.set_block_state(args.position, dead_block_state_id, BlockFlags::empty())
|
.set_block_state(args.position, dead_block_state_id, BlockFlags::empty())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> bool {
|
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> bool {
|
||||||
let support_block = args.block_accessor.get_block_state(&args.position.down());
|
let support_block = args.block_accessor.get_block_state(&args.position.down());
|
||||||
if support_block.is_center_solid(BlockDirection::Up) && !is_wall_fan(args.block) {
|
if support_block.is_center_solid(BlockDirection::Up) && !is_wall_fan(args.block) {
|
||||||
@ -150,11 +162,7 @@ impl BlockBehaviour for CoralFanBlock {
|
|||||||
if is_wall_fan(args.block) {
|
if is_wall_fan(args.block) {
|
||||||
let props = CoralWallFanLikeProperties::from_state_id(args.state_id, args.block);
|
let props = CoralWallFanLikeProperties::from_state_id(args.state_id, args.block);
|
||||||
if props.facing.to_block_direction().opposite() == args.direction
|
if props.facing.to_block_direction().opposite() == args.direction
|
||||||
&& !can_place_at(
|
&& !can_place_at(args.world, args.position, props.facing.opposite())
|
||||||
args.world,
|
|
||||||
args.position,
|
|
||||||
props.facing.to_block_direction().opposite(),
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -164,15 +172,18 @@ impl BlockBehaviour for CoralFanBlock {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.state_id
|
args.state_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_default_coral_fan_state_id(block: &Block, waterlogged: bool) -> BlockStateId {
|
fn get_default_coral_fan_state_id(block: &Block, waterlogged: bool) -> BlockStateId {
|
||||||
let mut props = CoralFanLikeProperties::default(block);
|
let mut props = CoralFanLikeProperties::default(block);
|
||||||
props.waterlogged = waterlogged;
|
props.waterlogged = waterlogged;
|
||||||
props.to_state_id(block)
|
props.to_state_id(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_wall_fan(block: &Block) -> bool {
|
fn is_wall_fan(block: &Block) -> bool {
|
||||||
block.has_tag(&tag::Block::MINECRAFT_WALL_CORALS)
|
block.has_tag(&tag::Block::MINECRAFT_WALL_CORALS)
|
||||||
|| block == &Block::DEAD_BRAIN_CORAL_WALL_FAN
|
|| block == &Block::DEAD_BRAIN_CORAL_WALL_FAN
|
||||||
@ -181,6 +192,7 @@ fn is_wall_fan(block: &Block) -> bool {
|
|||||||
|| block == &Block::DEAD_HORN_CORAL_WALL_FAN
|
|| block == &Block::DEAD_HORN_CORAL_WALL_FAN
|
||||||
|| block == &Block::DEAD_TUBE_CORAL_WALL_FAN
|
|| block == &Block::DEAD_TUBE_CORAL_WALL_FAN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dead_type(block: &Block) -> Block {
|
fn get_dead_type(block: &Block) -> Block {
|
||||||
if block == &Block::BRAIN_CORAL_FAN {
|
if block == &Block::BRAIN_CORAL_FAN {
|
||||||
Block::DEAD_BRAIN_CORAL_FAN
|
Block::DEAD_BRAIN_CORAL_FAN
|
||||||
@ -204,6 +216,7 @@ fn get_dead_type(block: &Block) -> Block {
|
|||||||
Block::DEAD_TUBE_CORAL_WALL_FAN
|
Block::DEAD_TUBE_CORAL_WALL_FAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_corresponding_wall_fan_type(block: &Block) -> Option<Block> {
|
fn get_corresponding_wall_fan_type(block: &Block) -> Option<Block> {
|
||||||
if block == &Block::TUBE_CORAL_FAN {
|
if block == &Block::TUBE_CORAL_FAN {
|
||||||
Some(Block::TUBE_CORAL_WALL_FAN)
|
Some(Block::TUBE_CORAL_WALL_FAN)
|
||||||
@ -229,8 +242,9 @@ fn get_corresponding_wall_fan_type(block: &Block) -> Option<Block> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos, facing: BlockDirection) -> bool {
|
|
||||||
|
fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos, facing: HorizontalFacing) -> bool {
|
||||||
world
|
world
|
||||||
.get_block_state(&block_pos.offset(facing.to_offset()))
|
.get_block_state(&block_pos.offset(facing.to_offset()))
|
||||||
.is_side_solid(facing.opposite())
|
.is_side_solid(facing.opposite().to_block_direction())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use pumpkin_data::Block;
|
use pumpkin_data::Block;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
|
||||||
@ -14,8 +15,8 @@ pub mod coral_plant;
|
|||||||
pub async fn scan_for_water(world: &Arc<World>, pos: &BlockPos) -> bool {
|
pub async fn scan_for_water(world: &Arc<World>, pos: &BlockPos) -> bool {
|
||||||
for direction in BlockDirection::all() {
|
for direction in BlockDirection::all() {
|
||||||
let neighbor_pos = pos.offset(direction.to_offset());
|
let neighbor_pos = pos.offset(direction.to_offset());
|
||||||
let block = world.get_block(&neighbor_pos);
|
let block = world.get_fluid(&neighbor_pos);
|
||||||
if block == &Block::WATER {
|
if block.has_tag(&pumpkin_data::tag::Fluid::MINECRAFT_WATER) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use crate::entity::EntityBase;
|
use crate::entity::EntityBase;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
use pumpkin_data::HorizontalFacingExt;
|
|
||||||
use pumpkin_data::block_properties::Axis;
|
use pumpkin_data::block_properties::Axis;
|
||||||
use pumpkin_data::block_properties::BlockProperties;
|
use pumpkin_data::block_properties::BlockProperties;
|
||||||
use pumpkin_data::block_properties::DoorHinge;
|
use pumpkin_data::block_properties::DoorHinge;
|
||||||
@ -112,14 +111,14 @@ async fn get_hinge(
|
|||||||
) -> DoorHinge {
|
) -> DoorHinge {
|
||||||
let top_pos = pos.up();
|
let top_pos = pos.up();
|
||||||
let left_dir = facing.rotate_counter_clockwise();
|
let left_dir = facing.rotate_counter_clockwise();
|
||||||
let left_pos = pos.offset(left_dir.to_block_direction().to_offset());
|
let left_pos = pos.offset(left_dir.to_offset());
|
||||||
let (left_block, left_state) = world.get_block_and_state(&left_pos);
|
let (left_block, left_state) = world.get_block_and_state(&left_pos);
|
||||||
let top_facing = top_pos.offset(facing.to_block_direction().to_offset());
|
let top_facing = top_pos.offset(facing.to_offset());
|
||||||
let top_state = world.get_block_state(&top_facing);
|
let top_state = world.get_block_state(&top_facing);
|
||||||
let right_dir = facing.rotate_clockwise();
|
let right_dir = facing.rotate_clockwise();
|
||||||
let right_pos = pos.offset(right_dir.to_block_direction().to_offset());
|
let right_pos = pos.offset(right_dir.to_offset());
|
||||||
let (right_block, right_state) = world.get_block_and_state(&right_pos);
|
let (right_block, right_state) = world.get_block_and_state(&right_pos);
|
||||||
let top_right = top_pos.offset(facing.to_block_direction().to_offset());
|
let top_right = top_pos.offset(facing.to_offset());
|
||||||
let top_right_state = world.get_block_state(&top_right);
|
let top_right_state = world.get_block_state(&top_right);
|
||||||
|
|
||||||
let has_left_door = world
|
let has_left_door = world
|
||||||
@ -139,7 +138,7 @@ async fn get_hinge(
|
|||||||
|
|
||||||
if (!has_left_door || has_right_door) && score <= 0 {
|
if (!has_left_door || has_right_door) && score <= 0 {
|
||||||
if (!has_right_door || has_left_door) && score >= 0 {
|
if (!has_right_door || has_left_door) && score >= 0 {
|
||||||
let offset = facing.to_block_direction().to_offset();
|
let offset = facing.to_offset();
|
||||||
let hit = use_item.cursor_pos;
|
let hit = use_item.cursor_pos;
|
||||||
if (offset.x >= 0 || hit.z > 0.5)
|
if (offset.x >= 0 || hit.z > 0.5)
|
||||||
&& (offset.x <= 0 || hit.z < 0.5)
|
&& (offset.x <= 0 || hit.z < 0.5)
|
||||||
|
|||||||
@ -3,7 +3,9 @@ use crate::block::GetStateForNeighborUpdateArgs;
|
|||||||
use crate::block::OnPlaceArgs;
|
use crate::block::OnPlaceArgs;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
use pumpkin_data::BlockState;
|
use pumpkin_data::BlockState;
|
||||||
|
use pumpkin_data::HorizontalFacingExt;
|
||||||
use pumpkin_data::block_properties::BlockProperties;
|
use pumpkin_data::block_properties::BlockProperties;
|
||||||
|
use pumpkin_data::block_properties::HorizontalFacing;
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_data::{Block, tag};
|
use pumpkin_data::{Block, tag};
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
@ -53,13 +55,17 @@ pub fn compute_fence_state(
|
|||||||
let other_block_pos = block_pos.offset(direction.to_offset());
|
let other_block_pos = block_pos.offset(direction.to_offset());
|
||||||
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
||||||
|
|
||||||
let connected = connects_to(block, other_block, other_block_state, direction);
|
let connected = connects_to(
|
||||||
|
block,
|
||||||
|
other_block,
|
||||||
|
other_block_state,
|
||||||
|
direction.to_block_direction(),
|
||||||
|
);
|
||||||
match direction {
|
match direction {
|
||||||
BlockDirection::North => fence_props.north = connected,
|
HorizontalFacing::North => fence_props.north = connected,
|
||||||
BlockDirection::South => fence_props.south = connected,
|
HorizontalFacing::South => fence_props.south = connected,
|
||||||
BlockDirection::West => fence_props.west = connected,
|
HorizontalFacing::West => fence_props.west = connected,
|
||||||
BlockDirection::East => fence_props.east = connected,
|
HorizontalFacing::East => fence_props.east = connected,
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,19 +103,17 @@ impl FireBlockBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dir = if direction.is_horizontal() {
|
let dir = if direction.is_horizontal() {
|
||||||
direction.rotate_counter_clockwise()
|
direction
|
||||||
|
.rotate_counter_clockwise()
|
||||||
|
.to_horizontal_axis()
|
||||||
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
BlockDirection::random_horizontal(&mut RandomGenerator::Xoroshiro(
|
BlockDirection::random_horizontal(&mut RandomGenerator::Xoroshiro(
|
||||||
Xoroshiro::from_seed(rand::rng().random()),
|
Xoroshiro::from_seed(rand::rng().random()),
|
||||||
))
|
))
|
||||||
|
.to_axis()
|
||||||
};
|
};
|
||||||
NetherPortal::get_new_portal(
|
NetherPortal::get_new_portal(world, block_pos, dir).is_some()
|
||||||
world,
|
|
||||||
block_pos,
|
|
||||||
dir.to_horizontal_axis()
|
|
||||||
.expect("Direction should be horizontal"),
|
|
||||||
)
|
|
||||||
.is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shared fire collision behavior used by `fire` and `soul_fire`.
|
/// Shared fire collision behavior used by `fire` and `soul_fire`.
|
||||||
|
|||||||
@ -2,7 +2,9 @@ use crate::block::BlockFuture;
|
|||||||
use crate::block::GetStateForNeighborUpdateArgs;
|
use crate::block::GetStateForNeighborUpdateArgs;
|
||||||
use crate::block::OnPlaceArgs;
|
use crate::block::OnPlaceArgs;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
|
use pumpkin_data::HorizontalFacingExt;
|
||||||
use pumpkin_data::block_properties::BlockProperties;
|
use pumpkin_data::block_properties::BlockProperties;
|
||||||
|
use pumpkin_data::block_properties::HorizontalFacing;
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_data::{Block, tag};
|
use pumpkin_data::{Block, tag};
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
@ -52,17 +54,16 @@ pub fn compute_pane_state(
|
|||||||
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
||||||
|
|
||||||
let connected = other_block == block
|
let connected = other_block == block
|
||||||
|| other_block_state.is_side_solid(direction.opposite())
|
|| other_block_state.is_side_solid(direction.opposite().to_block_direction())
|
||||||
|| other_block.has_tag(&tag::Block::C_GLASS_PANES)
|
|| other_block.has_tag(&tag::Block::C_GLASS_PANES)
|
||||||
|| other_block == &Block::IRON_BARS
|
|| other_block == &Block::IRON_BARS
|
||||||
|| other_block.has_tag(&tag::Block::MINECRAFT_WALLS);
|
|| other_block.has_tag(&tag::Block::MINECRAFT_WALLS);
|
||||||
|
|
||||||
match direction {
|
match direction {
|
||||||
BlockDirection::North => pane_props.north = connected,
|
HorizontalFacing::North => pane_props.north = connected,
|
||||||
BlockDirection::South => pane_props.south = connected,
|
HorizontalFacing::South => pane_props.south = connected,
|
||||||
BlockDirection::West => pane_props.west = connected,
|
HorizontalFacing::West => pane_props.west = connected,
|
||||||
BlockDirection::East => pane_props.east = connected,
|
HorizontalFacing::East => pane_props.east = connected,
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,9 @@ use crate::block::BlockFuture;
|
|||||||
use crate::block::GetStateForNeighborUpdateArgs;
|
use crate::block::GetStateForNeighborUpdateArgs;
|
||||||
use crate::block::OnPlaceArgs;
|
use crate::block::OnPlaceArgs;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
|
use pumpkin_data::HorizontalFacingExt;
|
||||||
use pumpkin_data::block_properties::BlockProperties;
|
use pumpkin_data::block_properties::BlockProperties;
|
||||||
|
use pumpkin_data::block_properties::HorizontalFacing;
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_data::{Block, tag};
|
use pumpkin_data::{Block, tag};
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
@ -49,16 +51,15 @@ pub fn compute_bars_state(
|
|||||||
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
||||||
|
|
||||||
let connected = other_block == block
|
let connected = other_block == block
|
||||||
|| other_block_state.is_side_solid(direction.opposite())
|
|| other_block_state.is_side_solid(direction.opposite().to_block_direction())
|
||||||
|| other_block.has_tag(&tag::Block::C_GLASS_PANES)
|
|| other_block.has_tag(&tag::Block::C_GLASS_PANES)
|
||||||
|| other_block.has_tag(&tag::Block::MINECRAFT_WALLS);
|
|| other_block.has_tag(&tag::Block::MINECRAFT_WALLS);
|
||||||
|
|
||||||
match direction {
|
match direction {
|
||||||
BlockDirection::North => bars_props.north = connected,
|
HorizontalFacing::North => bars_props.north = connected,
|
||||||
BlockDirection::South => bars_props.south = connected,
|
HorizontalFacing::South => bars_props.south = connected,
|
||||||
BlockDirection::West => bars_props.west = connected,
|
HorizontalFacing::West => bars_props.west = connected,
|
||||||
BlockDirection::East => bars_props.east = connected,
|
HorizontalFacing::East => bars_props.east = connected,
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,6 @@ impl BlockBehaviour for LadderBlock {
|
|||||||
}
|
}
|
||||||
props.facing = dir
|
props.facing = dir
|
||||||
.opposite()
|
.opposite()
|
||||||
.to_block_direction()
|
|
||||||
.to_horizontal_facing()
|
.to_horizontal_facing()
|
||||||
.expect("Opposite of horizontal direction should be horizontal");
|
.expect("Opposite of horizontal direction should be horizontal");
|
||||||
return props.to_state_id(args.block);
|
return props.to_state_id(args.block);
|
||||||
@ -59,7 +58,7 @@ impl BlockBehaviour for LadderBlock {
|
|||||||
//this won't happen
|
//this won't happen
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if can_place_ladder_at(world, args.position, dir) {
|
if can_place_ladder_at(world, args.position, dir.to_block_direction()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,10 @@ use crate::block::{
|
|||||||
};
|
};
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
Block, BlockDirection,
|
Block, BlockDirection,
|
||||||
block_properties::{BlockProperties, WallTorchLikeProperties, WheatLikeProperties},
|
block_properties::{
|
||||||
tag,
|
BlockProperties, HorizontalFacing, WallTorchLikeProperties, WheatLikeProperties,
|
||||||
tag::Taggable,
|
},
|
||||||
|
tag::{self, Taggable},
|
||||||
};
|
};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::position::BlockPos,
|
math::position::BlockPos,
|
||||||
@ -37,14 +38,14 @@ impl StemBlock {
|
|||||||
props.to_state_id(block)
|
props.to_state_id(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attached_stem(dir: BlockDirection, block: &Block) -> BlockStateId {
|
fn get_attached_stem(dir: HorizontalFacing, block: &Block) -> BlockStateId {
|
||||||
let attached_block = match block.id {
|
let attached_block = match block.id {
|
||||||
id if id == Block::PUMPKIN_STEM.id => &Block::ATTACHED_PUMPKIN_STEM,
|
id if id == Block::PUMPKIN_STEM.id => &Block::ATTACHED_PUMPKIN_STEM,
|
||||||
id if id == Block::MELON_STEM.id => &Block::ATTACHED_MELON_STEM,
|
id if id == Block::MELON_STEM.id => &Block::ATTACHED_MELON_STEM,
|
||||||
_ => &Block::ATTACHED_MELON_STEM, // Should never happen
|
_ => &Block::ATTACHED_MELON_STEM, // Should never happen
|
||||||
};
|
};
|
||||||
let mut props = AttachedStemProperties::default(attached_block);
|
let mut props = AttachedStemProperties::default(attached_block);
|
||||||
props.facing = dir.to_horizontal_facing().unwrap();
|
props.facing = dir;
|
||||||
props.to_state_id(attached_block)
|
props.to_state_id(attached_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -154,12 +154,9 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
fn get_output_level<'a>(&'a self, world: &'a World, pos: BlockPos) -> BlockFuture<'a, u8> {
|
fn get_output_level<'a>(&'a self, world: &'a World, pos: BlockPos) -> BlockFuture<'a, u8> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(blockentity) = world.get_block_entity(&pos)
|
if let Some(blockentity) = world.get_block_entity(&pos)
|
||||||
&& blockentity.resource_location() == ComparatorBlockEntity::ID
|
&& let Some(comparator) =
|
||||||
|
blockentity.as_any().downcast_ref::<ComparatorBlockEntity>()
|
||||||
{
|
{
|
||||||
let comparator = blockentity
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<ComparatorBlockEntity>()
|
|
||||||
.unwrap();
|
|
||||||
return comparator.output_signal.load(Ordering::Relaxed);
|
return comparator.output_signal.load(Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
@ -178,24 +175,25 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let i = self.calculate_output_signal(world, pos, state, block).await;
|
let i = self.calculate_output_signal(world, pos, state, block).await;
|
||||||
|
|
||||||
let j = RedstoneGateBlock::get_output_level(self, world, pos).await;
|
let j = RedstoneGateBlock::get_output_level(self, world, pos).await;
|
||||||
|
|
||||||
let props = ComparatorLikeProperties::from_state_id(state.id, block);
|
let props = ComparatorLikeProperties::from_state_id(state.id, block);
|
||||||
|
|
||||||
if i != j
|
if i != j
|
||||||
|| props.powered
|
|| props.powered
|
||||||
!= RedstoneGateBlock::has_power(self, world, pos, state, block).await
|
!= RedstoneGateBlock::has_power(self, world, pos, state, block).await
|
||||||
{
|
{
|
||||||
world.schedule_block_tick(
|
let priority =
|
||||||
block,
|
|
||||||
pos,
|
|
||||||
RedstoneGateBlock::get_update_delay_internal(self, state.id, block),
|
|
||||||
if RedstoneGateBlock::is_target_not_aligned(self, world, pos, state, block) {
|
if RedstoneGateBlock::is_target_not_aligned(self, world, pos, state, block) {
|
||||||
TickPriority::High
|
TickPriority::High
|
||||||
} else {
|
} else {
|
||||||
TickPriority::Normal
|
TickPriority::Normal
|
||||||
},
|
};
|
||||||
|
|
||||||
|
world.schedule_block_tick(
|
||||||
|
block,
|
||||||
|
pos,
|
||||||
|
RedstoneGateBlock::get_update_delay_internal(self, state.id, block),
|
||||||
|
priority,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -217,6 +215,7 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
self, world, pos, state.id, block, false,
|
self, world, pos, state.id, block, false,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if i > j {
|
if i > j {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -244,7 +243,6 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
let source_pos = pos.offset(facing.to_offset());
|
let source_pos = pos.offset(facing.to_offset());
|
||||||
let (source_block, source_state) = world.get_block_and_state(&source_pos);
|
let (source_block, source_state) = world.get_block_and_state(&source_pos);
|
||||||
|
|
||||||
// Note: .get_comparator_output is assumed to be an async method returning Option<u8>
|
|
||||||
if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block.id)
|
if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block.id)
|
||||||
&& let Some(level) = pumpkin_block
|
&& let Some(level) = pumpkin_block
|
||||||
.get_comparator_output(GetComparatorOutputArgs {
|
.get_comparator_output(GetComparatorOutputArgs {
|
||||||
@ -259,25 +257,28 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if redstone_level < 15 && source_state.is_solid_block() {
|
if redstone_level < 15 && source_state.is_solid_block() {
|
||||||
let source_pos = source_pos.offset(facing.to_offset());
|
let deeper_source_pos = source_pos.offset(facing.to_offset());
|
||||||
let (source_block, source_state) = world.get_block_and_state(&source_pos);
|
let (deeper_block, deeper_state) = world.get_block_and_state(&deeper_source_pos);
|
||||||
|
|
||||||
// Note: self.get_attached_itemframe_level is assumed to be an async method
|
let itemframe_level =
|
||||||
let itemframe_level = Self::get_attached_itemframe_level(world, facing, source_pos);
|
Self::get_attached_itemframe_level(world, facing, deeper_source_pos);
|
||||||
|
|
||||||
|
// This is the correct way to handle the async call within the Option
|
||||||
let block_level = if let Some(pumpkin_block) =
|
let block_level = if let Some(pumpkin_block) =
|
||||||
world.block_registry.get_pumpkin_block(source_block.id)
|
world.block_registry.get_pumpkin_block(deeper_block.id)
|
||||||
{
|
{
|
||||||
pumpkin_block
|
pumpkin_block
|
||||||
.get_comparator_output(GetComparatorOutputArgs {
|
.get_comparator_output(GetComparatorOutputArgs {
|
||||||
world,
|
world,
|
||||||
block: source_block,
|
block: deeper_block,
|
||||||
state: source_state,
|
state: deeper_state,
|
||||||
position: &source_pos,
|
position: &deeper_source_pos,
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(level) = itemframe_level.max(block_level) {
|
if let Some(level) = itemframe_level.max(block_level) {
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
@ -287,7 +288,7 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_update_delay_internal(&self, _state_id: BlockStateId, _block: &Block) -> u8 {
|
fn get_update_delay_internal(&self, _state_id: BlockStateId, _block: &Block) -> u8 {
|
||||||
2
|
2 // Vanilla Delay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,10 +300,15 @@ impl ComparatorBlock {
|
|||||||
block_pos: BlockPos,
|
block_pos: BlockPos,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
) {
|
) {
|
||||||
|
// Vanilla Parity TODO:
|
||||||
|
// playSound(player, pos, SoundEvents.COMPARATOR_CLICK, SoundSource.BLOCKS, 0.3F, pitch);
|
||||||
|
// Pitch is 0.55F if SUBTRACT, 0.5F if COMPARE.
|
||||||
|
|
||||||
props.mode = match props.mode {
|
props.mode = match props.mode {
|
||||||
ModeComparator::Compare => ModeComparator::Subtract,
|
ModeComparator::Compare => ModeComparator::Subtract,
|
||||||
ModeComparator::Subtract => ModeComparator::Compare,
|
ModeComparator::Subtract => ModeComparator::Compare,
|
||||||
};
|
};
|
||||||
|
|
||||||
let state_id = props.to_state_id(block);
|
let state_id = props.to_state_id(block);
|
||||||
world
|
world
|
||||||
.set_block_state(&block_pos, state_id, BlockFlags::empty())
|
.set_block_state(&block_pos, state_id, BlockFlags::empty())
|
||||||
@ -320,12 +326,18 @@ impl ComparatorBlock {
|
|||||||
block: &Block,
|
block: &Block,
|
||||||
) -> u8 {
|
) -> u8 {
|
||||||
let power = self.get_power(world, pos, state, block).await;
|
let power = self.get_power(world, pos, state, block).await;
|
||||||
|
if power == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
let sub_power = self
|
let sub_power = self
|
||||||
.get_max_input_level_sides(world, pos, state.id, block, false)
|
.get_max_input_level_sides(world, pos, state.id, block, false)
|
||||||
.await;
|
.await;
|
||||||
if sub_power >= power {
|
|
||||||
|
if sub_power > power {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let props = ComparatorLikeProperties::from_state_id(state.id, block);
|
let props = ComparatorLikeProperties::from_state_id(state.id, block);
|
||||||
if props.mode == ModeComparator::Subtract {
|
if props.mode == ModeComparator::Subtract {
|
||||||
power - sub_power
|
power - sub_power
|
||||||
@ -346,10 +358,10 @@ impl ComparatorBlock {
|
|||||||
entity.get_entity().entity_type == &EntityType::ITEM_FRAME
|
entity.get_entity().entity_type == &EntityType::ITEM_FRAME
|
||||||
&& entity.get_entity().get_horizontal_facing() == facing
|
&& entity.get_entity().get_horizontal_facing() == facing
|
||||||
});
|
});
|
||||||
if let Some(_itemframe) = itemframes.next()
|
|
||||||
&& itemframes.next().is_none()
|
if itemframes.next().is_some() && itemframes.next().is_none() {
|
||||||
{
|
// Vanilla Parity TODO:
|
||||||
// TODO itemframe.getComparatorPower()
|
// Return itemframe.getAnalogOutput() which calculates based on item rotation
|
||||||
return Some(1);
|
return Some(1);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -358,22 +370,21 @@ impl ComparatorBlock {
|
|||||||
async fn update(&self, world: &Arc<World>, pos: BlockPos, state: &BlockState, block: &Block) {
|
async fn update(&self, world: &Arc<World>, pos: BlockPos, state: &BlockState, block: &Block) {
|
||||||
let future_level = i32::from(self.calculate_output_signal(world, pos, state, block).await);
|
let future_level = i32::from(self.calculate_output_signal(world, pos, state, block).await);
|
||||||
let mut now_level = 0;
|
let mut now_level = 0;
|
||||||
|
|
||||||
if let Some(blockentity) = world.get_block_entity(&pos)
|
if let Some(blockentity) = world.get_block_entity(&pos)
|
||||||
&& blockentity.resource_location() == ComparatorBlockEntity::ID
|
&& let Some(comparator) = blockentity.as_any().downcast_ref::<ComparatorBlockEntity>()
|
||||||
{
|
{
|
||||||
let comparator = blockentity
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<ComparatorBlockEntity>()
|
|
||||||
.unwrap();
|
|
||||||
now_level = i32::from(comparator.output_signal.load(Ordering::Relaxed));
|
now_level = i32::from(comparator.output_signal.load(Ordering::Relaxed));
|
||||||
comparator
|
comparator
|
||||||
.output_signal
|
.output_signal
|
||||||
.store(future_level as u8, Ordering::Relaxed);
|
.store(future_level as u8, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut props = ComparatorLikeProperties::from_state_id(state.id, block);
|
let mut props = ComparatorLikeProperties::from_state_id(state.id, block);
|
||||||
if now_level != future_level || props.mode == ModeComparator::Compare {
|
if now_level != future_level || props.mode == ModeComparator::Compare {
|
||||||
let future_power = self.has_power(world, pos, state, block).await;
|
let future_power = self.has_power(world, pos, state, block).await;
|
||||||
let now_power = props.powered;
|
let now_power = props.powered;
|
||||||
|
|
||||||
if now_power && !future_power {
|
if now_power && !future_power {
|
||||||
props.powered = false;
|
props.powered = false;
|
||||||
world
|
world
|
||||||
@ -385,6 +396,7 @@ impl ComparatorBlock {
|
|||||||
.set_block_state(&pos, props.to_state_id(block), BlockFlags::NOTIFY_LISTENERS)
|
.set_block_state(&pos, props.to_state_id(block), BlockFlags::NOTIFY_LISTENERS)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
RedstoneGateBlock::update_target(self, world, pos, props.to_state_id(block), block)
|
RedstoneGateBlock::update_target(self, world, pos, props.to_state_id(block), block)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
|
use rand::{Rng, RngExt, rng};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::block::blocks::redstone::block_receives_redstone_power;
|
use crate::block::blocks::redstone::block_receives_redstone_power;
|
||||||
use crate::block::registry::BlockActionResult;
|
use crate::block::registry::BlockActionResult;
|
||||||
use crate::block::{
|
use crate::block::{
|
||||||
BlockBehaviour, BlockFuture, NormalUseArgs, OnNeighborUpdateArgs, OnPlaceArgs,
|
BlockBehaviour, BlockFuture, NormalUseArgs, OnNeighborUpdateArgs, OnPlaceArgs,
|
||||||
OnScheduledTickArgs, PlacedArgs,
|
OnScheduledTickArgs, PlacedArgs,
|
||||||
};
|
};
|
||||||
use crate::entity::Entity;
|
|
||||||
use crate::entity::EntityBase;
|
|
||||||
use crate::entity::item::ItemEntity;
|
use crate::entity::item::ItemEntity;
|
||||||
|
use crate::entity::{Entity, EntityBase};
|
||||||
|
|
||||||
use crate::block::entities::dropper::DropperBlockEntity;
|
use crate::block::entities::dropper::DropperBlockEntity;
|
||||||
use crate::block::entities::hopper::HopperBlockEntity;
|
use crate::block::entities::hopper::HopperBlockEntity;
|
||||||
@ -26,9 +29,6 @@ use pumpkin_world::BlockStateId;
|
|||||||
use pumpkin_world::inventory::Inventory;
|
use pumpkin_world::inventory::Inventory;
|
||||||
use pumpkin_world::tick::TickPriority;
|
use pumpkin_world::tick::TickPriority;
|
||||||
use pumpkin_world::world::BlockFlags;
|
use pumpkin_world::world::BlockFlags;
|
||||||
use rand::{Rng, RngExt, rng};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
struct DropperScreenFactory(Arc<dyn Inventory>);
|
struct DropperScreenFactory(Arc<dyn Inventory>);
|
||||||
|
|
||||||
@ -120,10 +120,12 @@ impl BlockBehaviour for DropperBlock {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let powered = block_receives_redstone_power(args.world, args.position).await
|
let powered = block_receives_redstone_power(args.world, args.position).await
|
||||||
|| block_receives_redstone_power(args.world, &args.position.up()).await;
|
|| block_receives_redstone_power(args.world, &args.position.up()).await;
|
||||||
|
|
||||||
let mut props = DispenserLikeProperties::from_state_id(
|
let mut props = DispenserLikeProperties::from_state_id(
|
||||||
args.world.get_block_state(args.position).id,
|
args.world.get_block_state(args.position).id,
|
||||||
args.block,
|
args.block,
|
||||||
);
|
);
|
||||||
|
|
||||||
if powered && !props.triggered {
|
if powered && !props.triggered {
|
||||||
args.world
|
args.world
|
||||||
.schedule_block_tick(args.block, *args.position, 4, TickPriority::Normal);
|
.schedule_block_tick(args.block, *args.position, 4, TickPriority::Normal);
|
||||||
@ -151,76 +153,79 @@ impl BlockBehaviour for DropperBlock {
|
|||||||
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(block_entity) = args.world.get_block_entity(args.position) {
|
if let Some(block_entity) = args.world.get_block_entity(args.position) {
|
||||||
let dropper = block_entity
|
// Safely extract the dropper instead of unwrap()
|
||||||
.as_any()
|
let Some(dropper) = block_entity.as_any().downcast_ref::<DropperBlockEntity>()
|
||||||
.downcast_ref::<DropperBlockEntity>()
|
else {
|
||||||
.unwrap();
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(mut item) = dropper.get_random_slot().await {
|
if let Some(mut item) = dropper.get_random_slot().await {
|
||||||
let props = DispenserLikeProperties::from_state_id(
|
let props = DispenserLikeProperties::from_state_id(
|
||||||
args.world.get_block_state(args.position).id,
|
args.world.get_block_state(args.position).id,
|
||||||
args.block,
|
args.block,
|
||||||
);
|
);
|
||||||
if let Some(entity) = args.world.get_block_entity(
|
|
||||||
&args
|
let target_pos = args
|
||||||
.position
|
.position
|
||||||
.offset(props.facing.to_block_direction().to_offset()),
|
.offset(props.facing.to_block_direction().to_offset());
|
||||||
) && let Some(container) = entity.get_inventory()
|
|
||||||
|
if let Some(entity) = args.world.get_block_entity(&target_pos)
|
||||||
|
&& let Some(container) = entity.get_inventory()
|
||||||
{
|
{
|
||||||
// TODO check WorldlyContainer
|
|
||||||
let mut is_full = true;
|
|
||||||
for i in 0..container.size() {
|
|
||||||
let bind = container.get_stack(i).await;
|
|
||||||
let item = bind.lock().await;
|
|
||||||
if item.item_count < item.get_max_stack_size() {
|
|
||||||
is_full = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if is_full {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//TODO WorldlyContainer
|
|
||||||
let backup = item.clone();
|
let backup = item.clone();
|
||||||
let one_item = item.split(1);
|
let one_item = item.split(1);
|
||||||
|
|
||||||
if HopperBlockEntity::add_one_item(dropper, container.as_ref(), one_item)
|
if HopperBlockEntity::add_one_item(dropper, container.as_ref(), one_item)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*item = backup;
|
*item = backup;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No container found, dispense item into the world
|
||||||
let drop_item = item.split(1);
|
let drop_item = item.split(1);
|
||||||
let facing = to_normal(props.facing);
|
let facing = to_normal(props.facing);
|
||||||
let mut position = args.position.to_centered_f64().add(&(facing * 0.7));
|
let mut position = args.position.to_centered_f64().add(&(facing * 0.7));
|
||||||
|
|
||||||
position.y -= match props.facing {
|
position.y -= match props.facing {
|
||||||
Facing::Up | Facing::Down => 0.125,
|
Facing::Up | Facing::Down => 0.125,
|
||||||
_ => 0.15625,
|
_ => 0.15625,
|
||||||
};
|
};
|
||||||
|
|
||||||
let entity = Entity::new(args.world.clone(), position, &EntityType::ITEM);
|
let entity = Entity::new(args.world.clone(), position, &EntityType::ITEM);
|
||||||
let rd = rng().random::<f64>().mul_add(0.1, 0.2);
|
let rd = rng().random::<f64>().mul_add(0.1, 0.2);
|
||||||
|
|
||||||
let velocity = Vector3::new(
|
let velocity = Vector3::new(
|
||||||
triangle(&mut rng(), facing.x * rd, 0.017_227_5 * 6.),
|
triangle(&mut rng(), facing.x * rd, 0.017_227_5 * 6.),
|
||||||
triangle(&mut rng(), 0.2, 0.017_227_5 * 6.),
|
triangle(&mut rng(), 0.2, 0.017_227_5 * 6.),
|
||||||
triangle(&mut rng(), facing.z * rd, 0.017_227_5 * 6.),
|
triangle(&mut rng(), facing.z * rd, 0.017_227_5 * 6.),
|
||||||
);
|
);
|
||||||
|
|
||||||
let item_entity = Arc::new(ItemEntity::new_with_velocity(
|
let item_entity = Arc::new(ItemEntity::new_with_velocity(
|
||||||
entity, drop_item, velocity, 40,
|
entity, drop_item, velocity, 40,
|
||||||
));
|
));
|
||||||
args.world.spawn_entity(item_entity).await;
|
args.world.spawn_entity(item_entity).await;
|
||||||
|
|
||||||
args.world.sync_world_event(
|
args.world.sync_world_event(
|
||||||
WorldEvent::SoundDispenserDispense,
|
WorldEvent::SoundDispenserDispense,
|
||||||
*args.position,
|
*args.position,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
args.world.sync_world_event(
|
args.world.sync_world_event(
|
||||||
WorldEvent::SoundDispenserProjectileLaunch,
|
WorldEvent::ParticlesShootSmoke,
|
||||||
*args.position,
|
*args.position,
|
||||||
to_data3d(props.facing),
|
to_data3d(props.facing),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
args.world
|
args.world.sync_world_event(
|
||||||
.sync_world_event(WorldEvent::SoundDispenserFail, *args.position, 0);
|
WorldEvent::SoundDispenserDispense,
|
||||||
|
*args.position,
|
||||||
|
0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -79,11 +79,7 @@ impl BlockBehaviour for RedstoneTorchBlock {
|
|||||||
&& can_place_at(world, location, dir.to_block_direction())
|
&& can_place_at(world, location, dir.to_block_direction())
|
||||||
{
|
{
|
||||||
let mut torch_props = RWallTorchProps::default(&Block::REDSTONE_WALL_TORCH);
|
let mut torch_props = RWallTorchProps::default(&Block::REDSTONE_WALL_TORCH);
|
||||||
torch_props.facing = dir
|
torch_props.facing = dir.opposite().to_horizontal_facing().unwrap();
|
||||||
.opposite()
|
|
||||||
.to_block_direction()
|
|
||||||
.to_horizontal_facing()
|
|
||||||
.unwrap();
|
|
||||||
return torch_props.to_state_id(&Block::REDSTONE_WALL_TORCH);
|
return torch_props.to_state_id(&Block::REDSTONE_WALL_TORCH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +99,7 @@ impl BlockBehaviour for RedstoneTorchBlock {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
if can_place_at(args.block_accessor, args.position, dir) {
|
if can_place_at(args.block_accessor, args.position, dir.to_block_direction()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::block_properties::{
|
use pumpkin_data::block_properties::{
|
||||||
BlockProperties, EastRedstone, NorthRedstone, ObserverLikeProperties,
|
BlockProperties, EastRedstone, HorizontalFacing, NorthRedstone, ObserverLikeProperties,
|
||||||
RedstoneWireLikeProperties, RepeaterLikeProperties, SouthRedstone, WestRedstone,
|
RedstoneWireLikeProperties, RepeaterLikeProperties, SouthRedstone, WestRedstone,
|
||||||
};
|
};
|
||||||
use pumpkin_data::{Block, BlockDirection, BlockState, HorizontalFacingExt};
|
use pumpkin_data::{Block, BlockDirection, BlockState, HorizontalFacingExt};
|
||||||
@ -116,7 +116,7 @@ impl BlockBehaviour for RedstoneWireBlock {
|
|||||||
args.world
|
args.world
|
||||||
.replace_with_state_for_neighbor_update(
|
.replace_with_state_for_neighbor_update(
|
||||||
&up_block_pos,
|
&up_block_pos,
|
||||||
direction.opposite(),
|
direction.opposite().to_block_direction(),
|
||||||
args.flags,
|
args.flags,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -128,7 +128,7 @@ impl BlockBehaviour for RedstoneWireBlock {
|
|||||||
args.world
|
args.world
|
||||||
.replace_with_state_for_neighbor_update(
|
.replace_with_state_for_neighbor_update(
|
||||||
&down_block_pos,
|
&down_block_pos,
|
||||||
direction.opposite(),
|
direction.opposite().to_block_direction(),
|
||||||
args.flags,
|
args.flags,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -201,7 +201,7 @@ impl BlockBehaviour for RedstoneWireBlock {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let wire = RedstoneWireProperties::from_state_id(args.state.id, args.block);
|
let wire = RedstoneWireProperties::from_state_id(args.state.id, args.block);
|
||||||
if args.direction == BlockDirection::Up
|
if args.direction == BlockDirection::Up
|
||||||
|| wire.is_side_connected(args.direction.opposite())
|
|| wire.is_side_connected(args.direction.opposite().to_horizontal_facing().unwrap())
|
||||||
{
|
{
|
||||||
wire.power
|
wire.power
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +217,7 @@ impl BlockBehaviour for RedstoneWireBlock {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let wire = RedstoneWireProperties::from_state_id(args.state.id, args.block);
|
let wire = RedstoneWireProperties::from_state_id(args.state.id, args.block);
|
||||||
if args.direction == BlockDirection::Up
|
if args.direction == BlockDirection::Up
|
||||||
|| wire.is_side_connected(args.direction.opposite())
|
|| wire.is_side_connected(args.direction.opposite().to_horizontal_facing().unwrap())
|
||||||
{
|
{
|
||||||
wire.power
|
wire.power
|
||||||
} else {
|
} else {
|
||||||
@ -398,18 +398,17 @@ pub async fn get_regulated_sides(
|
|||||||
}
|
}
|
||||||
|
|
||||||
trait RedstoneWireLikePropertiesExt {
|
trait RedstoneWireLikePropertiesExt {
|
||||||
fn is_side_connected(&self, direction: BlockDirection) -> bool;
|
fn is_side_connected(&self, direction: HorizontalFacing) -> bool;
|
||||||
//fn get_connection_type(&self, direction: BlockDirection) -> WireConnection;
|
//fn get_connection_type(&self, direction: BlockDirection) -> WireConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedstoneWireLikePropertiesExt for RedstoneWireLikeProperties {
|
impl RedstoneWireLikePropertiesExt for RedstoneWireLikeProperties {
|
||||||
fn is_side_connected(&self, direction: BlockDirection) -> bool {
|
fn is_side_connected(&self, direction: HorizontalFacing) -> bool {
|
||||||
match direction {
|
match direction {
|
||||||
BlockDirection::North => self.north.to_wire_connection().is_connected(),
|
HorizontalFacing::North => self.north.to_wire_connection().is_connected(),
|
||||||
BlockDirection::South => self.south.to_wire_connection().is_connected(),
|
HorizontalFacing::South => self.south.to_wire_connection().is_connected(),
|
||||||
BlockDirection::East => self.east.to_wire_connection().is_connected(),
|
HorizontalFacing::East => self.east.to_wire_connection().is_connected(),
|
||||||
BlockDirection::West => self.west.to_wire_connection().is_connected(),
|
HorizontalFacing::West => self.west.to_wire_connection().is_connected(),
|
||||||
_ => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use std::sync::atomic::Ordering;
|
|||||||
use crate::block::entities::sign::SignBlockEntity;
|
use crate::block::entities::sign::SignBlockEntity;
|
||||||
use pumpkin_data::Block;
|
use pumpkin_data::Block;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
|
use pumpkin_data::HorizontalFacingExt;
|
||||||
use pumpkin_data::block_properties::EnumVariants;
|
use pumpkin_data::block_properties::EnumVariants;
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
||||||
@ -74,7 +75,7 @@ impl SignBlock {
|
|||||||
let mut side_direction = None;
|
let mut side_direction = None;
|
||||||
for direction in BlockDirection::horizontal() {
|
for direction in BlockDirection::horizontal() {
|
||||||
let pos = position.offset(direction.to_offset());
|
let pos = position.offset(direction.to_offset());
|
||||||
if Self::is_valid_support(world, &pos, direction.opposite()) {
|
if Self::is_valid_support(world, &pos, direction.opposite().to_block_direction()) {
|
||||||
side_direction = Some(direction);
|
side_direction = Some(direction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -82,7 +83,7 @@ impl SignBlock {
|
|||||||
|
|
||||||
SupportInfo {
|
SupportInfo {
|
||||||
above_is_valid,
|
above_is_valid,
|
||||||
side_direction,
|
side_direction: side_direction.map(|d| d.to_block_direction()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +335,7 @@ impl BlockBehaviour for SignBlock {
|
|||||||
for d in pumpkin_data::BlockDirection::horizontal() {
|
for d in pumpkin_data::BlockDirection::horizontal() {
|
||||||
let wall_pos = args.position.offset(d.to_offset());
|
let wall_pos = args.position.offset(d.to_offset());
|
||||||
let (block, state) = args.block_accessor.get_block_and_state(&wall_pos);
|
let (block, state) = args.block_accessor.get_block_and_state(&wall_pos);
|
||||||
if state.is_side_solid(d.opposite())
|
if state.is_side_solid(d.opposite().to_block_direction())
|
||||||
|| block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_LEAVES)
|
|| block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_LEAVES)
|
||||||
|| block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_SIGNS)
|
|| block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_SIGNS)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -74,11 +74,7 @@ impl BlockBehaviour for TorchBlock {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut torch_props = WallTorchProps::default(&wall_block);
|
let mut torch_props = WallTorchProps::default(&wall_block);
|
||||||
torch_props.facing = dir
|
torch_props.facing = dir.opposite().to_horizontal_facing().unwrap();
|
||||||
.opposite()
|
|
||||||
.to_block_direction()
|
|
||||||
.to_horizontal_facing()
|
|
||||||
.unwrap();
|
|
||||||
return torch_props.to_state_id(&wall_block);
|
return torch_props.to_state_id(&wall_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +94,7 @@ impl BlockBehaviour for TorchBlock {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
if can_place_at(args.block_accessor, args.position, dir) {
|
if can_place_at(args.block_accessor, args.position, dir.to_block_direction()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use pumpkin_inventory::player::player_inventory::PlayerInventory;
|
|||||||
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
||||||
use pumpkin_protocol::bedrock::client::take_item_actor::CTakeItemActor;
|
use pumpkin_protocol::bedrock::client::take_item_actor::CTakeItemActor;
|
||||||
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent};
|
use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent};
|
||||||
|
use pumpkin_protocol::codec::var_ulong::VarULong;
|
||||||
use pumpkin_util::GameMode;
|
use pumpkin_util::GameMode;
|
||||||
use pumpkin_util::Hand;
|
use pumpkin_util::Hand;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
@ -207,11 +208,11 @@ impl LivingEntity {
|
|||||||
&CTakeItemEntity::new(
|
&CTakeItemEntity::new(
|
||||||
item.entity_id.into(),
|
item.entity_id.into(),
|
||||||
self.entity.entity_id.into(),
|
self.entity.entity_id.into(),
|
||||||
stack_amount.try_into().unwrap(),
|
VarInt(stack_amount as i32),
|
||||||
),
|
),
|
||||||
&CTakeItemActor::new(
|
&CTakeItemActor::new(
|
||||||
item.entity_id.try_into().unwrap(),
|
VarULong(item.entity_id as u64),
|
||||||
self.entity.entity_id.try_into().unwrap(),
|
VarULong(self.entity.entity_id as u64),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,15 +63,15 @@ use pumpkin_protocol::bedrock::client::container_open::CContainerOpen;
|
|||||||
use pumpkin_protocol::codec::var_int::VarInt;
|
use pumpkin_protocol::codec::var_int::VarInt;
|
||||||
use pumpkin_protocol::codec::var_long::VarLong;
|
use pumpkin_protocol::codec::var_long::VarLong;
|
||||||
use pumpkin_protocol::java::client::play::{
|
use pumpkin_protocol::java::client::play::{
|
||||||
Animation, CAcknowledgeBlockChange, CActionBar, CAwardStats, CChangeDifficulty,
|
Animation, CActionBar, CAwardStats, CChangeDifficulty, CCloseContainer, CCombatDeath,
|
||||||
CCloseContainer, CCombatDeath, CCustomPayload, CDisguisedChatMessage, CEntityAnimation,
|
CCustomPayload, CDisguisedChatMessage, CEntityAnimation, CEntityPositionSync, CGameEvent,
|
||||||
CEntityPositionSync, CGameEvent, CItemCooldown, CMapItemData, COpenScreen, CParticle,
|
CItemCooldown, CMapItemData, COpenScreen, CParticle, CPlayerAbilities, CPlayerInfoUpdate,
|
||||||
CPlayerAbilities, CPlayerInfoUpdate, CPlayerPosition, CPlayerSpawnPosition, CRespawn,
|
CPlayerPosition, CPlayerSpawnPosition, CRespawn, CSetCamera, CSetContainerContent,
|
||||||
CSetCamera, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem,
|
CSetContainerProperty, CSetContainerSlot, CSetCursorItem, CSetEquipment, CSetExperience,
|
||||||
CSetEquipment, CSetExperience, CSetHealth, CSetPlayerInventory, CSetSelectedSlot, CSoundEffect,
|
CSetHealth, CSetPlayerInventory, CSetSelectedSlot, CSoundEffect, CStopSound, CSubtitle,
|
||||||
CStopSound, CSubtitle, CSystemChatMessage, CTabList, CTitleAnimation, CTitleText, CUnloadChunk,
|
CSystemChatMessage, CTabList, CTitleAnimation, CTitleText, CUnloadChunk, CUpdateMobEffect,
|
||||||
CUpdateMobEffect, CUpdateTime, GameEvent, MapIcon, MapPatch, Metadata, PlayerAction,
|
CUpdateTime, GameEvent, MapIcon, MapPatch, Metadata, PlayerAction, PlayerInfoFlags,
|
||||||
PlayerInfoFlags, PlayerSpawnData, PreviousMessage, Statistic,
|
PlayerSpawnData, PreviousMessage, Statistic,
|
||||||
};
|
};
|
||||||
use pumpkin_protocol::java::server::play::{
|
use pumpkin_protocol::java::server::play::{
|
||||||
SClickSlot, SContainerButtonClick, SRenameItem, SlotActionType,
|
SClickSlot, SContainerButtonClick, SRenameItem, SlotActionType,
|
||||||
@ -452,7 +452,6 @@ pub struct Player {
|
|||||||
pub mining: AtomicBool,
|
pub mining: AtomicBool,
|
||||||
pub start_mining_time: AtomicI32,
|
pub start_mining_time: AtomicI32,
|
||||||
pub tick_counter: AtomicI32,
|
pub tick_counter: AtomicI32,
|
||||||
pub packet_sequence: AtomicI32,
|
|
||||||
pub mining_pos: Mutex<BlockPos>,
|
pub mining_pos: Mutex<BlockPos>,
|
||||||
pub last_input: AtomicI8,
|
pub last_input: AtomicI8,
|
||||||
/// A counter for teleport IDs used to track pending teleports.
|
/// A counter for teleport IDs used to track pending teleports.
|
||||||
@ -646,7 +645,6 @@ impl Player {
|
|||||||
open_container: AtomicCell::new(None),
|
open_container: AtomicCell::new(None),
|
||||||
open_container_pos: AtomicCell::new(None),
|
open_container_pos: AtomicCell::new(None),
|
||||||
tick_counter: AtomicI32::new(0),
|
tick_counter: AtomicI32::new(0),
|
||||||
packet_sequence: AtomicI32::new(-1),
|
|
||||||
start_mining_time: AtomicI32::new(0),
|
start_mining_time: AtomicI32::new(0),
|
||||||
last_input: AtomicI8::new(0),
|
last_input: AtomicI8::new(0),
|
||||||
carried_item: Mutex::new(None),
|
carried_item: Mutex::new(None),
|
||||||
@ -1859,7 +1857,6 @@ impl Player {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Abstract the chunk sending
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
pub async fn tick(self: &Arc<Self>, server: &Server) {
|
pub async fn tick(self: &Arc<Self>, server: &Server) {
|
||||||
if let Some(camera_id) = self.camera_target_id.load() {
|
if let Some(camera_id) = self.camera_target_id.load() {
|
||||||
@ -1900,13 +1897,6 @@ impl Player {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let seq = self.packet_sequence.swap(-1, Ordering::Relaxed);
|
|
||||||
if seq != -1 {
|
|
||||||
self.client
|
|
||||||
.send_packet_now(&CAcknowledgeBlockChange::new(seq.into()))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistics updates
|
// Statistics updates
|
||||||
{
|
{
|
||||||
let mut stats = self.stats.lock().await;
|
let mut stats = self.stats.lock().await;
|
||||||
|
|||||||
@ -511,6 +511,11 @@ impl PumpkinServer {
|
|||||||
match udp_result {
|
match udp_result {
|
||||||
Ok((len, client_addr)) => {
|
Ok((len, client_addr)) => {
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
|
let Some(socket) = self.udp_socket.clone() else {
|
||||||
|
error!("UDP socket disappeared during receive");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
let id = udp_buf[0];
|
let id = udp_buf[0];
|
||||||
let is_online = id & 128 != 0;
|
let is_online = id & 128 != 0;
|
||||||
|
|
||||||
@ -531,7 +536,7 @@ impl PumpkinServer {
|
|||||||
*master_client_id_counter += 1;
|
*master_client_id_counter += 1;
|
||||||
|
|
||||||
let new_client = Arc::new(BedrockClient::new(
|
let new_client = Arc::new(BedrockClient::new(
|
||||||
self.udp_socket.as_ref().unwrap().clone(),
|
socket,
|
||||||
client_addr,
|
client_addr,
|
||||||
be_clients
|
be_clients
|
||||||
));
|
));
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
use pumpkin_protocol::java::client::play::{
|
use pumpkin_protocol::java::client::play::{
|
||||||
CChunkBatchEnd, CChunkBatchStart, CChunkData, CPlayDisconnect,
|
CAcknowledgeBlockChange, CChunkBatchEnd, CChunkBatchStart, CChunkData, CPlayDisconnect,
|
||||||
};
|
};
|
||||||
use pumpkin_world::level::SyncChunk;
|
use pumpkin_world::level::SyncChunk;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
use std::{io::Write, sync::Arc};
|
use std::{io::Write, sync::Arc};
|
||||||
|
|
||||||
@ -118,6 +118,8 @@ pub struct JavaClient {
|
|||||||
pub keep_alive_id: AtomicCell<i64>,
|
pub keep_alive_id: AtomicCell<i64>,
|
||||||
/// The last time we sent a keep alive packet.
|
/// The last time we sent a keep alive packet.
|
||||||
pub last_keep_alive_time: AtomicCell<Instant>,
|
pub last_keep_alive_time: AtomicCell<Instant>,
|
||||||
|
|
||||||
|
pub packet_sequence: AtomicI32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum OutgoingPacketType {
|
pub enum OutgoingPacketType {
|
||||||
@ -173,6 +175,7 @@ impl JavaClient {
|
|||||||
wait_for_keep_alive: AtomicBool::new(false),
|
wait_for_keep_alive: AtomicBool::new(false),
|
||||||
keep_alive_id: AtomicCell::new(0),
|
keep_alive_id: AtomicCell::new(0),
|
||||||
last_keep_alive_time: AtomicCell::new(std::time::Instant::now()),
|
last_keep_alive_time: AtomicCell::new(std::time::Instant::now()),
|
||||||
|
packet_sequence: AtomicI32::new(-1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn set_encryption(
|
pub async fn set_encryption(
|
||||||
@ -272,6 +275,13 @@ impl JavaClient {
|
|||||||
self.last_keep_alive_time.store(Instant::now());
|
self.last_keep_alive_time.store(Instant::now());
|
||||||
let packet = pumpkin_protocol::java::client::play::CKeepAlive::new(keep_alive_id);
|
let packet = pumpkin_protocol::java::client::play::CKeepAlive::new(keep_alive_id);
|
||||||
self.enqueue_packet(&packet).await;
|
self.enqueue_packet(&packet).await;
|
||||||
|
|
||||||
|
let seq = self.packet_sequence.swap(-1, Ordering::Relaxed);
|
||||||
|
if seq != -1 {
|
||||||
|
self
|
||||||
|
.send_packet_now(&CAcknowledgeBlockChange::new(seq.into()))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// INCOMING PACKETS
|
// INCOMING PACKETS
|
||||||
|
|||||||
@ -2074,12 +2074,12 @@ impl JavaClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_sequence(&self, player: &Player, sequence: i32) {
|
pub fn update_sequence(&self, _player: &Player, sequence: i32) {
|
||||||
if sequence < 0 {
|
if sequence < 0 {
|
||||||
error!("Expected packet sequence >= 0");
|
error!("Expected packet sequence >= 0");
|
||||||
}
|
}
|
||||||
player.packet_sequence.store(
|
self.packet_sequence.store(
|
||||||
player.packet_sequence.load(Ordering::Relaxed).max(sequence),
|
self.packet_sequence.load(Ordering::Relaxed).max(sequence),
|
||||||
Ordering::Relaxed,
|
Ordering::Relaxed,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::{Block, BlockState, damage::DamageType, entity::EntityType};
|
use pumpkin_data::{Block, BlockState, damage::DamageType, entity::EntityType, fluid::Fluid};
|
||||||
use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos, vector3::Vector3};
|
use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos, vector3::Vector3};
|
||||||
|
use pumpkin_world::chunk::ChunkData;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -27,51 +28,102 @@ impl Explosion {
|
|||||||
&self,
|
&self,
|
||||||
world: &World,
|
world: &World,
|
||||||
) -> FxHashMap<BlockPos, (&'static Block, &'static BlockState)> {
|
) -> FxHashMap<BlockPos, (&'static Block, &'static BlockState)> {
|
||||||
// Somethings are not vanilla here but make it way faster
|
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::default();
|
||||||
let random_val = rand::random::<f32>();
|
|
||||||
|
let mut chunk_cache: FxHashMap<
|
||||||
|
pumpkin_util::math::vector2::Vector2<i32>,
|
||||||
|
Option<Arc<ChunkData>>,
|
||||||
|
> = FxHashMap::default();
|
||||||
|
|
||||||
for x in 0..16 {
|
for x in 0..16 {
|
||||||
for y in 0..16 {
|
for y in 0..16 {
|
||||||
'block2: for z in 0..16 {
|
for z in 0..16 {
|
||||||
if x > 0 && x < 15 && y > 0 && y < 15 && z > 0 && z < 15 {
|
if x > 0 && x < 15 && y > 0 && y < 15 && z > 0 && z < 15 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut x = f64::from(x) / 7.5 - 1.0;
|
let mut dir_x = f64::from(x) / 7.5 - 1.0;
|
||||||
let mut y = f64::from(y) / 7.5 - 1.0;
|
let mut dir_y = f64::from(y) / 7.5 - 1.0;
|
||||||
let mut z = f64::from(z) / 7.5 - 1.0;
|
let mut dir_z = f64::from(z) / 7.5 - 1.0;
|
||||||
|
|
||||||
let sqrt = 1.0 / (x * x + y * y + z * z).sqrt();
|
let length = (dir_x * dir_x + dir_y * dir_y + dir_z * dir_z).sqrt();
|
||||||
x *= sqrt;
|
dir_x /= length;
|
||||||
y *= sqrt;
|
dir_y /= length;
|
||||||
z *= sqrt;
|
dir_z /= length;
|
||||||
|
|
||||||
let mut pos_x = self.pos.x;
|
let mut pos_x = self.pos.x;
|
||||||
let mut pos_y = self.pos.y + 0.0625;
|
let mut pos_y = self.pos.y;
|
||||||
let mut pos_z = self.pos.z;
|
let mut pos_z = self.pos.z;
|
||||||
|
|
||||||
|
let random_val = rand::random::<f32>();
|
||||||
let mut h = self.power * random_val.mul_add(0.6, 0.7);
|
let mut h = self.power * random_val.mul_add(0.6, 0.7);
|
||||||
|
|
||||||
while h > 0.0 {
|
while h > 0.0 {
|
||||||
let block_pos = BlockPos::floored(pos_x, pos_y, pos_z);
|
let block_pos = BlockPos::floored(pos_x, pos_y, pos_z);
|
||||||
let (block, state) = world.get_block_and_state(&block_pos);
|
|
||||||
let (_, fluid_state) = world.get_fluid_and_fluid_state(&block_pos);
|
|
||||||
|
|
||||||
// if !world.is_in_build_limit(&block_pos) {
|
if !world.is_in_build_limit(block_pos) {
|
||||||
// // Pass by reference
|
break;
|
||||||
// continue 'block2;
|
}
|
||||||
// }
|
|
||||||
|
let (chunk_pos, relative) = block_pos.chunk_and_chunk_relative_position();
|
||||||
|
|
||||||
|
let chunk_opt = chunk_cache.entry(chunk_pos).or_insert_with(|| {
|
||||||
|
world
|
||||||
|
.level
|
||||||
|
.read_chunk_sync(&chunk_pos, std::clone::Clone::clone)
|
||||||
|
});
|
||||||
|
|
||||||
|
let state_id = if let Some(chunk) = chunk_opt {
|
||||||
|
chunk
|
||||||
|
.section
|
||||||
|
.get_block_absolute_y(
|
||||||
|
relative.x as usize,
|
||||||
|
block_pos.0.y,
|
||||||
|
relative.z as usize,
|
||||||
|
)
|
||||||
|
.unwrap_or(Block::AIR.default_state.id)
|
||||||
|
} else {
|
||||||
|
Block::AIR.default_state.id
|
||||||
|
};
|
||||||
|
|
||||||
|
let (block, state) = BlockState::from_id_with_block(state_id);
|
||||||
|
|
||||||
|
let (_fluid, fluid_state) = Fluid::from_state_id(state_id).map_or_else(
|
||||||
|
|| {
|
||||||
|
let is_waterlogged =
|
||||||
|
block.properties(state_id).is_some_and(|props| {
|
||||||
|
props
|
||||||
|
.to_props()
|
||||||
|
.into_iter()
|
||||||
|
.any(|(k, v)| k == "waterlogged" && v == "true")
|
||||||
|
});
|
||||||
|
|
||||||
|
if is_waterlogged {
|
||||||
|
(&Fluid::FLOWING_WATER, &Fluid::FLOWING_WATER.states[0])
|
||||||
|
} else {
|
||||||
|
(&Fluid::EMPTY, &Fluid::EMPTY.states[0])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|raw_fluid| {
|
||||||
|
let f = raw_fluid.to_flowing();
|
||||||
|
(f, &f.states[0])
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if !state.is_air() || !fluid_state.is_empty {
|
if !state.is_air() || !fluid_state.is_empty {
|
||||||
let resistance =
|
let resistance =
|
||||||
fluid_state.blast_resistance.max(block.blast_resistance);
|
fluid_state.blast_resistance.max(block.blast_resistance);
|
||||||
h -= resistance * 0.3;
|
|
||||||
|
h -= (resistance + 0.3) * 0.3;
|
||||||
|
|
||||||
if h > 0.0 {
|
if h > 0.0 {
|
||||||
map.insert(block_pos, (block, state));
|
map.insert(block_pos, (block, state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos_x += x * 0.3;
|
|
||||||
pos_y += y * 0.3;
|
pos_x += dir_x * 0.3;
|
||||||
pos_z += z * 0.3;
|
pos_y += dir_y * 0.3;
|
||||||
|
pos_z += dir_z * 0.3;
|
||||||
h -= 0.225_000_01;
|
h -= 0.225_000_01;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ use border::Worldborder;
|
|||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use explosion::Explosion;
|
use explosion::Explosion;
|
||||||
use pumpkin_config::BasicConfiguration;
|
use pumpkin_config::BasicConfiguration;
|
||||||
use pumpkin_data::block_properties::is_air;
|
use pumpkin_data::block_properties::{blocks_movement, is_air};
|
||||||
use pumpkin_data::block_rotation::{Mirror, Rotation};
|
use pumpkin_data::block_rotation::{Mirror, Rotation};
|
||||||
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
use pumpkin_data::chunk_gen_settings::GenerationSettings;
|
||||||
use pumpkin_data::data_component_impl::EquipmentSlot;
|
use pumpkin_data::data_component_impl::EquipmentSlot;
|
||||||
@ -73,7 +73,7 @@ use pumpkin_data::{
|
|||||||
sound_id_remap::remap_sound_id_for_version,
|
sound_id_remap::remap_sound_id_for_version,
|
||||||
world::{RAW, WorldEvent},
|
world::{RAW, WorldEvent},
|
||||||
};
|
};
|
||||||
use pumpkin_data::{BlockDirection, BlockState, translation};
|
use pumpkin_data::{BlockDirection, BlockState, HorizontalFacingExt, translation};
|
||||||
use pumpkin_inventory::crafting::recipe_provider::RecipeProvider;
|
use pumpkin_inventory::crafting::recipe_provider::RecipeProvider;
|
||||||
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
use pumpkin_inventory::screen_handler::InventoryPlayer;
|
||||||
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
|
use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed};
|
||||||
@ -1324,7 +1324,7 @@ impl World {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlowableFluid.getVelocity()
|
// FlowingFluid.getFlow()
|
||||||
pub fn get_fluid_velocity(
|
pub fn get_fluid_velocity(
|
||||||
&self,
|
&self,
|
||||||
pos0: BlockPos,
|
pos0: BlockPos,
|
||||||
@ -1334,66 +1334,57 @@ impl World {
|
|||||||
let mut velo = Vector3::default();
|
let mut velo = Vector3::default();
|
||||||
|
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
let mut amplitude = 0.0;
|
|
||||||
|
|
||||||
let offset = dir.to_offset();
|
let offset = dir.to_offset();
|
||||||
|
|
||||||
let pos = pos0.offset(offset);
|
let pos = pos0.offset(offset);
|
||||||
|
|
||||||
let block_state_id = self.get_block_state_id(&pos);
|
let (neighbor_fluid, neighbor_state) = self.get_fluid_and_fluid_state(&pos);
|
||||||
|
|
||||||
let fluid = Fluid::from_state_id(block_state_id).unwrap_or(&Fluid::EMPTY);
|
if neighbor_fluid.matches_type(fluid0) {
|
||||||
|
let mut neighbor_height = neighbor_state.height;
|
||||||
|
let mut amplitude = 0.0;
|
||||||
|
|
||||||
if fluid.id == Fluid::EMPTY.id {
|
if neighbor_height == 0.0 {
|
||||||
let block = Block::get_raw_id_from_state_id(block_state_id);
|
let block_state_id = self.get_block_state_id(&pos);
|
||||||
let block_state = BlockState::from_id(block_state_id);
|
let block = Block::get_raw_id_from_state_id(block_state_id);
|
||||||
|
let block_state = BlockState::from_id(block_state_id);
|
||||||
|
|
||||||
let blocks_movement = block_state.is_solid()
|
let blocks_movement = blocks_movement(block_state, block);
|
||||||
&& block != Block::COBWEB
|
|
||||||
&& block != Block::BAMBOO_SAPLING;
|
|
||||||
|
|
||||||
if !blocks_movement {
|
if !blocks_movement {
|
||||||
let down_pos = pos.down();
|
let down_pos = pos.down();
|
||||||
|
let (down_fluid, down_state) = self.get_fluid_and_fluid_state(&down_pos);
|
||||||
|
|
||||||
let (down_fluid, down_state) = self.get_fluid_and_fluid_state(&down_pos);
|
if down_fluid.matches_type(fluid0) {
|
||||||
|
neighbor_height = down_state.height;
|
||||||
if down_fluid.matches_type(fluid0) {
|
if neighbor_height > 0.0 {
|
||||||
amplitude = f64::from(state0.height - down_state.height) + 0.888_888_9;
|
amplitude = f64::from(state0.height)
|
||||||
|
- (f64::from(neighbor_height) - 0.888_888_9);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if neighbor_height > 0.0 {
|
||||||
} else {
|
amplitude = f64::from(state0.height) - f64::from(neighbor_height);
|
||||||
if !fluid.matches_type(fluid0) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//let state = fluid.get_state(block_state_id);
|
if amplitude != 0.0 {
|
||||||
amplitude = f64::from(state0.height - fluid.states[0].height);
|
velo.x += f64::from(offset.x) * amplitude;
|
||||||
|
velo.z += f64::from(offset.z) * amplitude;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if amplitude == 0.0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
velo.x += f64::from(offset.x) * amplitude;
|
|
||||||
|
|
||||||
velo.z += f64::from(offset.z) * amplitude;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: FALLING
|
|
||||||
|
|
||||||
if state0.falling {
|
if state0.falling {
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
let pos = pos0.offset(dir.to_offset());
|
let pos = pos0.offset(dir.to_offset());
|
||||||
|
|
||||||
if self.is_flow_blocked(fluid0.id, pos, dir)
|
if self.is_solid_face(fluid0.id, pos, dir.to_block_direction())
|
||||||
|| self.is_flow_blocked(fluid0.id, pos.up(), dir)
|
|| self.is_solid_face(fluid0.id, pos.up(), dir.to_block_direction())
|
||||||
{
|
{
|
||||||
if velo.length_squared() != 0.0 {
|
if velo.length_squared() != 0.0 {
|
||||||
velo = velo.normalize();
|
velo = velo.normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
velo.y -= 6.0;
|
velo.y -= 6.0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1406,9 +1397,8 @@ impl World {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlowableFluid.isFlowBlocked()
|
// FlowingFluid.isSolidFace()
|
||||||
|
fn is_solid_face(&self, fluid0_id: u16, pos: BlockPos, direction: BlockDirection) -> bool {
|
||||||
fn is_flow_blocked(&self, fluid0_id: u16, pos: BlockPos, direction: BlockDirection) -> bool {
|
|
||||||
let id = self.get_block_state_id(&pos);
|
let id = self.get_block_state_id(&pos);
|
||||||
|
|
||||||
let fluid = Fluid::from_state_id(id).unwrap_or(&Fluid::EMPTY);
|
let fluid = Fluid::from_state_id(id).unwrap_or(&Fluid::EMPTY);
|
||||||
|
|||||||
@ -52,10 +52,9 @@ impl EndPortal {
|
|||||||
|
|
||||||
fn is_valid_portal(world: &World, pos: BlockPos) -> bool {
|
fn is_valid_portal(world: &World, pos: BlockPos) -> bool {
|
||||||
for dir in BlockDirection::horizontal() {
|
for dir in BlockDirection::horizontal() {
|
||||||
let facing = dir.to_horizontal_facing().unwrap();
|
|
||||||
let mid_pos = pos.offset_dir(dir.to_offset(), 2);
|
let mid_pos = pos.offset_dir(dir.to_offset(), 2);
|
||||||
let left_pos = mid_pos.offset_dir(facing.rotate_clockwise().to_offset(), 1);
|
let left_pos = mid_pos.offset_dir(dir.rotate_clockwise().to_offset(), 1);
|
||||||
let right_pos = mid_pos.offset_dir(facing.rotate_counter_clockwise().to_offset(), 1);
|
let right_pos = mid_pos.offset_dir(dir.rotate_counter_clockwise().to_offset(), 1);
|
||||||
|
|
||||||
let (mid_block, mid_state) = world.get_block_and_state_id(&mid_pos);
|
let (mid_block, mid_state) = world.get_block_and_state_id(&mid_pos);
|
||||||
let (left_block, left_state) = world.get_block_and_state_id(&left_pos);
|
let (left_block, left_state) = world.get_block_and_state_id(&left_pos);
|
||||||
@ -73,6 +72,8 @@ impl EndPortal {
|
|||||||
let right_properties =
|
let right_properties =
|
||||||
EndPortalFrameProperties::from_state_id(right_state, right_block);
|
EndPortalFrameProperties::from_state_id(right_state, right_block);
|
||||||
|
|
||||||
|
let facing = dir.to_facing();
|
||||||
|
|
||||||
if left_properties.facing != facing.opposite()
|
if left_properties.facing != facing.opposite()
|
||||||
|| mid_properties.facing != facing.opposite()
|
|| mid_properties.facing != facing.opposite()
|
||||||
|| right_properties.facing != facing.opposite()
|
|| right_properties.facing != facing.opposite()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user