Skip to main content

Net

Struct Net 

Source
pub struct Net { /* private fields */ }
Expand description

The network connection: ctx.net. See the module docs.

Implementations§

Source§

impl Net

Source

pub fn new(game: impl Into<String>) -> Self

An offline network for the game game. Only clients with the same game name can join. The engine creates this as ctx.net with the game title.

Source

pub fn set_name(&mut self, name: impl Into<String>)

The name others see (default "Player", at most 32 characters). Set it before Net::host or Net::join.

Examples found in repository?
examples/online.rs (line 66)
54    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
55        match event {
56            UiEvent::Changed { item, value, .. } if item == "name" => {
57                self.name = value.as_str().to_string();
58                ctx.storage.set("name", &self.name);
59            }
60            UiEvent::Changed { item, value, .. } if item == "address" => {
61                self.address = value.as_str().to_string();
62                ctx.storage.set("address", &self.address);
63            }
64            UiEvent::Activated { item, .. } => match item.as_str() {
65                "host" => {
66                    ctx.net.set_name(&self.name);
67                    match ctx.net.host(net::DEFAULT_PORT) {
68                        Ok(()) => {
69                            let address = Net::local_ip().map_or("unknown".to_string(), |ip| ip.to_string());
70                            ctx.speak(format!("Hosting. Your address is {address}"));
71                            Self::start_game(ctx);
72                        }
73                        Err(e) => ctx.ui.message("error", e.to_string()),
74                    }
75                }
76                "join" => {
77                    ctx.net.set_name(&self.name);
78                    ctx.net.join(&self.address);
79                    ctx.speak(format!("Connecting to {}", self.address));
80                }
81                "quit" => ctx.quit(),
82                _ => {}
83            },
84            _ => {}
85        }
86    }
Source

pub fn set_version(&mut self, version: impl Into<String>)

The version of your game, e.g. "1.2" (default empty). Clients with another version cannot join, so old and new game code never meet. Set it before hosting or joining.

Source

pub fn set_max_players(&mut self, max: usize)

How many clients may join (default 32). The host does not count.

Source

pub fn host(&mut self, port: u16) -> Result<()>

Starts a WebSocket server on port that others can join. Port 0 picks a free port (see Net::port). Ends any connection that is open. Fails when the port is in use. Any URL path is accepted, so a web server can pass on wss://example.com/game.

Players outside your local network need the host’s public address, and the port must be forwarded in the host’s router.

Examples found in repository?
examples/online.rs (line 67)
54    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
55        match event {
56            UiEvent::Changed { item, value, .. } if item == "name" => {
57                self.name = value.as_str().to_string();
58                ctx.storage.set("name", &self.name);
59            }
60            UiEvent::Changed { item, value, .. } if item == "address" => {
61                self.address = value.as_str().to_string();
62                ctx.storage.set("address", &self.address);
63            }
64            UiEvent::Activated { item, .. } => match item.as_str() {
65                "host" => {
66                    ctx.net.set_name(&self.name);
67                    match ctx.net.host(net::DEFAULT_PORT) {
68                        Ok(()) => {
69                            let address = Net::local_ip().map_or("unknown".to_string(), |ip| ip.to_string());
70                            ctx.speak(format!("Hosting. Your address is {address}"));
71                            Self::start_game(ctx);
72                        }
73                        Err(e) => ctx.ui.message("error", e.to_string()),
74                    }
75                }
76                "join" => {
77                    ctx.net.set_name(&self.name);
78                    ctx.net.join(&self.address);
79                    ctx.speak(format!("Connecting to {}", self.address));
80                }
81                "quit" => ctx.quit(),
82                _ => {}
83            },
84            _ => {}
85        }
86    }
Source

pub fn join(&mut self, address: &str)

