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

feat: packet handling functions #771

Merged
merged 26 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a3b9e38
feat: packet handler registry
andrewgazelka Dec 19, 2024
9e1bd3a
stuck
andrewgazelka Dec 19, 2024
88bd398
Use unsafe transmutes to fix HandlerRegistry
james-j-obrien Dec 19, 2024
a119418
Free leaked boxes
james-j-obrien Dec 19, 2024
f7f8b01
Clean-up drop handling
james-j-obrien Dec 19, 2024
38f59bb
Fix typo
james-j-obrien Dec 19, 2024
3ea1fc2
Fix string literal
james-j-obrien Dec 19, 2024
59a7258
Fix more typos
james-j-obrien Dec 19, 2024
5d8f3e4
Move process packet logic into deserializer
james-j-obrien Dec 19, 2024
8bf6f81
Remove compiler error reports
james-j-obrien Dec 19, 2024
227c115
change a lil
andrewgazelka Dec 20, 2024
f362e11
add lifetime utils
TestingPlant Dec 29, 2024
6e4a20d
get registry working
TestingPlant Dec 29, 2024
1fab615
convert code to use RegistryHandler
TestingPlant Dec 31, 2024
fe00a24
reimplement RuntimeLifetime
TestingPlant Jan 1, 2025
b3cd7f5
set up LifetimeTracker
TestingPlant Jan 8, 2025
56ef103
re-add events
TestingPlant Jan 8, 2025
bf96ecc
remove GlobalEventHandlers
TestingPlant Jan 9, 2025
78fd0a3
remove ReducedLifetime
TestingPlant Jan 9, 2025
8a46ace
prohibit lifetimes stored in events
TestingPlant Jan 9, 2025
26b925c
Merge remote-tracking branch 'origin/main' into unsafe-packet-handling
TestingPlant Jan 11, 2025
211f4a0
fix: make packet_switch unsafe
TestingPlant Jan 11, 2025
e21b11a
fix: seal LifetimeHandle::references
TestingPlant Jan 11, 2025
6abeceb
fix: use Relaxed ordering for reference count
TestingPlant Jan 11, 2025
f4dd1cf
docs: clean up comments
TestingPlant Jan 12, 2025
5eb73f2
docs: fix link to PacketSwitchQuery::compose
TestingPlant Jan 12, 2025
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
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions crates/hyperion/src/simulation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ pub mod handlers;
pub mod metadata;
pub mod skin;
pub mod util;
pub mod packet;











#[derive(Component, Default, Debug, Deref, DerefMut)]
pub struct StreamLookup {
Expand Down
103 changes: 103 additions & 0 deletions crates/hyperion/src/simulation/packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use std::{collections::HashMap, ptr::NonNull};

use anyhow::Result;
use rustc_hash::FxBuildHasher;
use valence_protocol::{Decode, Packet, packets::play::ChatMessageC2s};

// We'll store the deserialization function separately from handlers
type DeserializerFn = Box<dyn Fn(&HandlerRegistry, &[u8]) -> Result<()>>;

type PacketHandler = Box<dyn Fn(NonNull<u8>) -> Result<()>>;

pub struct HandlerRegistry {
// Store deserializer and multiple handlers separately
deserializers: HashMap<i32, DeserializerFn, FxBuildHasher>,
handlers: HashMap<i32, Vec<PacketHandler>, FxBuildHasher>,
}

impl HandlerRegistry {
#[must_use]
pub fn new() -> Self {
Self {
deserializers: HashMap::default(),
handlers: HashMap::default(),
}
}

// Register a packet type's deserializer
pub fn register_packet<'p, P>(&mut self)
where
P: Packet + Send + Sync + Decode<'p>,
{
let deserializer: DeserializerFn =
Box::new(|registry: &Self, bytes: &[u8]| -> Result<()> {
// transmute to bypass lifetime issue with Decode
// packet is dropped at end of scope and references in handlers are locked to the scope of the handler
let mut bytes = unsafe { std::mem::transmute(bytes) };
let mut packet = P::decode(&mut bytes)?;
// packet is always non-null, swap to NonNull::from_mut after stabilization
let ptr = unsafe { NonNull::new_unchecked(&mut packet).cast::<u8>() };
TestingPlant marked this conversation as resolved.
Show resolved Hide resolved

// Get all handlers for this packet type
let handlers = registry.handlers.get(&P::ID).ok_or_else(|| {
anyhow::anyhow!("No handlers registered for packet ID: {}", P::ID)
})?;

// Call all handlers with the deserialized packet
for handler in handlers {
handler(ptr)?;
}

Ok(())
});

self.deserializers.insert(P::ID, deserializer);
// Initialize the handlers vector if it doesn't exist
self.handlers.entry(P::ID).or_insert_with(Vec::new);
}

// Add a handler for a packet type
pub fn add_handler<'p, P>(
&mut self,
handler: impl for<'a> Fn(&'a P) -> Result<()> + Send + Sync + 'static,
) where
P: Packet + Send + Sync + Decode<'p>,
{
// Ensure the packet type is registered
if !self.deserializers.contains_key(&P::ID) {
self.register_packet::<P>();
}

// Wrap the typed handler to work with Any
let boxed_handler: PacketHandler = Box::new(move |any_packet| {
let packet = unsafe { any_packet.cast::<P>().as_ref() };
handler(packet)
});

// Add the handler to the vector
self.handlers.entry(P::ID).or_default().push(boxed_handler);
}

// Process a packet, calling all registered handlers
pub fn process_packet(&self, id: i32, bytes: &[u8]) -> Result<()> {
// Get the deserializer
let deserializer = self
.deserializers
.get(&id)
.ok_or_else(|| anyhow::anyhow!("No deserializer registered for packet ID: {}", id))?;

deserializer(self, bytes)
}
}

fn main() -> Result<()> {
let mut registry = HandlerRegistry::new();

// Register multiple handlers for ChatPacket
registry.add_handler::<ChatMessageC2s<'_>>(|packet| {
println!("Handler 1: {:?}", packet);
Ok(())
});

Ok(())
}
Loading