Skip to content

Commit 0988454

Browse files
authored
Merge pull request #7 from firefly-zero/net
Multiplayer
2 parents 8a5e91a + 8944861 commit 0988454

File tree

5 files changed

+150
-84
lines changed

5 files changed

+150
-84
lines changed

src/bindings.rs

-23
Original file line numberDiff line numberDiff line change
@@ -1,24 +1 @@
1-
#[link(wasm_import_module = "fs")]
2-
extern {
3-
pub(crate) fn get_rom_file_size(path_ptr: u32, path_len: u32) -> u32;
4-
pub(crate) fn get_file_size(path_ptr: u32, path_len: u32) -> u32;
5-
pub(crate) fn load_rom_file(path_ptr: u32, path_len: u32, buf_ptr: u32, buf_len: u32) -> u32;
6-
pub(crate) fn load_file(path_ptr: u32, path_len: u32, buf_ptr: u32, buf_len: u32) -> u32;
7-
pub(crate) fn dump_file(path_ptr: u32, path_len: u32, buf_ptr: u32, buf_len: u32) -> u32;
8-
pub(crate) fn remove_file(path_ptr: u32, path_len: u32);
9-
}
101

11-
#[link(wasm_import_module = "input")]
12-
extern {
13-
pub(crate) fn read_pad(player: u32) -> u32;
14-
pub(crate) fn read_buttons(player: u32) -> u32;
15-
}
16-
17-
#[link(wasm_import_module = "misc")]
18-
extern {
19-
pub(crate) fn log_debug(ptr: u32, len: u32);
20-
pub(crate) fn log_error(ptr: u32, len: u32);
21-
pub(crate) fn set_seed(seed: u32);
22-
pub(crate) fn get_random() -> u32;
23-
pub(crate) fn quit();
24-
}

