Skip to content

Commit 6178de5

Browse files
fix: variety of small things (#1265)
* scheduled ticks for banners * scheduled ticks and can place at for cakes * add pitch to world spawn and setworldspawn command * add ability migrate LevelDat from SpawnAngle to SpawnYaw * backwards compatibility * use minecraft name for setworldspawn make PlayerSpawnPosition not panic anymore fix infinite skipping of night when no players were online * fix more clippy lints * send abilities update on initial spawn * Revert "fix more clippy lints" This reverts commit 19d4ae5. * .-. * implement advance time gamerule * still tick world_age * advance weather * add dropping of inventory on death * keep inventory gamerule * clippy --------- Co-authored-by: CuzImClicks <cuzimclicks@proton.me> Co-authored-by: Alexander Medvedev <lilalexmed@proton.me>
1 parent 1ff5f71 commit 6178de5

File tree

15 files changed

+297
-87
lines changed

15 files changed

+297
-87
lines changed

pumpkin-protocol/src/java/client/play/player_spawn_position.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@ use pumpkin_util::math::position::BlockPos;
77
#[derive(Serialize)]
88
#[packet(PLAY_SET_DEFAULT_SPAWN_POSITION)]
99
pub struct CPlayerSpawnPosition {
10+
pub dimension_name: String,
1011
pub location: BlockPos,
11-
pub angle: f32,
12+
pub yaw: f32,
13+
pub pitch: f32,
1214
}
1315

1416
impl CPlayerSpawnPosition {
15-
pub fn new(location: BlockPos, angle: f32) -> Self {
16-
Self { location, angle }
17+
pub fn new(location: BlockPos, yaw: f32, pitch: f32, dimension_name: String) -> Self {
18+
Self {
19+
location,
20+
yaw,
21+
pitch,
22+
dimension_name,
23+
}
1724
}
1825
}

pumpkin-world/src/world_info/anvil.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ mod test {
236236
spawn_x: 160,
237237
spawn_y: 70,
238238
spawn_z: 160,
239-
spawn_angle: 0.0,
239+
spawn_yaw: 0.0,
240+
spawn_pitch: 0.0,
240241
level_version: 19133,
241242
world_version: WorldVersion {
242243
name: "1.21.4".to_string(),

pumpkin-world/src/world_info/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ pub struct LevelData {
8383
// The Z coordinate of the world spawn.
8484
pub spawn_z: i32,
8585
// The Yaw rotation of the world spawn.
86-
pub spawn_angle: f32,
86+
#[serde(alias = "SpawnAngle")]
87+
pub spawn_yaw: f32,
88+
// The Pitch rotation of the world spawn.
89+
#[serde(default)]
90+
pub spawn_pitch: f32,
8791
#[serde(rename = "Version")]
8892
pub world_version: WorldVersion,
8993
#[serde(rename = "version")]
@@ -243,7 +247,8 @@ impl LevelData {
243247
spawn_x: 0,
244248
spawn_y: 200,
245249
spawn_z: 0,
246-
spawn_angle: 0.0,
250+
spawn_yaw: 0.0,
251+
spawn_pitch: 0.0,
247252
world_version: Default::default(),
248253
level_version: MAXIMUM_SUPPORTED_LEVEL_VERSION,
249254
}

pumpkin/src/block/blocks/banners.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs};
1+
use crate::block::{
2+
BlockBehaviour, BlockFuture, GetStateForNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs,
3+
};
24
use crate::entity::EntityBase;
35
use pumpkin_data::block_properties::{BlockProperties, WhiteBannerLikeProperties};
46
use pumpkin_data::tag::{RegistryKey, get_tag_values};
57
use pumpkin_macros::pumpkin_block_from_tag;
8+
use pumpkin_util::math::position::BlockPos;
69
use pumpkin_world::BlockStateId;
10+
use pumpkin_world::tick::TickPriority;
11+
use pumpkin_world::world::{BlockAccessor, BlockFlags};
712

813
#[pumpkin_block_from_tag("minecraft:banners")]
914
pub struct BannerBlock;
@@ -16,4 +21,37 @@ impl BlockBehaviour for BannerBlock {
1621
props.to_state_id(args.block)
1722
})
1823
}
24+
25+
fn can_place_at<'a>(&'a self, args: crate::block::CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
26+
Box::pin(async move { can_place_at(args.block_accessor, args.position).await })
27+
}
28+
29+
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
30+
Box::pin(async move {
31+
if !can_place_at(args.world.as_ref(), args.position).await {
32+
args.world
33+
.break_block(args.position, None, BlockFlags::empty())
34+
.await;
35+
}
36+
})
37+
}
38+
39+
fn get_state_for_neighbor_update<'a>(
40+
&'a self,
41+
args: GetStateForNeighborUpdateArgs<'a>,
42+
) -> BlockFuture<'a, BlockStateId> {
43+
Box::pin(async move {
44+
if !can_place_at(args.world, args.position).await {
45+
args.world
46+
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
47+
.await;
48+
}
49+
args.state_id
50+
})
51+
}
52+
}
53+
54+
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
55+
let state = world.get_block_state(&position.down()).await;
56+
state.is_solid()
1957
}