Joins the server at address: a host name or IP address, with or without port ("example.com", "192.168.1.20:7777", "[::1]:7777"), or a WebSocket URL ("ws://example.com:7777/", "wss://example.com/game"). Without a port, DEFAULT_PORT is used (URLs: 80 for ws://, 443 for wss://). Ends any connection that is open.

Returns at once. Later a NetEvent::Connected says the connection is ready, or a NetEvent::Disconnected says why it failed (after at most about 10 seconds).

Examples found in repository?
examples/online.rs (line 78)
54    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
55        match event {
56            UiEvent::Changed { item, value, .. } if item == "name" => {
57                self.name = value.as_str().to_string();
58                ctx.storage.set("name", &self.name);
59            }
60            UiEvent::Changed { item, value, .. } if item == "address" => {
61                self.address = value.as_str().to_string();
62                ctx.storage.set("address", &self.address);
63            }
64            UiEvent::Activated { item, .. } => match item.as_str() {
65                "host" => {
66                    ctx.net.set_name(&self.name);
67                    match ctx.net.host(net::DEFAULT_PORT) {
68                        Ok(()) => {
69                            let address = Net::local_ip().map_or("unknown".to_string(), |ip| ip.to_string());
70                            ctx.speak(format!("Hosting. Your address is {address}"));
71                            Self::start_game(ctx);
72                        }
73                        Err(e) => ctx.ui.message("error", e.to_string()),
74                    }
75                }
76                "join" => {
77                    ctx.net.set_name(&self.name);
78                    ctx.net.join(&self.address);
79                    ctx.speak(format!("Connecting to {}", self.address));
80                }
81                "quit" => ctx.quit(),
82                _ => {}
83            },
84            _ => {}
85        }
86    }
Source

pub fn close(&mut self)

Leaves the game, or stops the server and sends every player away with Reason::Closed. Called automatically when the game quits. Does nothing when offline. Produces no events.

Examples found in repository?
examples/online.rs (line 273)
231    fn update(&mut self, ctx: &mut Context) {
232        let step = vec3(
233            ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234            ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235            0.0,
236        );
237        if step != Vec3::ZERO {
238            self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239            ctx.play("step");
240            if ctx.net.is_host() {
241                ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242            } else {
243                ctx.net.send_all(Packet::new("move").with(self.position));
244            }
245        }
246        ctx.audio.set_listener(self.position, 0.0);
247
248        if ctx.pressed(Key::Enter) {
249            ctx.ui.input("chat", "Message");
250        }
251        if ctx.pressed(Key::Space) {
252            let text = if self.others.is_empty() {
253                "Nobody else is here".to_string()
254            } else {
255                let places: Vec<String> = self
256                    .others
257                    .values()
258                    .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259                    .collect();
260                places.join(". ")
261            };
262            ctx.speak(text);
263        }
264        if ctx.pressed(Key::P) {
265            if ctx.net.is_host() {
266                ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267            } else {
268                let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269                ctx.speak(format!("Ping {ms} milliseconds"));
270            }
271        }
272        if ctx.pressed(Key::Escape) {
273            ctx.net.close();
274            ctx.audio.stop_all();
275            ctx.speak("You left");
276            let scene = Lobby::new(ctx);
277            ctx.switch_scene(scene);
278        }
279    }
Source

pub fn kick(&mut self, peer: PeerId, reason: &str)

Host: sends a player away. They get Reason::Kicked with reason (may be empty). The host gets a NetEvent::Disconnected for them next frame.

Source

pub fn send(&mut self, peer: PeerId, packet: impl Into<Packet>)

Sends a packet to one peer. On a client, the only peer is PeerId::SERVER. Does nothing if the peer is not connected.

Examples found in repository?
examples/online.rs (line 153)
147    fn host_events(&mut self, event: &NetEvent, ctx: &mut Context) {
148        match event {
149            NetEvent::Connected(id) => {
150                let name = ctx.net.name(*id).to_string();
151                ctx.speak(format!("{name} joined"));
152                // Tell the newcomer about everybody, and everybody about the newcomer.
153                ctx.net.send(*id, Packet::new("player").with(PeerId::SERVER).with(ctx.net.name(PeerId::SERVER)).with(self.position));
154                for (other, o) in &self.others {
155                    ctx.net.send(*id, Packet::new("player").with(*other).with(&o.name).with(o.position));
156                }
157                ctx.net.send_all_except(*id, Packet::new("player").with(*id).with(&name).with(Vec3::ZERO));
158                self.add(ctx, *id, &name, Vec3::ZERO);
159            }
160            NetEvent::Message(from, packet) => match packet.kind() {
161                "move" => {
162                    self.moved(*from, packet.vec3(0));
163                    ctx.net.send_all_except(*from, Packet::new("pos").with(*from).with(packet.vec3(0)));
164                }
165                "chat" => {
166                    let text = packet.text(0);
167                    ctx.play("chat");
168                    ctx.speak(format!("{}: {text}", self.name(ctx, *from)));
169                    ctx.net.send_all_except(*from, Packet::new("chat").with(*from).with(text));
170                }
171                _ => {}
172            },
173            NetEvent::Disconnected(id, _) => {
174                self.remove(ctx, *id);
175                ctx.net.send_all(Packet::new("gone").with(*id));
176            }
177        }
178    }
Source

