Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle arrow shooting (#101) #121

Merged
merged 11 commits into from
Sep 9, 2019
3 changes: 3 additions & 0 deletions codegen/src/entity_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ enum EntryType {
String,
Slot,
Boolean,
OptUuid,
}

impl Parse for EntryType {
Expand All @@ -134,6 +135,7 @@ impl EntryType {
EntryType::String => "String",
EntryType::Slot => "Slot",
EntryType::Boolean => "bool",
EntryType::OptUuid => "OptUuid",
}
}

Expand All @@ -145,6 +147,7 @@ impl EntryType {
"String" => EntryType::String,
"bool" => EntryType::Boolean,
"Slot" => EntryType::Slot,
"OptUuid" => EntryType::OptUuid,
_ => panic!("Invalid entry type {}", ty),
}
}
Expand Down
10 changes: 9 additions & 1 deletion core/src/entitymeta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::Slot;
use hashbrown::HashMap;
use uuid::Uuid;

type OptUuid = Option<Uuid>;

#[derive(Clone, Debug, PartialEq)]
pub enum MetaEntry {
Byte(i8),
Expand All @@ -23,7 +25,7 @@ pub enum MetaEntry {
Position(BlockPosition),
OptPosition(Option<BlockPosition>),
Direction(Direction),
OptUuid(Option<Uuid>),
OptUuid(OptUuid),
OptBlockId(Option<i32>),
Nbt, // TODO
Particle, // TODO
Expand Down Expand Up @@ -92,6 +94,12 @@ impl IntoMetaEntry for f32 {
}
}

impl IntoMetaEntry for OptUuid {
fn into_meta_entry(&self) -> MetaEntry {
MetaEntry::OptUuid(*self)
}
}

#[derive(Clone)]
pub struct EntityMetadata {
values: HashMap<u8, MetaEntry>,
Expand Down
6 changes: 3 additions & 3 deletions core/src/network/packet/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl Packet for PlayerDigging {
2 => PlayerDiggingStatus::FinishedDigging,
3 => PlayerDiggingStatus::DropItemStack,
4 => PlayerDiggingStatus::DropItem,
5 => PlayerDiggingStatus::ShootArrow,
5 => PlayerDiggingStatus::ConsumeItem,
6 => PlayerDiggingStatus::SwapItemInHand,
_ => return Err(()),
}
Expand Down Expand Up @@ -472,7 +472,7 @@ pub enum PlayerDiggingStatus {
FinishedDigging = 2,
DropItemStack = 3,
DropItem = 4,
ShootArrow = 5,
ConsumeItem = 5,
SwapItemInHand = 6,
}

Expand Down Expand Up @@ -788,7 +788,7 @@ pub struct Pong {

// PLAY
#[allow(clippy::too_many_arguments)]
#[derive(Default, AsAny, new, Packet, Clone)]
#[derive(Default, AsAny, new, Packet, Clone, Debug)]
pub struct SpawnObject {
pub entity_id: VarInt,
pub object_uuid: Uuid,
Expand Down
65 changes: 65 additions & 0 deletions server/src/entity/arrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use shrev::EventChannel;
use specs::{
Component, Entity, Read, ReadStorage, ReaderId, System, SystemData, VecStorage, World,
};

use feather_core::{Item, Position};

use crate::entity::NamedComponent;
use crate::player::PLAYER_EYE_HEIGHT;
use crate::util::Util;

/// Component for arrow entities.
#[derive(Default)]
pub struct ArrowComponent;

impl Component for ArrowComponent {
type Storage = VecStorage<Self>;
aramperes marked this conversation as resolved.
Show resolved Hide resolved
}

/// Event triggered when arrow is shot.
#[derive(Debug, Clone)]
pub struct ShootArrowEvent {
pub arrow_type: Item,
pub shooter: Option<Entity>,
pub position: Position,
pub critical: bool,
}

#[derive(Default)]
pub struct ShootArrowSystem {
reader: Option<ReaderId<ShootArrowEvent>>,
}

impl<'a> System<'a> for ShootArrowSystem {
type SystemData = (
Read<'a, Util>,
Read<'a, EventChannel<ShootArrowEvent>>,
ReadStorage<'a, NamedComponent>,
);

fn run(&mut self, data: Self::SystemData) {
let (util, shoot_arrow_events, nameds) = data;

for event in shoot_arrow_events.read(self.reader.as_mut().unwrap()) {
let mut pos = event.position + glm::vec3(0.0, PLAYER_EYE_HEIGHT, 0.0);
pos.on_ground = false;

// TODO: Scale velocity based on power
let velocity = pos.direction();

let shooter = match event.shooter {
Some(e) => Some(nameds.get(e).unwrap().uuid),
None => None,
};

util.spawn_arrow(pos, velocity, event.critical, shooter);
}
}

fn setup(&mut self, world: &mut World) {
Self::SystemData::setup(world);

self.reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader());
}
}
18 changes: 18 additions & 0 deletions server/src/entity/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,24 @@ fn packet_to_spawn_entity(

Box::new(packet)
}
EntityType::Arrow => {
let packet = SpawnObject {
entity_id: entity.id() as i32,
object_uuid: Uuid::new_v4(),
ty: 60,
x: position.current.x,
y: position.current.y,
z: position.current.z,
pitch: degrees_to_stops(position.current.pitch),
yaw: degrees_to_stops(position.current.yaw),
data: 1, // TODO: Shooter entity ID
velocity_x,
velocity_y,
velocity_z,
};

Box::new(packet)
}
_ => unimplemented!(),
}
}
Expand Down
18 changes: 18 additions & 0 deletions server/src/entity/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use specs::{
BitSet, Component, Entities, FlaggedStorage, Join, Read, ReaderId, System, VecStorage,
WriteStorage,
};
use uuid::Uuid;

type OptUuid = Option<Uuid>;

bitflags! {
pub struct EntityBitMask: u8 {
Expand All @@ -23,6 +26,14 @@ bitflags! {
}
}

bitflags! {
#[derive(Default)]
pub struct ArrowBitMask: u8 {
const CRITICAL = 0x01;
const NO_CLIP = 0x02;
}
}

entity_metadata! {
Metadata,
Entity {
Expand All @@ -47,6 +58,13 @@ entity_metadata! {
displayed_skin_parts: u8() = 13,
main_hand: u8() = 14,
},
Arrow: Entity {
arrow_bit_mask: u8() = 6,
shooter: OptUuid() = 7,
},
TippedArrow: Arrow {
color: VarInt() = 8,
},
}

impl Component for Metadata {
Expand Down
6 changes: 5 additions & 1 deletion server/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! and `PlayerComponent`. In the future, will also
//! provide entity-specific components and systems.

mod arrow;
mod broadcast;
mod chunk;
mod component;
Expand All @@ -14,8 +15,9 @@ mod types;
use crate::systems::{
CHUNK_CROSS, CHUNK_ENTITIES_UPDATE, ENTITY_DESTROY, ENTITY_DESTROY_BROADCAST,
ENTITY_METADATA_BROADCAST, ENTITY_MOVE_BROADCAST, ENTITY_SEND, ENTITY_SPAWN_BROADCAST,
ENTITY_VELOCITY_BROADCAST, ITEM_COLLECT, ITEM_MERGE, ITEM_SPAWN, JOIN_BROADCAST,
ENTITY_VELOCITY_BROADCAST, ITEM_COLLECT, ITEM_MERGE, ITEM_SPAWN, JOIN_BROADCAST, SHOOT_ARROW,
};
pub use arrow::{ArrowComponent, ShootArrowEvent};
pub use broadcast::EntitySendSystem;
pub use broadcast::EntitySender;
pub use broadcast::EntitySpawnEvent;
Expand All @@ -28,6 +30,7 @@ pub use metadata::{EntityBitMask, Metadata};
pub use movement::broadcast_entity_movement;
pub use types::EntityType;

use crate::entity::arrow::ShootArrowSystem;
use crate::entity::destroy::EntityDestroyBroadcastSystem;
use crate::entity::item::ItemCollectSystem;
use crate::entity::metadata::MetadataBroadcastSystem;
Expand Down Expand Up @@ -56,6 +59,7 @@ pub fn init_handlers(dispatcher: &mut DispatcherBuilder) {
ENTITY_METADATA_BROADCAST,
&[],
);
dispatcher.add(ShootArrowSystem::default(), SHOOT_ARROW, &[]);
}

pub fn init_broadcast(dispatcher: &mut DispatcherBuilder) {
Expand Down
6 changes: 6 additions & 0 deletions server/src/entity/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub enum EntityType {
Item,
ExperienceOrb,
Thunderbolt,
Arrow,
TippedArrow,
#[cfg(test)]
Test,
// TODO more...
Expand All @@ -31,6 +33,10 @@ impl EntityType {
self == EntityType::Item
}

pub fn is_arrow(self) -> bool {
self == EntityType::Arrow || self == EntityType::TippedArrow
}

pub fn is_other(self) -> bool {
self == EntityType::ExperienceOrb || self == EntityType::Thunderbolt
}
Expand Down
Loading