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;
}
}