Add explosion knockback hook for players

This commit is contained in:
arismoko committed 2026-11-02 13:31:44 +00:00
1 parent c5c8a33a8a
commit e1084abe75
4 files changed
+41 -2

No files matched your search

+9 -2
View File
@@ -397,6 +397,7 @@ impl Game<'_> {
exploding: Option<u32>,
attacker: Option<&(u32, Text)>,
cause: Option<&horizon_client::advancements::EntityView>,
blocks: &[[i32; 3]],
) -> Option<[f64; 3]> {
let diameter = f64::from(radius * 2.0);
// Blast protection: `EXPLOSION_KNOCKBACK_RESISTANCE` (0.15 per level and
@@ -450,6 +451,10 @@ impl Game<'_> {
let flying = self.player.as_ref().is_some_and(|p| p.flying);
let mut outcome = horizon_client::health::BlockOutcome::default();
let mut pushed = None;
let mut push = [dir[0] * power, dir[1] * power, dir[2] * power];
if !spectator && !(creative && flying) {
self.native_explosion_knockback(self.dim.id(), center, blocks, None, &mut push);
}
// The death message names the blast's causing entity. It goes to this
// player's tracker, the host's or a guest's.
if let Some((id, name)) = attacker.filter(|_| !creative && !spectator && hurtable) {
@@ -482,7 +487,6 @@ impl Game<'_> {
}
}
if !spectator && !(creative && flying) {
let push = [dir[0] * power, dir[1] * power, dir[2] * power];
p.velocity = Vec3::new(
p.velocity.x + push[0],
p.velocity.y + push[1],
@@ -544,6 +548,7 @@ impl Game<'_> {
radius: f32,
damage_type: &str,
interaction: BlockInteraction,
blocks: &[[i32; 3]],
) -> Vec<(u32, [f64; 3])> {
if radius < 1.0e-5 {
return Vec::new();
@@ -575,6 +580,7 @@ impl Game<'_> {
exploding,
attacker.as_ref(),
blast_source.as_ref(),
blocks,
);
let mut pushed: Vec<_> = self.lan_acting.zip(own).into_iter().collect();
if let Some(mut host) = self.lan.take() {
@@ -594,6 +600,7 @@ impl Game<'_> {
exploding,
attacker.as_ref(),
blast_source.as_ref(),
blocks,
)
});
if let Some(Some(push)) = push {
@@ -871,7 +878,7 @@ impl Game<'_> {
let mut targets = self.exploded_positions(center, radius, resists);
let dimension = self.dim.id();
self.native_explosion_detonate(dimension, center, &mut targets);
let pushed = self.explosion_hurt_entities(center, radius, damage_type, interaction);
let pushed = self.explosion_hurt_entities(center, radius, damage_type, interaction, &targets);
if interaction != BlockInteraction::Keep {
// Util.shuffle(list, level.random)
for i in (2..=targets.len()).rev() {
@@ -5293,6 +5293,18 @@ impl Game<'_> {
) {
mod_api::dispatch_explosion_detonate(self, mod_api::mods(), dimension, center, blocks);
}
/// Server explosion knockback for `entity` (None for the acting player).
/// Replace the velocity added to its existing velocity. API @API:explosion_knockback@.
pub(super) fn native_explosion_knockback(
&mut self,
dimension: &str,
center: [f64; 3],
blocks: &[[i32; 3]],
entity: Option<u32>,
knockback_velocity: &mut [f64; 3],
) {
let _ = (dimension, center, blocks, entity, knockback_velocity);
}
/// A player fills (`stack` an empty bucket) or empties a bucket at `pos`:
/// `BucketItem.use`, where it asks `Level.mayInteract`. Set `canceled`
/// and the bucket does nothing. Server-side, for every player of the
+3
View File
@@ -1735,6 +1735,9 @@ For mods that run where the world is simulated: a dedicated server, a LAN host,
that is still there (`ServerLevel.tickBlock`), before its own `tick`; the same contract as `native_random_tick`.
- **`native_explosion_detonate(dimension, center, blocks)`** (API 22): the positions an explosion is about to break,
before any is hit; take out the ones to spare. Entities are hurt as before.
- **`native_explosion_knockback(dimension, center, blocks, entity, knockback_velocity)`**: a server explosion's
calculated velocity, before it is added to the entity. Replace `knockback_velocity` to change the push;
`entity` is None for the acting player. The player packet uses the same replacement.
- **`native_fill_bucket(stack, pos, canceled)`** and **`native_attack_entity(entity, kind, pos, canceled)`** (API 22):
a player's bucket at a block, and their blow on an entity, with the acting player swapped in. Canceled, the bucket
does nothing and the blow does no harm.
@@ -0,0 +1,17 @@
{
"hooks": [
{
"name": "explosion_knockback",
"target": "horizon_client::game::native_hooks::Game<'_>::native_explosion_knockback",
"neoforge": "ExplosionKnockbackEvent",
"side": "server",
"cancellable": false,
"mod_api": {
"contract": "replace",
"out": "knockback_velocity"
}
}
],
"rust_summary": "Explosion velocity replacement (`native_explosion_knockback`).",
"doc_summary": "A server explosion calculates an entity's added velocity: `native_explosion_knockback(dimension, center, blocks, entity, knockback_velocity)` can replace it. Bundles need \"hooks\": @API:explosion_knockback@."
}