2025-05-09 19:49:40 -04:00
|
|
|
use std::{
|
|
|
|
net::SocketAddr,
|
|
|
|
sync::{
|
|
|
|
Arc,
|
|
|
|
atomic::{AtomicUsize, Ordering},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
use tokio::sync::mpsc::Sender;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
common::Position,
|
2025-05-11 10:12:02 -04:00
|
|
|
ipc::zone::{
|
2025-06-21 10:36:44 -04:00
|
|
|
ActionRequest, ActorControl, ActorControlSelf, ActorControlTarget, ClientTrigger,
|
|
|
|
CommonSpawn, NpcSpawn,
|
2025-05-11 10:12:02 -04:00
|
|
|
},
|
2025-05-09 19:49:40 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
use super::Actor;
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
|
|
|
pub struct ClientId(usize);
|
|
|
|
|
|
|
|
pub enum FromServer {
|
|
|
|
/// A chat message.
|
|
|
|
Message(String),
|
|
|
|
/// An actor has been spawned.
|
2025-06-18 20:28:03 -04:00
|
|
|
ActorSpawn(Actor, NpcSpawn),
|
2025-05-09 19:49:40 -04:00
|
|
|
/// An actor moved to a new position.
|
|
|
|
ActorMove(u32, Position, f32),
|
|
|
|
// An actor has despawned.
|
|
|
|
ActorDespawn(u32),
|
|
|
|
/// We need to update an actor
|
|
|
|
ActorControl(u32, ActorControl),
|
2025-05-11 10:12:02 -04:00
|
|
|
/// We need to update an actor's target
|
2025-05-09 19:49:40 -04:00
|
|
|
ActorControlTarget(u32, ActorControlTarget),
|
2025-05-11 10:12:02 -04:00
|
|
|
/// We need to update the player actor
|
|
|
|
ActorControlSelf(ActorControlSelf),
|
2025-06-21 10:36:44 -04:00
|
|
|
/// Action has completed and needs to be executed
|
|
|
|
ActionComplete(ActionRequest),
|
|
|
|
/// Action has been cancelled
|
|
|
|
ActionCancelled(),
|
2025-05-09 19:49:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct ClientHandle {
|
|
|
|
pub id: ClientId,
|
|
|
|
pub ip: SocketAddr,
|
|
|
|
pub channel: Sender<FromServer>,
|
|
|
|
pub actor_id: u32,
|
|
|
|
pub common: CommonSpawn,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ClientHandle {
|
|
|
|
/// Send a message to this client actor. Will emit an error if sending does
|
|
|
|
/// not succeed immediately, as this means that forwarding messages to the
|
|
|
|
/// tcp connection cannot keep up.
|
|
|
|
pub fn send(&mut self, msg: FromServer) -> Result<(), std::io::Error> {
|
|
|
|
if self.channel.try_send(msg).is_err() {
|
|
|
|
Err(std::io::Error::new(
|
|
|
|
std::io::ErrorKind::BrokenPipe,
|
|
|
|
"Can't keep up or dead",
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Kill the actor.
|
|
|
|
pub fn kill(self) {
|
|
|
|
// run the destructor
|
|
|
|
drop(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum ToServer {
|
|
|
|
/// A new connection has started.
|
|
|
|
NewClient(ClientHandle),
|
|
|
|
/// The connection sent a message.
|
|
|
|
Message(ClientId, String),
|
|
|
|
/// The connection's player moved.
|
|
|
|
ActorMoved(ClientId, u32, Position, f32),
|
|
|
|
/// The connection has recieved a client trigger.
|
|
|
|
ClientTrigger(ClientId, u32, ClientTrigger),
|
|
|
|
/// The connection loaded into a zone.
|
|
|
|
// TODO: the connection should not be in charge and telling the global server what zone they just loaded in! but this will work for now
|
|
|
|
ZoneLoaded(ClientId, u16),
|
|
|
|
/// The connection left a zone.
|
|
|
|
LeftZone(ClientId, u32, u16),
|
|
|
|
/// The connection disconnected.
|
|
|
|
Disconnected(ClientId),
|
|
|
|
/// A fatal error occured.
|
|
|
|
FatalError(std::io::Error),
|
2025-06-18 20:38:55 -04:00
|
|
|
/// Spawn a friendly debug NPC.
|
2025-06-18 20:28:03 -04:00
|
|
|
DebugNewNpc(ClientId, u32),
|
2025-06-18 20:38:55 -04:00
|
|
|
/// Spawn an enemy debug NPC.
|
|
|
|
DebugNewEnemy(ClientId, u32),
|
2025-06-18 20:57:20 -04:00
|
|
|
/// Spawn a debug clone.
|
|
|
|
DebugSpawnClone(ClientId, u32),
|
2025-06-21 10:36:44 -04:00
|
|
|
/// Request to perform an action
|
|
|
|
ActionRequest(ClientId, u32, ActionRequest),
|
2025-05-09 19:49:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct ServerHandle {
|
|
|
|
pub chan: Sender<ToServer>,
|
|
|
|
pub next_id: Arc<AtomicUsize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerHandle {
|
|
|
|
pub async fn send(&mut self, msg: ToServer) {
|
|
|
|
if self.chan.send(msg).await.is_err() {
|
|
|
|
panic!("Main loop has shut down.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn next_id(&self) -> ClientId {
|
|
|
|
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
|
|
|
ClientId(id)
|
|
|
|
}
|
|
|
|
}
|