use super::messages::{MessageFrame, SceneMessage};
use super::transport::{Transport, TransportConfig, TransportError};
use crate::components::{Name, OnGui, Renderable};
use crate::network::component_registry::ReceivableComponentRegistry;
use crate::scene::Scene;
use gloss_hecs::{CommandBuffer, EntityBuilder};
use log::{info, warn};
use std::sync::Arc;
#[derive(Clone)]
pub struct SceneReceiver {
transport: Option<Arc<dyn Transport>>,
last_sequence: u64,
config: TransportConfig,
registry: ReceivableComponentRegistry,
last_connect_attempt: Option<std::time::Instant>,
}
impl SceneReceiver {
pub fn new(config: TransportConfig) -> Self {
let mut registry = ReceivableComponentRegistry::new();
registry.register_default_components();
Self {
transport: None,
last_sequence: 0,
config,
registry,
last_connect_attempt: None,
}
}
pub fn registry(&self) -> &ReceivableComponentRegistry {
&self.registry
}
pub fn registry_mut(&mut self) -> &mut ReceivableComponentRegistry {
&mut self.registry
}
pub fn set_transport(&mut self, transport: Arc<dyn Transport>) {
self.transport = Some(transport);
}
pub fn connect_to_sender(&mut self) -> Result<(), TransportError> {
use super::transport::TcpClient;
if !self.should_attempt_reconnect() {
return Err(TransportError::NotConnected);
}
self.last_connect_attempt = Some(std::time::Instant::now());
let addr = format!("{}:{}", self.config.address, self.config.port);
let tcp_client = TcpClient::new(&addr)?;
tcp_client.connect()?;
self.set_transport(Arc::new(tcp_client));
log::info!("Successfully connected to sender at {addr}");
Ok(())
}
fn should_attempt_reconnect(&self) -> bool {
if !self.config.auto_reconnect {
return false;
}
if self.is_connected() {
return false;
}
match self.last_connect_attempt {
None => true, Some(last_attempt) => {
let reconnect_delay = std::time::Duration::from_millis(self.config.reconnect_delay_ms);
last_attempt.elapsed() >= reconnect_delay
}
}
}
pub fn is_enabled(&self) -> bool {
self.transport.is_some()
}
pub fn is_connected(&self) -> bool {
if let Some(ref transport) = self.transport {
transport.is_connected()
} else {
false
}
}
pub fn receive_pending_frames(&mut self) -> Result<Vec<crate::network::MessageFrame>, TransportError> {
if !self.is_enabled() {
println!("Receiver not enabled, transport is not set, skipping receive.");
return Ok(Vec::new());
}
let mut frames = Vec::new();
if let Some(ref transport) = self.transport {
loop {
match transport.receive(false) {
Ok(Some(frame)) => {
frames.push(frame);
if frames.len() >= 30 {
warn!("Filled the maximum buffer of 30 frames, returning to apply them");
break;
}
}
Ok(None) => {
break;
}
Err(TransportError::ConnectionClosed) => {
log::warn!("Connection lost, clearing transport for reconnection");
self.transport = None;
return Err(TransportError::ConnectionClosed);
}
Err(e) => {
return Err(e);
}
}
}
}
Ok(frames)
}
pub fn process_frame(&mut self, scene: &Scene, command_buffer: &mut CommandBuffer, frame: &MessageFrame) {
if frame.sequence > 0 && frame.sequence != self.last_sequence + 1 {
warn!("Sequence gap detected: expected {}, got {}", self.last_sequence + 1, frame.sequence);
}
self.last_sequence = frame.sequence;
self.process_message(scene, command_buffer, &frame.message);
}
fn process_message(&mut self, scene: &Scene, command_buffer: &mut CommandBuffer, message: &SceneMessage) {
match message {
SceneMessage::Batch(messages) => {
for msg in messages {
self.process_message(scene, command_buffer, msg);
}
}
SceneMessage::EntitySpawn {
entity_name,
is_renderable,
is_on_gui,
} => {
if entity_name == "floor" || entity_name == "gloss_camera" {
return;
}
if scene.get_entity_with_name(entity_name).is_some() {
warn!("Entity with name '{entity_name}' already exists, skipping spawn");
return;
}
let mut entity_builder = EntityBuilder::new();
let mut entity_builder = entity_builder.add(Name(entity_name.to_string()));
if *is_renderable {
entity_builder = entity_builder.add(Renderable);
}
if *is_on_gui {
entity_builder = entity_builder.add(OnGui);
}
command_buffer.spawn(entity_builder.build());
}
SceneMessage::ComponentInsert {
entity_name,
component_type,
data,
} => {
let ent = if entity_name == "entity_resource" {
Some(scene.get_entity_resource())
} else {
scene.get_entity_with_name(entity_name)
};
if let Some(entity) = ent {
if let Err(e) = self.registry.apply_component(command_buffer, entity, component_type, data) {
warn!("Failed to apply component {}: {}", component_type.0, e);
}
} else {
warn!("Entity with name '{entity_name}' not found for ComponentInsert");
}
}
SceneMessage::FrameBegin { frame_number } => {
info!("Received FrameBegin: {frame_number}");
}
SceneMessage::FrameEnd { frame_number } => {
info!("Received FrameEnd: {frame_number}");
}
SceneMessage::Ping { timestamp_ms } => {
info!("Received Ping: {timestamp_ms}");
}
SceneMessage::Pong { timestamp_ms } => {
info!("Received Pong: {timestamp_ms}");
}
}
}
pub fn close(&mut self) {
if let Some(ref transport) = self.transport {
transport.close();
}
}
}
impl Default for SceneReceiver {
fn default() -> Self {
Self::new(TransportConfig::default())
}
}