Allow multiplayer joins across different maps

This commit is contained in:
chazmm committed 2026-09-09 03:54:36 +01:00
1 parent 09e00d758a
commit ec68000364
6 files changed
+24 -16

No files matched your search

+1 -1
View File
@@ -599,7 +599,7 @@ fn labels(
if r.compatible {
""
} else {
" | different map/build"
" | incompatible physics/protocol"
}
)
})
+1 -1
View File
@@ -202,7 +202,7 @@ impl Multiplayer {
};
if !row.compatible {
self.browser_status =
"Different map/build. Load the matching map before joining.".into();
"Incompatible physics or multiplayer protocol. Use compatible game versions.".into();
return;
}
if row.players >= row.capacity {
+2 -4
View File
@@ -287,9 +287,8 @@ impl Session {
return;
}
let own = self.local_info();
let error = if info.map != own.map {
1
} else if info.physics != own.physics {
// Map identity is descriptive; joining different worlds is allowed.
let error = if info.physics != own.physics {
2
} else if !self.links.contains_key(&peer) && self.links.len() >= MAX_PLAYERS - 1 {
3
@@ -345,7 +344,6 @@ impl Session {
};
if info.id == 0
|| infos.iter().any(|i: &Info| i.id == info.id)
|| info.map != self.local_info().map
|| info.physics != self.local_info().physics
{
return;
+16 -5
View File
@@ -122,11 +122,6 @@ fn admission_full_lobby_mismatch_departure_and_rejoin() {
assert!(extra.notice.contains("full"));
assert!(!extra.connected());
let mut bad = info(12);
bad.map = 88;
let mut guest = Session::new(1, bad, Some(1));
exchange(&mut host, &mut guest, 12, 1200);
assert!(guest.notice.contains("Map"));
bad.map = 1;
bad.physics = 99;
let mut guest = Session::new(1, bad, Some(1));
exchange(&mut host, &mut guest, 12, 1300);
@@ -264,3 +259,19 @@ fn occupied_driver_flag_preserves_root_without_native_collision_parts() {
assert_eq!(decoded.enabled,1u64<<62);assert_eq!(decoded.root.p,frame.root.p);
frame.enabled=1u64<<61;assert!(Packed::body(&frame).is_none());
}
#[test]
fn different_maps_can_join_and_exchange_body_updates() {
let mut host = Session::new(1, info(1), None);
let mut other = info(2);
other.map = 88;
let mut guest = Session::new(1, other, Some(1));
exchange(&mut host, &mut guest, 2, 100);
assert!(guest.connected());
assert_eq!(host.actors[&2].info.map, 88);
host.publish(packed::BODY, Packed::body(&body()).unwrap(), 150);
guest.publish(packed::BODY, Packed::body(&body()).unwrap(), 150);
exchange(&mut host, &mut guest, 2, 200);
assert!(host.actors[&2].body.latest().is_some());
assert!(guest.actors[&1].body.latest().is_some());
}
+2 -3
View File
@@ -124,9 +124,8 @@ impl Directory {
};
None
}
fn compatible(mm: &Matchmaking, l: LobbyId, map: u64, physics: u64) -> bool {
fn compatible(mm: &Matchmaking, l: LobbyId, _map: u64, physics: u64) -> bool {
mm.lobby_data(l, "sk8game").as_deref() == Some(directory::NAMESPACE)
&& mm.lobby_data(l, "map") == Some(map.to_string())
&& mm.lobby_data(l, "physics") == Some(physics.to_string())
}
fn owner_event(&mut self, mm: &Matchmaking, own: u64) -> Option<Event> {
@@ -212,7 +211,7 @@ impl Directory {
Ok(l) => {
if !Self::compatible(&mm, l, map, physics) {
mm.leave_lobby(l);
Event::Error("Different map, physics, or game version. Load the matching map/build first.".into())
Event::Error("Incompatible physics or multiplayer protocol. Use compatible game versions.".into())
} else {
self.lobby = Some(l);
self.owner_event(&mm, own)
+2 -2
View File
@@ -38,7 +38,7 @@ Test skating into each other, board impacts, tricks, bails, walking, board retri
## Online setup
On one PC choose **Esc > Multiplayer > Host via Steam / Spacewar**. On each other PC/account enter the same host code in the multiplayer menu and choose Join. Up to nine guests can join. Everyone needs this protocol version and the same map and physical definitions. Visual outfit/rig differences use the default skater. Unknown identifiers never become asset paths. An incompatible visual hierarchy uses the default idle pose instead of foreign bone indices.
On one PC choose **Esc > Multiplayer > Host via Steam / Spacewar**. On each other PC/account enter the same host code in the multiplayer menu and choose Join. Up to nine guests can join. Everyone needs compatible protocol and physical definitions. Map differences do not block joining; players on different maps can appear inside scenery or see different collisions. Visual outfit/rig differences use the default skater. Unknown identifiers never become asset paths. An incompatible visual hierarchy uses the default idle pose instead of foreign bone indices.
The host is an ordinary player, not a dedicated server. All guests connect to that host; it forwards the newest state to the other players. Transport, player IDs, codec, membership, budgets and rendering are independent of Steam. Spacewar/AppID 480 is the optional connection/relay provider. The game has no Steam DLL dependency and neither executable invokes Steam Input. Two processes under one Steam account still require the local launcher for testing.
@@ -79,7 +79,7 @@ The previous representative serializer used 117.6 kB/s per direction for one pee
The pause menu includes both Character customiser and Multiplayer. Offline map
changes use the in-process loader. Leave multiplayer before loading another map;
the loader cancels pending discovery/join requests and refreshes the map fingerprint
and physics schema before another session starts. Both players need matching maps.
and physics schema before another session starts. Matching maps are recommended but are not required to join.
The build helper links into its own staging directory while reusing the dependency
cache. Supply your prepared asset view through `-AssetRoot`. If using a separate