1use bevy::prelude::*;
2pub use packet::Packet;
3use std::{
4 io,
5 net::{SocketAddr, ToSocketAddrs},
6 sync::Arc,
7};
8use tcp::{Connection, Listener};
9
10mod packet;
11mod tcp;
12
13#[derive(Resource)]
15pub struct ServerConnection(Connection);
16
17impl ServerConnection {
18 pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
20 Ok(Self(Connection::connect(addr)?))
21 }
22
23 pub fn send<P: Packet>(&self, packet: P) {
25 self.0.send(packet);
26 }
27
28 pub fn address(&self) -> SocketAddr {
30 self.0.address()
31 }
32}
33
34#[derive(Resource)]
36pub struct ClientListener(Listener);
37
38impl ClientListener {
39 pub fn bind<A: ToSocketAddrs>(address: A) -> io::Result<Self> {
41 Ok(Self(Listener::bind(address)?))
42 }
43
44 pub fn address(&self) -> SocketAddr {
46 self.0.address()
47 }
48}
49
50#[derive(Component)]
52pub struct ClientConnection(Arc<Connection>);
53
54impl ClientConnection {
55 pub fn send<P: Packet>(&self, packet: P) {
57 self.0.send(packet);
58 }
59
60 pub fn address(&self) -> SocketAddr {
62 self.0.address()
63 }
64}
65
66pub struct ClientNetworkPlugin;
68
69impl ClientNetworkPlugin {
70 fn remove_disconnected(mut commands: Commands, connection: Res<ServerConnection>) {
72 if !connection.0.connected() {
73 commands.remove_resource::<ServerConnection>();
74 }
75 }
76
77 fn clear_cache(connection: Res<ServerConnection>) {
79 connection.0.clear();
80 }
81}
82
83impl Plugin for ClientNetworkPlugin {
84 fn build(&self, app: &mut App) {
85 app.add_systems((
86 Self::remove_disconnected.run_if(resource_exists::<ServerConnection>()),
87 Self::clear_cache
88 .run_if(resource_exists::<ServerConnection>())
89 .after(Self::remove_disconnected),
90 ));
91 }
92}
93
94pub struct ServerNetworkPlugin;
96
97impl ServerNetworkPlugin {
98 fn remove_disconnected(
100 mut commands: Commands,
101 connections: Query<(Entity, &ClientConnection)>,
102 ) {
103 for (entity, connection) in connections.iter() {
104 if !connection.0.connected() {
105 commands.entity(entity).remove::<ClientConnection>();
106 }
107 }
108 }
109
110 fn clear_cache(connections: Query<&ClientConnection>) {
112 for connection in connections.iter() {
113 connection.0.clear();
114 }
115 }
116
117 fn remove_not_listening(mut commands: Commands, listener: Res<ClientListener>) {
119 if !listener.0.listening() {
120 commands.remove_resource::<ClientListener>();
121 }
122 }
123
124 fn accept_connections(mut commands: Commands, listener: Res<ClientListener>) {
126 while let Some(connection) = listener.0.accept() {
127 commands.spawn(ClientConnection(Arc::new(connection)));
128 }
129 }
130}
131
132impl Plugin for ServerNetworkPlugin {
133 fn build(&self, app: &mut App) {
134 app.add_systems((
135 Self::remove_disconnected,
136 Self::clear_cache.after(Self::remove_disconnected),
137 Self::remove_not_listening.run_if(resource_exists::<ClientListener>()),
138 Self::accept_connections
139 .run_if(resource_exists::<ClientListener>())
140 .after(Self::remove_not_listening),
141 ));
142 }
143}
144
145fn receive_server_packets<P: Packet>(
147 mut writer: EventWriter<PacketEvent<P>>,
148 connection: Query<(Entity, &ClientConnection)>,
149) {
150 for (entity, connection) in connection.iter() {
151 for packet in connection.0.recv() {
152 writer.send(PacketEvent {
153 connection: ClientConnection(Arc::clone(&connection.0)),
154 entity,
155 packet,
156 });
157 }
158 }
159}
160
161pub trait AppServerNetwork {
163 fn register_server_packet<P: Packet>(&mut self) -> &mut Self;
165}
166
167impl AppServerNetwork for App {
168 fn register_server_packet<P: Packet>(&mut self) -> &mut Self {
169 self.add_event::<PacketEvent<P>>();
170 self.add_system(
171 receive_server_packets::<P>
172 .after(ServerNetworkPlugin::remove_disconnected)
173 .before(ServerNetworkPlugin::clear_cache),
174 );
175 self
176 }
177}
178
179pub struct PacketEvent<P: Packet> {
181 pub connection: ClientConnection,
183
184 pub entity: Entity,
186
187 pub packet: P,
189}
190
191fn receive_client_packets<P: Packet>(
193 mut writer: EventWriter<P>,
194 connection: Res<ServerConnection>,
195) {
196 for packet in connection.0.recv() {
197 writer.send(packet);
198 }
199}
200
201pub trait AppClientNetwork {
203 fn register_client_packet<P: Packet>(&mut self) -> &mut Self;
205}
206
207impl AppClientNetwork for App {
208 fn register_client_packet<P: Packet>(&mut self) -> &mut Self {
209 self.add_event::<P>();
210 self.add_system(
211 receive_client_packets::<P>
212 .run_if(resource_exists::<ServerConnection>())
213 .after(ClientNetworkPlugin::remove_disconnected)
214 .before(ClientNetworkPlugin::clear_cache),
215 );
216 self
217 }
218}