Skip to content

Commit 11c9684

Browse files
author
Bazzirovan
committed
fix(rapier): don't panic on JNI calls referencing removed physics bodies
Replace expect()/index panics in the rapier JNI bridge with Option guards. A Rust panic crossing the JNI boundary aborts the whole JVM, which on a dedicated server manifests as instant shutdowns or ServerHangWatchdog freezes whenever a rigid body, kinematic contraption or joint endpoint was already removed (e.g. sublevel unload races) but is still referenced by a pending JNI call. - get_rigid_body(_mut): return Option instead of expect() - getPose: fall back to identity pose instead of panicking - removeSubLevel/removeBox/removeKinematicContraption: no-op if missing - setMassProperties/teleport/wakeUp/velocities/forces: no-op if missing - createKinematicContraption: drop mount reference if mount id is stale - add*Constraint: return invalid handle (0) if an endpoint is missing - rope tick: drop rope attachments whose endpoint collider is gone Verified on a live dedicated server (Windows): rope/sublevel crashes and native step hangs are gone after rebuilding the natives with this patch.
1 parent 550e644 commit 11c9684

5 files changed

Lines changed: 124 additions & 77 deletions

File tree

sable_rapier/src/main/rust/rapier/src/boxes.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_rem
8181
let sim_data = &mut *sim_data;
8282
let mut sable_data = scene.sable_data.write().unwrap();
8383

