Skip to content

Commit 2d60101

Browse files
authored
Merge pull request #147 from teoscura/feat/entityanimation
feat/entityanimation
2 parents f823b33 + 75a616e commit 2d60101

File tree

11 files changed

+193
-8
lines changed

11 files changed

+193
-8
lines changed

scripts/new_packet.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import os.path
2+
3+
incoming_template = """
4+
use crate::packets::IncomingPacket;
5+
use crate::NetResult;
6+
use ferrumc_macros::{packet, NetDecode};
7+
use ferrumc_state::ServerState;
8+
use std::sync::Arc;
9+
10+
#[derive(NetDecode)]
11+
#[packet(packet_id = ++id++, state = "play")]
12+
pub struct ++name++ {
13+
}
14+
15+
impl IncomingPacket for ++name++ {
16+
async fn handle(self, conn_id: usize, state: Arc<ServerState>) -> NetResult<()> {
17+
todo!()
18+
}
19+
}
20+
"""
21+
22+
outgoing_template = """
23+
use ferrumc_macros::{packet, NetEncode};\
24+
use std::io::Write;
25+
26+
#[derive(NetEncode)]
27+
#[packet(packet_id = ++id++)]
28+
pub struct ++name++ {}
29+
"""
30+
31+
32+
def to_snake_case(string) -> str:
33+
return string.lower().replace(" ", "_")
34+
35+
36+
def to_camel_case(string) -> str:
37+
return string.title().replace(" ", "")
38+
39+
40+
packet_type_input = input("Incoming or outgoing packet? (i/o): ")
41+
packet_type = ""
42+
if packet_type_input == "i":
43+
packet_type = "incoming"
44+
elif packet_type_input == "o":
45+
packet_type = "outgoing"
46+
else:
47+
print("Invalid input")
48+
exit()
49+
50+
packet_name = input("Packet name: ")
51+
packets_dir = os.path.join(os.path.join(os.path.dirname(__file__), ".."), "src/lib/net/src/packets")
52+
53+
packet_id = input("Packet ID (formatted like 0x01): ")
54+
packet_id = packet_id[:-2] + packet_id[-2:].upper()
55+
56+
with open(f"{packets_dir}/{packet_type}/{to_snake_case(packet_name)}.rs", "x") as f:
57+
if packet_type == "incoming":
58+
f.write(incoming_template.replace("++name++", to_camel_case(packet_name)).replace("++id++", packet_id))
59+
with open(f"{packets_dir}/incoming/mod.rs", "a") as modfile:
60+
modfile.write(f"\npub mod {to_snake_case(packet_name)};")
61+
else:
62+
f.write(outgoing_template.replace("++name++", to_camel_case(packet_name)).replace("++id++", packet_id))
63+
with open(f"{packets_dir}/outgoing/mod.rs", "a") as modfile:
64+
modfile.write(f"\npub mod {to_snake_case(packet_name)};")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use ferrumc_macros::event_handler;
2+
use ferrumc_net::errors::NetError;
3+
use ferrumc_net::packets::outgoing::entity_animation::EntityAnimationEvent;
4+
use ferrumc_net::utils::broadcast::{broadcast, BroadcastOptions};
5+
use ferrumc_state::GlobalState;
6+
7+
#[event_handler]
8+
async fn entity_animation(
9+
event: EntityAnimationEvent,
10+
state: GlobalState,
11+
) -> Result<EntityAnimationEvent, NetError> {
12+
//TODO change this global broadcast to a broadcast that affects only players in the view distance
13+
// of the player doing it, but as long as we still cant see other players, this will be fine.
14+
broadcast(
15+
&event.packet,
16+
&state,
17+
BroadcastOptions::default().except([event.entity]),
18+
)
19+
.await?;
20+
Ok(event)
21+
}

src/bin/src/packet_handlers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod animations;
12
mod handshake;
23
mod login_process;
34
mod tick_handler;

src/lib/net/crates/codec/src/decode/primitives.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl_for_primitives!(
3535
u32 | i32,
3636
u64 | i64,
3737
u128 | i128,
38+
usize | isize,
3839
f32,
3940
f64
4041
);

src/lib/net/crates/codec/src/encode/primitives.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ impl_for_primitives!(
4040
u32 | i32,
4141
u64 | i64,
4242
u128 | i128,
43+
usize | isize,
4344
f32,
4445
f64
4546
);