src/fs.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,14 @@ impl<'a> File<'a> {
6767
/// Functions for accessing files in the app ROM.
6868
pub mod rom {
6969
use super::*;
70-
use crate::bindings as b;
7170

7271
/// Determine the required size (in bytes) to store the given file.
7372
///
7473
/// If the file does not exist, 0 is returned.
7574
#[must_use]
7675
pub fn get_size(name: &str) -> usize {
7776
let path_ptr = name.as_ptr();
78-
let size = unsafe { b::get_rom_file_size(path_ptr as u32, name.len() as u32) };
77+
let size = unsafe { bindings::get_rom_file_size(path_ptr as u32, name.len() as u32) };
7978
size as usize
8079
}
8180

@@ -87,7 +86,7 @@ pub mod rom {
8786
let path_ptr = name.as_ptr();
8887
let buf_ptr = buf.as_mut_ptr();
8988
unsafe {
90-
b::load_rom_file(
89+
bindings::load_rom_file(
9190
path_ptr as u32,
9291
name.len() as u32,
9392
buf_ptr as u32,
@@ -123,15 +122,14 @@ pub mod rom {
123122
/// The device owner may empty this dir if they wish to remove the app data.
124123
pub mod data {
125124
use super::*;
126-
use crate::bindings as b;
127125

128126
/// Get a file size in the data dir.
129127
///
130128
/// If the file does not exist, 0 is returned.
131129
#[must_use]
132130
pub fn get_size(name: &str) -> usize {
133131
let path_ptr = name.as_ptr();
134-
let size = unsafe { b::get_file_size(path_ptr as u32, name.len() as u32) };
132+
let size = unsafe { bindings::get_file_size(path_ptr as u32, name.len() as u32) };
135133
size as usize
136134
}
137135

@@ -143,7 +141,7 @@ pub mod data {
143141
let path_ptr = name.as_ptr();
144142
let buf_ptr = buf.as_mut_ptr();
145143
unsafe {
146-
b::load_file(
144+
bindings::load_file(
147145
path_ptr as u32,
148146
name.len() as u32,
149147
buf_ptr as u32,
@@ -178,7 +176,7 @@ pub mod data {
178176
let path_ptr = name.as_ptr();
179177
let buf_ptr = buf.as_ptr();
180178
unsafe {
181-
b::dump_file(
179+
bindings::dump_file(
182180
path_ptr as u32,
183181
name.len() as u32,
184182
buf_ptr as u32,
@@ -191,7 +189,7 @@ pub mod data {
191189
pub fn remove(name: &str) {
192190
let path_ptr = name.as_ptr();
193191
unsafe {
194-
b::remove_file(path_ptr as u32, name.len() as u32);
192+
bindings::remove_file(path_ptr as u32, name.len() as u32);
195193
}
196194
}
197195
}
@@ -256,3 +254,20 @@ pub struct SubImage<'a> {
256254
pub(crate) size: Size,
257255
pub(crate) raw: &'a [u8],
258256
}
257+
258+
mod bindings {
259+
#[link(wasm_import_module = "fs")]
260+
extern {
261+
pub(crate) fn get_rom_file_size(path_ptr: u32, path_len: u32) -> u32;
262+
pub(crate) fn get_file_size(path_ptr: u32, path_len: u32) -> u32;
263+
pub(crate) fn load_rom_file(
264+
path_ptr: u32,
265+
path_len: u32,
266+
buf_ptr: u32,
267+
buf_len: u32,
268+
) -> u32;
269+
pub(crate) fn load_file(path_ptr: u32, path_len: u32, buf_ptr: u32, buf_len: u32) -> u32;
270+
pub(crate) fn dump_file(path_ptr: u32, path_len: u32, buf_ptr: u32, buf_len: u32) -> u32;
271+
pub(crate) fn remove_file(path_ptr: u32, path_len: u32);
272+
}
273+
}

src/input.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Read inputs: touch pad, buttons, accelerometer.
22
3-
use crate::{bindings as b, *};
3+
use crate::*;
44

55
const DPAD_THRESHOLD: i32 = 100;
66

@@ -203,11 +203,10 @@ impl Buttons {
203203
}
204204

205205
/// Get the current touch pad state.
206-
///
207-
/// In singleplayer game, the player ID doesn't matter.
208206
#[must_use]
209-
pub fn read_pad(player: Player) -> Option<Pad> {
210-
let raw = unsafe { b::read_pad(player.into()) };
207+
pub fn read_pad(p: Peer) -> Option<Pad> {
208+
let p = u32::from(p.0);
209+
let raw = unsafe { bindings::read_pad(p) };
211210
if raw == 0xffff {
212211
None
213212
} else {
@@ -219,11 +218,10 @@ pub fn read_pad(player: Player) -> Option<Pad> {
219218
}
220219

221220
/// Get the currently pressed buttons.
222-
///
223-
/// In singleplayer game, the player ID doesn't matter.
224221
#[must_use]
225-
pub fn read_buttons(player: Player) -> Buttons {
226-
let raw = unsafe { b::read_buttons(player.into()) };
222+
pub fn read_buttons(p: Peer) -> Buttons {
223+
let p = u32::from(p.0);
224+
let raw = unsafe { bindings::read_buttons(p) };
227225
Buttons {
228226
a: has_bit_set(raw, 0),
229227
b: has_bit_set(raw, 1),
@@ -238,3 +236,11 @@ pub fn read_buttons(player: Player) -> Buttons {
238236
fn has_bit_set(val: u32, bit: usize) -> bool {
239237
(val >> bit) & 0b1 != 0
240238
}
239+
240+
mod bindings {
241+
#[link(wasm_import_module = "input")]
242+
extern {
243+
pub(crate) fn read_pad(peer: u32) -> u32;
244+
pub(crate) fn read_buttons(peer: u32) -> u32;
245+
}
246+
}

src/misc.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
use crate::bindings as b;
2-
31
/// Log a debug message.
42
pub fn log_debug(t: &str) {
53
let ptr = t.as_ptr() as u32;
64
let len = t.len() as u32;
75
unsafe {
8-
b::log_debug(ptr, len);
6+
bindings::log_debug(ptr, len);
97
}
108
}
119

@@ -14,24 +12,35 @@ pub fn log_error(t: &str) {
1412
let ptr = t.as_ptr() as u32;
1513
let len = t.len() as u32;
1614
unsafe {
17-
b::log_error(ptr, len);
15+
bindings::log_error(ptr, len);
1816
}
1917
}
2018

2119
/// Set the random seed.
2220
pub fn set_seed(seed: u32) {
2321
unsafe {
24-
b::set_seed(seed);
22+
bindings::set_seed(seed);
2523
}
2624
}
2725

2826
/// Get a random value.
2927
#[must_use]
3028
pub fn get_random() -> u32 {
31-
unsafe { b::get_random() }
29+
unsafe { bindings::get_random() }
3230
}
3331

3432
/// Exit the app after the current update is finished.
3533
pub fn quit() {
36-
unsafe { b::quit() }
34+
unsafe { bindings::quit() }
35+
}
36+
37+
mod bindings {
38+
#[link(wasm_import_module = "misc")]
39+
extern {
40+
pub(crate) fn log_debug(ptr: u32, len: u32);
41+
pub(crate) fn log_error(ptr: u32, len: u32);
42+
pub(crate) fn set_seed(seed: u32);
43+
pub(crate) fn get_random() -> u32;
44+
pub(crate) fn quit();
45+
}
3746
}

src/net.rs

+96-37
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,114 @@
1-
/// The player ID.
1+
// The peer ID.
22
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
3-
pub enum Player {
4-
P0,
5-
P1,
6-
P2,
7-
P3,
3+
pub struct Peer(pub(crate) u8);
4+
5+
impl Peer {
6+
pub const COMBINED: Self = Peer(0xFF);
87
}
98

10-
impl Player {
11-
/// Get all players.
12-
#[inline]
9+
/// The list of peers online.
10+
///
11+
/// Includes all connected peers as well as the local device.
12+
///
13+
/// The order is deterministic between calls and between runs.
14+
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
15+
pub struct Peers(pub(crate) u32);
16+
17+
impl Peers {
18+
/// Iterate over peers.
1319
#[must_use]
14-
pub fn all() -> [Player; 4] {
15-
use Player::{P0, P1, P2, P3};
16-
[P0, P1, P2, P3]
20+
pub fn iter(&self) -> PeersIter {
21+
PeersIter {
22+
peer: 0,
23+
peers: self.0,
24+
}
1725
}
1826

19-
/// Get all players except this one.
27+
/// Check if the given peer is online.
2028
#[must_use]
21-
pub fn others(&self) -> [Player; 3] {
22-
use Player::{P0, P1, P2, P3};
23-
match self {
24-
P0 => [P1, P2, P3],
25-
P1 => [P0, P2, P3],
26-
P2 => [P0, P1, P3],
27-
P3 => [P0, P1, P2],
28-
}
29+
pub fn contains(&self, p: &Peer) -> bool {
30+
self.0 >> p.0 & 1 != 0
31+
}
32+
33+
/// Get the number of peers online.
34+
///
35+
/// Never zero. 1 for local single-player game. 2 or more for multiplayer.
36+
#[must_use]
37+
#[allow(clippy::len_without_is_empty)] // always non-empty
38+
pub fn len(&self) -> usize {
39+
self.0.count_ones() as usize
40+
}
41+
42+
/// Convert the list of peers into a vector.
43+
#[cfg(feature = "alloc")]
44+
#[must_use]
45+
pub fn as_vec(&self) -> alloc::vec::Vec<Peer> {
46+
self.iter().collect()
2947
}
3048
}
3149

32-
impl From<Player> for u32 {
33-
fn from(value: Player) -> Self {
34-
match value {
35-
Player::P0 => 0,
36-
Player::P1 => 1,
37-
Player::P2 => 2,
38-
Player::P3 => 3,
50+
impl IntoIterator for Peers {
51+
type Item = Peer;
52+
type IntoIter = PeersIter;
53+
54+
fn into_iter(self) -> Self::IntoIter {
55+
PeersIter {
56+
peer: 0,
57+
peers: self.0,
3958
}
4059
}
4160
}
4261

43-
impl TryFrom<usize> for Player {
44-
type Error = ();
62+
pub struct PeersIter {
63+
peer: u8,
64+
peers: u32,
65+
}
66+
67+
impl Iterator for PeersIter {
68+
type Item = Peer;
4569

46-
fn try_from(value: usize) -> Result<Self, Self::Error> {
47-
match value {
48-
0 => Ok(Player::P0),
49-
1 => Ok(Player::P1),
50-
2 => Ok(Player::P2),
51-
3 => Ok(Player::P3),
52-
_ => Err(()),
70+
fn next(&mut self) -> Option<Self::Item> {
71+
while self.peers != 0 {
72+
let peer = self.peer;
73+
let peers = self.peers;
74+
self.peer += 1;
75+
self.peers >>= 1;
76+
if peers & 1 != 0 {
77+
return Some(Peer(peer));
78+
}
5379
}
80+
None
81+
}
82+
83+
fn size_hint(&self) -> (usize, Option<usize>) {
84+
let size = self.peers.count_ones() as usize;
85+
(size, Some(size))
86+
}
87+
88+
fn count(self) -> usize {
89+
self.peers.count_ones() as usize
90+
}
91+
}
92+
93+
/// Get the peer cirresponding to the local device.
94+
#[must_use]
95+
pub fn get_me() -> Peer {
96+
let me = unsafe { bindings::get_me() };
97+
Peer(me as u8)
98+
}
99+
100+
/// Get the list of peers online.
101+
#[must_use]
102+
pub fn get_peers() -> Peers {
103+
let peers = unsafe { bindings::get_peers() };
104+
Peers(peers)
105+
}
106+
107+
/// Internal bindings to the raw runtime functions.
108+
mod bindings {
109+
#[link(wasm_import_module = "net")]
110+
extern {
111+
pub(crate) fn get_me() -> u32;
112+
pub(crate) fn get_peers() -> u32;
54113
}
55114
}

0 commit comments

Comments
 (0)