Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
be4c626
Initial health/hunger system.
kirawi Mar 7, 2021
be2848b
Initial health/hunger system.
kirawi Mar 7, 2021
eb73c9b
Merge branch 'main' of github.com:feather-rs/feather
kirawi Mar 8, 2021
83933c6
Starting to work on generalizing to all mobs.
kirawi Mar 8, 2021
7cdd8ec
fix fmt
kirawi Mar 8, 2021
7e83bc3
regeneration method implemented, working on hunger next.
kirawi Mar 8, 2021
ae32d0c
fix fmt
kirawi Mar 8, 2021
a60be30
Initial hunger methods.
kirawi Mar 8, 2021
b097712
hunger systems
kirawi Mar 9, 2021
3f35b71
quick change
kirawi Mar 9, 2021
56dfc58
wip
kirawi Mar 10, 2021
c239772
fmt
kirawi Mar 10, 2021
c5d4b78
clippy
kirawi Mar 10, 2021
95d918e
wip
kirawi Mar 10, 2021
ab4a407
wip
kirawi Mar 11, 2021
9966496
Merge remote-tracking branch 'upstream/main'
kirawi Mar 29, 2021
5b3bf60
Merge branch 'main' of github.com:feather-rs/feather
kirawi Apr 1, 2021
86af7a3
wip
kirawi Apr 2, 2021
0008646
moved core event to quill
kirawi Apr 3, 2021
72be25e
wip
kirawi Apr 3, 2021
4ee4cee
wip
kirawi Apr 3, 2021
abfc718
wip
kirawi Apr 5, 2021
6a5a4a8
wip
kirawi Apr 6, 2021
96beeef
wip
kirawi Apr 6, 2021
30c3ae5
wip
kirawi Apr 7, 2021
989060a
wip
kirawi Apr 7, 2021
a108201
wip
kirawi Apr 7, 2021
e94891a
sos
kirawi Apr 7, 2021
ec59159
wip
kirawi Apr 8, 2021
992cb7a
wip
kirawi Apr 9, 2021
3a0fc32
Merge branch 'generic' of github.com:kirawi/feather
kirawi Apr 9, 2021
4561963
wip
kirawi Apr 9, 2021
e1bd602
wip
kirawi Apr 10, 2021
ce77fac
wip
kirawi Apr 10, 2021
6330b3f
error handling
kirawi Apr 10, 2021
763ad09
Revert "wip"
kirawi Apr 10, 2021
68be14c
Merge branch 'generic' of github.com:kirawi/feather into generic
kirawi Apr 10, 2021
d24a42d
fmt
kirawi Apr 10, 2021
3f2e2bf
Merge branch 'generic' of github.com:kirawi/feather
kirawi Apr 10, 2021
10740b3
wip
kirawi Apr 11, 2021
bb4baa5
wip
kirawi Apr 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion feather/common/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod plugin_message;
pub use block_change::BlockChangeEvent;
pub use plugin_message::PluginMessageEvent;

/// Triggered when a player joins the `Game`.
/// Triggered when a player joins the game.
#[derive(Debug)]
pub struct PlayerJoinEvent;

Expand Down
1 change: 1 addition & 0 deletions feather/protocol/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ where

pub type VarIntPrefixedVec<'a, T> = LengthPrefixedVec<'a, VarInt, T>;
pub type ShortPrefixedVec<'a, T> = LengthPrefixedVec<'a, u16, T>;
pub type IntPrefixedVec<'a, T> = LengthPrefixedVec<'a, i32, T>;