pub fn send_all(&mut self, packet: impl Into<Packet>)

Sends a packet to every connected peer. On a client that is the server.

Examples found in repository?
examples/online.rs (line 175)
147    fn host_events(&mut self, event: &NetEvent, ctx: &mut Context) {
148        match event {
149            NetEvent::Connected(id) => {
150                let name = ctx.net.name(*id).to_string();
151                ctx.speak(format!("{name} joined"));
152                // Tell the newcomer about everybody, and everybody about the newcomer.
153                ctx.net.send(*id, Packet::new("player").with(PeerId::SERVER).with(ctx.net.name(PeerId::SERVER)).with(self.position));
154                for (other, o) in &self.others {
155                    ctx.net.send(*id, Packet::new("player").with(*other).with(&o.name).with(o.position));
156                }
157                ctx.net.send_all_except(*id, Packet::new("player").with(*id).with(&name).with(Vec3::ZERO));
158                self.add(ctx, *id, &name, Vec3::ZERO);
159            }
160            NetEvent::Message(from, packet) => match packet.kind() {
161                "move" => {
162                    self.moved(*from, packet.vec3(0));
163                    ctx.net.send_all_except(*from, Packet::new("pos").with(*from).with(packet.vec3(0)));
164                }
165                "chat" => {
166                    let text = packet.text(0);
167                    ctx.play("chat");
168                    ctx.speak(format!("{}: {text}", self.name(ctx, *from)));
169                    ctx.net.send_all_except(*from, Packet::new("chat").with(*from).with(text));
170                }
171                _ => {}
172            },
173            NetEvent::Disconnected(id, _) => {
174                self.remove(ctx, *id);
175                ctx.net.send_all(Packet::new("gone").with(*id));
176            }
177        }
178    }
179
180    /// The client's side of the protocol.
181    fn client_events(&mut self, event: &NetEvent, ctx: &mut Context) {
182        match event {
183            NetEvent::Message(_, packet) => match packet.kind() {
184                "player" => self.add(ctx, packet.peer(0), packet.text(1), packet.vec3(2)),
185                "pos" => self.moved(packet.peer(0), packet.vec3(1)),
186                "gone" => self.remove(ctx, packet.peer(0)),
187                "chat" => {
188                    ctx.play("chat");
189                    ctx.speak(format!("{}: {}", self.name(ctx, packet.peer(0)), packet.text(1)));
190                }
191                _ => {}
192            },
193            NetEvent::Disconnected(_, reason) => {
194                ctx.speak(ctx.lang.describe_reason(reason));
195                ctx.audio.stop_all();
196                let scene = Lobby::new(ctx);
197                ctx.switch_scene(scene);
198            }
199            NetEvent::Connected(_) => {}
200        }
201    }
202}
203
204impl Scene for Field {
205    fn start(&mut self, ctx: &mut Context) {
206        ctx.speech.speak_queued("Arrows walk, Enter chats, Space finds the others, Escape leaves.");
207    }
208
209    fn on_net(&mut self, event: &NetEvent, ctx: &mut Context) {
210        if ctx.net.is_host() {
211            self.host_events(event, ctx);
212        } else {
213            self.client_events(event, ctx);
214        }
215    }
216
217    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
218        if let UiEvent::TextSubmitted { id, text } = event
219            && id == "chat"
220        {
221            // The host sends to everybody, a client sends to the host, who passes it on.
222            if ctx.net.is_host() {
223                ctx.net.send_all(Packet::new("chat").with(PeerId::SERVER).with(text));
224            } else {
225                ctx.net.send_all(Packet::new("chat").with(text));
226            }
227            ctx.play("chat");
228        }
229    }
230
231    fn update(&mut self, ctx: &mut Context) {
232        let step = vec3(
233            ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234            ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235            0.0,
236        );
237        if step != Vec3::ZERO {
238            self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239            ctx.play("step");
240            if ctx.net.is_host() {
241                ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242            } else {
243                ctx.net.send_all(Packet::new("move").with(self.position));
244            }
245        }
246        ctx.audio.set_listener(self.position, 0.0);
247
248        if ctx.pressed(Key::Enter) {
249            ctx.ui.input("chat", "Message");
250        }
251        if ctx.pressed(Key::Space) {
252            let text = if self.others.is_empty() {
253                "Nobody else is here".to_string()
254            } else {
255                let places: Vec<String> = self
256                    .others
257                    .values()
258                    .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259                    .collect();
260                places.join(". ")
261            };
262            ctx.speak(text);
263        }
264        if ctx.pressed(Key::P) {
265            if ctx.net.is_host() {
266                ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267            } else {
268                let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269                ctx.speak(format!("Ping {ms} milliseconds"));
270            }
271        }
272        if ctx.pressed(Key::Escape) {
273            ctx.net.close();
274            ctx.audio.stop_all();
275            ctx.speak("You left");
276            let scene = Lobby::new(ctx);
277            ctx.switch_scene(scene);
278        }
279    }
Source