pumpkin/src/block/blocks/bed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ impl BlockBehaviour for BedBlock {
238238
args.world.dimension,
239239
bed_head_pos,
240240
args.player.get_entity().yaw.load(),
241+
args.player.get_entity().pitch.load(),
241242
)
242243
.await
243244
{

pumpkin/src/block/blocks/cake.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use std::sync::Arc;
22

33
use crate::{
44
block::{
5-
BlockBehaviour, BlockFuture, NormalUseArgs, UseWithItemArgs,
6-
blocks::candle_cakes::cake_from_candle, registry::BlockActionResult,
5+
BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, NormalUseArgs,
6+
OnPlaceArgs, OnScheduledTickArgs, UseWithItemArgs, blocks::candle_cakes::cake_from_candle,
7+
registry::BlockActionResult,
78
},
89
entity::player::Player,
910
world::World,
@@ -16,7 +17,11 @@ use pumpkin_data::{
1617
};
1718
use pumpkin_macros::pumpkin_block;
1819
use pumpkin_util::{GameMode, math::position::BlockPos};
19-
use pumpkin_world::world::BlockFlags;
20+
use pumpkin_world::{
21+
BlockStateId,
22+
tick::TickPriority,
23+
world::{BlockAccessor, BlockFlags},
24+
};
2025
use rand::{Rng, rng};
2126

2227
#[pumpkin_block("minecraft:cake")]
@@ -77,6 +82,19 @@ impl CakeBlock {
7782
}
7883

7984
impl BlockBehaviour for CakeBlock {
85+
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
86+
Box::pin(async move {
87+
if !can_place_at(args.world, args.position).await {
88+
return Block::AIR.default_state.id;
89+
}
90+
Block::CAKE.default_state.id
91+
})
92+
}
93+
94+
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
95+
Box::pin(async move { can_place_at(args.block_accessor, args.position).await })
96+
}
97+
8098
fn use_with_item<'a>(
8199
&'a self,
82100
args: UseWithItemArgs<'a>,
@@ -146,4 +164,33 @@ impl BlockBehaviour for CakeBlock {
146164
.await
147165
})
148166
}
167+
168+
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
169+
Box::pin(async move {
170+
if !can_place_at(args.world.as_ref(), args.position).await {
171+
args.world
172+
.break_block(args.position, None, BlockFlags::empty())
173+
.await;
174+
}
175+
})
176+
}
177+
178+
fn get_state_for_neighbor_update<'a>(
179+
&'a self,
180+
args: GetStateForNeighborUpdateArgs<'a>,
181+
) -> BlockFuture<'a, BlockStateId> {
182+
Box::pin(async move {
183+
if !can_place_at(args.world, args.position).await {
184+
args.world
185+
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
186+
.await;
187+
}
188+
args.state_id
189+
})
190+
}
191+
}
192+
193+
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
194+
let state = world.get_block_state(&position.down()).await;
195+
state.is_solid()
149196
}

