Add digging to ECS
This commit is contained in:
parent
d601ec3907
commit
700a31013f
|
@ -1,3 +1,5 @@
|
|||
use steven_blocks as block;
|
||||
use steven_protocol::protocol::packet;
|
||||
pub mod block_entity;
|
||||
pub mod player;
|
||||
|
||||
|
@ -23,6 +25,8 @@ pub fn add_systems(m: &mut ecs::Manager) {
|
|||
m.add_render_system(sys);
|
||||
let sys = systems::LightEntity::new(m);
|
||||
m.add_render_system(sys);
|
||||
let sys = systems::ApplyDigging::new(m);
|
||||
m.add_render_system(sys);
|
||||
|
||||
block_entity::add_systems(m);
|
||||
}
|
||||
|
@ -161,3 +165,37 @@ impl Light {
|
|||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DiggingState {
|
||||
pub block: block::Block,
|
||||
pub position: shared::Position,
|
||||
pub face: shared::Direction,
|
||||
pub start: std::time::Instant,
|
||||
pub finished: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Digging {
|
||||
pub last: Option<DiggingState>,
|
||||
pub current: Option<DiggingState>,
|
||||
pub packets: std::collections::VecDeque<packet::play::serverbound::PlayerDigging>,
|
||||
}
|
||||
|
||||
impl Digging {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MouseButtons {
|
||||
pub left: bool,
|
||||
pub right: bool,
|
||||
}
|
||||
|
||||
impl MouseButtons {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use super::{
|
||||
Bounds, GameInfo, Gravity, Light, Position, Rotation, TargetPosition, TargetRotation, Velocity,
|
||||
Bounds, GameInfo, Gravity, Light, Position, Rotation, TargetPosition, TargetRotation, Velocity, MouseButtons, Digging
|
||||
};
|
||||
use crate::ecs;
|
||||
use crate::format;
|
||||
|
@ -43,6 +43,8 @@ pub fn create_local(m: &mut ecs::Manager) -> ecs::Entity {
|
|||
);
|
||||
m.add_component_direct(entity, PlayerModel::new("", false, false, true));
|
||||
m.add_component_direct(entity, Light::new());
|
||||
m.add_component_direct(entity, Digging::new());
|
||||
m.add_component_direct(entity, MouseButtons::new());
|
||||
entity
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use super::*;
|
||||
use crate::ecs;
|
||||
use crate::render;
|
||||
use crate::shared::Position as BPos;
|
||||
use crate::world;
|
||||
use cgmath::InnerSpace;
|
||||
use steven_protocol::protocol;
|
||||
|
||||
pub struct ApplyVelocity {
|
||||
filter: ecs::Filter,
|
||||
|
@ -285,3 +288,138 @@ impl ecs::System for LightEntity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ApplyDigging {
|
||||
filter: ecs::Filter,
|
||||
mouse_buttons: ecs::Key<MouseButtons>,
|
||||
digging: ecs::Key<Digging>,
|
||||
}
|
||||
|
||||
impl ApplyDigging {
|
||||
pub fn new(m: &mut ecs::Manager) -> Self {
|
||||
let mouse_buttons = m.get_key();
|
||||
let digging = m.get_key();
|
||||
Self {
|
||||
filter: ecs::Filter::new().with(mouse_buttons).with(digging),
|
||||
mouse_buttons,
|
||||
digging,
|
||||
}
|
||||
}
|
||||
|
||||
fn send_packet(&self,
|
||||
packets: &mut VecDeque<packet::play::serverbound::PlayerDigging>,
|
||||
target: &DiggingState,
|
||||
state: i32
|
||||
) {
|
||||
match state {
|
||||
0 => println!("Send start dig packet {:?}", target),
|
||||
1 => println!("Send cancel dig packet {:?}", target),
|
||||
2 => println!("Send finish dig packet {:?}", target),
|
||||
n => panic!("Invalid dig state {}", n),
|
||||
}
|
||||
|
||||
packets.push_back(packet::play::serverbound::PlayerDigging {
|
||||
status: protocol::VarInt(state),
|
||||
location: target.position,
|
||||
face: target.face.index() as u8,
|
||||
});
|
||||
}
|
||||
|
||||
fn next_state(&self,
|
||||
last: &Option<DiggingState>,
|
||||
mouse_buttons: &MouseButtons,
|
||||
target: Option<(shared::Position, block::Block, shared::Direction, Vector3<f64>)>
|
||||
) -> Option<DiggingState> {
|
||||
// Figure out the next state
|
||||
if !mouse_buttons.left {
|
||||
return None;
|
||||
}
|
||||
|
||||
match (last, target) {
|
||||
// Started digging
|
||||
(None, Some((position, block, face, _))) => Some(DiggingState {
|
||||
block, face, position,
|
||||
start: std::time::Instant::now(),
|
||||
finished: false,
|
||||
}),
|
||||
(Some(current), Some((position, block, face, _))) => {
|
||||
// Continue digging
|
||||
if position == current.position {
|
||||
return last.clone();
|
||||
}
|
||||
|
||||
// Start digging a different block.
|
||||
Some(DiggingState {
|
||||
block, face, position,
|
||||
start: std::time::Instant::now(),
|
||||
finished: false,
|
||||
})
|
||||
}
|
||||
// Not pointing at any target
|
||||
(_, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_finished(&self, state: &DiggingState) -> bool {
|
||||
let mining_time = state.block.get_mining_time(&None);
|
||||
match mining_time {
|
||||
Some(mining_time) => {
|
||||
let finish_time = state.start + mining_time;
|
||||
finish_time > std::time::Instant::now()
|
||||
},
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ecs::System for ApplyDigging {
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
use crate::server::target::{trace_ray, test_block};
|
||||
use cgmath::EuclideanSpace;
|
||||
|
||||
let target = trace_ray(
|
||||
world,
|
||||
4.0,
|
||||
renderer.camera.pos.to_vec(),
|
||||
renderer.view_vector.cast().unwrap(),
|
||||
test_block,
|
||||
);
|
||||
|
||||
for e in m.find(&self.filter) {
|
||||
let mouse_buttons = m.get_component(e, self.mouse_buttons).unwrap();
|
||||
let digging = m.get_component_mut(e, self.digging).unwrap();
|
||||
let packets = &mut digging.packets;
|
||||
|
||||
// Update last and current state
|
||||
std::mem::swap(&mut digging.last, &mut digging.current);
|
||||
digging.current = self.next_state(&digging.last, mouse_buttons, target);
|
||||
|
||||
// Handle digging packets
|
||||
match (&digging.last, &mut digging.current) {
|
||||
// Start the new digging operation.
|
||||
(None, Some(current)) => self.send_packet(packets, current, 0),
|
||||
// Cancel the previous digging operation.
|
||||
(Some(last), None) if !last.finished => self.send_packet(packets, last, 1),
|
||||
// Move to digging a new block
|
||||
(Some(last), Some(current)) if last.position != current.position => {
|
||||
// Cancel the previous digging operation.
|
||||
if !current.finished {
|
||||
self.send_packet(packets, last, 1);
|
||||
}
|
||||
// Start the new digging operation.
|
||||
self.send_packet(packets, current, 0);
|
||||
},
|
||||
// Finish the new digging operation.
|
||||
(Some(_), Some(current)) if !self.is_finished(current) && !current.finished => {
|
||||
self.send_packet(packets, current, 2);
|
||||
current.finished = true;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
src/main.rs
16
src/main.rs
|
@ -739,9 +739,25 @@ fn handle_window_event<T>(
|
|||
height,
|
||||
);
|
||||
}
|
||||
|
||||
if game.focused {
|
||||
game.server.on_left_mouse_button(false);
|
||||
}
|
||||
}
|
||||
(ElementState::Pressed, MouseButton::Left) => {
|
||||
if game.focused {
|
||||
game.server.on_left_mouse_button(true);
|
||||
}
|
||||
}
|
||||
(ElementState::Released, MouseButton::Right) => {
|
||||
if game.focused {
|
||||
game.server.on_right_mouse_button(false);
|
||||
game.server.on_right_click(&mut game.renderer);
|
||||
}
|
||||
}
|
||||
(ElementState::Pressed, MouseButton::Right) => {
|
||||
if game.focused {
|
||||
game.server.on_right_mouse_button(true);
|
||||
game.server.on_right_click(&mut game.renderer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ pub struct Server {
|
|||
// Entity accessors
|
||||
game_info: ecs::Key<entity::GameInfo>,
|
||||
player_movement: ecs::Key<entity::player::PlayerMovement>,
|
||||
mouse_buttons: ecs::Key<entity::MouseButtons>,
|
||||
digging: ecs::Key<entity::Digging>,
|
||||
gravity: ecs::Key<entity::Gravity>,
|
||||
position: ecs::Key<entity::Position>,
|
||||
target_position: ecs::Key<entity::TargetPosition>,
|
||||
|
@ -477,6 +479,8 @@ impl Server {
|
|||
// Entity accessors
|
||||
game_info,
|
||||
player_movement: entities.get_key(),
|
||||
mouse_buttons: entities.get_key(),
|
||||
digging: entities.get_key(),
|
||||
gravity: entities.get_key(),
|
||||
position: entities.get_key(),
|
||||
target_position: entities.get_key(),
|
||||
|
@ -778,6 +782,12 @@ impl Server {
|
|||
};
|
||||
self.write_packet(packet);
|
||||
}
|
||||
|
||||
let digging = self.entities.get_component_mut(player, self.digging).unwrap();
|
||||
let packets = &mut digging.packets;
|
||||
while let Some(packet) = packets.pop_front() {
|
||||
self.write_packet(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,6 +802,28 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn on_left_mouse_button(&mut self, pressed: bool) {
|
||||
if let Some(player) = self.player {
|
||||
if let Some(mouse_buttons) = self
|
||||
.entities
|
||||
.get_component_mut(player, self.mouse_buttons)
|
||||
{
|
||||
mouse_buttons.left = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_right_mouse_button(&mut self, pressed: bool) {
|
||||
if let Some(player) = self.player {
|
||||
if let Some(mouse_buttons) = self
|
||||
.entities
|
||||
.get_component_mut(player, self.mouse_buttons)
|
||||
{
|
||||
mouse_buttons.right = pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_right_click(&mut self, renderer: &mut render::Renderer) {
|
||||
use crate::shared::Direction;
|
||||
if self.player.is_some() {
|
||||
|
|
Loading…
Reference in New Issue