pub fn send_all_except(&mut self, except: PeerId, packet: impl Into<Packet>)

Sends a packet to every connected peer except one. The usual way for a host to pass on what one player did to everybody else.

Examples found in repository?
examples/online.rs (line 157)
147    fn host_events(&mut self, event: &NetEvent, ctx: &mut Context) {
148        match event {
149            NetEvent::Connected(id) => {
150                let name = ctx.net.name(*id).to_string();
151                ctx.speak(format!("{name} joined"));
152                // Tell the newcomer about everybody, and everybody about the newcomer.
153                ctx.net.send(*id, Packet::new("player").with(PeerId::SERVER).with(ctx.net.name(PeerId::SERVER)).with(self.position));
154                for (other, o) in &self.others {
155                    ctx.net.send(*id, Packet::new("player").with(*other).with(&o.name).with(o.position));
156                }
157                ctx.net.send_all_except(*id, Packet::new("player").with(*id).with(&name).with(Vec3::ZERO));
158                self.add(ctx, *id, &name, Vec3::ZERO);
159            }
160            NetEvent::Message(from, packet) => match packet.kind() {
161                "move" => {
162                    self.moved(*from, packet.vec3(0));
163                    ctx.net.send_all_except(*from, Packet::new("pos").with(*from).with(packet.vec3(0)));
164                }
165                "chat" => {
166                    let text = packet.text(0);
167                    ctx.play("chat");
168                    ctx.speak(format!("{}: {text}", self.name(ctx, *from)));
169                    ctx.net.send_all_except(*from, Packet::new("chat").with(*from).with(text));
170                }
171                _ => {}
172            },
173            NetEvent::Disconnected(id, _) => {
174                self.remove(ctx, *id);
175                ctx.net.send_all(Packet::new("gone").with(*id));
176            }
177        }
178    }
Source

pub fn events(&self) -> &[NetEvent]

Everything that happened on the network this frame, in order.

Source

pub fn joined(&self) -> Vec<PeerId>

Players who connected this frame. On a client: PeerId::SERVER when the connection became ready.

Source

pub fn left(&self) -> Vec<(PeerId, Reason)>

Players who left this frame and why. On a client: PeerId::SERVER when the connection ended or could not be made.

Source

pub fn messages(&self) -> Vec<(PeerId, Packet)>

All packets that arrived this frame, with their sender.

Source

pub fn received(&self, kind: &str) -> Vec<(PeerId, Packet)>

The packets of one kind that arrived this frame, with their sender.

Source

pub fn players(&self) -> Vec<PeerId>

The connected peers in the order they joined. Host: all clients. Client: the server, once connected.

Source

pub fn player_count(&self) -> usize

Number of connected peers (the host does not count itself).

Examples found in repository?
examples/online.rs (line 266)
231    fn update(&mut self, ctx: &mut Context) {
232        let step = vec3(
233            ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234            ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235            0.0,
236        );
237        if step != Vec3::ZERO {
238            self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239            ctx.play("step");
240            if ctx.net.is_host() {
241                ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242            } else {
243                ctx.net.send_all(Packet::new("move").with(self.position));
244            }
245        }
246        ctx.audio.set_listener(self.position, 0.0);
247
248        if ctx.pressed(Key::Enter) {
249            ctx.ui.input("chat", "Message");
250        }
251        if ctx.pressed(Key::Space) {
252            let text = if self.others.is_empty() {
253                "Nobody else is here".to_string()
254            } else {
255                let places: Vec<String> = self
256                    .others
257                    .values()
258                    .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259                    .collect();
260                places.join(". ")
261            };
262            ctx.speak(text);
263        }
264        if ctx.pressed(Key::P) {
265            if ctx.net.is_host() {
266                ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267            } else {
268                let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269                ctx.speak(format!("Ping {ms} milliseconds"));
270            }
271        }
272        if ctx.pressed(Key::Escape) {
273            ctx.net.close();
274            ctx.audio.stop_all();
275            ctx.speak("You left");
276            let scene = Lobby::new(ctx);
277            ctx.switch_scene(scene);
278        }
279    }
Source

