mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 02:56:17 -10:00
refactor: move the client's input modules into horizon-client-input
Key bindings and names, toggle keys, mouse options, controller settings, the clipboard and window options move to their own crate, re-exported under their old paths. Their unit tests now rebuild in about a second after an edit instead of rebuilding the client lib's test binary. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
6af60956ec
commit
beac63849c
23 files changed
+73
-22
No files matched your search
@@ -38,6 +38,7 @@ Game workspace (root `Cargo.toml`); `launcher/` and `crates/horizon-telemetry-se
|
||||
| `horizon-client` | The game: a lib (`src/lib.rs`, ~180 flat modules) and the bin (`src/main.rs` → `game.rs` + `game/`), plus `horizon-ctl` (`src/bin/horizon-ctl/`). Also the dedicated server (`--dedicated`) |
|
||||
| `horizon-command` | Command parsing (Brigadier): the vanilla tree, argument types, selectors, suggestions, the tree's network form. Re-exported as `horizon_client::command` |
|
||||
| `horizon-client-core` | The client lib's bottom layer: `text.rs`, `lang.rs`, `snbt.rs`, `nbt_path.rs`, `component.rs`, `scoreboard.rs`, `bossbar.rs`, `gamerules.rs`, `block_entity_nbt.rs`, registry/particle/sound tables. Re-exported under the old paths (`horizon_client::text`...) |
|
||||
| `horizon-client-input` | Key bindings and key names, toggle keys, mouse options, controller settings and glyphs, the clipboard, window options (`keybinds.rs`, `gamepad.rs`, `mouse.rs`, `window.rs`...). Re-exported under the old paths |
|
||||
| `horizon-world` | Vanilla world data with no gameplay loop: NBT, regions, chunks, `datafix/`, `worldgen/`, `level/` (server-side block behaviour, ticks, redstone), entity physics, items, effects, food, damage |
|
||||
| `horizon-core` | Simulation primitives: Java `Random`s, `jmath` (HotSpot-exact `Math`), positions, noise, density, paletted storage, `version.rs` (the pinned version) |
|
||||
| `horizon-protocol` | Network protocol 777: codecs, framing, encryption, `packets/{handshake,status,login,configuration,play}.rs`, `entity_data.rs` |
|
||||
@@ -112,7 +113,7 @@ python3 tools/agent_control_e2e.py # horizon-ctl / MCP end to end
|
||||
|
||||
| Subsystem | Files |
|
||||
|---|---|
|
||||
| Game loop, tick, frame | `game.rs`: `fn run`, `impl ApplicationHandler for Game` (`window_event`, `about_to_wait`), `fn tick`, `fn tick_world`, `fn render`; L: `clock.rs`, `window.rs`, `spans.rs` |
|
||||
| Game loop, tick, frame | `game.rs`: `fn run`, `impl ApplicationHandler for Game` (`window_event`, `about_to_wait`), `fn tick`, `fn tick_world`, `fn render`; L: `clock.rs`, `spans.rs`; `horizon-client-input/src/window.rs` |
|
||||
| Rendering | L: `gfx.rs` (`Renderer::new`, `Renderer::render`), `gfx/` (cull, occlusion, translucency, upload, timing, lod, weather, stars, end_sky), `*.wgsl`, `particles.rs`, `block_entity_render.rs`, `item_render.rs`, `fog.rs`, `clouds.rs`, `camera.rs`, `first_person.rs`; G: `render_tick.rs`, `item_draw.rs` |
|
||||
| Chunks, streaming, light | L: `streaming.rs` (worker pool: generate, light, mesh), `world.rs`, `chunk.rs`, `chunk_map.rs`, `light.rs`, `mesher.rs` + `mesher/`, `vanillagen.rs` (binds horizon-world's generator), `lod.rs` + `lod/`, `ticket_levels.rs`; G: `world_loading.rs`, `postprocess.rs`; game.rs `fn update_world` |
|
||||
| World generation | `crates/horizon-world/src/worldgen/` (`generator*.rs`, `feature_graph.rs`, `structure/`, `carver/`) |
|
||||
@@ -128,7 +129,7 @@ python3 tools/agent_control_e2e.py # horizon-ctl / MCP end to end
|
||||
| Integrated server | G: `integrated.rs` (the server thread), `levels.rs` (one level per dimension, `fn tick_server`), `server_travel.rs` |
|
||||
| Dedicated server | G: `dedicated.rs`, `dedicated/status.rs`; crates `horizon-server-files`, `horizon-server` |
|
||||
| Save and load | L: `save.rs` (level.dat, regions, playerdata), `entity_nbt.rs`, `options_file.rs`; `horizon-client-core/src/block_entity_nbt.rs`; G: `saving.rs`, `persist.rs` (entities); `crates/horizon-world/src/{region.rs,nbt.rs,datafix/}` |
|
||||
| Input | game.rs `fn window_event`, `fn key_pressed`, `fn play_mouse`; L: `keybinds.rs`, `keymapping.rs`, `key_names.rs`, `mouse.rs`, `input.rs`, `interaction_input.rs`, `gamepad.rs`, `osk.rs`, `clipboard.rs`; G: `pad.rs`, `pad_menu.rs` |
|
||||
| Input | game.rs `fn window_event`, `fn key_pressed`, `fn play_mouse`; crate `horizon-client-input` (`keybinds.rs`, `keymapping.rs`, `key_names.rs`, `mouse.rs`, `input.rs`, `interaction_input.rs`, `gamepad.rs`, `clipboard.rs`); L: `osk.rs`; G: `pad.rs`, `pad_menu.rs` |
|
||||
| Audio | L: `audio.rs` (mixer), `sound_engine.rs`, `sound_events.rs`, `music.rs`, `ambience.rs`; G: `music.rs`, `subtitle_hud.rs` |
|
||||
| Resource packs | L: `packs.rs` + `packs/`, `pack_screen.rs`, `atlas_sources.rs`, `sprites.rs`, `mipmap.rs`, `model_library.rs`, `font.rs`; `horizon-client-core/src/lang.rs`; crate `horizon-assets`; G: `packs.rs` |
|
||||
| Agent control | L: `control.rs` (socket), `bin/horizon-ctl/`; G: `control.rs`, `agent.rs`, `events.rs`, `ui_control.rs` ([docs/agent-control.md](docs/agent-control.md)) |
|
||||
|
||||
Generated
+13
-1
@@ -1363,7 +1363,6 @@ name = "horizon-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"arboard",
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
"cpal",
|
||||
@@ -1373,6 +1372,7 @@ dependencies = [
|
||||
"horizon-assets",
|
||||
"horizon-bench",
|
||||
"horizon-client-core",
|
||||
"horizon-client-input",
|
||||
"horizon-command",
|
||||
"horizon-core",
|
||||
"horizon-dualsense",
|
||||
@@ -1413,6 +1413,18 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "horizon-client-input"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"horizon-client-core",
|
||||
"horizon-dualsense",
|
||||
"horizon-theme",
|
||||
"png",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "horizon-command"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -8,6 +8,7 @@ members = [
|
||||
"crates/horizon-world",
|
||||
"crates/horizon-client",
|
||||
"crates/horizon-client-core",
|
||||
"crates/horizon-client-input",
|
||||
"crates/horizon-command",
|
||||
"crates/horizon-server-files",
|
||||
"crates/horizon-server",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "horizon-client-input"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
rust-version = "1.90"
|
||||
description = "The client's input layer: key bindings and their names, mouse, controllers, clipboard and window options"
|
||||
|
||||
[dependencies]
|
||||
horizon-client-core = { path = "../horizon-client-core" }
|
||||
winit = "0.30.13"
|
||||
# The window icon.
|
||||
horizon-theme = { path = "../horizon-theme" }
|
||||
png = "0.18"
|
||||
arboard = { version = "3.6.1", default-features = false, features = ["wayland-data-control"] }
|
||||
# The DualSense's trigger effects (the `controllers` feature).
|
||||
horizon-dualsense = { path = "../horizon-dualsense", optional = true }
|
||||
|
||||
[features]
|
||||
controllers = ["dep:horizon-dualsense"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,14 @@
|
||||
//! The client's input layer, below gameplay and screens: key bindings and their
|
||||
//! names, toggle keys, mouse settings, controllers, the clipboard and window
|
||||
//! options. horizon-client re-exports each module under its old path
|
||||
//! (`horizon_client::keybinds`, ...).
|
||||
#![forbid(unsafe_code)]
|
||||
pub mod clipboard;
|
||||
pub mod gamepad;
|
||||
pub mod input;
|
||||
pub mod interaction_input;
|
||||
pub mod key_names;
|
||||
pub mod keybinds;
|
||||
pub mod keymapping;
|
||||
pub mod mouse;
|
||||
pub mod window;
|
||||
File renamed without changes.
File renamed without changes.
@@ -10,6 +10,7 @@ description = "Horizon native development client"
|
||||
[dependencies]
|
||||
horizon-assets = { path = "../horizon-assets" }
|
||||
horizon-client-core = { path = "../horizon-client-core" }
|
||||
horizon-client-input = { path = "../horizon-client-input" }
|
||||
horizon-command = { path = "../horizon-command" }
|
||||
horizon-core = { path = "../horizon-core" }
|
||||
# The server thread ahead of the workers (MinecraftServer.spin's Thread.setPriority).
|
||||
@@ -54,7 +55,6 @@ horizon-theme = { path = "../horizon-theme" }
|
||||
# the anonymous "I'm playing" ping the game sends itself (`heartbeat.rs`).
|
||||
horizon-telemetry = { path = "../horizon-telemetry", default-features = false, features = ["live"] }
|
||||
horizon-bench = { path = "../horizon-bench" }
|
||||
arboard = { version = "3.6.1", default-features = false, features = ["wayland-data-control"] }
|
||||
zip = { version = "2", default-features = false, features = ["deflate"] }
|
||||
# Controllers (evdev + libudev on Linux, IOKit on macOS, Windows.Gaming.Input); the `controllers` feature.
|
||||
gilrs = { version = "0.11", optional = true }
|
||||
@@ -88,7 +88,7 @@ default = ["audio", "controllers"]
|
||||
# Linux: the server build (`--no-default-features`, released as horizon-engine; docs/server.md).
|
||||
audio = ["dep:cpal"]
|
||||
# Controllers: gilrs, and the DualSense's own output. Without it only `horizon-ctl pad`'s virtual pad.
|
||||
controllers = ["dep:gilrs", "dep:horizon-dualsense"]
|
||||
controllers = ["dep:gilrs", "dep:horizon-dualsense", "horizon-client-input/controllers"]
|
||||
# Runs code mods (wasmtime and cranelift: a quarter of a clean build). On in every release build
|
||||
# (release.yml); the tests and probes don't need it. Content mods load without it.
|
||||
mods = ["horizon-mods/runtime"]
|
||||
|
||||
@@ -32,7 +32,6 @@ pub mod cauldron;
|
||||
pub mod chat;
|
||||
pub mod chunk;
|
||||
pub mod chunk_map;
|
||||
pub mod clipboard;
|
||||
pub mod clock;
|
||||
pub mod clouds;
|
||||
pub mod collisions;
|
||||
@@ -74,7 +73,6 @@ pub mod fog;
|
||||
pub mod font;
|
||||
pub mod friends_screen;
|
||||
pub mod game_mode_switcher;
|
||||
pub mod gamepad;
|
||||
pub mod gfx;
|
||||
pub mod gizmos;
|
||||
pub mod gossip;
|
||||
@@ -88,8 +86,6 @@ pub mod hud;
|
||||
pub mod hud_layout;
|
||||
pub mod hud_overlays;
|
||||
pub mod hunger;
|
||||
pub mod input;
|
||||
pub mod interaction_input;
|
||||
pub mod inv_sort;
|
||||
pub mod inventory_effects;
|
||||
pub mod item_data;
|
||||
@@ -98,9 +94,6 @@ pub mod item_sync;
|
||||
pub mod item_tooltip;
|
||||
pub mod items;
|
||||
pub mod java_text;
|
||||
pub mod key_names;
|
||||
pub mod keybinds;
|
||||
pub mod keymapping;
|
||||
pub mod lan;
|
||||
pub mod landing;
|
||||
pub mod level_loading;
|
||||
@@ -120,7 +113,6 @@ pub mod mod_list;
|
||||
mod model_library;
|
||||
pub mod models;
|
||||
pub mod motion;
|
||||
pub mod mouse;
|
||||
pub mod moved_extras;
|
||||
pub mod multiplayer;
|
||||
pub mod music;
|
||||
@@ -190,7 +182,6 @@ pub mod vault;
|
||||
pub mod weather;
|
||||
pub mod widgets;
|
||||
pub mod win_screen;
|
||||
pub mod window;
|
||||
pub mod world;
|
||||
pub mod world_spawn;
|
||||
pub mod worldborder;
|
||||
@@ -206,4 +197,13 @@ pub use horizon_client_core::nbt_path;
|
||||
pub use horizon_client_core::scoreboard;
|
||||
pub use horizon_client_core::snbt;
|
||||
pub use horizon_client_core::text;
|
||||
pub use horizon_client_input::clipboard;
|
||||
pub use horizon_client_input::gamepad;
|
||||
pub use horizon_client_input::input;
|
||||
pub use horizon_client_input::interaction_input;
|
||||
pub use horizon_client_input::key_names;
|
||||
pub use horizon_client_input::keybinds;
|
||||
pub use horizon_client_input::keymapping;
|
||||
pub use horizon_client_input::mouse;
|
||||
pub use horizon_client_input::window;
|
||||
pub use horizon_command as command;
|
||||
+1
-1
@@ -25,7 +25,7 @@ Select/Start). No second windowing or event stack: gilrs is polled once per
|
||||
loop iteration next to winit's events.
|
||||
|
||||
- The pure logic (mapping table, deadzones and curves, button edges, the
|
||||
settings file, glyph choice) lives in `crates/horizon-client/src/gamepad.rs`
|
||||
settings file, glyph choice) lives in `crates/horizon-client-input/src/gamepad.rs`
|
||||
and is unit-tested. The game owns a thin gilrs backend and applies actions.
|
||||
- Controller actions go through the same path a keyboard key takes after
|
||||
rebinding: an action names a vanilla key mapping (`key.jump`, `key.attack`,
|
||||
|
||||
@@ -62,7 +62,7 @@ def main():
|
||||
'real OS sleep accuracy is outside the comparison.')
|
||||
harness.differential(
|
||||
'rust-frame-limiter-parity', 'VanillaFrameLimiterOracle', 'frame_limiter_probe', make_cases, scope,
|
||||
sources=[lab.ROOT / 'crates/horizon-client/src/window.rs'])
|
||||
sources=[lab.ROOT / 'crates/horizon-client-input/src/window.rs'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -43,7 +43,7 @@ def main():
|
||||
"Includes passing entity interactions over solid blocks: only the held "
|
||||
"item may be tried afterward. "
|
||||
"Game-mode side effects and world simulation are controlled fixtures.",
|
||||
sources=[lab.ROOT / "crates/horizon-client/src/interaction_input.rs",
|
||||
sources=[lab.ROOT / "crates/horizon-client-input/src/interaction_input.rs",
|
||||
lab.ROOT / "crates/horizon-client/src/game/remote.rs",
|
||||
lab.ROOT / "crates/horizon-client/src/game/hand.rs",
|
||||
lab.ROOT / "mods/horizon/src/test/java/dev/horizonlab/parity/ParityData.java"])
|
||||
|
||||
@@ -35,7 +35,7 @@ def main():
|
||||
build=lab.LOCAL/'rust-local-input';build.mkdir(exist_ok=True)
|
||||
report=build/'report.json';report.unlink(missing_ok=True)
|
||||
oracle=lab.ROOT/'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaLocalInputOracle.java'
|
||||
sources=[Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/test_model_baking_parity.py',lab.ROOT/'tools/lab.py',oracle,lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-client/Cargo.toml',lab.ROOT/'crates/horizon-client/src/input.rs',lab.ROOT/'crates/horizon-client/src/lib.rs',lab.ROOT/'crates/horizon-client/examples/probe/input_probe.rs']
|
||||
sources=[Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/test_model_baking_parity.py',lab.ROOT/'tools/lab.py',oracle,lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-client/Cargo.toml',lab.ROOT/'crates/horizon-client-input/src/input.rs',lab.ROOT/'crates/horizon-client/src/lib.rs',lab.ROOT/'crates/horizon-client/examples/probe/input_probe.rs']
|
||||
tested=base.source_hashes(sources)
|
||||
def run(command,name):
|
||||
with (build/(name+'.log')).open('w') as log:subprocess.run(list(map(str,command)),cwd=lab.ROOT,check=True,timeout=600,stdout=log,stderr=subprocess.STDOUT)
|
||||
|
||||
@@ -189,8 +189,8 @@ def main():
|
||||
harness.differential(
|
||||
'rust-options-parity', 'VanillaOptionsOracle', 'options_probe', make_cases, scope,
|
||||
sources=[lab.ROOT / 'crates/horizon-client/src/options_file.rs', lab.ROOT / 'crates/horizon-client/src/options_fixes.rs',
|
||||
lab.ROOT / 'crates/horizon-client/src/java_text.rs', lab.ROOT / 'crates/horizon-client/src/key_names.rs',
|
||||
lab.ROOT / 'crates/horizon-client/src/keybinds.rs'])
|
||||
lab.ROOT / 'crates/horizon-client/src/java_text.rs', lab.ROOT / 'crates/horizon-client-input/src/key_names.rs',
|
||||
lab.ROOT / 'crates/horizon-client-input/src/keybinds.rs'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -40,7 +40,7 @@ def main():
|
||||
build=lab.LOCAL/'rust-sprint-input';build.mkdir(exist_ok=True)
|
||||
report=build/'report.json';report.unlink(missing_ok=True)
|
||||
oracle=lab.ROOT/'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaSprintInputOracle.java'
|
||||
sources=[Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/test_model_baking_parity.py',lab.ROOT/'tools/lab.py',oracle,lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-client/Cargo.toml',lab.ROOT/'crates/horizon-client/src/input.rs',lab.ROOT/'crates/horizon-client/src/sprint.rs',lab.ROOT/'crates/horizon-client/src/lib.rs',lab.ROOT/'crates/horizon-client/examples/probe/sprint_probe.rs']
|
||||
sources=[Path(__file__),lab.ROOT/'tools/test_rust_parity.py',lab.ROOT/'tools/test_model_baking_parity.py',lab.ROOT/'tools/lab.py',oracle,lab.ROOT/'Cargo.toml',lab.ROOT/'Cargo.lock',lab.ROOT/'crates/horizon-client/Cargo.toml',lab.ROOT/'crates/horizon-client-input/src/input.rs',lab.ROOT/'crates/horizon-client/src/sprint.rs',lab.ROOT/'crates/horizon-client/src/lib.rs',lab.ROOT/'crates/horizon-client/examples/probe/sprint_probe.rs']
|
||||
tested=base.source_hashes(sources)
|
||||
def run(command,name):
|
||||
with (build/(name+'.log')).open('w') as log:subprocess.run(list(map(str,command)),cwd=lab.ROOT,check=True,timeout=600,stdout=log,stderr=subprocess.STDOUT)
|
||||
|
||||
@@ -69,7 +69,7 @@ def main():
|
||||
'not exercised; KeyboardInput then reads isDown as the sprint and local input harnesses compare.')
|
||||
harness.differential(
|
||||
'rust-toggle-keys-parity', 'VanillaToggleKeysOracle', 'toggle_keys_probe', make_cases, scope,
|
||||
sources=[lab.ROOT / 'crates/horizon-client/src/keymapping.rs'])
|
||||
sources=[lab.ROOT / 'crates/horizon-client-input/src/keymapping.rs'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in new issue
Block a user