/// A vector of bytes which consumes all remaining bytes in this packet.
/// This is used by the plugin messaging packets, for one.
Expand Down
10 changes: 9 additions & 1 deletion feather/protocol/src/packets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ macro_rules! user_type {
(VarIntPrefixedVec <$inner:ident>) => {
Vec<$inner>
};
(IntPrefixedVec <$inner:ident>) => {
Vec<$inner>
};
(ShortPrefixedVec <$inner:ident>) => {
Vec<$inner>
};
Expand All @@ -26,6 +29,9 @@ macro_rules! user_type_convert_to_writeable {
(VarIntPrefixedVec <$inner:ident>, $e:expr) => {
VarIntPrefixedVec::from($e.as_slice())
};
(IntPrefixedVec <$inner:ident>, $e:expr) => {
IntPrefixedVec::from($e.as_slice())
};
(ShortPrefixedVec <$inner:ident>, $e:expr) => {
ShortPrefixedVec::from($e.as_slice())
};
Expand Down Expand Up @@ -284,7 +290,9 @@ pub trait VariantOf<Enum> {
Self: Sized;
}

use crate::io::{Angle, LengthInferredVecU8, Nbt, ShortPrefixedVec, VarInt, VarIntPrefixedVec};
use crate::io::{
Angle, IntPrefixedVec, LengthInferredVecU8, Nbt, ShortPrefixedVec, VarInt, VarIntPrefixedVec,
};
use crate::Slot;
use base::{BlockId, BlockPosition};
use nbt::Blob;
Expand Down
72 changes: 71 additions & 1 deletion feather/protocol/src/packets/server/play.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,9 @@ packets! {
}

EntityProperties {
__todo__ LengthInferredVecU8;
entity_id VarInt;
properties IntPrefixedVec<EntityProperty>;

}

EntityEffect {
Expand All @@ -1183,6 +1185,74 @@ packets! {
}
}

def_enum! {
OperationKind (u8) {
0 = AddSubtract,
1 = AddSubtractPercent,
2 = MultiplyPercent
}
}

def_enum! {
EntityAttributeKind (String) {
"generic.max_health" = MaxHealth,
"generic.follow_range" = FollowRange,
"generic.knockback_resistance" = KnockbackResistance,
"generic.movement_speed" = MovementSpeed,
"generic.attack_damage" = AttackDamage,
"generic.attack_speed" = AttackSpeed,
"generic.attack_knockback" = AttackKnockback,
"generic.flying_speed" = FlyingSpeed,
"generic.armor" = Armor,
"generic.armor_toughness" = ArmorToughness,
"generic.luck" = Luck,
"horse.jump_strength" = HorseJumpStrength,
"zombie.spawn_reinforcements" = ZombieSpawnReinforcements,
}
}

impl EntityAttributeKind {
pub fn max_value(&self) -> f32 {
match &self {
EntityAttributeKind::MaxHealth => 1024.0,
EntityAttributeKind::FollowRange => 2048.0,
EntityAttributeKind::KnockbackResistance => 1.0,
EntityAttributeKind::MovementSpeed => 1024.0,
EntityAttributeKind::AttackDamage => 2048.0,
EntityAttributeKind::AttackSpeed => 1024.0,
EntityAttributeKind::AttackKnockback => 5.0,
EntityAttributeKind::FlyingSpeed => 1024.0,
EntityAttributeKind::Armor => 30.0,
EntityAttributeKind::ArmorToughness => 20.0,
EntityAttributeKind::Luck => 1024.0,
EntityAttributeKind::HorseJumpStrength => 2.0,
EntityAttributeKind::ZombieSpawnReinforcements => 1.0,
}
}

pub fn min_value(&self) -> f32 {
if let EntityAttributeKind::Luck = &self {
Comment thread
kirawi marked this conversation as resolved.
return -1024.0;
}

0.0
}
}

packets! {
AttributeModifier {
uuid Uuid;
amount f64;
operation OperationKind;
}

EntityProperty {
attribute EntityAttributeKind;
value f64;
modifiers VarIntPrefixedVec<AttributeModifier>
}
}

def_enum! {
Recipe (String) {
"minecraft:crafting_shapeless" = Shapeless {
Expand Down
32 changes: 30 additions & 2 deletions feather/server/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use common::{
Window,
};
use flume::{Receiver, Sender};
use packets::server::{Particle, SetSlot, SpawnLivingEntity, UpdateLight, WindowConfirmation};
use packets::server::{
Particle, Respawn, SetSlot, SpawnLivingEntity, UpdateHealth, UpdateLight, WindowConfirmation,
};
use parking_lot::RwLock;
use protocol::{
packets::{
Expand All @@ -29,7 +31,7 @@ use protocol::{
},
ClientPlayPacket, Nbt, ProtocolVersion, ServerPlayPacket, Writeable,
};
use quill_common::components::OnGround;
use quill_common::components::{Health, Hunger, OnGround};
use uuid::Uuid;
use vec_arena::Arena;

Expand Down Expand Up @@ -512,6 +514,32 @@ impl Client {
self.set_slot(-1, item);
}

pub fn update_status(&self, player_health: &Health, player_hunger: &Hunger) {
self.send_packet(UpdateHealth {
health: player_health.health as f32,
food: player_hunger.food as i32,
food_saturation: player_hunger.saturation as f32,
});
}

pub fn send_respawn(&self, gamemode: Gamemode, copy_metadata: bool) {
let dimension = nbt::Blob::from_reader(&mut Cursor::new(include_bytes!(
"../../../assets/dimension.nbt"
)))
.expect("dimension asset is malformed");

self.send_packet(Respawn {
dimension: Nbt(dimension),
world_name: "world".to_owned(),
hashed_seed: 0,
gamemode,
previous_gamemode: gamemode,
is_debug: false,
is_flat: false,
copy_metadata,
});
}

pub fn send_player_model_flags(&self, netowrk_id: NetworkId, model_flags: u8) {
let mut entity_metadata = EntityMetadata::new();
entity_metadata.set(16, model_flags);
Expand Down
6 changes: 5 additions & 1 deletion feather/server/src/packet_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use quill_common::components::Name;

use crate::{NetworkId, Server};

mod health;
mod interaction;
pub mod inventory;
mod movement;
Expand Down Expand Up @@ -64,12 +65,15 @@ pub fn handle_packet(
handle_interact_entity(game, server, packet, player_id)
}

ClientPlayPacket::ClientStatus(packet) => {
health::handle_client_status(game, server, player_id, packet)
}

ClientPlayPacket::ClientSettings(packet) => handle_client_settings(server, player, packet),

ClientPlayPacket::TeleportConfirm(_)
| ClientPlayPacket::QueryBlockNbt(_)
| ClientPlayPacket::SetDifficulty(_)
| ClientPlayPacket::ClientStatus(_)
| ClientPlayPacket::TabComplete(_)
| ClientPlayPacket::WindowConfirmation(_)
| ClientPlayPacket::ClickWindowButton(_)
Expand Down
40 changes: 40 additions & 0 deletions feather/server/src/packet_handlers/health.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use base::Gamemode;
use common::Game;
use ecs::{Entity, SysResult};
use protocol::packets::client::ClientStatus;
use quill_common::events::entity_special_event_kind;

use crate::{ClientId, Server};

pub fn handle_client_status(
game: &mut Game,
server: &mut Server,
player: Entity,
packet: ClientStatus,
) -> SysResult {
match packet {
ClientStatus::PerformRespawn => {
let mut send_event = false;
{
let client_id = game.ecs.get::<ClientId>(player)?;
if let Some(client) = server.clients.get(*client_id) {
let gamemode = game.ecs.get::<Gamemode>(player)?;
client.send_respawn(*gamemode, false);

send_event = true;
}
}

if send_event {
game.ecs.insert_entity_event(
player,
entity_special_event_kind::EntityResurrectionEvent,
)?;
}
}

ClientStatus::RequestStats => {}
}

Ok(())
}
4 changes: 4 additions & 0 deletions feather/server/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
mod block;
mod chat;
mod entity;
mod health;
mod hunger;
mod particle;
mod player_join;
mod player_leave;
Expand Down Expand Up @@ -35,6 +37,8 @@ pub fn register(server: Server, game: &mut Game, systems: &mut SystemExecutor<Ga
entity::register(game, systems);
chat::register(game, systems);
particle::register(systems);
health::register(game, systems);
hunger::register(game, systems);
plugin_message::register(systems);

systems.group::<Server>().add_system(tick_clients);
Expand Down
109 changes: 109 additions & 0 deletions feather/server/src/systems/health.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use crate::{ClientId, Game, Server};
use ecs::{SysResult, SystemExecutor};
use quill_common::{
components::{Health, Hunger},
events::{
entity_damage_event_kind, entity_regen_event_kind, entity_special_event_kind,
EntityHealthEvent,
},
};

pub fn register(_game: &mut Game, systems: &mut SystemExecutor<Game>) {
systems
.group::<Server>()
.add_system(entity_resurrection)
.add_system(entity_suicide)
.add_system(player_eating_regen)
.add_system(player_hunger)
.add_system(health_events_handler);
}

// TODO: Implement for entities besides players.
fn health_events_handler(game: &mut Game, server: &mut Server) -> SysResult {
for (entity, (event, health)) in game.ecs.query::<(&EntityHealthEvent, &mut Health)>().iter() {
match event {
EntityHealthEvent::Regen(amount) => health.heal(*amount),
EntityHealthEvent::Damage(amount) => health.harm(*amount),
}

if let Ok(client_id) = game.ecs.get::<ClientId>(entity) {
if let Some(client) = server.clients.get(*client_id) {
let hunger = game.ecs.entity(entity)?.get::<Hunger>()?;
client.update_status(&health, &hunger);
}
}
}

Ok(())
}

fn entity_resurrection(game: &mut Game, _server: &mut Server) -> SysResult {
let mut events = Vec::new();

for (entity, (_, health)) in game
.ecs
.query::<(
&entity_special_event_kind::EntityResurrectionEvent,
&mut Health,
)>()
.iter()
{
events.push((entity, EntityHealthEvent::Regen(health.max_health)));
}

for (entity, event) in events {
game.ecs.insert_entity_event(entity, event)?;
}

Ok(())
}

fn entity_suicide(game: &mut Game, _server: &mut Server) -> SysResult {
let mut events = Vec::new();

for (entity, (_, health)) in game
.ecs
.query::<(&entity_special_event_kind::EntitySuicideEvent, &mut Health)>()
.iter()
{
events.push((entity, EntityHealthEvent::Damage(health.max_health)));
}

for (entity, event) in events {
game.ecs.insert_entity_event(entity, event)?;
}

Ok(())
}

fn player_eating_regen(game: &mut Game, _server: &mut Server) -> SysResult {
let mut events = Vec::new();

for (entity, _) in game.ecs.query::<&entity_regen_event_kind::Eating>().iter() {
events.push((entity, EntityHealthEvent::Regen(1)));
}

for (entity, event) in events {
game.ecs.insert_entity_event(entity, event)?;
}

Ok(())
}

fn player_hunger(game: &mut Game, _server: &mut Server) -> SysResult {
let mut events = Vec::new();

for (entity, _) in game
.ecs
.query::<&entity_damage_event_kind::Starvation>()
.iter()
{
events.push((entity, EntityHealthEvent::Damage(1)));
}

for (entity, event) in events {
game.ecs.insert_entity_event(entity, event)?;
}

Ok(())
}
Loading