84-
let handle = sable_data.rigid_bodies[&(id as LevelColliderID)];
84+
let Some(handle) = sable_data.rigid_bodies.get(&(id as LevelColliderID)) else {
85+
return;
86+
};
87+
let handle = *handle;
8588
sim_data.rigid_body_set.remove(
8689
handle,
8790
&mut sim_data.island_manager,

sable_rapier/src/main/rust/rapier/src/contraptions.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,8 @@ macro_rules! extract_jint_array {
3636
fn get_kinematic_collider_info(
3737
sable: &mut SableSceneData,
3838
id: jint,
39-
) -> &mut ActiveLevelColliderInfo {
40-
sable
41-
.level_colliders
42-
.get_mut(&(id as LevelColliderID))
43-
.expect("No kinematic contraption with given ID!")
39+
) -> Option<&mut ActiveLevelColliderInfo> {
40+
sable.level_colliders.get_mut(&(id as LevelColliderID))
4441
}
4542

4643
#[unsafe(no_mangle)]
@@ -61,17 +58,16 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_cre
6158

6259
let should_be_static = mount_id == -1;
6360
let mount_rigid_body = if should_be_static {
64-
let new_body = sim_data
65-
.rigid_body_set
66-
.insert(RigidBodyBuilder::kinematic_position_based());
67-
Some(new_body)
68-
} else {
6961
Some(
70-
*sable_data
71-
.rigid_bodies
72-
.get(&(mount_id as LevelColliderID))
73-
.unwrap(),
62+
sim_data
63+
.rigid_body_set
64+
.insert(RigidBodyBuilder::kinematic_position_based()),
7465
)
66+
} else {
67+
sable_data
68+
.rigid_bodies
69+
.get(&(mount_id as LevelColliderID))
70+
.copied()
7571
};
7672

7773
let mount_rigid_body: RigidBodyHandle = if let Some(body) = mount_rigid_body {
@@ -140,7 +136,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_set
140136
let mut sim_data = scene.sim_data.write().unwrap();
141137
let mut sable_data = scene.sable_data.write().unwrap();
142138

143-
let info = get_kinematic_collider_info(&mut sable_data, id);
139+
let Some(info) = get_kinematic_collider_info(&mut sable_data, id) else {
140+
return;
141+
};
144142
let collider_handle = info.collider;
145143

146144
let collider = sim_data.collider_set.get_mut(collider_handle);
@@ -218,7 +216,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
218216

219217
with_handle(handle, |scene| {
220218
let mut sable_data = scene.sable_data.write().unwrap();
221-
let info = get_kinematic_collider_info(&mut sable_data, id);
219+
let Some(info) = get_kinematic_collider_info(&mut sable_data, id) else {
220+
return;
221+
};
222222
if let Some(chunk_map) = &mut info.chunk_map {
223223
chunk_map.insert(crate::scene::pack_section_pos(x, y, z), chunk);
224224
}
@@ -240,8 +240,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_rem
240240
let sim_data = &mut *sim_data;
241241
let mut sable_data = scene.sable_data.write().unwrap();
242242

243-
let info = sable_data.level_colliders.remove(&(id as LevelColliderID));
244-
let info = info.unwrap();
243+
let Some(info) = sable_data.level_colliders.remove(&(id as LevelColliderID)) else {
244+
return;
245+
};
245246

246247
sim_data.collider_set.remove(
247248
info.collider,

sable_rapier/src/main/rust/rapier/src/joints.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,19 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
329329
let rb_a = if id_a == -1 {
330330
scene.ground_handle.unwrap()
331331
} else {
332-
sable_data.rigid_bodies[&(id_a as LevelColliderID)]
332+
let Some(rb) = sable_data.rigid_bodies.get(&(id_a as LevelColliderID)) else {
333+
return 0;
334+
};
335+
*rb
333336
};
334337

335338
let rb_b = if id_b == -1 {
336339
scene.ground_handle.unwrap()
337340
} else {
338-
sable_data.rigid_bodies[&(id_b as LevelColliderID)]
341+
let Some(rb) = sable_data.rigid_bodies.get(&(id_b as LevelColliderID)) else {
342+
return 0;
343+
};
344+
*rb
339345
};
340346

341347
let revolute = RevoluteJointBuilder::new(
@@ -416,13 +422,19 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
416422
let rb_a = if id_a == -1 {
417423
scene.ground_handle.unwrap()
418424
} else {
419-
sable_data.rigid_bodies[&(id_a as LevelColliderID)]
425+
let Some(rb) = sable_data.rigid_bodies.get(&(id_a as LevelColliderID)) else {
426+
return 0;
427+
};
428+
*rb
420429
};
421430

422431
let rb_b = if id_b == -1 {
423432
scene.ground_handle.unwrap()
424433
} else {
425-
sable_data.rigid_bodies[&(id_b as LevelColliderID)]
434+
let Some(rb) = sable_data.rigid_bodies.get(&(id_b as LevelColliderID)) else {
435+
return 0;
436+
};
437+
*rb
426438
};
427439

428440
let quat = Quat::from_xyzw(
@@ -508,13 +520,19 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
508520
let rb_a = if id_a == -1 {
509521
scene.ground_handle.unwrap()
510522
} else {
511-
sable_data.rigid_bodies[&(id_a as LevelColliderID)]
523+
let Some(rb) = sable_data.rigid_bodies.get(&(id_a as LevelColliderID)) else {
524+
return 0;
525+
};
526+
*rb
512527
};
513528

514529
let rb_b = if id_b == -1 {
515530
scene.ground_handle.unwrap()
516531
} else {
517-
sable_data.rigid_bodies[&(id_b as LevelColliderID)]
532+
let Some(rb) = sable_data.rigid_bodies.get(&(id_b as LevelColliderID)) else {
533+
return 0;
534+
};
535+
*rb
518536
};
519537

520538
let mut joint = GenericJointBuilder::new(JointAxesMask::empty()).softness(
@@ -602,13 +620,19 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
602620
let rb_a = if id_a == -1 {
603621
scene.ground_handle.unwrap()
604622
} else {
605-
sable_data.rigid_bodies[&(id_a as LevelColliderID)]
623+
let Some(rb) = sable_data.rigid_bodies.get(&(id_a as LevelColliderID)) else {
624+
return 0;
625+
};
626+
*rb
606627
};
607628

608629
let rb_b = if id_b == -1 {
609630
scene.ground_handle.unwrap()
610631
} else {
611-
sable_data.rigid_bodies[&(id_b as LevelColliderID)]
632+
let Some(rb) = sable_data.rigid_bodies.get(&(id_b as LevelColliderID)) else {
633+
return 0;
634+
};
635+
*rb
612636
};
613637

614638
let locked_axes = JointAxesMask::from_bits_truncate(locked_axes_mask as u8);

sable_rapier/src/main/rust/rapier/src/lib.rs

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -282,25 +282,19 @@ pub fn get_rigid_body_mut<'a>(
282282
sim: &'a mut SimulationSceneData,
283283
sable_data: &SableSceneData,
284284
id: LevelColliderID,
285-
) -> &'a mut RigidBody {
286-
let handle = sable_data
287-
.rigid_bodies
288-
.get(&id)
289-
.expect("No rigid body for id");
290-
&mut sim.rigid_body_set[*handle]
285+
) -> Option<&'a mut RigidBody> {
286+
let handle = sable_data.rigid_bodies.get(&id)?;
287+
sim.rigid_body_set.get_mut(*handle)
291288
}
292289

293290
#[inline(always)]
294291
pub fn get_rigid_body<'a>(
295292
sim: &'a SimulationSceneData,
296293
sable_data: &SableSceneData,
297294
id: LevelColliderID,
298-
) -> &'a RigidBody {
299-
let handle = sable_data
300-
.rigid_bodies
301-
.get(&id)
302-
.expect("No rigid body for id");
303-
&sim.rigid_body_set[*handle]
295+
) -> Option<&'a RigidBody> {
296+
let handle = sable_data.rigid_bodies.get(&id)?;
297+
sim.rigid_body_set.get(*handle)
304298
}
305299

306300
#[unsafe(no_mangle)]
@@ -527,18 +521,22 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_get
527521
let sable_data = scene.sable_data.read().unwrap();
528522
let sim_data = scene.sim_data.read().unwrap();
529523

530-
let rb: &RigidBody =
531-
&sim_data.rigid_body_set[sable_data.rigid_bodies[&(id as LevelColliderID)]];
532-
533-
let arr: [jdouble; 7] = [
534-
rb.translation().x as jdouble,
535-
rb.translation().y as jdouble,
536-
rb.translation().z as jdouble,
537-
rb.rotation().x as jdouble,
538-
rb.rotation().y as jdouble,
539-
rb.rotation().z as jdouble,
540-
rb.rotation().w as jdouble,
541-
];
524+
let arr: [jdouble; 7] = match sable_data
525+
.rigid_bodies
526+
.get(&(id as LevelColliderID))
527+
.and_then(|body| sim_data.rigid_body_set.get(*body))
528+
{
529+
Some(rb) => [
530+
rb.translation().x as jdouble,
531+
rb.translation().y as jdouble,
532+
rb.translation().z as jdouble,
533+
rb.rotation().x as jdouble,
534+
rb.rotation().y as jdouble,
535+
rb.rotation().z as jdouble,
536+
rb.rotation().w as jdouble,
537+
],
538+
None => [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
539+
};
542540

543541
env.set_double_array_region(&store, 0, &arr).unwrap();
544542
})
@@ -691,10 +689,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_rem
691689
let mut sable_data = scene.sable_data.write().unwrap();
692690

693691
sable_data.level_colliders.remove(&(id as LevelColliderID));
694-
let handle = sable_data
695-
.rigid_bodies
696-
.remove(&(id as LevelColliderID))
697-
.expect("No rigid body for id");
692+
let Some(handle) = sable_data.rigid_bodies.remove(&(id as LevelColliderID)) else {
693+
return;
694+
};
698695

699696
let mut sim_data = scene.sim_data.write().unwrap();
700697

@@ -1112,7 +1109,13 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_set
11121109
let sable_data = scene.sable_data.read().unwrap();
11131110
let mut sim_data = scene.sim_data.write().unwrap();
11141111

1115-
let rb = &mut sim_data.rigid_body_set[sable_data.rigid_bodies[&(id as LevelColliderID)]];
1112+
let Some(rb) = sable_data
1113+
.rigid_bodies
1114+
.get(&(id as LevelColliderID))
1115+
.and_then(|body| sim_data.rigid_body_set.get_mut(*body))
1116+
else {
1117+
return;
1118+
};
11161119

11171120
rb.set_additional_mass_properties(
11181121
MassProperties::with_inertia_matrix(Vec3::ZERO, mass as Real, inertia_tensor.into()),
@@ -1142,7 +1145,13 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_tel
11421145
let sable_data = scene.sable_data.read().unwrap();
11431146
let mut sim_data = scene.sim_data.write().unwrap();
11441147

1145-
let rb = &mut sim_data.rigid_body_set[sable_data.rigid_bodies[&(id as LevelColliderID)]];
1148+
let Some(rb) = sable_data
1149+
.rigid_bodies
1150+
.get(&(id as LevelColliderID))
1151+
.and_then(|body| sim_data.rigid_body_set.get_mut(*body))
1152+
else {
1153+
return;
1154+
};
11461155

11471156
let mut pose = *rb.position();
11481157
pose.translation = Vec3::new(x as Real, y as Real, z as Real);
@@ -1164,7 +1173,13 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_wak
11641173
with_handle(handle, |scene| {
11651174
let sable_data = scene.sable_data.read().unwrap();
11661175
let mut sim_data = scene.sim_data.write().unwrap();
1167-
let rb = &mut sim_data.rigid_body_set[sable_data.rigid_bodies[&(id as LevelColliderID)]];
1176+
let Some(rb) = sable_data
1177+
.rigid_bodies
1178+
.get(&(id as LevelColliderID))
1179+
.and_then(|body| sim_data.rigid_body_set.get_mut(*body))
1180+
else {
1181+
return;
1182+
};
11681183
rb.wake_up(true);
11691184
})
11701185
}
@@ -1188,7 +1203,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_add
11881203
with_handle(handle, |scene| {
11891204
let sable_data = scene.sable_data.read().unwrap();
11901205
let mut sim_data = scene.sim_data.write().unwrap();
1191-
let rb = get_rigid_body_mut(&mut sim_data, &sable_data, id as LevelColliderID);
1206+
let Some(rb) = get_rigid_body_mut(&mut sim_data, &sable_data, id as LevelColliderID) else {
1207+
return;
1208+
};
11921209

11931210
if wake_up == 0 && rb.is_sleeping() {
11941211
return;
@@ -1288,10 +1305,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_app
12881305
let sable_data = scene.sable_data.read().unwrap();
12891306
let mut sim_data = scene.sim_data.write().unwrap();
12901307

1291-
let body = sable_data
1292-
.rigid_bodies
1293-
.get(&(id as LevelColliderID))
1294-
.unwrap();
1308+
let Some(body) = sable_data.rigid_bodies.get(&(id as LevelColliderID)) else {
1309+
return;
1310+
};
12951311
let rb = &mut sim_data.rigid_body_set[*body];
12961312

12971313
if wake_up == 0 && rb.is_sleeping() {
@@ -1333,10 +1349,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_app
13331349
let sable_data = scene.sable_data.read().unwrap();
13341350
let mut sim_data = scene.sim_data.write().unwrap();
13351351

1336-
let body = sable_data
1337-
.rigid_bodies
1338-
.get(&(id as LevelColliderID))
1339-
.unwrap();
1352+
let Some(body) = sable_data.rigid_bodies.get(&(id as LevelColliderID)) else {
1353+
return;
1354+
};
13401355
let rb = &mut sim_data.rigid_body_set[*body];
13411356

13421357
if wake_up == 0 && rb.is_sleeping() {
@@ -1370,10 +1385,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_get
13701385
let sable_data = scene.sable_data.read().unwrap();
13711386
let sim_data = scene.sim_data.read().unwrap();
13721387

1373-
let body = sable_data
1374-
.rigid_bodies
1375-
.get(&(id as LevelColliderID))
1376-
.unwrap();
1388+
let Some(body) = sable_data.rigid_bodies.get(&(id as LevelColliderID)) else {
1389+
return;
1390+
};
13771391
let rb = &sim_data.rigid_body_set[*body];
13781392

13791393
let vel = rb.linvel();
@@ -1402,10 +1416,9 @@ pub extern "system" fn Java_dev_ryanhcode_sable_physics_impl_rapier_Rapier3D_get
14021416
let sable_data = scene.sable_data.read().unwrap();
14031417
let sim_data = scene.sim_data.read().unwrap();
14041418

1405-
let body = sable_data
1406-
.rigid_bodies
1407-
.get(&(id as LevelColliderID))
1408-
.unwrap();
1419+
let Some(body) = sable_data.rigid_bodies.get(&(id as LevelColliderID)) else {
1420+
return;
1421+
};
14091422
let rb = &sim_data.rigid_body_set[*body];
14101423

14111424
let vel = rb.angvel();

sable_rapier/src/main/rust/rapier/src/rope.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ pub fn tick(scene: &PhysicsScene) {
5151

5252
for (id, rope) in sable_data.rope_map.ropes.iter() {
5353
if let Some(attachment) = &rope.start_attachment {
54-
if !sim.impulse_joint_set.contains(attachment.joint) {
54+
let endpoint_gone = attachment
55+
.sub_level_id
56+
.is_some_and(|id_b| !sable_data.level_colliders.contains_key(&id_b));
57+
if !sim.impulse_joint_set.contains(attachment.joint) || endpoint_gone {
5558
dead_start_attachments.push(id.clone());
5659
} else {
5760
let local_anchor = attachment.location
@@ -71,7 +74,10 @@ pub fn tick(scene: &PhysicsScene) {
7174
}
7275

7376
if let Some(attachment) = &rope.end_attachment {
74-
if !sim.impulse_joint_set.contains(attachment.joint) {
77+
let endpoint_gone = attachment
78+
.sub_level_id
79+
.is_some_and(|id_b| !sable_data.level_colliders.contains_key(&id_b));
80+
if !sim.impulse_joint_set.contains(attachment.joint) || endpoint_gone {
7581
dead_end_attachments.push(id.clone());
7682
} else {
7783
let local_anchor = attachment.location

0 commit comments

Comments
 (0)