src/lib/net/src/packets/incoming/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ pub mod packet_skeleton;
1414
pub mod set_player_position;
1515
pub mod set_player_position_and_rotation;
1616
pub mod set_player_rotation;
17+
18+
pub mod swing_arm;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use crate::packets::outgoing::entity_animation::EntityAnimationEvent;
2+
use crate::packets::IncomingPacket;
3+
use crate::NetResult;
4+
use ferrumc_ecs::entities::Entity;
5+
use ferrumc_events::infrastructure::Event;
6+
use ferrumc_macros::{packet, NetDecode};
7+
use ferrumc_net_codec::net_types::var_int::VarInt;
8+
use ferrumc_state::ServerState;
9+
use std::sync::Arc;
10+
11+
#[derive(NetDecode)]
12+
#[packet(packet_id = 0x36, state = "play")]
13+
pub struct SwingArmPacket {
14+
hand: VarInt,
15+
}
16+
17+
impl IncomingPacket for SwingArmPacket {
18+
async fn handle(self, conn_id: Entity, state: Arc<ServerState>) -> NetResult<()> {
19+
let animation = {
20+
if self.hand == 0 {
21+
0
22+
} else {
23+
3
24+
}
25+
};
26+
let event = EntityAnimationEvent::new(conn_id, animation);
27+
EntityAnimationEvent::trigger(event, state).await?;
28+
Ok(())
29+
}
30+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use ferrumc_ecs::entities::Entity;
2+
use ferrumc_macros::{packet, Event, NetEncode};
3+
use std::io::Write;
4+
5+
#[derive(NetEncode)]
6+
#[packet(packet_id = 0x03)]
7+
pub struct EntityAnimationPacket {
8+
pub eid: Entity,
9+
pub animation: u8,
10+
}
11+
12+
#[derive(Event)]
13+
pub struct EntityAnimationEvent {
14+
pub entity: Entity,
15+
pub animation: u8,
16+
pub packet: EntityAnimationPacket,
17+
}
18+
19+
impl EntityAnimationPacket {
20+
pub fn new(eid: Entity, animation: u8) -> Self {
21+
Self { eid, animation }
22+
}
23+
}
24+
25+
impl EntityAnimationEvent {
26+
pub fn new(eid: Entity, animation: u8) -> Self {
27+
Self {
28+
entity: eid,
29+
animation,
30+
packet: EntityAnimationPacket::new(eid, animation),
31+
}
32+
}
33+
}

src/lib/net/src/packets/outgoing/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ pub mod set_render_distance;
1717
pub mod status_response;
1818
pub mod synchronize_player_position;
1919
pub mod update_time;
20+
21+
pub mod entity_animation;

src/lib/net/src/utils/broadcast.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use ferrumc_ecs::entities::Entity;
55
use ferrumc_net_codec::encode::{NetEncode, NetEncodeOpts};
66
use ferrumc_state::GlobalState;
77
use futures::StreamExt;
8+
use std::collections::HashSet;
89
use std::future::Future;
910
use std::pin::Pin;
1011
use tracing::debug;
@@ -16,14 +17,26 @@ type SyncCallbackFn = Box<dyn Fn(Entity, &GlobalState) + Send + Sync>;
1617

1718
#[derive(Default)]
1819
pub struct BroadcastOptions {
19-
pub only_entities: Option<Vec<Entity>>,
20+
pub only_entities: Option<HashSet<Entity>>,
21+
pub except_entities: Option<HashSet<Entity>>,
2022
pub async_callback: Option<AsyncCallbackFn>,
2123
pub sync_callback: Option<SyncCallbackFn>,
2224
}
2325

2426
impl BroadcastOptions {
25-
pub fn only(mut self, entities: Vec<Entity>) -> Self {
26-
self.only_entities = Some(entities);
27+
pub fn only<I>(mut self, entities: I) -> Self
28+
where
29+
I: IntoIterator<Item = Entity>,
30+
{
31+
self.only_entities = Some(entities.into_iter().collect());
32+
self
33+
}
34+
35+
pub fn except<I>(mut self, entities: I) -> Self
36+
where
37+
I: IntoIterator<Item = Entity>,
38+
{
39+
self.except_entities = Some(entities.into_iter().collect());
2740
self
2841
}
2942

@@ -50,19 +63,35 @@ impl BroadcastOptions {
5063
}
5164
}
5265

66+
fn get_all_entities(state: &GlobalState) -> HashSet<Entity> {
67+
state
68+
.universe
69+
.get_component_manager()
70+
.get_entities_with::<StreamWriter>()
71+
.into_iter()
72+
.collect()
73+
}
74+
5375
pub async fn broadcast(
5476
packet: &impl NetEncode,
5577
state: &GlobalState,
5678
opts: BroadcastOptions,
5779
) -> NetResult<()> {
58-
let entities = match opts.only_entities {
59-
None => state
60-
.universe
61-
.get_component_manager()
62-
.get_entities_with::<StreamWriter>(),
80+
let mut entities = match opts.only_entities {
81+
None => get_all_entities(state),
6382
Some(entities) => entities,
6483
};
6584

85+
// Remove excluded entities if any
86+
if let Some(except_entities) = opts.except_entities {
87+
entities.retain(|entity| !except_entities.contains(entity));
88+
}
89+
90+
// No entities to broadcast to
91+
if entities.is_empty() {
92+
return Ok(());
93+
}
94+
6695
// Pre-encode the packet to save resources.
6796
let packet = {
6897
let mut buffer = Vec::new();

0 commit comments

Comments
 (0)