lnkit 0.2.1

Multiplayer game library
Documentation
use crate::*;
use async_std::channel::{self, Receiver, RecvError, Sender};
use async_std::sync::{Arc, Mutex, RwLock};
use async_std::task::{self, JoinHandle};
use paperplane::tungstenite::Message;
use paperplane::{Event, Server};
use rapier3d::dynamics::{RigidBody, RigidBodyHandle};
use rapier3d::geometry::ColliderHandle;
use rapier3d::pipeline::ChannelEventCollector;
use serde::Serialize;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::time::{Duration, Instant};

pub struct Game<Input> {
    server: Arc<Server>,
    server_task: Mutex<Option<JoinHandle<()>>>,
    event_sender: Sender<Event<Input>>,
    event_receiver: Mutex<Receiver<Event<Input>>>,
    physics: RwLock<Physics>,
    physics_task: Mutex<Option<JoinHandle<()>>>,
    entities: RwLock<Vec<u128>>,
    shapes: RwLock<HashMap<u128, Shape>>,
    materials: RwLock<HashMap<u128, Material>>,
    body_handles: RwLock<HashMap<u128, RigidBodyHandle>>,
    collider_handles: RwLock<HashMap<u128, ColliderHandle>>,
}

impl<Input> Game<Input>
where
    Input: TryFrom<Message> + Send + 'static,
    <Input as TryFrom<Message>>::Error: Send,
{
    pub fn new() -> Self {
        let (event_sender, event_receiver) = channel::bounded(1000);
        Self {
            server: Server::new(1000),
            server_task: Mutex::new(None),
            event_sender,
            event_receiver: Mutex::new(event_receiver),
            physics: RwLock::new(Physics::new()),
            physics_task: Mutex::new(None),
            entities: RwLock::new(Vec::new()),
            shapes: RwLock::new(HashMap::new()),
            materials: RwLock::new(HashMap::new()),
            body_handles: RwLock::new(HashMap::new()),
            collider_handles: RwLock::new(HashMap::new()),
        }
    }

    async fn share<M>(&self, id: Option<u128>, msg: M)
    where
        M: Into<ServerMessage<()>>,
    {
        let srv_msg: ServerMessage<()> = msg.into();
        self.server.send_transform(id, &srv_msg).await.ok();
    }

    pub async fn send<Output>(&self, id: Option<u128>, output: Output)
    where
        Output: Serialize,
    {
        self.server
            .send_transform(id, &ServerMessage::Custom(output))
            .await
            .ok();
    }

    pub async fn next(&self) -> Result<Event<Input>, RecvError> {
        self.event_receiver.lock().await.recv().await
    }

    async fn new_entity(&self) -> u128 {
        let mut entities = self.entities.write().await;
        let entity = entities.last().map(|id| id + 1).unwrap_or_default();
        entities.push(entity);
        entity
    }

    async fn remove_entity(&self, entity: u128) {
        let entity_index = self.entities.read().await.iter().position(|e| e == &entity);
        if let Some(entity_index) = entity_index {
            self.entities.write().await.remove(entity_index);
        }
    }

    pub async fn add_mesh(&self, mesh: Mesh) -> MeshHandle {
        let entity = self.new_entity().await;
        let isometry = mesh.body.position().clone();
        let (body_handle, collider_handle) =
            self.physics.write().await.add(mesh.body, mesh.shape.into());
        self.shapes.write().await.insert(entity, mesh.shape);
        self.materials.write().await.insert(entity, mesh.material);
        self.body_handles.write().await.insert(entity, body_handle);
        self.collider_handles
            .write()
            .await
            .insert(entity, collider_handle);
        self.share(
            None,
            (
                entity,
                vec![mesh.shape.into(), mesh.material.into(), isometry.into()],
            ),
        )
        .await;
        MeshHandle {
            entity,
            body_handle,
            collider_handle,
        }
    }

    pub async fn remove_mesh(&self, entity: u128) {
        self.remove_entity(entity).await;
        let body_handle = self.body_handles.write().await.get(&entity).map(|v| *v);
        if let Some(body_handle) = body_handle {
            self.physics.write().await.remove(body_handle);
        }
        self.shapes.write().await.remove(&entity);
        self.materials.write().await.remove(&entity);
        self.body_handles.write().await.remove(&entity);
        self.collider_handles.write().await.remove(&entity);
        self.share(None, vec![(entity, Component::Shape(None))])
            .await;
    }

    pub async fn set_shape(&self, entity: u128, shape: Shape) {
        let collider_handle = self.collider_handles.read().await.get(&entity).map(|v| *v);
        if let Some(collider_handle) = collider_handle {
            if self
                .physics
                .write()
                .await
                .collider_mut(collider_handle)
                .map(|collider| collider.set_shape(shape.into()))
                .is_some()
            {
                self.shapes.write().await.insert(entity, shape);
                self.share(None, vec![(entity, shape.into())]).await;
            }
        }
    }

    pub async fn set_material(&self, entity: u128, material: Material) {
        if self
            .materials
            .write()
            .await
            .get_mut(&entity)
            .map(|mat_ref| *mat_ref = material)
            .is_some()
        {
            self.share(None, vec![(entity, material.into())]).await;
        }
    }

    pub async fn update_body<F>(&self, body_handle: RigidBodyHandle, predicate: F)
    where
        F: Fn(&mut RigidBody),
    {
        self.physics
            .write()
            .await
            .body_mut(body_handle)
            .map(|body| predicate(body));
    }

    pub async fn set_event_handler(&self, event_handler: Option<ChannelEventCollector>) {
        self.physics.write().await.set_event_handler(event_handler)
    }

    async fn initial_components(&self) -> Vec<(u128, Component)> {
        let mut list = vec![];
        let entities = self.entities.read().await;
        let shapes = self.shapes.read().await;
        let materials = self.materials.read().await;
        let body_handles = self.body_handles.read().await;
        let physics = self.physics.read().await;
        for entity in entities.iter() {
            if let Some(shape) = shapes.get(entity) {
                list.push((*entity, (*shape).into()));
                if let Some(material) = materials.get(entity) {
                    list.push((*entity, (*material).into()));
                }
                if let Some(isometry) = body_handles
                    .get(entity)
                    .map(|handle| physics.body(*handle).map(|body| *body.position()))
                    .flatten()
                {
                    list.push((*entity, isometry.into()));
                }
            }
        }
        list
    }

    async fn tick_components(&self) -> Vec<(u128, Component)> {
        let mut list = vec![];
        let entities = self.entities.read().await;
        let body_handles = self.body_handles.read().await;
        let physics = self.physics.read().await;
        for entity in entities.iter() {
            if let Some(isometry) = body_handles
                .get(entity)
                .map(|handle| {
                    physics
                        .body(*handle)
                        .map(|body| {
                            (!body.is_static() && !body.is_sleeping()).then(|| *body.position())
                        })
                        .flatten()
                })
                .flatten()
            {
                list.push((*entity, isometry.into()));
            }
        }
        list
    }

    async fn server_loop(self: &Arc<Self>) {
        self.server.listen("0.0.0.0:42069").await.unwrap();
        while let Some(transform) = self.server.next_transform::<Input>().await {
            if let Ok(event) = transform {
                match event {
                    Event::Connected(id) => {
                        let game = self.clone();
                        task::spawn(async move {
                            game.share(Some(id), game.initial_components().await).await
                        });
                    }
                    _ => {}
                }
                self.event_sender.send(event).await.ok();
            }
        }
    }

    async fn physics_loop(self: &Arc<Self>) {
        loop {
            let start = Instant::now();
            self.physics.write().await.step();
            {
                let game = self.clone();
                task::spawn(async move {
                    game.share(None, game.tick_components().await).await;
                });
            }
            task::sleep(Duration::from_nanos(
                16_666_666 - start.elapsed().as_nanos().min(16_666_666) as u64,
            ))
            .await;
        }
    }

    pub async fn start_server_task(self: &Arc<Self>) {
        let mut server_task = self.server_task.lock().await;
        if let Some(handle) = server_task.take() {
            handle.cancel().await;
            self.server.close().await.ok();
        }
        let game = self.clone();
        *server_task = Some(task::spawn(async move {
            game.server_loop().await;
        }));
    }

    pub async fn stop_server_task(&self) {
        let mut server_task = self.server_task.lock().await;
        if let Some(handle) = server_task.take() {
            handle.cancel().await;
            self.server.close().await.ok();
        }
        *server_task = None;
    }

    pub async fn start_physics_task(self: &Arc<Self>) {
        let mut physics_task = self.physics_task.lock().await;
        if let Some(handle) = physics_task.take() {
            handle.cancel().await;
        }
        let game = self.clone();
        *physics_task = Some(task::spawn(async move {
            game.physics_loop().await;
        }));
    }

    pub async fn stop_physics_task(&self) {
        let mut physics_task = self.physics_task.lock().await;
        if let Some(handle) = physics_task.take() {
            handle.cancel().await;
        }
        *physics_task = None;
    }
}