ブロードキャストサーバーを作ろう
システムを定義する
先に完成形を見てください。
use ecson::prelude::*;
fn broadcast_system(
mut ev_received: MessageReader<MessageReceived>,
mut ev_send: MessageWriter<SendMessage>,
client_query: Query<Entity, With<ClientId>>,
) {
for msg in ev_received.read() {
let NetworkPayload::Text(text) = &msg.payload else {
continue;
};
let broadcast_text = format!("User {}: {}", msg.client_id, text);
let payload = NetworkPayload::Text(broadcast_text);
for target_entity in client_query.iter() {
ev_send.write(SendMessage {
target: target_entity,
payload: payload.clone(),
});
}
}
}
引数
mut ev_received: MessageReader<MessageReceived>:
evはイベントの略で、ev_receivedは受信したイベントを読み取るためのものとしてます。エコーサーバーの引数と同じです。mut ev_send: MessageWriter<SendMessage>:
送るほうです。client_query: Query<Entity, With<ClientId>>:
以下で説明します。
Ecsonは内部でbevy_ecsを使用しています。QueryもEntityもWithもbevy_ecsのものです。
Query | どのコンポーネントを持っているエンティティが欲しいかを定義する。検索窓口のようなもの。 |
Entity | 取得したいデータの中身。Ecsonでは接続者として扱う。 |
With | フィルター |
つまり、Query<Entity, With<ClientId>>は「ClientIdという印が付いているエンティティ」を探しています。
ロジック
let NetworkPayload::Text(text) = &msg.payload else {
continue;
};
今回はTextだけ扱うので、それ以外はスルーするようにしています。
let broadcast_text = format!("User {}: {}", msg.client_id, text);
let payload = NetworkPayload::Text(broadcast_text);
送信するメッセージを作っています。
for target_entity in client_query.iter() {
ev_send.write(SendMessage {
target: target_entity,
payload: payload.clone(),
});
}
ClientIdを持ったエンティティ(Query<Entity, With<ClientId>>)をイテレータで取り出しています。
取り出したエンティティに対して上で作ったメッセージを内容にして送信しています。
フロントエンドからテストをしよう
先ほどと同じHTMLで構わないので、複数開いてください。 どちらかでメッセージを送信すると、自身含めて他のクライアントにも飛ぶことがわかると思います。

次回はルーム付きのチャットサーバーを作ります