24个版本 (11个破坏性更新)
0.12.0 | 2024年7月5日 |
---|---|
0.11.0 | 2024年5月7日 |
0.9.2 | 2024年3月8日 |
0.5.3 | 2023年12月19日 |
0.5.1 | 2023年11月29日 |
#83 in 游戏开发
在 bevy_simplenet_events 中使用
140KB
2K SLoC
Bevy Simplenet
提供通过WebSocket实现的双向服务器/客户端通道。此Crate适用于用户认证、与匹配服务通信、微服务之间的通信、对延迟要求不严格的游戏等。
- 客户端/服务器通道包括一次性消息和请求/响应API。
- 可以跟踪客户端消息的状态。
- 客户端自动在原生和WASM目标上工作。
- 服务器可以验证客户端(进行中)。
- 提供可选的TLS服务器。
查看示例,了解如何使用此Crate构建Bevy客户端。
查看 bevy_simplenet_events 了解在此Crate基础上构建的基于事件的网络框架。
功能
default
: 包含bevy
、client
、server
功能bevy
: 在Client
和Server
上派生Resource
client
: 启用客户端(原生和WASM目标)server
: 启用服务器(仅原生目标)tls-rustls
: 通过rustls
启用服务器TLStls-openssl
: 通过OpenSSL
启用服务器TLS
WASM
在WASM目标上,当其他任务正在运行时,客户端后端不会更新。您必须构建一个以IO为导向的应用程序,该应用程序自然花费大量时间轮询任务,或者定期手动释放主线程(例如,使用web_sys::Window::set_timeout_with_callback_and_timeout_and_arguments_0()
)。对于Bevy应用程序,后者在每次应用程序更新/计时结束时自动发生(参见bevy::app::ScheduleRunnerPlugin
实现)。
使用说明
- 服务器和客户端必须使用enfync运行时创建。后端是ezsockets。
- 客户端的
AuthRequest
类型必须与相应服务器的Authenticator
类型匹配。 - 客户端ID由客户端在连接到服务器时通过其
AuthRequest
定义。如果ID已经连接,连接将被拒绝。 - 客户端连接消息将在所有重连尝试中被克隆,因此应将其视为静态数据。
- 如果底层连接中断,服务器或客户端的消息可能无法发送。客户端可以使用
Client::send()
和Client::request()
返回的信号来跟踪消息的状态。客户端请求结果将始终由Client::next()
发出。消息跟踪对于服务器不可用。 - 跟踪级别假定服务器是可信的,而客户端不可信。
示例
设置
公共
定义一个通道。
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TestConnectMsg(pub String);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TestServerMsg(pub u64);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TestServerResponse(pub u64);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TestClientMsg(pub u64);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TestClientRequest(pub u64);
#[derive(Debug, Clone)]
pub struct TestChannel;
impl ChannelPack for TestChannel
{
type ConnectMsg = TestConnectMsg;
type ServerMsg = TestServerMsg;
type ServerResponse = TestServerResponse;
type ClientMsg = TestClientMsg;
type ClientRequest = TestClientRequest;
}
服务器
准备创建服务器。
type TestServerEvent = ServerEventFrom<TestChannel>;
fn server_factory() -> ServerFactory<TestChannel>
{
// It is recommended to make server/client factories with baked-in protocol versions (e.g.
// with env!("CARGO_PKG_VERSION")).
ServerFactory::<TestChannel>::new("test")
}
创建一个服务器并将其插入到应用程序中。
fn setup_server(mut commands: Commands)
{
let server = server_factory().new_server(
enfync::builtin::native::TokioHandle::default(),
"127.0.0.1:0",
AcceptorConfig::Default,
Authenticator::None,
ServerConfig::default(),
);
commands.insert_resource(server);
}
客户端
准备创建客户端。
type TestClientEvent = ClientEventFrom<TestChannel>;
fn client_factory() -> ClientFactory<TestChannel>
{
// You must use the same protocol version string as the server factory.
ClientFactory::<TestChannel>::new("test")
}
创建一个客户端并将其插入到应用程序中。
fn setup_client(mut commands: Commands)
{
let client_id = 0u128;
let client = client_factory().new_client(
enfync::builtin::Handle::default(), //automatically selects native/WASM runtime
server.url(),
AuthRequest::None{ client_id },
ClientConfig::default(),
TestConnectMsg(String::from("hello"))
);
commands.insert_resource(client);
}
从客户端发送
发送一条消息。
fn send_client_message(client: Client<TestChannel>)
{
let message_signal = client.send(TestClientMsg(42));
}
发送一个请求。
fn send_client_request(client: Client<TestChannel>)
{
let request_signal = client.request(TestClientRequest(24));
}
从服务器发送
发送一条消息。
fn send_server_message(server: Server<TestChannel>)
{
server.send(0u128, TestServerMsg(111));
}
发送响应。
fn send_server_response(In(token): In<RequestToken>, server: Server<TestChannel>)
{
server.respond(token, TestServerResponse(1));
}
客户端读取
fn read_on_client(client: &mut Client<TestChannel>)
{
while let Some(client_event) = client.next()
{
match client_event
{
TestClientEvent::Report(connection_report) => match connection_report
{
ClientReport::Connected => todo!(),
ClientReport::Disconnected => todo!(),
ClientReport::ClosedByServer(reason) => todo!(),
ClientReport::ClosedBySelf => todo!(),
ClientReport::IsDead(pending_requests) => todo!(),
}
TestClientEvent::Msg(message) => todo!(),
TestClientEvent::Response(response, request_id) => todo!(),
TestClientEvent::Ack(request_id) => todo!(),
TestClientEvent::Reject(request_id) => todo!(),
TestClientEvent::SendFailed(request_id) => todo!(),
TestClientEvent::ResponseLost(request_id) => todo!(),
}
}
}
服务器读取
fn read_on_server(server: &mut Server<TestChannel>)
{
while let Some((client_id, server_event)) = server.next()
{
match server_event
{
TestServerEvent::Report(connection_report) => match connection_report
{
ServerReport::Connected(env, message) => todo!(),
ServerReport::Disconnected => todo!(),
}
TestServerEvent::Msg(message) => todo!(),
TestServerEvent::Request(token, request) => todo!(),
}
}
}
待办事项
- 实现
AuthToken
以进行客户端/服务器身份验证。 - 添加服务器关闭程序。
- 使用const generics将协议版本直接烘焙到
Server
和Client
中,而不是依赖于工厂(目前由于缺乏健壮的编译器支持而受阻)。
Bevy兼容性
bevy | bevy_simplenet |
---|---|
0.14 | v0.12 - master |
0.13 | v0.9 - v0.11 |
0.12 | v0.5 - v0.8 |
0.11 | v0 - v0.4 |
依赖关系
~5–20MB
~313K SLoC