pub fn is_connected_to(&self, peer: PeerId) -> bool

Whether peer is connected right now.

Source

pub fn name(&self, peer: PeerId) -> &str

The name a peer chose with Net::set_name, or "" if not connected. Your own Net::id gives your own name.

Examples found in repository?
examples/online.rs (line 141)
139    fn name(&self, ctx: &Context, id: PeerId) -> String {
140        if id == ctx.net.id() {
141            return ctx.net.name(id).to_string();
142        }
143        self.others.get(&id).map_or("Someone".to_string(), |o| o.name.clone())
144    }
145
146    /// The host's side of the protocol.
147    fn host_events(&mut self, event: &NetEvent, ctx: &mut Context) {
148        match event {
149            NetEvent::Connected(id) => {
150                let name = ctx.net.name(*id).to_string();
151                ctx.speak(format!("{name} joined"));
152                // Tell the newcomer about everybody, and everybody about the newcomer.
153                ctx.net.send(*id, Packet::new("player").with(PeerId::SERVER).with(ctx.net.name(PeerId::SERVER)).with(self.position));
154                for (other, o) in &self.others {
155                    ctx.net.send(*id, Packet::new("player").with(*other).with(&o.name).with(o.position));
156                }
157                ctx.net.send_all_except(*id, Packet::new("player").with(*id).with(&name).with(Vec3::ZERO));
158                self.add(ctx, *id, &name, Vec3::ZERO);
159            }
160            NetEvent::Message(from, packet) => match packet.kind() {
161                "move" => {
162                    self.moved(*from, packet.vec3(0));
163                    ctx.net.send_all_except(*from, Packet::new("pos").with(*from).with(packet.vec3(0)));
164                }
165                "chat" => {
166                    let text = packet.text(0);
167                    ctx.play("chat");
168                    ctx.speak(format!("{}: {text}", self.name(ctx, *from)));
169                    ctx.net.send_all_except(*from, Packet::new("chat").with(*from).with(text));
170                }
171                _ => {}
172            },
173            NetEvent::Disconnected(id, _) => {
174                self.remove(ctx, *id);
175                ctx.net.send_all(Packet::new("gone").with(*id));
176            }
177        }
178    }
Source

pub fn ping(&self, peer: PeerId) -> f32

The round trip time to a peer in seconds: how long a message takes there and back. Updated every second; 0.0 until measured or when not connected.

Examples found in repository?
examples/online.rs (line 268)
231    fn update(&mut self, ctx: &mut Context) {
232        let step = vec3(
233            ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234            ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235            0.0,
236        );
237        if step != Vec3::ZERO {
238            self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239            ctx.play("step");
240            if ctx.net.is_host() {
241                ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242            } else {
243                ctx.net.send_all(Packet::new("move").with(self.position));
244            }
245        }
246        ctx.audio.set_listener(self.position, 0.0);
247
248        if ctx.pressed(Key::Enter) {
249            ctx.ui.input("chat", "Message");
250        }
251        if ctx.pressed(Key::Space) {
252            let text = if self.others.is_empty() {
253                "Nobody else is here".to_string()
254            } else {
255                let places: Vec<String> = self
256                    .others
257                    .values()
258                    .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259                    .collect();
260                places.join(". ")
261            };
262            ctx.speak(text);
263        }
264        if ctx.pressed(Key::P) {
265            if ctx.net.is_host() {
266                ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267            } else {
268                let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269                ctx.speak(format!("Ping {ms} milliseconds"));
270            }
271        }
272        if ctx.pressed(Key::Escape) {
273            ctx.net.close();
274            ctx.audio.stop_all();
275            ctx.speak("You left");
276            let scene = Lobby::new(ctx);
277            ctx.switch_scene(scene);
278        }
279    }
Source

pub fn id(&self) -> PeerId

Your own id: PeerId::SERVER for the host, the number the server gave you on a client.