pumpkin/src/block/blocks/candle_cakes.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ use pumpkin_data::{
77
};
88
use pumpkin_macros::pumpkin_block_from_tag;
99
use pumpkin_util::{GameMode, math::position::BlockPos};
10-
use pumpkin_world::{item::ItemStack, world::BlockFlags};
10+
use pumpkin_world::{
11+
BlockStateId,
12+
item::ItemStack,
13+
tick::TickPriority,
14+
world::{BlockAccessor, BlockFlags},
15+
};
1116

1217
use crate::{
1318
block::{
14-
BlockBehaviour, BlockFuture, NormalUseArgs, UseWithItemArgs, blocks::cake::CakeBlock,
15-
registry::BlockActionResult,
19+
BlockBehaviour, BlockFuture, GetStateForNeighborUpdateArgs, NormalUseArgs,
20+
OnScheduledTickArgs, UseWithItemArgs, blocks::cake::CakeBlock, registry::BlockActionResult,
1621
},
1722
entity::player::Player,
1823
world::World,
@@ -119,4 +124,33 @@ impl BlockBehaviour for CandleCakeBlock {
119124
Self::consume_and_drop_candle(args.block, args.player, args.position, args.world).await
120125
})
121126
}
127+
128+
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
129+
Box::pin(async move {
130+
if !can_place_at(args.world.as_ref(), args.position).await {
131+
args.world
132+
.break_block(args.position, None, BlockFlags::empty())
133+
.await;
134+
}
135+
})
136+
}
137+
138+
fn get_state_for_neighbor_update<'a>(
139+
&'a self,
140+
args: GetStateForNeighborUpdateArgs<'a>,
141+
) -> BlockFuture<'a, BlockStateId> {
142+
Box::pin(async move {
143+
if !can_place_at(args.world, args.position).await {
144+
args.world
145+
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
146+
.await;
147+
}
148+
args.state_id
149+
})
150+
}
151+
}
152+
153+
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
154+
let state = world.get_block_state(&position.down()).await;
155+
state.is_solid()
122156
}

pumpkin/src/block/blocks/redstone/tripwire_hook.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ impl TripwireHookBlock {
236236
}
237237
}
238238

239-
let future_attached = can_attach & (j > 1);
240-
let future_powered = wire_attached & future_attached;
239+
let future_attached = can_attach && (j > 1);
240+
let future_powered = wire_attached && future_attached;
241241
let mut future_hook_state = TripwireHookProperties::default(&Block::TRIPWIRE_HOOK);
242242
future_hook_state.attached = future_attached;
243243
future_hook_state.powered = future_powered;

pumpkin/src/command/commands/setworldspawn.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,18 @@ impl CommandExecutor for NoArgsWorldSpawnExecutor {
3131
_args: &'a ConsumedArgs<'a>,
3232
) -> CommandResult<'a> {
3333
Box::pin(async move {
34-
let Some(block_pos) = sender.position() else {
35-
let level_info_guard = server.level_info.read().await;
36-
sender
37-
.send_message(TextComponent::translate(
38-
"commands.setworldspawn.success",
39-
[
40-
TextComponent::text(level_info_guard.spawn_x.to_string()),
41-
TextComponent::text(level_info_guard.spawn_y.to_string()),
42-
TextComponent::text(level_info_guard.spawn_z.to_string()),
43-
TextComponent::text(level_info_guard.spawn_angle.to_string()),
44-
],
45-
))
46-
.await;
47-
48-
return Ok(());
34+
let Some(player) = sender.as_player() else {
35+
if sender.is_console() {
36+
return Err(CommandError::CommandFailed(TextComponent::text(
37+
"You must specify a Position!",
38+
)));
39+
}
40+
return Err(CommandError::CommandFailed(TextComponent::text(
41+
"Failed to get Sender as Player!",
42+
)));
4943
};
50-
51-
setworldspawn(sender, server, block_pos.to_block_pos(), 0.0).await
44+
let block_pos = player.position();
45+
setworldspawn(sender, server, block_pos.to_block_pos(), 0.0, 0.0).await
5246
})
5347
}
5448
}
@@ -67,7 +61,7 @@ impl CommandExecutor for DefaultWorldSpawnExecutor {
6761
return Err(InvalidConsumption(Some(ARG_BLOCK_POS.into())));
6862
};
6963

