mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Merge pull request #10200 from Hiuoy/feat/break-speed
Native hooks: PlayerEvent.BreakSpeed, how fast a player digs a block
This commit is contained in:
6 files changed
+65
-42
No files matched your search
@@ -7609,10 +7609,8 @@ impl Game<'_> {
|
||||
ticks: 0,
|
||||
});
|
||||
}
|
||||
let block_break_speed = self.block_break_speed();
|
||||
let state = self.world.block(hit.pos[0], hit.pos[1], hit.pos[2]);
|
||||
let facts = self.res.facts().get(state);
|
||||
if facts.hardness < 0.0 {
|
||||
if self.res.facts().get(state).hardness < 0.0 {
|
||||
// The server still counts its destroy ticks on an unbreakable block.
|
||||
let m = self.mining.as_mut().ok_or("mining")?;
|
||||
m.ticks += 1;
|
||||
@@ -7620,36 +7618,7 @@ impl Game<'_> {
|
||||
self.destroy_progress_event(pos, hit.face, ticks);
|
||||
return Ok(());
|
||||
}
|
||||
// Player.getDestroySpeed / BlockBehaviour.getDestroyProgress.
|
||||
let held = self.held();
|
||||
let mut speed = self.items().mining_speed(held, &facts.name);
|
||||
let hardness = facts.hardness;
|
||||
let harvest = !facts.requires_tool || self.items().correct_for_drops(held, &facts.name);
|
||||
speed = self.modify_destroy_speed(speed);
|
||||
speed *= block_break_speed;
|
||||
let player = self.player.as_ref().ok_or("no player")?;
|
||||
if !player.ground.on_ground {
|
||||
speed /= 5.0;
|
||||
}
|
||||
let eye = self.eye_position().unwrap_or_default();
|
||||
if self
|
||||
.res
|
||||
.facts()
|
||||
.get(self.world.block(
|
||||
eye[0].floor() as i32,
|
||||
eye[1].floor() as i32,
|
||||
eye[2].floor() as i32,
|
||||
))
|
||||
.fluid
|
||||
== Fluid::Water
|
||||
{
|
||||
speed *= self.submerged_mining_speed();
|
||||
}
|
||||
let progress = if hardness == 0.0 {
|
||||
1.0
|
||||
} else {
|
||||
speed / hardness / if harvest { 30.0 } else { 100.0 }
|
||||
};
|
||||
let progress = self.destroy_progress(hit.pos);
|
||||
self.swing_arm();
|
||||
let m = self.mining.as_mut().ok_or("mining")?;
|
||||
m.progress += progress;
|
||||
|
||||
@@ -383,7 +383,9 @@ impl Game<'_> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// `BlockBehaviour.getDestroyProgress` with `Player.getDestroySpeed`.
|
||||
/// `BlockBehaviour.getDestroyProgress` with `Player.getDestroySpeed`, whose
|
||||
/// end asks the mods' `native_break_speed`. Every dig's progress comes from
|
||||
/// here: single player's, a host's for each guest, a remote client's own.
|
||||
pub(super) fn destroy_progress(&mut self, pos: [i32; 3]) -> f32 {
|
||||
let block_break_speed = self.block_break_speed();
|
||||
let state = self.world.block(pos[0], pos[1], pos[2]);
|
||||
@@ -414,6 +416,8 @@ impl Game<'_> {
|
||||
if self.player.as_ref().is_some_and(|p| !p.ground.on_ground) {
|
||||
speed /= 5.0;
|
||||
}
|
||||
// NeoForge's PlayerEvent.BreakSpeed, where Player.getDestroySpeed ends.
|
||||
self.native_break_speed(pos, state, speed, &mut speed);
|
||||
speed / hardness / if harvest { 30.0 } else { 100.0 }
|
||||
}
|
||||
/// A key for the main-hand stack (`destroyingItem`): its item and components.
|
||||
|
||||
@@ -2587,6 +2587,30 @@ impl Game<'_> {
|
||||
) {
|
||||
mod_api::dispatch_left_click_block(self, mod_api::mods(), pos, face, state, canceled);
|
||||
}
|
||||
/// NeoForge's `PlayerEvent.BreakSpeed`: how fast the player digs the block
|
||||
/// `state` at `pos`, where `Player.getDestroySpeed` ends. `speed` starts as
|
||||
/// vanilla's, `original` (the tool, mining efficiency, Haste and Mining
|
||||
/// Fatigue, the block break speed attribute, the slowdowns under water and
|
||||
/// off the ground), and a mod may change it; every mod is called in turn,
|
||||
/// and `original` stays vanilla's. `BlockBehaviour.getDestroyProgress` then
|
||||
/// divides the speed by the block's hardness and by 30, or 100 without the
|
||||
/// right tool, for each tick of the dig: a speed of 0 makes no progress, so
|
||||
/// the block isn't broken, not even one that breaks at once. Not asked for
|
||||
/// an unbreakable block (hardness -1) nor in creative mode. Fires on the
|
||||
/// `Game` that works out the dig: single player's, a LAN or dedicated
|
||||
/// host's for each guest (the helpers read that player), and a remote
|
||||
/// client's own prediction, so a mod changes the speed alike on both sides
|
||||
/// to keep the crack in step with the server. It is asked every tick of a
|
||||
/// dig, on each side, so it should only compute. API @API:break_speed@.
|
||||
pub(super) fn native_break_speed(
|
||||
&self,
|
||||
pos: [i32; 3],
|
||||
state: BlockStateId,
|
||||
original: f32,
|
||||
speed: &mut f32,
|
||||
) {
|
||||
mod_api::dispatch_break_speed(self, mod_api::mods(), pos, state, original, speed);
|
||||
}
|
||||
/// A living player's server tick ends (`ServerPlayer.tick`): once a tick
|
||||
/// for every player in the world, after their digging, item use,
|
||||
/// cooldowns, statistics and advancements. The helpers read that player.
|
||||
|
||||
@@ -7492,15 +7492,12 @@ impl Game<'_> {
|
||||
}
|
||||
return;
|
||||
}
|
||||
let facts = self.res.facts().get(state).clone();
|
||||
// The server's own getDestroyProgress: under water, off the ground,
|
||||
// with haste, fatigue and efficiency, so the client stops digging
|
||||
// when the server is done too (#1254).
|
||||
let progress = if facts.hardness == 0.0 {
|
||||
1.0
|
||||
} else {
|
||||
self.destroy_progress(hit.pos)
|
||||
};
|
||||
// with haste, fatigue, efficiency and the mods' native_break_speed, so
|
||||
// the client stops digging when the server is done too (#1254). A
|
||||
// block of hardness 0 gives infinity, breaking at once, unless a mod
|
||||
// made the speed 0.
|
||||
let progress = self.destroy_progress(hit.pos);
|
||||
// sameDestroyTarget: the same block and still the item the break began with.
|
||||
let held = self.main_hand_key();
|
||||
let same = self.remote.as_ref().is_some_and(|r| {
|
||||
|
||||
@@ -455,6 +455,19 @@ a version. Helpers (`native_text`, `native_player`…) have no hook entry; the c
|
||||
the generated `Host` offers, and they are kept stable as the hook points are. A test (`catalog_matches_hook_points`) keeps the
|
||||
catalog and the hook points' sources (`native_hooks.rs`, `gfx/native_render.rs`, `horizon-world`'s `loot.rs`) in step.
|
||||
|
||||
### How fast a player digs
|
||||
|
||||
`native_break_speed` is NeoForge's `PlayerEvent.BreakSpeed`, at the end of vanilla's `Player.getDestroySpeed`. It is
|
||||
told the block's state and position, and the speed vanilla gives the player for it: the tool, mining efficiency, Haste
|
||||
and Mining Fatigue, the block break speed attribute, and the slowdowns under water and off the ground. A mod may change
|
||||
`speed`. Every mod is called in turn, and `original` stays vanilla's. `BlockBehaviour.getDestroyProgress` then divides
|
||||
the speed by the block's hardness, and by 30 (or 100 without the right tool), for each tick of the dig. A speed of 0
|
||||
makes no progress, so the block isn't broken, not even one that breaks at once. It isn't asked for an unbreakable
|
||||
block (hardness -1) or in creative mode. It fires on the `Game` that works out the dig: in single player, on a LAN or
|
||||
dedicated host for each guest (the helpers read that player), and in a remote client's own prediction. A mod that
|
||||
changes the speed alike on both sides keeps the crack in step with the server. It is asked every tick of a dig, on
|
||||
each side, so it takes `&self` and should only compute. API @API:break_speed@.
|
||||
|
||||
### Host-aware weapon damage (API next)
|
||||
|
||||
`living_incoming_damage_v2` is an additive hook, like `menu_button_v2`; v1 keeps its signature and firing point.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "break_speed",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_break_speed",
|
||||
"neoforge": "PlayerEvent.BreakSpeed",
|
||||
"side": "both",
|
||||
"cancellable": false,
|
||||
"mod_api": {
|
||||
"contract": "listen"
|
||||
}
|
||||
}
|
||||
],
|
||||
"rust_summary": "how fast a player digs a block (`native_break_speed`).",
|
||||
"doc_summary": "how fast a player digs a block: `native_break_speed` may change the speed that `Player.getDestroySpeed` gives, as NeoForge's `PlayerEvent.BreakSpeed` does, on both sides ([How fast a player digs](#how-fast-a-player-digs)). Bundles need \"hooks\": @API:break_speed@."
|
||||
}
|
||||
Reference in new issue
Block a user