forked from feather-rs/feather
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathfalling_block.rs
More file actions
125 lines (107 loc) · 4.03 KB
/
falling_block.rs
File metadata and controls
125 lines (107 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Implements falling block entities: sand, gravel, etc.
use crate::block::{BlockNotifyBlock, BlockNotifyFallingBlock, BlockNotifyPosition};
use crate::entity::{EntityId, SpawnPacketCreator, Velocity};
use crate::game::Game;
use crate::physics::{EntityPhysicsLandEvent, PhysicsBuilder};
use crate::util::{degrees_to_stops, protocol_velocity};
use crate::{entity, BumpVec};
use feather_blocks::{Block, BlockExt};
use feather_core::network::packet::implementation::SpawnObject;
use feather_core::{
BlockPosition, EntityMetadata, Packet, Position, META_INDEX_FALLING_BLOCK_SPAWN_POSITION,
};
use fecs::{component, EntityBuilder, EntityRef, IntoQuery, Read, World};
use uuid::Uuid;
/// Marker component indicating an entity is a falling block.
#[derive(Copy, Clone, Debug)]
pub struct FallingBlock;
/// Component storing the block type for a falling block.
#[derive(Copy, Clone, Debug)]
pub struct FallingBlockType(pub Block);
/// System to create a falling block when a block notify
/// entity is spawned with `BlockNotifyFallingBlock`.
#[system]
pub fn spawn_falling_blocks(game: &mut Game, world: &mut World) {
let mut actions = BumpVec::new_in(game.bump());
actions.extend(
<(Read<BlockNotifyBlock>, Read<BlockNotifyPosition>)>::query()
.filter(component::<BlockNotifyFallingBlock>())
.iter_entities(world.inner())
.map(|(entity, (block, position))| {
let builder = if game.block_at(position.0 - BlockPosition::new(0, 1, 0))
== Some(Block::Air)
{
Some(
create(block.0, position.0)
.with(position.0.position() + position!(0.5, 0.0, 0.5)),
)
} else {
None
};
(entity, builder, position.0)
}),
);
for (entity_to_delete, entity_builder, block_to_clear) in actions {
world.despawn(entity_to_delete);
if let Some(entity_builder) = entity_builder {
let created_entity = entity_builder.build().spawn_in(world);
game.on_entity_spawn(world, created_entity);
game.set_block_at(world, block_to_clear, Block::Air);
}
}
}
/// When a falling block lands on the ground, deletes
/// it and creates a solid block where it landed.
pub fn on_entity_land_remove_falling_block(
game: &mut Game,
world: &mut World,
event: &EntityPhysicsLandEvent,
) {
if let Some(block) = world
.try_get::<FallingBlockType>(event.entity)
.map(|block| block.0)
{
let pos = event.pos.block();
game.set_block_at(world, pos, block);
game.despawn(event.entity, world);
}
}
/// Returns an `EntityBuilder` for a falling block of the given type.
pub fn create(ty: Block, spawn_pos: BlockPosition) -> EntityBuilder {
let meta =
EntityMetadata::entity_base().with(META_INDEX_FALLING_BLOCK_SPAWN_POSITION, spawn_pos);
entity::base()
.with(FallingBlock)
.with(FallingBlockType(ty))
.with(SpawnPacketCreator(&create_spawn_packet))
.with(
PhysicsBuilder::new()
.bbox(0.98, 0.98, 0.98)
.drag(0.98)
.gravity(-0.04)
.build(),
)
.with(meta)
}
fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> {
let data = i32::from(accessor.get::<FallingBlockType>().0.native_state_id());
let position = accessor.get::<Position>();
let entity_id = accessor.get::<EntityId>().0;
let velocity = accessor.get::<Velocity>().0;
let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity);
let packet = SpawnObject {
entity_id,
object_uuid: Uuid::new_v4(),
ty: 70, // Type 70 for falling block
x: position.x,
y: position.y,
z: position.z,
pitch: degrees_to_stops(position.pitch),
yaw: degrees_to_stops(position.yaw),
data,
velocity_x,
velocity_y,
velocity_z,
};
Box::new(packet)
}