mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Wire explosion knockback for other entities and wind
This commit is contained in:
1 parent
e1084abe75
commit
355becd82d
4 files changed
+36
-24
No files matched your search
@@ -148,8 +148,12 @@ fn blast_direction(center: [f64; 3], origin: [f64; 3]) -> [f64; 3] {
|
||||
}
|
||||
}
|
||||
|
||||
/// An entity in the blast's reach: how far (as a share of the blast's
|
||||
/// diameter), how much of it the rays see, and the knockback.
|
||||
struct ExplosionHookContext<'a> {
|
||||
center: [f64; 3],
|
||||
blocks: &'a [[i32; 3]],
|
||||
}
|
||||
|
||||
/// An entity in the blast's reach: distance, exposure, and knockback.
|
||||
struct Hit {
|
||||
dist: f64,
|
||||
exposure: f32,
|
||||
@@ -389,16 +393,16 @@ impl Game<'_> {
|
||||
///
|
||||
/// `cause` is the blast's source as predicates see it, read before the
|
||||
/// guests' turns swap their own combat state in.
|
||||
pub(super) fn explosion_hurt_player(
|
||||
fn explosion_hurt_player(
|
||||
&mut self,
|
||||
center: [f64; 3],
|
||||
context: &ExplosionHookContext<'_>,
|
||||
radius: f32,
|
||||
damage_type: &str,
|
||||
exploding: Option<u32>,
|
||||
attacker: Option<&(u32, Text)>,
|
||||
cause: Option<&horizon_client::advancements::EntityView>,
|
||||
blocks: &[[i32; 3]],
|
||||
) -> Option<[f64; 3]> {
|
||||
let ExplosionHookContext { center, blocks } = *context;
|
||||
let diameter = f64::from(radius * 2.0);
|
||||
// Blast protection: `EXPLOSION_KNOCKBACK_RESISTANCE` (0.15 per level and
|
||||
// piece, so two Blast Protection IV pieces cancel it).
|
||||
@@ -451,10 +455,6 @@ 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) {
|
||||
@@ -486,7 +486,11 @@ impl Game<'_> {
|
||||
.indicate_damage(center[0] - feet[0], center[2] - feet[2], p.yaw);
|
||||
}
|
||||
}
|
||||
if !spectator && !(creative && flying) {
|
||||
}
|
||||
if !spectator && !(creative && flying) {
|
||||
let mut push = [dir[0] * power, dir[1] * power, dir[2] * power];
|
||||
self.native_explosion_knockback(self.dim.id(), center, blocks, None, &mut push);
|
||||
if let Some(p) = self.player.as_mut() {
|
||||
p.velocity = Vec3::new(
|
||||
p.velocity.x + push[0],
|
||||
p.velocity.y + push[1],
|
||||
@@ -573,14 +577,14 @@ impl Game<'_> {
|
||||
// same for all of them (`onExplosionHit(this.source)`).
|
||||
let attacker = self.blast_attacker();
|
||||
let blast_source = self.combat.explosion_cause.clone();
|
||||
let context = ExplosionHookContext { center, blocks };
|
||||
let own = self.explosion_hurt_player(
|
||||
center,
|
||||
&context,
|
||||
radius,
|
||||
damage_type,
|
||||
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,13 +598,12 @@ impl Game<'_> {
|
||||
for conn in guests {
|
||||
let push = self.as_guest(&mut host, conn, |g| {
|
||||
g.explosion_hurt_player(
|
||||
center,
|
||||
&context,
|
||||
radius,
|
||||
damage_type,
|
||||
exploding,
|
||||
attacker.as_ref(),
|
||||
blast_source.as_ref(),
|
||||
blocks,
|
||||
)
|
||||
});
|
||||
if let Some(Some(push)) = push {
|
||||
@@ -649,6 +652,12 @@ impl Game<'_> {
|
||||
}) = hit
|
||||
{
|
||||
let amount = damage(dist, exposure);
|
||||
let entity = with_entity!(self, handle, e => e.id());
|
||||
let mut velocity = [push.x, push.y, push.z];
|
||||
self.native_explosion_knockback(
|
||||
self.dim.id(), center, blocks, Some(entity), &mut velocity,
|
||||
);
|
||||
let push = Vec3::new(velocity[0], velocity[1], velocity[2]);
|
||||
match handle {
|
||||
EntityHandle::Mob(i) => {
|
||||
let hurtable = teams_allow(self, self.mob_team(self.mobs[i].id));
|
||||
|
||||
@@ -5294,7 +5294,7 @@ 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@.
|
||||
/// Replace the velocity added to its existing velocity. API @API:native_explosion_knockback@.
|
||||
pub(super) fn native_explosion_knockback(
|
||||
&mut self,
|
||||
dimension: &str,
|
||||
|
||||
@@ -226,8 +226,9 @@ impl Game<'_> {
|
||||
multiplier: f32,
|
||||
breeze: bool,
|
||||
wind_charge: bool,
|
||||
blocklike: bool,
|
||||
blocks: &[[i32; 3]],
|
||||
) -> Vec<(u32, [f64; 3])> {
|
||||
let blocklike = !breeze && !wind_charge && self.ui.rules.bool("mob_griefing");
|
||||
let diameter = f64::from(radius * 2.0);
|
||||
let distance = |p: [f64; 3]| {
|
||||
((p[0] - center[0]).powi(2) + (p[1] - center[1]).powi(2) + (p[2] - center[2]).powi(2))
|
||||
@@ -249,7 +250,7 @@ impl Game<'_> {
|
||||
// The player, then every other player in the level (LAN guests),
|
||||
// each swapped in as the player. In a guest's turn (a mace's wind
|
||||
// burst) the player is that guest.
|
||||
let own = self.wind_push_player(center, radius, multiplier, breeze, wind_charge);
|
||||
let own = self.wind_push_player(center, radius, multiplier, breeze, wind_charge, blocks);
|
||||
let mut pushed: Vec<_> = self.lan_acting.zip(own).into_iter().collect();
|
||||
if let Some(mut host) = self.lan.take() {
|
||||
let guests: Vec<u32> = host
|
||||
@@ -261,7 +262,7 @@ impl Game<'_> {
|
||||
.collect();
|
||||
for conn in guests {
|
||||
let push = self.as_guest(&mut host, conn, |g| {
|
||||
g.wind_push_player(center, radius, multiplier, breeze, wind_charge)
|
||||
g.wind_push_player(center, radius, multiplier, breeze, wind_charge, blocks)
|
||||
});
|
||||
if let Some(Some(push)) = push {
|
||||
pushed.push((conn, push));
|
||||
@@ -295,7 +296,9 @@ impl Game<'_> {
|
||||
let exposure = self.seen_percent(center, [lo.x, lo.y, lo.z], [hi.x, hi.y, hi.z]);
|
||||
let power = (1.0 - dist) * f64::from(exposure) * multiplier;
|
||||
let dir = direction([feet[0], feet[1] + entity.explosion_eye_height(), feet[2]]);
|
||||
entity.push_from_explosion(Vec3::new(dir[0] * power, dir[1] * power, dir[2] * power));
|
||||
let mut push = [dir[0] * power, dir[1] * power, dir[2] * power];
|
||||
self.native_explosion_knockback(self.dim.id(), center, blocks, Some(entity.id()), &mut push);
|
||||
entity.push_from_explosion(Vec3::new(push[0], push[1], push[2]));
|
||||
});
|
||||
self.restore_entities(entities);
|
||||
pushed
|
||||
@@ -310,6 +313,7 @@ impl Game<'_> {
|
||||
multiplier: f32,
|
||||
breeze: bool,
|
||||
wind_charge: bool,
|
||||
blocks: &[[i32; 3]],
|
||||
) -> Option<[f64; 3]> {
|
||||
if self.spectator() {
|
||||
return None;
|
||||
@@ -344,11 +348,12 @@ impl Game<'_> {
|
||||
);
|
||||
let power = (1.0 - dist) * f64::from(exposure) * f64::from(multiplier) * (1.0 - resistance);
|
||||
let l = (eye[0] * eye[0] + eye[1] * eye[1] + eye[2] * eye[2]).sqrt();
|
||||
let push = if l < 1.0e-5 {
|
||||
let mut push = if l < 1.0e-5 {
|
||||
[0.0; 3]
|
||||
} else {
|
||||
eye.map(|d| d / l * power)
|
||||
};
|
||||
self.native_explosion_knockback(self.dim.id(), center, blocks, None, &mut push);
|
||||
let p = self.player.as_mut()?;
|
||||
p.velocity = Vec3::new(
|
||||
p.velocity.x + push[0],
|
||||
@@ -402,10 +407,8 @@ impl Game<'_> {
|
||||
let ctx = horizon_client::sculk::Context::default();
|
||||
self.post_game_event("minecraft:explode", center, ctx);
|
||||
let mut targets = self.wind_positions(center, radius);
|
||||
// ServerExplosion.shouldAffectBlocklikeEntities
|
||||
let blocklike = !breeze && !wind_charge && self.ui.rules.bool("mob_griefing");
|
||||
let pushed =
|
||||
self.wind_knockback(center, radius, multiplier, breeze, wind_charge, blocklike);
|
||||
self.wind_knockback(center, radius, multiplier, breeze, wind_charge, &targets);
|
||||
let block_count = targets.len();
|
||||
// Explosion.canTriggerBlocks: a breeze's charge needs mob griefing.
|
||||
if !breeze || self.ui.rules.bool("mob_griefing") {
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
}
|
||||
],
|
||||
"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@."
|
||||
"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:native_explosion_knockback@."
|
||||
}
|
||||
Reference in new issue
Block a user