Examples found in repository?
examples/online.rs (line 140)
139    fn name(&self, ctx: &Context, id: PeerId) -> String {
140        if id == ctx.net.id() {
141            return ctx.net.name(id).to_string();
142        }
143        self.others.get(&id).map_or("Someone".to_string(), |o| o.name.clone())
144    }
Source

pub fn is_host(&self) -> bool

Whether this game is hosting.

Examples found in repository?
examples/online.rs (line 210)
209    fn on_net(&mut self, event: &NetEvent, ctx: &mut Context) {
210        if ctx.net.is_host() {
211            self.host_events(event, ctx);
212        } else {
213            self.client_events(event, ctx);
214        }
215    }
216
217    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
218        if let UiEvent::TextSubmitted { id, text } = event
219            && id == "chat"
220        {
221            // The host sends to everybody, a client sends to the host, who passes it on.
222            if ctx.net.is_host() {
223                ctx.net.send_all(Packet::new("chat").with(PeerId::SERVER).with(text));
224            } else {
225                ctx.net.send_all(Packet::new("chat").with(text));
226            }
227            ctx.play("chat");
228        }
229    }
230
231    fn update(&mut self, ctx: &mut Context) {
232        let step = vec3(
233            ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234            ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235            0.0,
236        );
237        if step != Vec3::ZERO {
238            self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239            ctx.play("step");
240            if ctx.net.is_host() {
241                ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242            } else {
243                ctx.net.send_all(Packet::new("move").with(self.position));
244            }
245        }
246        ctx.audio.set_listener(self.position, 0.0);
247
248        if ctx.pressed(Key::Enter) {
249            ctx.ui.input("chat", "Message");
250        }
251        if ctx.pressed(Key::Space) {
252            let text = if self.others.is_empty() {
253                "Nobody else is here".to_string()
254            } else {
255                let places: Vec<String> = self
256                    .others
257                    .values()
258                    .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259                    .collect();
260                places.join(". ")
261            };
262            ctx.speak(text);
263        }
264        if ctx.pressed(Key::P) {
265            if ctx.net.is_host() {
266                ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267            } else {
268                let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269                ctx.speak(format!("Ping {ms} milliseconds"));
270            }
271        }
272        if ctx.pressed(Key::Escape) {
273            ctx.net.close();
274            ctx.audio.stop_all();
275            ctx.speak("You left");
276            let scene = Lobby::new(ctx);
277            ctx.switch_scene(scene);
278        }
279    }
Source

pub fn is_client(&self) -> bool

Whether this game is a client that is connected to a server.

Source

pub fn is_joining(&self) -> bool

Whether a Net::join is still in progress.

Source

pub fn is_online(&self) -> bool

Whether this game is hosting or connected to a server.

Source

pub fn port(&self) -> Option<u16>

The port the server listens on while hosting.

Source

pub fn local_ip() -> Option<IpAddr>

This computer’s address in the local network, e.g. 192.168.1.20: what players in the same network type to join. None without a network. Sends nothing.

Examples found in repository?
examples/online.rs (line 69)
54    fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
55        match event {
56            UiEvent::Changed { item, value, .. } if item == "name" => {
57                self.name = value.as_str().to_string();
58                ctx.storage.set("name", &self.name);
59            }
60            UiEvent::Changed { item, value, .. } if item == "address" => {
61                self.address = value.as_str().to_string();
62                ctx.storage.set("address", &self.address);
63            }
64            UiEvent::Activated { item, .. } => match item.as_str() {
65                "host" => {
66                    ctx.net.set_name(&self.name);
67                    match ctx.net.host(net::DEFAULT_PORT) {
68                        Ok(()) => {
69                            let address = Net::local_ip().map_or("unknown".to_string(), |ip| ip.to_string());
70                            ctx.speak(format!("Hosting. Your address is {address}"));
71                            Self::start_game(ctx);
72                        }
73                        Err(e) => ctx.ui.message("error", e.to_string()),
74                    }
75                }
76                "join" => {
77                    ctx.net.set_name(&self.name);
78                    ctx.net.join(&self.address);
79                    ctx.speak(format!("Connecting to {}", self.address));
80                }
81                "quit" => ctx.quit(),
82                _ => {}
83            },
84            _ => {}
85        }
86    }

Trait Implementations§

Source§

impl Debug for Net

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for Net

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl !Sync for Net

§

impl Freeze for Net

§

impl RefUnwindSafe for Net

§

impl Send for Net

§

impl Unpin for Net

§

impl UnsafeUnpin for Net

§

impl UnwindSafe for Net

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more