我想在游戏客户端和服务器之间发送事件,我已经实现了这一点,但我不知道如何在bevy中实现。
我必须使用tokios异步TcpStream
,因为我需要能够使用stream.into_split()
将流分成OwnedWriteHalf
和OwnedReadhalf
。
我的第一个想法是只需生成一个处理连接的线程,然后使用mpsc::channel
将接收到的事件发送到队列中。
然后,我将此队列包括在一个bevy资源中,使用app.insert_resource(Queue)
将其插入,并从游戏循环中提取事件。
队列:
use tokio::sync::mpsc;
pub enum Instruction {
Push(GameEvent),
Pull(mpsc::Sender<Option<GameEvent>>),
}
#[derive(Clone, Debug)]
pub struct Queue {
sender: mpsc::Sender<Instruction>,
}
impl Queue {
pub fn init() -> Self {
let (tx, rx) = mpsc::channel(1024);
init(rx);
Self{sender: tx}
}
pub async fn send(&self, event: GameEvent) {
self.sender.send(Instruction::Push(event)).await.unwrap();
}
pub async fn pull(&self) -> Option<GameEvent> {
println!("new pull");
let (tx, mut rx) = mpsc::channel(1);
self.sender.send(Instruction::Pull(tx)).await.unwrap();
rx.recv().await.unwrap()
}
}
fn init(mut rx: mpsc::Receiver<Instruction>) {
tokio::spawn(async move {
let mut queue: Vec<GameEvent> = Vec::new();
loop {
match rx.recv().await.unwrap() {
Instruction::Push(ev) => {
queue.push(ev);
}
Instruction::Pull(sender) => {
sender.send(queue.pop()).await.unwrap();
}
}
}
});
}
但由于这一切都必须是异步的,所以我在同步游戏循环中阻塞了pull()
函数。
我使用futures-lite
创建来实现:
fn event_pull(
communication: Res<Communication>
) {
let ev = future::block_on(communication.event_queue.pull());
println!("got event: {:?}", ev);
}
这个代码可以正常工作,但是大约5秒后整个程序就会停止接收任何事件。
似乎future::block_on()
会无限期地阻塞。
将构建和运行bevy::prelude::App的主函数改为异步的tokio::main
函数也可能是一个问题。
最好将异步的TcpStream
初始化、tokio::sync::mpsc::Sender
以及Queue.pull
都包装成同步函数,但我不知道如何实现。
有人能帮忙吗?
如何重现
该代码库可以在此处找到。
只需编译server
和client
,然后按相同顺序运行两者即可。