mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 02:56:17 -10:00
feat(mods): allow cancelling targeted block highlights
Co-Authored-By: Codex <[email protected]>
This commit is contained in:
1 parent
5edb339a76
commit
f4d6ebab0c
4 files changed
+80
No files matched your search
@@ -14529,6 +14529,12 @@ impl Game<'_> {
|
||||
|| !self.block_action_restricted(h.pos)
|
||||
|| self.can_place_on_in_adventure(h.pos)
|
||||
})
|
||||
.filter(|h| {
|
||||
let state = self.world.block(h.pos[0], h.pos[1], h.pos[2]);
|
||||
let mut canceled = false;
|
||||
self.native_block_highlight(h.pos, state, alpha as f32, &mut canceled);
|
||||
!canceled
|
||||
})
|
||||
.map(|h| {
|
||||
let state = self.world.block(h.pos[0], h.pos[1], h.pos[2]);
|
||||
let f = self.res.facts().get(state);
|
||||
|
||||
@@ -1084,6 +1084,17 @@ impl Game<'_> {
|
||||
/// and on servers), and the server's own (`native_window` is false
|
||||
/// there: the single player server thread, a dedicated server).
|
||||
pub(super) fn native_tick(&mut self) {}
|
||||
/// Before an eligible targeted block's selection outline is built.
|
||||
/// Cancel skips only the default block highlight, after normal HUD and game-mode gates.
|
||||
pub(super) fn native_block_highlight(
|
||||
&self,
|
||||
pos: [i32; 3],
|
||||
state: BlockStateId,
|
||||
partial: f32,
|
||||
canceled: &mut bool,
|
||||
) {
|
||||
let _ = (pos, state, partial, canceled);
|
||||
}
|
||||
/// The world frame's local visual sources. Push requests; Horizon validates
|
||||
/// and limits them before rendering. Called only while a world is visible.
|
||||
pub(super) fn native_visuals(
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
"""Run the actual outline filter with a fake mod, without a renderer."""
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class BlockHighlightHookTests(unittest.TestCase):
|
||||
@unittest.skipUnless(shutil.which("rustc"), "requires Rust")
|
||||
def test_cancel_filters_only_the_target_outline(self):
|
||||
source = (ROOT / "crates/horizon-client/src/game.rs").read_text()
|
||||
call = source.index("self.native_block_highlight(")
|
||||
start = source.rindex(".filter(|h| {", 0, call)
|
||||
end = source.index(".map(|h| {", call)
|
||||
self.assertLess(source.index("let outline = if !self.ui.hide_gui"), start)
|
||||
self.assertLess(source.index("self.can_place_on_in_adventure(h.pos)"), start)
|
||||
fixture = r"""
|
||||
use std::cell::Cell;
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
struct Hit { pos: [i32; 3] }
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
struct BlockStateId(u32);
|
||||
struct World;
|
||||
impl World { fn block(&self, x: i32, y: i32, z: i32) -> BlockStateId { assert_eq!([x,y,z], [1,2,3]); BlockStateId(42) } }
|
||||
struct Game { world: World, cancel: bool, calls: Cell<usize> }
|
||||
impl Game {
|
||||
fn native_block_highlight(&self, pos: [i32; 3], state: BlockStateId, partial: f32, canceled: &mut bool) {
|
||||
assert_eq!(pos, [1,2,3]); assert_eq!(state, BlockStateId(42)); assert_eq!(partial, 0.5);
|
||||
self.calls.set(self.calls.get()+1); *canceled = self.cancel;
|
||||
}
|
||||
fn filter(&self, hit: Option<Hit>) -> Option<Hit> { let alpha = 0.5; hit FILTER }
|
||||
}
|
||||
#[test]
|
||||
fn cancelled_default_and_missing_target() {
|
||||
for cancel in [false, true] {
|
||||
let game = Game { world: World, cancel, calls: Cell::new(0) };
|
||||
let hit = Hit { pos: [1,2,3] };
|
||||
assert_eq!(game.filter(Some(hit)), if cancel { None } else { Some(hit) });
|
||||
assert_eq!(game.filter(None), None);
|
||||
assert_eq!(game.calls.get(), 1);
|
||||
}
|
||||
}
|
||||
""".replace("FILTER", source[start:end])
|
||||
with tempfile.TemporaryDirectory() as folder:
|
||||
src, exe = Path(folder) / "outline.rs", Path(folder) / "outline.exe"
|
||||
src.write_text(fixture)
|
||||
subprocess.run(["rustc", "--edition=2024", "--test", str(src), "-o", str(exe)], check=True)
|
||||
subprocess.run([str(exe)], check=True)
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"name": "block_highlight",
|
||||
"target": "horizon_client::game::native_hooks::Game<'_>::native_block_highlight",
|
||||
"side": "client",
|
||||
"cancellable": true
|
||||
}
|
||||
],
|
||||
"rust_summary": "a cancellable targeted-block highlight hook (`native_block_highlight`).",
|
||||
"doc_summary": "`native_block_highlight(pos, state, partial, canceled)` runs before building the eligible targeted block's selection outline, after hidden-HUD and game-mode restrictions. Set `canceled` to suppress only that outline; default behavior is unchanged otherwise. Position is block coordinates and state is the current block state ID. No entity outlines are affected. Bundles need \"hooks\": @API:block_highlight@."
|
||||
}
|
||||
Reference in new issue
Block a user