70-
setworldspawn(sender, server, *block_pos, 0.0).await
64+
setworldspawn(sender, server, *block_pos, 0.0, 0.0).await
7165
})
7266
}
7367
}
@@ -86,11 +80,11 @@ impl CommandExecutor for AngleWorldSpawnExecutor {
8680
return Err(InvalidConsumption(Some(ARG_BLOCK_POS.into())));
8781
};
8882

89-
let Some(Arg::Rotation(_, yaw)) = args.get(ARG_ANGLE) else {
83+
let Some(Arg::Rotation(pitch, yaw)) = args.get(ARG_ANGLE) else {
9084
return Err(InvalidConsumption(Some(ARG_ANGLE.into())));
9185
};
9286

93-
setworldspawn(sender, server, *block_pos, *yaw).await
87+
setworldspawn(sender, server, *block_pos, *yaw, *pitch).await
9488
})
9589
}
9690
}
@@ -100,6 +94,7 @@ async fn setworldspawn(
10094
server: &Server,
10195
block_pos: BlockPos,
10296
yaw: f32,
97+
pitch: f32,
10398
) -> Result<(), CommandError> {
10499
let Some(world) = sender.world() else {
105100
return Err(CommandError::CommandFailed(TextComponent::text(
@@ -121,7 +116,8 @@ async fn setworldspawn(
121116
level_info_guard.spawn_y = block_pos.0.y;
122117
level_info_guard.spawn_z = block_pos.0.z;
123118

124-
level_info_guard.spawn_angle = yaw;
119+
level_info_guard.spawn_yaw = yaw;
120+
level_info_guard.spawn_pitch = pitch;
125121

126122
drop(level_info_guard);
127123

@@ -133,6 +129,8 @@ async fn setworldspawn(
133129
TextComponent::text(block_pos.0.y.to_string()),
134130
TextComponent::text(block_pos.0.z.to_string()),
135131
TextComponent::text(yaw.to_string()),
132+
TextComponent::text(pitch.to_string()),
133+
TextComponent::text(world.dimension.minecraft_name),
136134
],
137135
))
138136
.await;

pumpkin/src/entity/living.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use pumpkin_inventory::build_equipment_slots;
55
use pumpkin_inventory::player::player_inventory::PlayerInventory;
66
use pumpkin_util::Hand;
77
use pumpkin_util::math::position::BlockPos;
8+
use std::mem;
89
use std::sync::Arc;
910
use std::sync::atomic::Ordering;
1011
use std::sync::atomic::{
@@ -808,9 +809,21 @@ impl LivingEntity {
808809
self.drop_loot(params).await;
809810
self.entity.pose.store(EntityPose::Dying);
810811

811-
let level_info = world.level_info.read().await;
812-
let game_rules = &level_info.game_rules;
813-
if self.entity.entity_type == &EntityType::PLAYER && game_rules.show_death_messages {
812+
let block_pos = self.entity.block_pos.load();
813+
814+
for slot in self.equipment_slots.values() {
815+
let item = {
816+
let lock = self.entity_equipment.lock().await;
817+
let equipment = lock.get(slot);
818+
let mut item_lock = equipment.lock().await;
819+
mem::replace(&mut *item_lock, ItemStack::EMPTY.clone())
820+
};
821+
world.drop_stack(&block_pos, item).await;
822+
}
823+
824+
let show_death_messages =
825+
{ world.level_info.read().await.game_rules.show_death_messages };
826+
if self.entity.entity_type == &EntityType::PLAYER && show_death_messages {
814827
//TODO: KillCredit
815828
let death_message =
816829
Self::get_death_message(&*dyn_self, damage_type, source, cause).await;

0 commit comments

Comments
 (0)