Live location tracking and playback for the game "manhunt"
at main 142 lines 3.7 kB view raw
1use std::{collections::HashMap, sync::Arc}; 2 3use tokio::{ 4 sync::{Mutex, mpsc}, 5 task::yield_now, 6}; 7use uuid::Uuid; 8 9use crate::{ 10 MsgPair, StateUpdateSender, Transport, TransportMessage, 11 location::{Location, LocationService}, 12 prelude::*, 13}; 14 15type GameEventRx = mpsc::Receiver<MsgPair>; 16type GameEventTx = mpsc::Sender<MsgPair>; 17 18pub struct MockTransport { 19 id: Uuid, 20 rx: Mutex<GameEventRx>, 21 txs: HashMap<Uuid, GameEventTx>, 22} 23 24impl MockTransport { 25 pub fn create_mesh(players: u32) -> (Vec<Uuid>, Vec<Self>) { 26 let uuids = (0..players) 27 .map(|_| uuid::Uuid::new_v4()) 28 .collect::<Vec<_>>(); 29 let channels = (0..players) 30 .map(|_| tokio::sync::mpsc::channel(20)) 31 .collect::<Vec<_>>(); 32 let txs = channels 33 .iter() 34 .enumerate() 35 .map(|(i, (tx, _))| (uuids[i], tx.clone())) 36 .collect::<HashMap<_, _>>(); 37 38 let transports = channels 39 .into_iter() 40 .enumerate() 41 .map(|(i, (_tx, rx))| Self::new(uuids[i], rx, txs.clone())) 42 .collect::<Vec<_>>(); 43 44 (uuids, transports) 45 } 46 47 pub async fn wait_for_queue_empty(&self) { 48 // println!("Waiting for {} queue to empty", self.id); 49 loop { 50 let all_empty = self 51 .txs 52 .values() 53 .all(|tx| tx.is_closed() || tx.capacity() == tx.max_capacity()); 54 55 if all_empty { 56 break; 57 } else { 58 yield_now().await; 59 } 60 } 61 } 62 63 pub async fn fake_join(&self) { 64 self.send_message(TransportMessage::PeerConnect(self.id)) 65 .await; 66 } 67 68 pub fn is_disconnected(&self) -> bool { 69 self.txs[&self.id].is_closed() 70 } 71 72 fn new(id: Uuid, rx: GameEventRx, txs: HashMap<Uuid, GameEventTx>) -> Self { 73 Self { 74 id, 75 rx: Mutex::new(rx), 76 txs, 77 } 78 } 79} 80 81impl Transport for MockTransport { 82 async fn initialize(_code: &str, _host: bool) -> Result<Arc<Self>> { 83 let (_, rx) = mpsc::channel(5); 84 Ok(Arc::new(Self { 85 id: Uuid::default(), 86 rx: Mutex::new(rx), 87 txs: HashMap::default(), 88 })) 89 } 90 91 async fn disconnect(&self) { 92 self.send_message(TransportMessage::PeerDisconnect(self.id)) 93 .await; 94 let mut rx = self.rx.lock().await; 95 rx.close(); 96 } 97 98 async fn receive_messages(&self) -> impl Iterator<Item = MsgPair> { 99 let mut rx = self.rx.lock().await; 100 let mut buf = Vec::with_capacity(20); 101 rx.recv_many(&mut buf, 20).await; 102 buf.into_iter() 103 } 104 105 async fn send_message(&self, msg: TransportMessage) { 106 for (_id, tx) in self.txs.iter().filter(|(id, _)| **id != self.id) { 107 tx.send((Some(self.id), msg.clone())).await.ok(); 108 } 109 } 110 111 async fn send_message_single(&self, peer: Uuid, msg: TransportMessage) { 112 if let Some(tx) = self.txs.get(&peer) { 113 tx.send((Some(self.id), msg)).await.ok(); 114 } 115 } 116 117 async fn send_self(&self, msg: TransportMessage) { 118 self.txs[&self.id].send((Some(self.id), msg)).await.ok(); 119 } 120 121 fn self_id(&self) -> Uuid { 122 self.id 123 } 124} 125 126pub struct MockLocation; 127 128impl LocationService for MockLocation { 129 fn get_loc(&self) -> Option<Location> { 130 Some(crate::location::Location { 131 lat: 0.0, 132 long: 0.0, 133 heading: None, 134 }) 135 } 136} 137 138pub struct DummySender; 139 140impl StateUpdateSender for DummySender { 141 fn send_update(&self) {} 142}