Fix spectator explosion immunity and TNT fuse underflow (#1587) (#1588)

* made it so spectators don't take knockback from explosions

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* fix(tnt): prevent fuse underflow

Underflow Prevention: By checking if current_fuse <= 1 before subtracting, we ensure the fuse never rolls over from 0 to 4,294,967,295.

Instant Summon Fix: If a player uses /summon tnt and the fuse is somehow initialized to 0, it will now explode on the very first tick instead of bouncing forever.


Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* fix

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* Update explosion.rs

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* fixes

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* fix spectator check

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* fix

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

* CLIPPY

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>

---------

Signed-off-by: Musawer <118316797+TheRealMusawer@users.noreply.github.com>
This commit is contained in:
Musawer
2026-02-18 22:50:23 -05:00
committed by GitHub
parent bce7359d4c
commit 59b7e0a14e
2 changed files with 18 additions and 7 deletions

View File

@@ -49,19 +49,21 @@ impl EntityBase for TNTEntity {
entity.move_entity(caller.clone(), velo).await;
entity.tick_block_collisions(&caller, server).await;
entity.velocity.store(velo.multiply(0.98, 0.98, 0.98));
if entity.on_ground.load(Ordering::Relaxed) {
entity.velocity.store(velo.multiply(0.7, -0.5, 0.7));
}
let velocity_dirty = entity.velocity_dirty.swap(false, Ordering::SeqCst);
if velocity_dirty {
if entity.velocity_dirty.swap(false, Ordering::SeqCst) {
entity.send_pos_rot().await;
entity.send_velocity().await;
}
let fuse = self.fuse.fetch_sub(1, Relaxed);
if fuse == 0 {
// FIX: Prevent fuse underflow (vanilla parity)
let fuse = self.fuse.load(Relaxed);
if fuse <= 1 {
// TNT explodes now
self.entity.remove().await;
self.entity
.world
@@ -69,6 +71,8 @@ impl EntityBase for TNTEntity {
.explode(self.entity.pos.load(), self.power)
.await;
} else {
// Safe decrement
self.fuse.store(fuse - 1, Relaxed);
entity.update_fluid_state(&caller).await;
}
})
@@ -76,13 +80,12 @@ impl EntityBase for TNTEntity {
fn init_data_tracker(&self) -> EntityBaseFuture<'_, ()> {
Box::pin(async {
// TODO: Yes, this is the wrong function, but we need to send this after spawning the entity.
let pos: f64 = rand::random::<f64>() * TAU;
self.entity
.set_velocity(Vector3::new(-pos.sin() * 0.02, 0.2, -pos.cos() * 0.02))
.await;
// We can merge multiple `Metadata`s into one meta packet.
self.entity
.send_meta_data(&[
Metadata::new(

View File

@@ -16,11 +16,13 @@ pub struct Explosion {
power: f32,
pos: Vector3<f64>,
}
impl Explosion {
#[must_use]
pub const fn new(power: f32, pos: Vector3<f64>) -> Self {
Self { power, pos }
}
async fn get_blocks_to_destroy(
&self,
world: &World,
@@ -103,6 +105,12 @@ impl Explosion {
if entity_base.is_immune_to_explosion() {
continue;
}
// Skip spectators (no damage, no knockback)
if entity_base.is_spectator() {
continue;
}
let entity = entity_base.get_entity();
let distance = (entity.pos.load().squared_distance_to_vec(&self.pos)).sqrt() / radius;