mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 17:21:49 -10:00
Compare commits
199
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
643f331f8c | ||
|
|
4e7c25bb55 | ||
|
|
e423e570c9 | ||
|
|
87aa88de54 | ||
|
|
535f2d2a04 | ||
|
|
7eb7791240 | ||
|
|
ca90a20992 | ||
|
|
923368f4df | ||
|
|
25bdaf5321 | ||
|
|
8a04e18b91 | ||
|
|
5d54f28c42 | ||
|
|
818d1515c6 | ||
|
|
e61e6345bc | ||
|
|
02039fed5b | ||
|
|
976956fc3e | ||
|
|
dfae12cfe2 | ||
|
|
8a8348c93f | ||
|
|
0a3965a7b1 | ||
|
|
704931ed14 | ||
|
|
a713dbd46d | ||
|
|
1868fc39ae | ||
|
|
50f2894ca8 | ||
|
|
4b44399242 | ||
|
|
43e6bfcf98 | ||
|
|
f688726b34 | ||
|
|
826cf8ffe6 | ||
|
|
e2dd6b67df | ||
|
|
ebd25abd0e | ||
|
|
9624e99801 | ||
|
|
6a5c749f7c | ||
|
|
c33acfdd05 | ||
|
|
7c83fbb6df | ||
|
|
c26ced533e | ||
|
|
e0d29dc233 | ||
|
|
6eb34eb868 | ||
|
|
b21423ae01 | ||
|
|
a6e9374f88 | ||
|
|
50aee22996 | ||
|
|
01133fac82 | ||
|
|
4507ded0e4 | ||
|
|
46304cc1a7 | ||
|
|
377d81a329 | ||
|
|
905acfe7cd | ||
|
|
c18f3dbfde | ||
|
|
9c843819b7 | ||
|
|
c466c5ddad | ||
|
|
d5bd35025e | ||
|
|
2cd8b88a5b | ||
|
|
0b581f9ffe | ||
|
|
f67b2b3204 | ||
|
|
d139f9bee6 | ||
|
|
03d93d79b2 | ||
|
|
1b14e0d171 | ||
|
|
f8e4e31b12 | ||
|
|
67e07f3faa | ||
|
|
2bbbc70620 | ||
|
|
9c134f54ac | ||
|
|
a00dc868ec | ||
|
|
08306d1586 | ||
|
|
3b70dc9c16 | ||
|
|
13c14563c4 | ||
|
|
99b058442c | ||
|
|
8cce2e2f8a | ||
|
|
582856aac2 | ||
|
|
0a95a78e03 | ||
|
|
5205b909f7 | ||
|
|
5ec40c8004 | ||
|
|
82bba24f43 | ||
|
|
7b0316e6a4 | ||
|
|
a29e10ef9b | ||
|
|
92050712fa | ||
|
|
122e3bf287 | ||
|
|
65031a7739 | ||
|
|
82218db860 | ||
|
|
040ac1bec4 | ||
|
|
59f018eabe | ||
|
|
969bcec6c9 | ||
|
|
ca0637da80 | ||
|
|
47459b0b19 | ||
|
|
9b16d37e80 | ||
|
|
03be14bb59 | ||
|
|
45e5b64520 | ||
|
|
d65be4183f | ||
|
|
e307f03684 | ||
|
|
26a91e3a08 | ||
|
|
8c81cc63f7 | ||
|
|
221545e92b | ||
|
|
88b27070bd | ||
|
|
499f8bddfc | ||
|
|
5904922865 | ||
|
|
49e706e8be | ||
|
|
5e63b0512d | ||
|
|
d66466db81 | ||
|
|
6b55abd66a | ||
|
|
22b2711cf9 | ||
|
|
6ea7167cbb | ||
|
|
51de8afe95 | ||
|
|
d8dd2023dd | ||
|
|
3e04df41c8 | ||
|
|
7371b2cccd | ||
|
|
d84d7a7e61 | ||
|
|
077c4c9214 | ||
|
|
1cd0dd8c5d | ||
|
|
8f081ae460 | ||
|
|
14461c1d96 | ||
|
|
7f60a55ca3 | ||
|
|
ea424ebd52 | ||
|
|
16db2f44ae | ||
|
|
0b56d62273 | ||
|
|
574e3ca567 | ||
|
|
2a2b4acb5c | ||
|
|
52bc81ca5b | ||
|
|
e1fff77a48 | ||
|
|
265461f2eb | ||
|
|
fc9822b241 | ||
|
|
d6dc08098a | ||
|
|
4b1e298a44 | ||
|
|
a4a101ca9c | ||
|
|
c6ed3112e7 | ||
|
|
f96101cd47 | ||
|
|
fa4ea80d32 | ||
|
|
0bbe50c6e8 | ||
|
|
c924894624 | ||
|
|
ba8bdc7179 | ||
|
|
455a9996d2 | ||
|
|
cbc469249e | ||
|
|
287d7a7eb5 | ||
|
|
c86996c234 | ||
|
|
e436116e38 | ||
|
|
d7b5cd8c85 | ||
|
|
35d2781e9d | ||
|
|
66d1292d10 | ||
|
|
4daa91cf52 | ||
|
|
d3de3cd0a9 | ||
|
|
5595db9077 | ||
|
|
e3b168688e | ||
|
|
974e18e52a | ||
|
|
c89695dd93 | ||
|
|
fe70ff90b4 | ||
|
|
4d9baf60d4 | ||
|
|
0a36a6d8c6 | ||
|
|
b9501fc826 | ||
|
|
9dd9a83699 | ||
|
|
341576a084 | ||
|
|
0b0e4a8aae | ||
|
|
4a442f7250 | ||
|
|
f47f6ee472 | ||
|
|
85c6103d45 | ||
|
|
c19418b55d | ||
|
|
8acb46756b | ||
|
|
ee79b8f0cd | ||
|
|
8667cef3a1 | ||
|
|
fe1d544d02 | ||
|
|
0cc3b4a057 | ||
|
|
81fb4c7371 | ||
|
|
60611ed5a3 | ||
|
|
4fa5966338 | ||
|
|
eb79cfdb01 | ||
|
|
7dac46ec3c | ||
|
|
717f54bf28 | ||
|
|
8ef418e223 | ||
|
|
ad76f911bd | ||
|
|
5ed8181adc | ||
|
|
5617d702cc | ||
|
|
52d8ed6721 | ||
|
|
de358cd721 | ||
|
|
b8e729b950 | ||
|
|
9acc68f09f | ||
|
|
a8c21c27df | ||
|
|
55264459ce | ||
|
|
0f3a92ac2b | ||
|
|
441774c229 | ||
|
|
693556ce32 | ||
|
|
dfbb106c69 | ||
|
|
38bce65c21 | ||
|
|
a79077b30e | ||
|
|
ac811d4708 | ||
|
|
82d6d27567 | ||
|
|
a6da925837 | ||
|
|
4a922a5772 | ||
|
|
858f701ee8 | ||
|
|
ed847d43dc | ||
|
|
ab4c246cda | ||
|
|
7092f16a06 | ||
|
|
fdae4b895c | ||
|
|
c1f8ec81d8 | ||
|
|
2e953c625b | ||
|
|
b15e5e893e | ||
|
|
4b8fecfe58 | ||
|
|
4aa1f8e14a | ||
|
|
63baec3ac8 | ||
|
|
0b7fa14030 | ||
|
|
5d2f1804e7 | ||
|
|
c7abc8c718 | ||
|
|
337d7d7a7a | ||
|
|
5858cb113e | ||
|
|
fe6ae937ef | ||
|
|
c344a26e80 | ||
|
|
6a58fc20da |
No files matched your search
@@ -0,0 +1,5 @@
|
||||
# Generated files that tests compare byte for byte with what they generate: LF on every OS, also
|
||||
# where Git for Windows' core.autocrlf would check them out with CRLF.
|
||||
docs/launcher-commands.md text eol=lf
|
||||
docs/horizon-ctl-commands.md text eol=lf
|
||||
website/src/tokens.css text eol=lf
|
||||
@@ -61,7 +61,8 @@ jobs:
|
||||
if: steps.rust.outputs.required != 'false'
|
||||
run: |
|
||||
cargo +stable fmt --all -- --check
|
||||
cargo +stable clippy --workspace --all-targets -- -D warnings
|
||||
# With the game's code mods (on in every release build, off by default).
|
||||
cargo +stable clippy --workspace --all-targets --features horizon-client/mods -- -D warnings
|
||||
# The server build (released as horizon-engine): the game without sound or controllers.
|
||||
cargo +stable clippy -p horizon-client --all-targets --no-default-features -- -D warnings
|
||||
# Libraries, binaries and integration tests, then doc tests: not the ~275 examples, which clippy above already
|
||||
@@ -69,8 +70,8 @@ jobs:
|
||||
- name: Test Rust core and voxel kernel correctness
|
||||
if: steps.rust.outputs.required != 'false'
|
||||
run: |
|
||||
cargo +stable test --workspace --lib --bins --tests
|
||||
cargo +stable test --workspace --doc
|
||||
cargo +stable test --workspace --lib --bins --tests --features horizon-client/mods,horizon-mods/pack
|
||||
cargo +stable test --workspace --doc --features horizon-client/mods,horizon-mods/pack
|
||||
parity:
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: ./.github/workflows/parity.yml
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: release
|
||||
# Automatic game releases (docs/release-flow.md). After every green `checks` run on main, every 10 minutes (so a
|
||||
# release waiting for merges to settle goes out without another merge) and by hand, tools/release_train.py decides:
|
||||
# a release when pull requests merged since the last one changed what players run and the newest merged 5 minutes
|
||||
# ago (the oldest 20 minutes ago, if merges never pause), or at once for a pull request labelled release-now.
|
||||
# a release when 5 pull requests merged since the last one changed what players run and the newest merged 5 minutes
|
||||
# ago, or when the oldest has waited 6 hours, or at once for a pull request labelled release-now.
|
||||
# RELEASES_PAUSED=1 (repository variable) stops them; so does an open issue labelled release-blocker, forced runs too.
|
||||
# Builds Linux (an older Ubuntu, so the binary runs on any recent distribution and on NixOS through nix-ld) and
|
||||
# Windows on GitHub, macOS on the Mac mini's runner (MAC_RUNNER=macos-latest sends it to GitHub), then
|
||||
@@ -133,7 +133,8 @@ jobs:
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libasound2-dev libudev-dev
|
||||
- name: Build the client, horizon-ctl, horizon-prepare and horizon-server
|
||||
run: cargo build --release --locked -p horizon-client --bin horizon-client --bin horizon-ctl -p horizon-prepare --bin horizon-prepare -p horizon-server --bin horizon-server
|
||||
# `horizon-client/mods`: every released game runs code mods (the feature is off in dev builds).
|
||||
run: cargo build --release --locked --features horizon-client/mods -p horizon-client --bin horizon-client --bin horizon-ctl -p horizon-prepare --bin horizon-prepare -p horizon-server --bin horizon-server
|
||||
- name: Every program the release folder takes was built
|
||||
run: |
|
||||
for binary in horizon-client horizon-ctl horizon-prepare horizon-server; do
|
||||
@@ -255,8 +256,9 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# After the client is packaged: target/release/horizon-client is rebuilt without the audio and
|
||||
# controllers features, so it needs neither libasound nor libudev (minimal server images lack them).
|
||||
cargo build --release --locked -p horizon-client --no-default-features --bin horizon-client
|
||||
# controllers features, so it needs neither libasound nor libudev (minimal server images lack them),
|
||||
# and with code mods like the client.
|
||||
cargo build --release --locked -p horizon-client --no-default-features --features mods --bin horizon-client
|
||||
cargo run --locked -p xtask -- package-server target/release/horizon-client "dist/${{ matrix.server_dir }}"
|
||||
folder="dist/${{ matrix.server_dir }}"
|
||||
python3 tools/check_imports.py --server "$folder/horizon-engine" "$folder/horizon-server" "$folder/horizon-prepare"
|
||||
|
||||
@@ -12,17 +12,20 @@ Feature → files → harness for the most-changed areas: [docs/architecture.md]
|
||||
folders in `HORIZON_HOME` (the game's data), `HORIZON_LAUNCHER_HOME`, `XDG_DATA_HOME` and
|
||||
`XDG_CONFIG_HOME`, plus `HORIZON_LAUNCHER_NO_SELF_UPDATE=1` and `HORIZON_NO_AUDIO=1`. Never write to
|
||||
`~/.local/share/{applications,horizon,horizon-launcher}` or `~/.local/bin`.
|
||||
- **Mark what an agent posts.** A PR body starts with
|
||||
`> 🤖 Opened by Ludovic's AI agent (Claude), not by Ludovic himself.` (issues: "Filed by", reviews:
|
||||
"Review by"); every comment starts with `🤖 Agent:`. Never write as Ludovic.
|
||||
- **Attribution.** Commits end with `Co-Authored-By: Claude <model> <[email protected]>`; PR bodies end
|
||||
with `🤖 Generated with [Claude Code](https://claude.com/claude-code)`.
|
||||
- **Mark what an agent posts.** A PR body starts with a line naming whose agent opened it and with what.
|
||||
Ludovic's agents write `> 🤖 Opened by Ludovic's AI agent (Claude), not by Ludovic himself.`, and a
|
||||
contributor's agent names its own person and tool (issues: "Filed by", reviews: "Review by"). Every
|
||||
comment starts with `🤖 Agent:`. Never write as Ludovic or as anyone else.
|
||||
- **Attribution.** Commits end with a `Co-Authored-By:` line for the agent that wrote them, and PR bodies
|
||||
with that agent's own "Generated with" line. Ludovic's agents use
|
||||
`Co-Authored-By: Claude <model> <[email protected]>` and
|
||||
`🤖 Generated with [Claude Code](https://claude.com/claude-code)`.
|
||||
- Everything players run is Rust. Python/Java only for dev tools and harness drivers in `tools/`.
|
||||
- Horizon-only features follow [docs/design-system.md](docs/design-system.md) and are off by default where
|
||||
they would change the vanilla look.
|
||||
- Small PRs (< ~500 lines). Labels: `feature` (players get something new), `skip-release` (they see no
|
||||
change), none for a fix. Agents never add `release-now`: the maintainer decides it. Every merge to main ships
|
||||
([docs/release-flow.md](docs/release-flow.md)).
|
||||
change), none for a fix. Agents never add `release-now`: the maintainer decides it. Merges ship in batches of 5, or after
|
||||
6 hours ([docs/release-flow.md](docs/release-flow.md)).
|
||||
- Contributors first: `gh pr list --state open --search <area>` before you start; never duplicate theirs.
|
||||
|
||||
## Crates
|
||||
@@ -40,7 +43,6 @@ Game workspace (root `Cargo.toml`); `launcher/` and `crates/horizon-telemetry-se
|
||||
| `horizon-server` | `horizon-server`: `server.toml`, CLI, supervisor of the headless game ([docs/hosting.md](docs/hosting.md)) |
|
||||
| `horizon-server-files` | `server.properties`, eula, ops/whitelist/bans, usercache |
|
||||
| `horizon-friends`, `horizon-relay` | Play with Friends: invite codes, encrypted tunnel, the relay ([docs/play-with-friends.md](docs/play-with-friends.md)) |
|
||||
| `horizon-shaderpack` | OptiFine/Iris packs: preprocessor, GLSL → WGSL ([docs/shader-packs.md](docs/shader-packs.md)) |
|
||||
| `horizon-mods`, `horizon-mod-sdk`, `cargo-horizon-mod` | Sandboxed WebAssembly mods: runtime, SDK + WIT, `cargo horizon-mod` ([docs/mods.md](docs/mods.md)) |
|
||||
| `horizon-port-pack` | Porting Java modpacks ([docs/modpacks.md](docs/modpacks.md)) |
|
||||
| `horizon-theme` | Design tokens and fonts for the launcher, the game's own menus and the website |
|
||||
@@ -123,7 +125,6 @@ python3 tools/agent_control_e2e.py # horizon-ctl / MCP end to end
|
||||
| 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` |
|
||||
| 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`, `lang.rs`; crate `horizon-assets`; G: `packs.rs` |
|
||||
| Shader packs | L: `shader_pack.rs` (Horizon WGSL packs), `java_pack.rs` + crate `horizon-shaderpack` (Iris/OptiFine), `gfx/pack_stages.rs`, `gfx/java_stages.rs`; G: `shader_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)) |
|
||||
| Mods | crate `horizon-mods`; G: `mods.rs`; L: `mod_content.rs`, `mod_list.rs` |
|
||||
| Horizon extras, settings | L: `extras.rs`, `graphics.rs`, `settings.rs`, `minimap.rs`; G: `extras.rs`, `tweaks.rs`, `options.rs` |
|
||||
@@ -148,19 +149,19 @@ python3 tools/agent_control_e2e.py # horizon-ctl / MCP end to end
|
||||
|
||||
## The two single-player paths
|
||||
|
||||
1. **In-frame (default since #1428):** the window's `Game` ticks the world itself, one level that follows
|
||||
the player (`fn enter_dimension`). This is what Stable players run and what harnesses test.
|
||||
2. **Server thread (`--server-thread` or `HORIZON_SERVER_THREAD=1`):** `game/integrated.rs` runs a second
|
||||
`Game` (`serving`) on a "Server thread" with one level per dimension; the window joins it as a client
|
||||
through memory (`remote`), exactly as a LAN guest or a dedicated server's player does. Not at parity yet:
|
||||
open `[server-thread]` issues list the gaps.
|
||||
1. **Server thread (default since #1514):** `game/integrated.rs` runs a second `Game` (`serving`) on a
|
||||
"Server thread" with one level per dimension; the window joins it as a client through memory (`remote`),
|
||||
exactly as a LAN guest or a dedicated server's player does. This is what players run. Open
|
||||
`[server-thread]` issues list the gaps left.
|
||||
2. **In-frame (`--in-frame`, `--no-server-thread` or `HORIZON_SERVER_THREAD=0`):** the window's `Game` ticks
|
||||
the world itself, one level that follows the player (`fn enter_dimension`). Most harnesses test this path.
|
||||
|
||||
LAN guests and dedicated servers always use the server code, so a fix there serves both. Test both paths
|
||||
when you touch player-facing gameplay:
|
||||
|
||||
```sh
|
||||
cargo run --profile fast -p horizon-client -- --resources .local/horizon-client/26.3 --world T # in-frame
|
||||
cargo run --profile fast -p horizon-client -- --resources .local/horizon-client/26.3 --world T --server-thread # server thread
|
||||
cargo run --profile fast -p horizon-client -- --resources .local/horizon-client/26.3 --world T # server thread
|
||||
cargo run --profile fast -p horizon-client -- --resources .local/horizon-client/26.3 --world T --in-frame # in-frame
|
||||
python3 tools/lan_e2e.py --check <name> # host in-frame, guest is a server client
|
||||
python3 tools/lan_e2e.py --server-thread --check <name> # host on its server thread (portals, levels, distance, lava need it)
|
||||
python3 tools/parity.py dedicated_server server_entities server_player_damage
|
||||
|
||||
Generated
+7
-399
@@ -178,15 +178,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||
|
||||
[[package]]
|
||||
name = "ascii-canvas"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891"
|
||||
dependencies = [
|
||||
"term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
version = "0.38.0+1.3.281"
|
||||
@@ -214,30 +205,15 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||
dependencies = [
|
||||
"bit-vec 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d"
|
||||
dependencies = [
|
||||
"bit-vec 0.9.1",
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.9.1"
|
||||
@@ -283,16 +259,6 @@ dependencies = [
|
||||
"objc2 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
@@ -484,15 +450,6 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coords-hud"
|
||||
version = "0.1.0"
|
||||
@@ -797,41 +754,6 @@ dependencies = [
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
@@ -849,29 +771,6 @@ dependencies = [
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.119",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -958,15 +857,6 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.42"
|
||||
@@ -1230,58 +1120,6 @@ version = "0.30.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9"
|
||||
|
||||
[[package]]
|
||||
name = "glsl-lang"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "983a18d0c2ecad18ac9ff3c94b069d6bd03b47405a200836d9d8d63def8e34de"
|
||||
dependencies = [
|
||||
"glsl-lang-lexer",
|
||||
"glsl-lang-types",
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
"lang-util",
|
||||
"once_cell",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glsl-lang-lexer"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abdbc0bdfbc81d557f4865e695457eb23d68031bfb061fda3444f56511b26eee"
|
||||
dependencies = [
|
||||
"glsl-lang-pp",
|
||||
"glsl-lang-types",
|
||||
"lalrpop-util",
|
||||
"lang-util",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glsl-lang-pp"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88677876fb27f116015d0ecebda6d77bdf65f3a6fa3f5dfeed10b8c8f04cb2c5"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"derive_more",
|
||||
"lang-util",
|
||||
"string_cache",
|
||||
"string_cache_codegen",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glsl-lang-types"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd8b1532b424d40df634cf2dc2be56d59f994b9ac07fa7c1e3183fd33db9cb07"
|
||||
dependencies = [
|
||||
"lang-util",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-allocator"
|
||||
version = "0.28.0"
|
||||
@@ -1428,7 +1266,6 @@ dependencies = [
|
||||
"horizon-mods",
|
||||
"horizon-protocol",
|
||||
"horizon-server-files",
|
||||
"horizon-shaderpack",
|
||||
"horizon-telemetry",
|
||||
"horizon-theme",
|
||||
"horizon-threads",
|
||||
@@ -1443,7 +1280,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"symphonia",
|
||||
"toml",
|
||||
"ureq",
|
||||
"wgpu",
|
||||
"winit",
|
||||
@@ -1493,7 +1329,6 @@ dependencies = [
|
||||
name = "horizon-mods"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"horizon-mods",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1595,16 +1430,6 @@ dependencies = [
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "horizon-shaderpack"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"glsl-lang",
|
||||
"naga",
|
||||
"pp-rs",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "horizon-telemetry"
|
||||
version = "0.1.0"
|
||||
@@ -1756,12 +1581,6 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.1.0"
|
||||
@@ -1944,73 +1763,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501"
|
||||
dependencies = [
|
||||
"ascii-canvas",
|
||||
"bit-set 0.8.0",
|
||||
"ena",
|
||||
"itertools",
|
||||
"lalrpop-util",
|
||||
"petgraph 0.7.1",
|
||||
"pico-args",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"sha3",
|
||||
"string_cache",
|
||||
"term",
|
||||
"unicode-xid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop-util"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lang-util"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1715a1e56998f119cd6d49ac8a69802dcbe4fca96d8291243d6dae87abeb913"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"lalrpop-util",
|
||||
"lang-util-derive",
|
||||
"line-span",
|
||||
"smol_str 0.3.6",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lang-util-derive"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f2acc66aedf0e445534e0a6b3f0f6ee20ef6ebb9647dbe10735e52ea8d6a096"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.1"
|
||||
@@ -2067,12 +1819,6 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line-span"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fc123b2f6600099ca18248f69e3ee02b09c4188c0d98e9a690d90dec3e408a"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
@@ -2184,7 +1930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a616d2fb8c89516ac2723a581f69d6c18576046bed761bd6b305e5618e6ae130"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set 0.10.0",
|
||||
"bit-set",
|
||||
"bitflags 2.13.2",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
@@ -2197,7 +1943,6 @@ dependencies = [
|
||||
"naga-types",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"pp-rs",
|
||||
"rustc-hash 1.1.0",
|
||||
"spirv",
|
||||
"thiserror 2.0.21",
|
||||
@@ -2246,12 +1991,6 @@ dependencies = [
|
||||
"jni-sys 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.31.3"
|
||||
@@ -2751,16 +2490,6 @@ version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
@@ -2772,31 +2501,6 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.13"
|
||||
@@ -2915,21 +2619,6 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pp-rs"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "presser"
|
||||
version = "0.3.1"
|
||||
@@ -3023,15 +2712,6 @@ version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
@@ -3370,16 +3050,6 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
@@ -3408,12 +3078,6 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
@@ -3463,16 +3127,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol_str"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
@@ -3522,37 +3176,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"parking_lot",
|
||||
"phf_shared",
|
||||
"precomputed-hash",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache_codegen"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
@@ -3669,15 +3292,6 @@ version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
@@ -3687,12 +3301,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-size"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@@ -3853,7 +3461,7 @@ checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"nom",
|
||||
"petgraph 0.8.3",
|
||||
"petgraph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4574,8 +4182,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c018fce9b6270aa203c2fdd56f3cce996713534bd757e4ea58c8560b121f14"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set 0.10.0",
|
||||
"bit-vec 0.9.1",
|
||||
"bit-set",
|
||||
"bit-vec",
|
||||
"bitflags 2.13.2",
|
||||
"bytemuck",
|
||||
"cfg_aliases",
|
||||
@@ -4625,7 +4233,7 @@ dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
"ash",
|
||||
"bit-set 0.10.0",
|
||||
"bit-set",
|
||||
"bitflags 2.13.2",
|
||||
"block2 0.6.2",
|
||||
"bytemuck",
|
||||
@@ -5123,7 +4731,7 @@ dependencies = [
|
||||
"rustix 0.38.44",
|
||||
"sctk-adwaita",
|
||||
"smithay-client-toolkit",
|
||||
"smol_str 0.2.2",
|
||||
"smol_str",
|
||||
"tracing",
|
||||
"unicode-segmentation",
|
||||
"wasm-bindgen",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
exclude = ["launcher", "crates/horizon-telemetry-server", "third_party/wgpu-hal"]
|
||||
members = ["crates/horizon-core", "crates/horizon-dualsense", "crates/horizon-threads", "crates/horizon-world", "crates/voxel-kernels", "crates/horizon-client", "crates/horizon-server-files", "crates/horizon-server", "crates/horizon-bots", "crates/horizon-assets", "crates/horizon-protocol", "crates/horizon-theme", "crates/horizon-shaderpack", "crates/horizon-prepare", "crates/horizon-telemetry", "crates/horizon-bench", "crates/horizon-friends", "crates/horizon-relay", "crates/horizon-mod-sdk", "crates/horizon-mods", "crates/horizon-mods/tests/guest", "crates/cargo-horizon-mod", "crates/horizon-port-pack", "crates/horizon-release-sign", "crates/horizon-mod-sdk/examples/coords-hud", "xtask"]
|
||||
members = ["crates/horizon-core", "crates/horizon-dualsense", "crates/horizon-threads", "crates/horizon-world", "crates/voxel-kernels", "crates/horizon-client", "crates/horizon-server-files", "crates/horizon-server", "crates/horizon-bots", "crates/horizon-assets", "crates/horizon-protocol", "crates/horizon-theme", "crates/horizon-prepare", "crates/horizon-telemetry", "crates/horizon-bench", "crates/horizon-friends", "crates/horizon-relay", "crates/horizon-mod-sdk", "crates/horizon-mods", "crates/horizon-mods/tests/guest", "crates/cargo-horizon-mod", "crates/horizon-port-pack", "crates/horizon-release-sign", "crates/horizon-mod-sdk/examples/coords-hud", "xtask"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
|
||||
@@ -45,7 +45,7 @@ The [documentation](https://playhorizon.dev/docs/) covers each of these.
|
||||
|
||||
- **The game:** singleplayer with vanilla's world generation, mobs, villagers, raids, redstone, every command, the HUD and the recipe book, on saves in vanilla's format. Worlds from 1.8 to 26.2 are upgraded as vanilla does. [Status table](#project-status).
|
||||
- **Horizon's own extras:** new menus (vanilla's are one setting away), graphics presets, distant terrain up to 1024 chunks, controller support, optional zoom, minimap and more, all off by default where they would change the vanilla look. See [Settings](https://playhorizon.dev/docs/settings).
|
||||
- **Resource packs, shader packs and data packs:** resource packs work, Java shader packs run their full-screen effects (experimental), and data packs load functions, predicates and item modifiers.
|
||||
- **Resource packs and data packs:** resource packs work, and data packs load functions, predicates and item modifiers.
|
||||
- **Playing with others:** invite friends from the pause menu's Friends button with a code, Open to LAN, and joining offline-mode servers. Horizon cannot sign in to a Microsoft account yet, so it cannot join servers that check accounts. See [Multiplayer](https://playhorizon.dev/docs/multiplayer).
|
||||
- **Mods:** Horizon has its own mod system (Rust compiled to WebAssembly). Java mod jars do not run. See [Mods and data packs](https://playhorizon.dev/docs/mods).
|
||||
|
||||
@@ -57,7 +57,7 @@ Screenshots, captured in the Rust client itself with vanilla assets and no mods
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%"><img src="docs/media/survival.webp" alt="Survival at dusk: a zombie walks up, with the hotbar, health, hunger and experience"></td>
|
||||
<td width="50%"><img src="docs/media/settings.webp" alt="Vanilla's Video Settings screen with Horizon's own buttons at the top: Horizon Graphics, Advanced Graphics and Shader Packs"></td>
|
||||
<td width="50%"><img src="docs/media/settings.webp" alt="Vanilla's Video Settings screen with Horizon's own buttons at the top: Horizon Graphics and Advanced Graphics"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%"><img src="docs/media/village.webp" alt="A plains village among savanna hills, with farms, villagers and an iron golem"></td>
|
||||
|
||||
@@ -18,7 +18,8 @@ horizon-protocol = { path = "../horizon-protocol" }
|
||||
horizon-server-files = { path = "../horizon-server-files" }
|
||||
horizon-friends = { path = "../horizon-friends" }
|
||||
# Horizon mods: sandboxed WebAssembly components, off unless installed and turned on (docs/mods.md).
|
||||
horizon-mods = { path = "../horizon-mods" }
|
||||
# Their runtime is the `mods` feature.
|
||||
horizon-mods = { path = "../horizon-mods", default-features = false }
|
||||
wgpu = { version = "30.0.1", default-features = false, features = ["std", "parking_lot", "vulkan", "metal", "wgsl"] }
|
||||
winit = "0.30.13"
|
||||
pollster = "0.4"
|
||||
@@ -28,13 +29,9 @@ png = "0.18"
|
||||
sha2 = "0.10.9"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1.0.151", features = ["raw_value"] }
|
||||
# Shader packs: pack.toml, and WGSL checked before it reaches wgpu.
|
||||
toml = "1.1"
|
||||
# hlsl-out: the gfx.rs tests translate every shader as wgpu's DirectX 12 backend does. A normal feature,
|
||||
# not a dev-dependency's, so builds, tests and examples share one build of naga, wgpu and this crate.
|
||||
naga = { version = "30.0.1", features = ["wgsl-in", "hlsl-out"] }
|
||||
# Java (OptiFine/Iris) shader packs, translated to WGSL.
|
||||
horizon-shaderpack = { path = "../horizon-shaderpack" }
|
||||
# Sound (ALSA on Linux); the `audio` feature.
|
||||
cpal = { version = "0.16", optional = true }
|
||||
symphonia = { version = "0.5", default-features = false, features = ["ogg", "vorbis"] }
|
||||
@@ -78,8 +75,20 @@ default = ["audio", "controllers"]
|
||||
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"]
|
||||
# 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"]
|
||||
# Records the call sites of mob random draws (`mob_ai_probe` traces).
|
||||
rng-trace = ["horizon-core/rng-trace"]
|
||||
|
||||
# Its own name, not `probe`: Cargo copies every crate's examples into one target/<profile>/examples.
|
||||
[[example]]
|
||||
name = "client_probe"
|
||||
path = "examples/probe/main.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
# Every WGSL shader translated as wgpu's DirectX 12 backend does (gfx.rs tests).
|
||||
naga = { version = "30.0.1", features = ["wgsl-in", "hlsl-out", "msl-out", "spv-out"] }
|
||||
@@ -1,104 +0,0 @@
|
||||
//! Full production fact loading, including file reads, interning and temporary destruction.
|
||||
//! cargo run --profile fast -p horizon-client --example block_facts_bench -- ROOT [SAMPLES]
|
||||
//! Use SAMPLES=1 with an OS peak-RSS wrapper; `digest` checks all facts
|
||||
//! and the shape sharing partition (including sharing between outlines and edges).
|
||||
use horizon_client::blocks::BlockFacts;
|
||||
use horizon_world::{DATA_VERSION, nbt::Tag, registry::BlockRegistry};
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::DefaultHasher},
|
||||
fs,
|
||||
hash::{Hash, Hasher},
|
||||
hint::black_box,
|
||||
path::Path,
|
||||
time::Instant,
|
||||
};
|
||||
type Result<T> = horizon_client::Result<T>;
|
||||
|
||||
fn tag(value: &Value) -> Result<Tag> {
|
||||
Ok(match value {
|
||||
Value::String(s) => Tag::String(s.as_str().into()),
|
||||
Value::Number(n) => Tag::Int(i32::try_from(n.as_i64().ok_or("registry number")?)?),
|
||||
Value::Array(a) => Tag::List(a.iter().map(tag).collect::<Result<_>>()?),
|
||||
Value::Object(o) => Tag::Compound(
|
||||
o.iter()
|
||||
.map(|(k, v)| Ok((k.as_str().into(), tag(v)?)))
|
||||
.collect::<Result<_>>()?,
|
||||
),
|
||||
_ => return Err("registry value".into()),
|
||||
})
|
||||
}
|
||||
fn registry(root: &Path) -> Result<BlockRegistry> {
|
||||
let facts: Value = serde_json::from_slice(&fs::read(root.join("facts.json"))?)?;
|
||||
Ok(BlockRegistry::from_nbt(&Tag::compound([
|
||||
("DataVersion", Tag::Int(DATA_VERSION)),
|
||||
(
|
||||
"states",
|
||||
Tag::List(
|
||||
facts["states"]
|
||||
.as_array()
|
||||
.ok_or("registry states")?
|
||||
.iter()
|
||||
.map(|s| tag(&s[4]))
|
||||
.collect::<Result<_>>()?,
|
||||
),
|
||||
),
|
||||
("defaults", tag(&facts["defaults"])?),
|
||||
]))?)
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
let root = Path::new(
|
||||
args.first()
|
||||
.ok_or("usage: block_facts_bench ROOT [SAMPLES|digest]")?,
|
||||
);
|
||||
let setup = Instant::now();
|
||||
let registry = registry(root)?;
|
||||
println!(
|
||||
"registry_setup_ms={:.3}",
|
||||
setup.elapsed().as_secs_f64() * 1000.0
|
||||
);
|
||||
if args.get(1).is_some_and(|s| s == "digest") {
|
||||
let facts = BlockFacts::load(root, ®istry)?;
|
||||
let mut hash = DefaultHasher::new();
|
||||
let mut shapes = HashMap::new();
|
||||
facts.air.hash(&mut hash);
|
||||
for state in &facts.states {
|
||||
format!("{state:?}").hash(&mut hash);
|
||||
for shape in [&state.outline, &state.outline_edges] {
|
||||
let next = shapes.len();
|
||||
shapes
|
||||
.entry((shape.as_ptr(), shape.len()))
|
||||
.or_insert(next)
|
||||
.hash(&mut hash);
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"states={} shared_shapes={} digest={:016x}",
|
||||
facts.states.len(),
|
||||
shapes.len(),
|
||||
hash.finish()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
let samples: usize = args.get(1).map(|s| s.parse()).transpose()?.unwrap_or(9);
|
||||
assert!(samples > 0);
|
||||
// First load is reported separately; OS file caches are not forcibly evicted.
|
||||
let load = || -> Result<f64> {
|
||||
let start = Instant::now();
|
||||
let facts = black_box(BlockFacts::load(black_box(root), black_box(®istry))?);
|
||||
let ms = start.elapsed().as_secs_f64() * 1000.0;
|
||||
drop(facts);
|
||||
Ok(ms)
|
||||
};
|
||||
println!("first_load_ms={:.3}", load()?);
|
||||
if samples > 1 {
|
||||
load()?;
|
||||
load()?;
|
||||
let mut times = (0..samples).map(|_| load()).collect::<Result<Vec<_>>>()?;
|
||||
println!("samples_ms={times:.3?}");
|
||||
times.sort_by(f64::total_cmp);
|
||||
println!("median_ms={:.3}", times[times.len() / 2]);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
//! Resident chunk storage benchmark: generates a block of vanilla terrain, then
|
||||
//! reports the resident block/biome memory, the cost of lookups, meshing and
|
||||
//! lighting on it.
|
||||
//!
|
||||
//! chunk_bench <client resource dir> [--seed S] [--size N]
|
||||
#![forbid(unsafe_code)]
|
||||
use horizon_client::{
|
||||
assets::Assets,
|
||||
biome::Biomes,
|
||||
blocks::BlockFacts,
|
||||
chunk::{Chunk, MIN_Y, SECTIONS},
|
||||
light::{LightTables, apply_lighting, light_chunk},
|
||||
mesher::{MeshTables, Mesher},
|
||||
models,
|
||||
streaming::{ChunkGenerator, Proto},
|
||||
vanillagen::VanillaTerrain,
|
||||
};
|
||||
use horizon_core::biome::BiomeZoom;
|
||||
use std::{path::PathBuf, sync::Arc, time::Instant};
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let root = PathBuf::from(args.first().ok_or("usage: chunk_bench RESOURCES")?);
|
||||
let flag = |name: &str, default: i64| -> i64 {
|
||||
args.iter()
|
||||
.position(|a| a == name)
|
||||
.and_then(|i| args.get(i + 1))
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(default)
|
||||
};
|
||||
let (seed, size) = (flag("--seed", 12345), flag("--size", 8) as i32);
|
||||
let assets = Assets::load(&root)?;
|
||||
let render = assets.reload(&root)?;
|
||||
let facts = BlockFacts::load(&root, assets.registry)?;
|
||||
let biomes = Biomes::load(&root)?;
|
||||
let tables = MeshTables::new(
|
||||
&assets,
|
||||
&render,
|
||||
&facts,
|
||||
models::load_visibility(&root, assets.registry)?,
|
||||
)?;
|
||||
let light = LightTables::load(&root, assets.registry, &facts)?;
|
||||
let terrain = VanillaTerrain::new(&root.join("worldgen"), assets.registry, &biomes, seed)?;
|
||||
let mut worker = terrain.worker();
|
||||
|
||||
// Protos for size+4 columns, decorated for the inner size+2, finished as size+2.
|
||||
let started = Instant::now();
|
||||
let outer = size + 4;
|
||||
let mut protos: Vec<Option<Proto>> = (0..outer * outer)
|
||||
.map(|i| Some(terrain.proto(&mut worker, i % outer, i / outer)))
|
||||
.collect();
|
||||
eprintln!("proto: {:.2}s", started.elapsed().as_secs_f64());
|
||||
let started = Instant::now();
|
||||
let inner = size + 2;
|
||||
for z in 1..=inner {
|
||||
for x in 1..=inner {
|
||||
let mut region: [Proto; 9] = std::array::from_fn(|k| {
|
||||
let (dx, dz) = (k as i32 % 3 - 1, k as i32 / 3 - 1);
|
||||
protos[((z + dz) * outer + x + dx) as usize]
|
||||
.take()
|
||||
.expect("proto")
|
||||
});
|
||||
terrain.decorate(&mut worker, &mut region);
|
||||
for (k, p) in region.into_iter().enumerate() {
|
||||
let (dx, dz) = (k as i32 % 3 - 1, k as i32 / 3 - 1);
|
||||
protos[((z + dz) * outer + x + dx) as usize] = Some(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!("decorate: {:.2}s", started.elapsed().as_secs_f64());
|
||||
let started = Instant::now();
|
||||
let mut chunks: Vec<Chunk> = Vec::new();
|
||||
for z in 1..=inner {
|
||||
for x in 1..=inner {
|
||||
let proto = protos[(z * outer + x) as usize].take().expect("proto");
|
||||
let mut chunk = terrain.finish(proto);
|
||||
chunk.x = x;
|
||||
chunk.z = z;
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
let finish = started.elapsed().as_secs_f64();
|
||||
println!(
|
||||
"finish (proto -> resident chunk): {:.1} ms per chunk",
|
||||
finish * 1e3 / chunks.len() as f64
|
||||
);
|
||||
|
||||
let chunks: Vec<Arc<Chunk>> = chunks.into_iter().map(Arc::new).collect();
|
||||
let at = |x: i32, z: i32| chunks[((z - 1) * inner + x - 1) as usize].clone();
|
||||
|
||||
// Light all inner-inner columns.
|
||||
let started = Instant::now();
|
||||
let mut lit = Vec::new();
|
||||
for z in 2..inner {
|
||||
for x in 2..inner {
|
||||
let region: [[Option<Arc<Chunk>>; 3]; 3] = std::array::from_fn(|dz| {
|
||||
std::array::from_fn(|dx| Some(at(x + dx as i32 - 1, z + dz as i32 - 1)))
|
||||
});
|
||||
let borrowed = horizon_client::mesher::borrow(®ion);
|
||||
lit.push(((x, z), light_chunk(&borrowed, &light, true)));
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"light: {:.2} ms per column",
|
||||
started.elapsed().as_secs_f64() * 1e3 / lit.len() as f64
|
||||
);
|
||||
let mut chunks: Vec<Chunk> = chunks.iter().map(|c| (**c).clone()).collect();
|
||||
for ((x, z), sections) in lit {
|
||||
apply_lighting(&mut chunks[((z - 1) * inner + x - 1) as usize], sections);
|
||||
}
|
||||
let chunks: Vec<Arc<Chunk>> = chunks.into_iter().map(Arc::new).collect();
|
||||
let at = |x: i32, z: i32| chunks[((z - 1) * inner + x - 1) as usize].clone();
|
||||
|
||||
// Memory.
|
||||
let (mut bytes, mut sections, mut uniform) = (0usize, 0usize, 0usize);
|
||||
for chunk in &chunks {
|
||||
bytes += chunk.heap_bytes();
|
||||
for s in &chunk.sections {
|
||||
sections += 1;
|
||||
uniform += usize::from(s.is_uniform(s.get(0)));
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"resident: {} chunks, {} sections ({} uniform), {:.1} KiB per chunk ({:.2} MiB total)",
|
||||
chunks.len(),
|
||||
sections,
|
||||
uniform,
|
||||
bytes as f64 / 1024.0 / chunks.len() as f64,
|
||||
bytes as f64 / 1048576.0
|
||||
);
|
||||
|
||||
// Meshing.
|
||||
let mut mesher = Mesher {
|
||||
nether_shading: false,
|
||||
assets: &assets,
|
||||
render: &render,
|
||||
tables: &tables,
|
||||
biomes: &biomes,
|
||||
visibility: tables.visibility.clone(),
|
||||
zoom: BiomeZoom::new(7),
|
||||
blend_radius: 2,
|
||||
smooth_lighting: true,
|
||||
cutout_leaves: true,
|
||||
cull_leaves: false,
|
||||
};
|
||||
let mut best = f64::MAX;
|
||||
let mut quads = 0usize;
|
||||
for _ in 0..3 {
|
||||
let started = Instant::now();
|
||||
let mut jobs = 0;
|
||||
quads = 0;
|
||||
for z in 2..inner {
|
||||
for x in 2..inner {
|
||||
let region: [[Option<Arc<Chunk>>; 3]; 3] = std::array::from_fn(|dz| {
|
||||
std::array::from_fn(|dx| Some(at(x + dx as i32 - 1, z + dz as i32 - 1)))
|
||||
});
|
||||
let borrowed = horizon_client::mesher::borrow(®ion);
|
||||
for sy in 0..SECTIONS as i32 {
|
||||
let mesh = mesher.mesh(&borrowed, sy);
|
||||
quads += (mesh.solid.len() + mesh.translucent.len()) / 4;
|
||||
jobs += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
best = best.min(started.elapsed().as_secs_f64() / f64::from(jobs));
|
||||
}
|
||||
println!(
|
||||
"mesh: {:.1} us per section ({} quads total)",
|
||||
best * 1e6,
|
||||
quads
|
||||
);
|
||||
|
||||
// Random lookups, as collision and entity queries do.
|
||||
let mut state = 0x9E37_79B9_7F4A_7C15u64;
|
||||
let started = Instant::now();
|
||||
let mut sum = 0u64;
|
||||
let lookups = 20_000_000u64;
|
||||
for _ in 0..lookups {
|
||||
state ^= state << 13;
|
||||
state ^= state >> 7;
|
||||
state ^= state << 17;
|
||||
let cx = 2 + (state % u64::from((inner - 2) as u32)) as i32;
|
||||
let cz = 2 + ((state >> 8) % u64::from((inner - 2) as u32)) as i32;
|
||||
let chunk = &chunks[((cz - 1) * inner + cx - 1) as usize];
|
||||
let (x, y, z) = (
|
||||
(state >> 16) as i32 & 15,
|
||||
MIN_Y + ((state >> 24) % 384) as i32,
|
||||
(state >> 40) as i32 & 15,
|
||||
);
|
||||
sum += u64::from(chunk.get(x, y, z));
|
||||
}
|
||||
println!(
|
||||
"random get: {:.2} ns per lookup (checksum {sum})",
|
||||
started.elapsed().as_secs_f64() * 1e9 / lookups as f64
|
||||
);
|
||||
// Coherent scan, as a column or area query does.
|
||||
let started = Instant::now();
|
||||
let mut sum = 0u64;
|
||||
for _ in 0..4 {
|
||||
for chunk in &chunks {
|
||||
for y in MIN_Y..MIN_Y + 384 {
|
||||
for z in 0..16 {
|
||||
for x in 0..16 {
|
||||
sum += u64::from(chunk.get(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"scan get: {:.2} ns per lookup (checksum {sum})",
|
||||
started.elapsed().as_secs_f64() * 1e9 / (4.0 * chunks.len() as f64 * 98304.0)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
//! Isolated production mob-model builder benchmark; no assets, Game, GPU or full-frame work.
|
||||
//! CARGO_TARGET_DIR=/home/bob/Documents/horizon/target CARGO_INCREMENTAL=0 \
|
||||
//! cargo run --profile fast -p horizon-client --example entity_geometry_bench
|
||||
use horizon_client::{
|
||||
mesher::Vertex,
|
||||
mobs::{Part, Polygon, anim::Poses, render},
|
||||
};
|
||||
use std::{hint::black_box, time::Instant};
|
||||
|
||||
fn cube(name: String, position: f32) -> Part {
|
||||
let polygons = (0..6)
|
||||
.map(|face| {
|
||||
let axis = face / 2;
|
||||
let side = (face % 2) as f32;
|
||||
let mut normal = [0.0; 3];
|
||||
normal[axis] = side * 2.0 - 1.0;
|
||||
Polygon {
|
||||
normal,
|
||||
vertices: [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]].map(|uv| {
|
||||
let mut vertex = [0.0; 5];
|
||||
vertex[axis] = side * 8.0;
|
||||
vertex[(axis + 1) % 3] = uv[0] * 8.0;
|
||||
vertex[(axis + 2) % 3] = uv[1] * 8.0;
|
||||
vertex[3] = uv[0];
|
||||
vertex[4] = uv[1];
|
||||
vertex
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Part {
|
||||
name,
|
||||
pose: [position, 0.0, 0.0, 0.1, 0.2, 0.0, 1.0, 1.0, 1.0],
|
||||
polygons,
|
||||
children: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build(model: &Part, poses: &Poses, count: usize, out: &mut Vec<Vertex>) {
|
||||
for i in 0..count {
|
||||
render::draw(
|
||||
black_box(model),
|
||||
glam::Mat4::from_translation(glam::Vec3::new((i % 32) as f32, 0.0, (i / 32) as f32)),
|
||||
black_box(poses),
|
||||
[0.125, 0.25, 0.5, 0.75],
|
||||
0xffc0_d0e0,
|
||||
0xf0f0,
|
||||
0,
|
||||
out,
|
||||
);
|
||||
}
|
||||
black_box(out.as_slice());
|
||||
}
|
||||
|
||||
fn measure(model: &Part, poses: &Poses, count: usize, iterations: usize, reuse: bool) -> f64 {
|
||||
let mut retained = Vec::new();
|
||||
build(model, poses, count, &mut retained); // Untimed warmup.
|
||||
let start = Instant::now();
|
||||
for _ in 0..iterations {
|
||||
let mut out = if reuse {
|
||||
std::mem::take(&mut retained)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
out.clear();
|
||||
build(model, poses, count, &mut out);
|
||||
if reuse {
|
||||
retained = out;
|
||||
}
|
||||
}
|
||||
start.elapsed().as_secs_f64() * 1e6 / iterations as f64
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut model = cube("body".into(), 0.0);
|
||||
model.children = (1..6).map(|i| cube(format!("part{i}"), i as f32)).collect();
|
||||
let poses = Poses::new(&model);
|
||||
for count in [32, 256, 1024, 4096, 8192] {
|
||||
let mut expected = Vec::new();
|
||||
build(&model, &poses, count, &mut expected);
|
||||
let mut retained = Vec::new();
|
||||
build(&model, &poses, count, &mut retained);
|
||||
let (pointer, capacity) = (retained.as_ptr(), retained.capacity());
|
||||
// Populated -> empty/reset -> smaller -> populated must never leave stale vertices.
|
||||
for n in [0, count / 2, count, count] {
|
||||
retained.clear();
|
||||
build(&model, &poses, n, &mut retained);
|
||||
let mut fresh = Vec::new();
|
||||
build(&model, &poses, n, &mut fresh);
|
||||
assert_eq!(
|
||||
bytemuck::cast_slice::<Vertex, u8>(&retained),
|
||||
bytemuck::cast_slice::<Vertex, u8>(&fresh)
|
||||
);
|
||||
assert_eq!(
|
||||
(retained.as_ptr(), retained.capacity()),
|
||||
(pointer, capacity)
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
bytemuck::cast_slice::<Vertex, u8>(&retained),
|
||||
bytemuck::cast_slice::<Vertex, u8>(&expected)
|
||||
);
|
||||
let iterations = (100_000 / count).clamp(40, 1000);
|
||||
let mut fresh = Vec::new();
|
||||
let mut reused = Vec::new();
|
||||
let mut paired_speedups = Vec::new();
|
||||
// Alternate order, reporting medians over eleven warmed batches.
|
||||
for batch in 0..11 {
|
||||
let mut pair = [0.0; 2];
|
||||
for reuse in if batch % 2 == 0 {
|
||||
[false, true]
|
||||
} else {
|
||||
[true, false]
|
||||
} {
|
||||
let time = measure(&model, &poses, count, iterations, reuse);
|
||||
pair[usize::from(reuse)] = time;
|
||||
if reuse {
|
||||
reused.push(time);
|
||||
} else {
|
||||
fresh.push(time);
|
||||
}
|
||||
}
|
||||
paired_speedups.push(pair[0] / pair[1]);
|
||||
}
|
||||
paired_speedups.sort_by(f64::total_cmp);
|
||||
fresh.sort_by(f64::total_cmp);
|
||||
reused.sort_by(f64::total_cmp);
|
||||
println!(
|
||||
"entities={count} vertices={} capacity={capacity} retained_bytes={} fresh_us={:.3} reused_us={:.3} speedup={:.3}x paired_speedup_median={:.3}x paired_speedup_range={:.3}..{:.3}x iterations={iterations} batches=11 byte_equivalence=pass pointer_capacity_reuse=pass",
|
||||
retained.len(),
|
||||
capacity * size_of::<Vertex>(),
|
||||
fresh[5],
|
||||
reused[5],
|
||||
fresh[5] / reused[5],
|
||||
paired_speedups[5],
|
||||
paired_speedups[0],
|
||||
paired_speedups[10]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
//! Compare the exact read/deserialize sequences used by the model loaders.
|
||||
//! Run with `cargo run -p horizon-client --profile fast --example json_readers_bench`.
|
||||
//! Optional arguments: resource directory, repetitions (default 9).
|
||||
use serde_json::{Map, Value, json};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::Debug,
|
||||
fs::{self, File},
|
||||
hint::black_box,
|
||||
io::BufReader,
|
||||
path::{Path, PathBuf},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
type Result<T> = horizon_client::Result<T>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Reader {
|
||||
File,
|
||||
Buffered,
|
||||
Slice,
|
||||
}
|
||||
const READERS: [Reader; 3] = [Reader::File, Reader::Buffered, Reader::Slice];
|
||||
|
||||
// These match the map types and reader expressions at all three production sites.
|
||||
macro_rules! reader {
|
||||
($name:ident, $map:ty) => {
|
||||
fn $name(path: &Path, reader: Reader) -> Result<$map> {
|
||||
Ok(match reader {
|
||||
Reader::File => serde_json::from_reader(File::open(path)?)?,
|
||||
Reader::Buffered => serde_json::from_reader(BufReader::new(File::open(path)?))?,
|
||||
Reader::Slice => serde_json::from_slice(&fs::read(path)?)?,
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
reader!(prepare_facts, Map<String, Value>);
|
||||
reader!(catalog_facts, BTreeMap<String, Value>);
|
||||
|
||||
struct Fixture(PathBuf);
|
||||
impl Fixture {
|
||||
fn new() -> Result<Self> {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("horizon-json-readers-{}", std::process::id()));
|
||||
fs::create_dir(&root)?;
|
||||
Ok(Self(root))
|
||||
}
|
||||
}
|
||||
impl Drop for Fixture {
|
||||
fn drop(&mut self) {
|
||||
let _ = fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn fixtures(root: &Path) -> Result<()> {
|
||||
let states: Vec<_> = (0..56)
|
||||
.map(|i| {
|
||||
json!({"facing": (["north", "east", "south", "west"][i % 4]),
|
||||
"powered": if i / 4 % 2 == 0 { "false" } else { "true" },
|
||||
"age": (i / 8).to_string()})
|
||||
})
|
||||
.collect();
|
||||
let mut models = Map::new();
|
||||
let mut render = Map::new();
|
||||
for i in 0..1024 {
|
||||
let name = format!("minecraft:fixture_block_{i:04}");
|
||||
models.insert(
|
||||
name.clone(),
|
||||
json!({
|
||||
"schema": {"facing": {"named": ["north", "east", "south", "west"]},
|
||||
"powered": {"named": ["false", "true"]}, "age": {"integer": [0, 6]}},
|
||||
"states": states
|
||||
}),
|
||||
);
|
||||
render.insert(
|
||||
name,
|
||||
json!({"rule": "never", "can_occlude": true, "bars_tag": false}),
|
||||
);
|
||||
}
|
||||
fs::write(root.join("model-states.json"), serde_json::to_vec(&models)?)?;
|
||||
fs::write(
|
||||
root.join("render-definitions.json"),
|
||||
serde_json::to_vec(&render)?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn benchmark<T: PartialEq + Debug>(
|
||||
label: &str,
|
||||
path: &Path,
|
||||
repetitions: usize,
|
||||
read: impl Fn(&Path, Reader) -> Result<T>,
|
||||
) -> Result<()> {
|
||||
let expected = read(path, Reader::File)?;
|
||||
for reader in READERS {
|
||||
assert_eq!(expected, read(path, reader)?);
|
||||
for _ in 0..2 {
|
||||
black_box(read(black_box(path), reader)?);
|
||||
}
|
||||
}
|
||||
drop(expected);
|
||||
let mut samples: [Vec<f64>; 3] = std::array::from_fn(|_| Vec::new());
|
||||
for repetition in 0..repetitions {
|
||||
// Rotate reader order to distribute drift across implementations.
|
||||
for offset in 0..3 {
|
||||
let index = (repetition + offset) % 3;
|
||||
let start = Instant::now();
|
||||
let value = black_box(read(black_box(path), READERS[index])?);
|
||||
samples[index].push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
drop(value); // Match the loaders: retain the parsed tree after loading.
|
||||
}
|
||||
}
|
||||
let median: Vec<_> = samples
|
||||
.iter_mut()
|
||||
.map(|s| {
|
||||
s.sort_by(f64::total_cmp);
|
||||
s[s.len() / 2]
|
||||
})
|
||||
.collect();
|
||||
println!(
|
||||
"{label}: {} bytes, {repetitions} samples/reader, median ms: File={:.3}, BufReader={:.3}, read+slice={:.3}; slice speedup={:.2}x",
|
||||
fs::metadata(path)?.len(),
|
||||
median[0],
|
||||
median[1],
|
||||
median[2],
|
||||
median[0] / median[2]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
let fixture = if args.is_empty() {
|
||||
Some(Fixture::new()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let root = fixture
|
||||
.as_ref()
|
||||
.map(|f| f.0.clone())
|
||||
.unwrap_or_else(|| PathBuf::from(&args[0]));
|
||||
if fixture.is_some() {
|
||||
fixtures(&root)?;
|
||||
println!(
|
||||
"Generated representative fixtures: 1024 blocks, 57344 model states; warm filesystem cache."
|
||||
);
|
||||
}
|
||||
let repetitions = args.get(1).map(|s| s.parse()).transpose()?.unwrap_or(9);
|
||||
assert!(repetitions > 0, "repetitions must be positive");
|
||||
benchmark(
|
||||
"prepare model states",
|
||||
&root.join("model-states.json"),
|
||||
repetitions,
|
||||
prepare_facts,
|
||||
)?;
|
||||
benchmark(
|
||||
"catalog model states",
|
||||
&root.join("model-states.json"),
|
||||
repetitions,
|
||||
catalog_facts,
|
||||
)?;
|
||||
benchmark(
|
||||
"render definitions",
|
||||
&root.join("render-definitions.json"),
|
||||
repetitions,
|
||||
catalog_facts,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn reader_equivalence_and_errors() -> Result<()> {
|
||||
let fixture = Fixture::new()?;
|
||||
let path = fixture.0.join("test.json");
|
||||
fs::write(&path, br#"{"minecraft:stone":{"schema":{},"states":[{}]},"unicode":"\u2603","duplicate":1,"duplicate":2}"#)?;
|
||||
let expected = prepare_facts(&path, Reader::File)?;
|
||||
for reader in READERS {
|
||||
assert_eq!(expected, prepare_facts(&path, reader)?);
|
||||
assert_eq!(
|
||||
expected.iter().collect::<BTreeMap<_, _>>(),
|
||||
catalog_facts(&path, reader)?.iter().collect()
|
||||
);
|
||||
}
|
||||
for invalid in [b"{\"a\": ".as_slice(), b"{} trailing", b"{\"a\":\"\xff\"}"] {
|
||||
fs::write(&path, invalid)?;
|
||||
for reader in READERS {
|
||||
let error = prepare_facts(&path, reader).unwrap_err();
|
||||
assert!(error.downcast_ref::<serde_json::Error>().is_some());
|
||||
assert!(catalog_facts(&path, reader).is_err());
|
||||
}
|
||||
}
|
||||
fs::remove_file(&path)?;
|
||||
for reader in READERS {
|
||||
let error = prepare_facts(&path, reader).unwrap_err();
|
||||
assert_eq!(
|
||||
error.downcast_ref::<std::io::Error>().unwrap().kind(),
|
||||
std::io::ErrorKind::NotFound
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
//! Serve a small flat world on the LAN server without the game, for joining
|
||||
//! with a real client while developing the protocol:
|
||||
//! `cargo run --release --example lan_flat -- RESOURCES PORT`.
|
||||
use horizon_client::{
|
||||
assets::Assets,
|
||||
blocks::BlockFacts,
|
||||
chunk::{Chunk, MIN_Y},
|
||||
lan::{
|
||||
Lan,
|
||||
chunks::ChunkEncoder,
|
||||
data::SyncData,
|
||||
hub::{HostEvent, HostState, Hub, HubConfig, TickCtx},
|
||||
},
|
||||
world::World,
|
||||
};
|
||||
use horizon_protocol::packets::play::Serverbound as S;
|
||||
use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let root = PathBuf::from(args.next().ok_or("RESOURCES PORT")?);
|
||||
let port: u16 = args.next().ok_or("port")?.parse()?;
|
||||
let assets = Assets::load(&root)?;
|
||||
let facts = BlockFacts::load(&root, assets.registry)?;
|
||||
let state = |name: &str| assets.registry.default_state(name).map_or(0, |s| s.0);
|
||||
let sync = Arc::new(SyncData::load(&root)?);
|
||||
let biomes: Vec<String> = sync
|
||||
.dynamic
|
||||
.registries
|
||||
.get("minecraft:worldgen/biome")
|
||||
.map(|v| v.iter().map(|(n, _)| n.clone()).collect())
|
||||
.unwrap_or_default();
|
||||
let encoder = ChunkEncoder::new(
|
||||
facts
|
||||
.states
|
||||
.iter()
|
||||
.map(|s| (s.name.clone(), s.fluid_level > 0 || s.waterlogged)),
|
||||
&sync.builtin,
|
||||
&biomes,
|
||||
&biomes,
|
||||
);
|
||||
let (stone, dirt, grass) = (
|
||||
state("minecraft:stone"),
|
||||
state("minecraft:dirt"),
|
||||
state("minecraft:grass_block"),
|
||||
);
|
||||
let mut world = World::new(facts.air, 0);
|
||||
for cz in -8..=8 {
|
||||
for cx in -8..=8 {
|
||||
let mut chunk = Chunk::empty(cx, cz);
|
||||
for z in 0..16 {
|
||||
for x in 0..16 {
|
||||
for y in MIN_Y..60 {
|
||||
let v = if y == 59 {
|
||||
grass
|
||||
} else if y > 55 {
|
||||
dirt
|
||||
} else {
|
||||
stone
|
||||
};
|
||||
chunk.set(x, y, z, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk.lit = true;
|
||||
world.chunks.insert((cx, cz), Arc::new(chunk));
|
||||
}
|
||||
}
|
||||
let lan = Lan::start(sync.clone(), port, "Flat - Example".into(), 8)?;
|
||||
println!("listening on {}", lan.port);
|
||||
let mut hub = Hub::new(
|
||||
lan,
|
||||
sync,
|
||||
encoder,
|
||||
HubConfig {
|
||||
default_game_mode: 1,
|
||||
guest_commands: true,
|
||||
force_game_mode: false,
|
||||
hardcore: false,
|
||||
view_distance: 8,
|
||||
simulation_distance: 8,
|
||||
dimension: "minecraft:overworld".into(),
|
||||
seed: 0,
|
||||
max_players: 8,
|
||||
dedicated: false,
|
||||
integrated: false,
|
||||
},
|
||||
);
|
||||
let mut next_entity = 100u32;
|
||||
let host = HostState {
|
||||
uuid: 42,
|
||||
name: "Host".into(),
|
||||
entity_id: 1,
|
||||
position: [0.5, 60.0, 0.5],
|
||||
yaw: 0.0,
|
||||
pitch: 0.0,
|
||||
head_yaw: 0.0,
|
||||
on_ground: true,
|
||||
game_mode: 1,
|
||||
sneaking: false,
|
||||
sprinting: false,
|
||||
equipment: Default::default(),
|
||||
health: 20.0,
|
||||
attributes: Vec::new(),
|
||||
bed: None,
|
||||
living_flags: 0,
|
||||
};
|
||||
loop {
|
||||
world.game_time += 1;
|
||||
world.day_time += 1;
|
||||
let mut ctx = TickCtx {
|
||||
world: &mut world,
|
||||
host: Some(&host),
|
||||
entities: &[],
|
||||
next_entity: &mut next_entity,
|
||||
spawn: [8.5, 60.0, 8.5],
|
||||
difficulty: 2,
|
||||
difficulty_locked: false,
|
||||
clock_rate: 1.0,
|
||||
tick_rate: 20.0,
|
||||
tick_frozen: false,
|
||||
tick_steps: (0, 0),
|
||||
collision: None,
|
||||
};
|
||||
for event in hub.tick(&mut ctx) {
|
||||
match event {
|
||||
HostEvent::Joined(conn) => hub.place_new_player(conn, &mut ctx),
|
||||
HostEvent::Packet(_, packet) => {
|
||||
if std::env::var_os("HORIZON_NET_DEBUG").is_some()
|
||||
&& !matches!(*packet, S::ClientTickEnd(_))
|
||||
{
|
||||
eprintln!("[lan] {packet:?}");
|
||||
}
|
||||
}
|
||||
HostEvent::Chat { line, .. } | HostEvent::Warn(line) | HostEvent::Error(line) => {
|
||||
println!("{line}")
|
||||
}
|
||||
HostEvent::Left(_) => {}
|
||||
}
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
//! Read-only saved chunk benchmark. All timings exclude resource/corpus setup.
|
||||
//!
|
||||
//! load_bench RESOURCES DIMENSION_DIR [--rounds N] [--limit N] [--checksum]
|
||||
//! Add --profile-worker when a sampling collector cannot sample the main thread.
|
||||
//! Reports warm filesystem SaveDir::load (read, inflate, NBT, decode and light),
|
||||
//! plus isolated inflate/NBT and native decode. No files in the save are changed.
|
||||
use horizon_client::{
|
||||
assets::Assets,
|
||||
biome::Biomes,
|
||||
blocks::BlockFacts,
|
||||
save::{SaveDir, SaveTables, decode_with},
|
||||
};
|
||||
use horizon_world::{nbt::Limits, region::RegionFile};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{hint::black_box, path::PathBuf, sync::Arc, time::Instant};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
if std::env::args().any(|a| a == "--profile-worker") {
|
||||
std::thread::spawn(|| run().map_err(|e| e.to_string()))
|
||||
.join()
|
||||
.expect("benchmark worker")
|
||||
.map_err(Into::into)
|
||||
} else {
|
||||
run()
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let usage = "load_bench RESOURCES DIMENSION_DIR [--rounds N] [--limit N] [--checksum]";
|
||||
let root = PathBuf::from(args.first().ok_or(usage)?);
|
||||
let dimension = PathBuf::from(args.get(1).ok_or(usage)?);
|
||||
let flag = |name: &str, default: usize| -> Result<usize> {
|
||||
Ok(match args.iter().position(|a| a == name) {
|
||||
Some(i) => args.get(i + 1).ok_or(usage)?.parse()?,
|
||||
None => default,
|
||||
})
|
||||
};
|
||||
let rounds = flag("--rounds", 5)?;
|
||||
let limit = flag("--limit", 256)?;
|
||||
if rounds == 0 || limit == 0 {
|
||||
return Err("rounds and limit must be positive".into());
|
||||
}
|
||||
let assets = Assets::load(&root)?;
|
||||
let facts = BlockFacts::load(&root, assets.registry)?;
|
||||
let biomes = Biomes::load(&root)?;
|
||||
let tables = Arc::new(SaveTables::new(&assets).with_block_entities(&facts));
|
||||
let source = SaveDir::new(dimension.clone());
|
||||
let _ = source.tables.set(tables.clone());
|
||||
let mut paths: Vec<_> = std::fs::read_dir(dimension.join("region"))?
|
||||
.map(|e| e.map(|e| e.path()))
|
||||
.collect::<std::io::Result<_>>()?;
|
||||
paths.retain(|p| p.extension().is_some_and(|e| e == "mca"));
|
||||
paths.sort();
|
||||
let mut corpus = Vec::new();
|
||||
'regions: for path in paths {
|
||||
let mut region = RegionFile::open(path)?;
|
||||
let mut positions: Vec<_> = region.chunks().map(|(pos, _)| pos).collect();
|
||||
positions.sort_by_key(|p| (p.x, p.z));
|
||||
for pos in positions {
|
||||
let record = region.read(pos)?.ok_or("missing record")?;
|
||||
let tag = record.nbt(Limits::default())?;
|
||||
if decode_with(&tag, assets.registry, &biomes, Some(&tables)).is_none() {
|
||||
continue;
|
||||
}
|
||||
corpus.push((pos, record, tag));
|
||||
if corpus.len() == limit {
|
||||
break 'regions;
|
||||
}
|
||||
}
|
||||
}
|
||||
if corpus.is_empty() {
|
||||
return Err("no full chunks in corpus".into());
|
||||
}
|
||||
let mut records_hash = Sha256::new();
|
||||
for (pos, record, _) in &corpus {
|
||||
records_hash.update(pos.x.to_le_bytes());
|
||||
records_hash.update(pos.z.to_le_bytes());
|
||||
records_hash.update((record.compressed.len() as u64).to_le_bytes());
|
||||
records_hash.update(&record.compressed);
|
||||
}
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::json!({"corpus": dimension, "chunks": corpus.len(), "rounds": rounds,
|
||||
"compressed_records_sha256": format!("{:x}", records_hash.finalize()),
|
||||
"compressed_bytes": corpus.iter().map(|(_, r, _)| r.compressed.len()).sum::<usize>()})
|
||||
);
|
||||
// Prime SaveDir's region handles and the filesystem cache before measurement.
|
||||
for (pos, _, _) in &corpus {
|
||||
black_box(
|
||||
source
|
||||
.load(pos.x, pos.z, assets.registry, &biomes)
|
||||
.ok_or("load failed")?,
|
||||
);
|
||||
}
|
||||
for round in 0..rounds {
|
||||
let started = Instant::now();
|
||||
for (pos, _, _) in &corpus {
|
||||
black_box(
|
||||
source
|
||||
.load(pos.x, pos.z, assets.registry, &biomes)
|
||||
.ok_or("load failed")?,
|
||||
);
|
||||
}
|
||||
let load_s = started.elapsed().as_secs_f64();
|
||||
let started = Instant::now();
|
||||
for (_, record, _) in &corpus {
|
||||
black_box(record.nbt(Limits::default())?);
|
||||
}
|
||||
let nbt_s = started.elapsed().as_secs_f64();
|
||||
let started = Instant::now();
|
||||
for (_, _, tag) in &corpus {
|
||||
black_box(
|
||||
decode_with(tag, assets.registry, &biomes, Some(&tables)).ok_or("decode failed")?,
|
||||
);
|
||||
}
|
||||
let decode_s = started.elapsed().as_secs_f64();
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::json!({"round": round, "load_s": load_s,
|
||||
"inflate_nbt_s": nbt_s, "decode_s": decode_s})
|
||||
);
|
||||
}
|
||||
if args.iter().any(|a| a == "--checksum") {
|
||||
let mut hash = Sha256::new();
|
||||
let mut light_loaded = 0;
|
||||
for (pos, _, _) in &corpus {
|
||||
let chunk = source
|
||||
.load(pos.x, pos.z, assets.registry, &biomes)
|
||||
.ok_or("load failed")?;
|
||||
hash.update(pos.x.to_le_bytes());
|
||||
hash.update(pos.z.to_le_bytes());
|
||||
light_loaded += usize::from(chunk.light_loaded);
|
||||
for section in &chunk.sections {
|
||||
for i in 0..4096 {
|
||||
hash.update(section.get(i).to_le_bytes());
|
||||
hash.update([section.light(i)]);
|
||||
}
|
||||
for i in 0..64 {
|
||||
hash.update(section.biomes.get(i).to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::json!({"blocks_biomes_light_sha256": format!("{:x}", hash.finalize()),
|
||||
"light_loaded": light_loaded})
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+3
-4
@@ -1,8 +1,7 @@
|
||||
//! Replays `tools/test_ambient_sound_parity.py` scripts through Horizon's
|
||||
//! ambient sound handlers over its `SoundEngine`:
|
||||
//! `ambient_fixture ROOT INPUT OUTPUT`.
|
||||
#[path = "audio_common/mod.rs"]
|
||||
mod common;
|
||||
use crate::audio_common as common;
|
||||
use common::{Fake, d, f, flush};
|
||||
use horizon_client::ambience::{Ambience, AmbientContext, AmbientSounds, Mood, bubble_column_in};
|
||||
use horizon_client::sound_engine::{Bound, SoundEngine, TickContext, Ticking};
|
||||
@@ -47,8 +46,8 @@ fn sounds(a: &[&str]) -> AmbientSounds {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut engine = SoundEngine::new(SoundRegistry::load(std::path::Path::new(&args[1])));
|
||||
engine.listening = true;
|
||||
let mut backend = Fake::default();
|
||||
+2
-2
@@ -50,8 +50,8 @@ fn particle(k: ArrowParticle) -> &'static str {
|
||||
ArrowParticle::Splash => "splash",
|
||||
}
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
if args.len() != 3 {
|
||||
return Err("usage: arrow_probe RESOURCES FIXTURE_DIRECTORY --describe|REFERENCE".into());
|
||||
}
|
||||
+2
-2
@@ -18,8 +18,8 @@ fn music(m: Option<&Music>) -> String {
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = std::path::Path::new(&args[1]);
|
||||
let tables = MusicTables::load(root);
|
||||
let ambient = AmbientTables::load(root);
|
||||
File renamed without changes.
+2
-2
@@ -24,8 +24,8 @@ fn db(v: &Value) -> f64 {
|
||||
f64::from_bits(u64::from_str_radix(v.as_str().unwrap(), 16).unwrap())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let [root, input, output, scene_json] = &args[..] else {
|
||||
return Err("usage: auto_jump_probe RESOURCES INPUT OUTPUT SCENE_JSON".into());
|
||||
};
|
||||
+2
-2
@@ -118,8 +118,8 @@ fn status(s: ShulkerStatus) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: block_entity_anim_fixture RESOURCES INPUTS OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -110,8 +110,8 @@ fn intern(s: &str) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, textures, output] = args.as_slice() else {
|
||||
return Err("usage: block_entity_render_fixture RESOURCES INPUTS TEXTURES OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -26,8 +26,8 @@ fn entity(name: &str) -> BlockEntity {
|
||||
.unwrap_or_else(|| panic!("no block entity for {name}"))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = std::fs::read_to_string(&args[1]).expect("input");
|
||||
let mut out = String::new();
|
||||
let mut entities = BlockEntities::default();
|
||||
+2
-2
@@ -8,8 +8,8 @@ use std::{
|
||||
io::{BufRead, BufReader, BufWriter, Write},
|
||||
path::Path,
|
||||
};
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let root = Path::new(&args[1]);
|
||||
let assets = Assets::load(root)?;
|
||||
let render = assets.reload(root)?;
|
||||
+2
-2
@@ -51,8 +51,8 @@ impl Around for Column {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: block_transform_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -16,8 +16,8 @@ use std::{
|
||||
};
|
||||
/// The stage sprite origin the cracks carry (the oracle compares the geometry and UVs only).
|
||||
const STAGE: [f32; 2] = [0.25, 0.5];
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let root = Path::new(&args[1]);
|
||||
let assets = Assets::load(root)?;
|
||||
let render = assets.reload(root)?;
|
||||
+2
-2
@@ -323,8 +323,8 @@ fn avatar(c: &Value, out: &mut impl Write) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -70,8 +70,8 @@ fn describe(state: &BlockState) -> String {
|
||||
format!("{}|{}", state.name, props.join(","))
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: cauldron_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+3
-5
@@ -5,6 +5,7 @@
|
||||
//! the oracle's JSON form.
|
||||
//!
|
||||
//! usage: chat_screen_fixture RESOURCES REGISTRIES CASES OUTPUT
|
||||
use crate::pack_screen_fixture;
|
||||
use horizon_client::{
|
||||
chat::{ChatAction, ChatScreen, Commands},
|
||||
command::vanilla,
|
||||
@@ -15,14 +16,11 @@ use horizon_client::{
|
||||
use serde_json::{Value, json};
|
||||
use std::{fmt::Write as _, fs, path::PathBuf};
|
||||
use winit::keyboard::KeyCode as K;
|
||||
#[path = "pack_screen_fixture.rs"]
|
||||
#[allow(dead_code)]
|
||||
mod pack_screen_fixture;
|
||||
#[path = "chat_screen_fixture/registries.rs"]
|
||||
mod registries;
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, registries, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: chat_screen_fixture RESOURCES REGISTRIES CASES OUTPUT".into());
|
||||
};
|
||||
File renamed without changes.
+2
-2
@@ -1,8 +1,8 @@
|
||||
//! CloudRenderer face selection and mesh traversal, without a GPU.
|
||||
use horizon_client::clouds;
|
||||
use std::{fmt::Write, fs};
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let mut output = String::new();
|
||||
for (case, line) in fs::read_to_string(&args[1])?.lines().enumerate() {
|
||||
let values: Vec<i32> = line
|
||||
+2
-2
@@ -132,8 +132,8 @@ fn tree(d: &Dispatcher, node: usize) -> Value {
|
||||
v
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
if args.get(1).map(String::as_str) == Some("tree") {
|
||||
let d = &vanilla::registered(false);
|
||||
let mut v = tree(d, 0);
|
||||
+2
-2
@@ -24,8 +24,8 @@ fn input_name(input: Input) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -11,8 +11,8 @@ use horizon_client::{
|
||||
use serde_json::{Value, json};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: creative_search_fixture RESOURCES CREATIVE_JSON VANILLA_JSON OUTPUT";
|
||||
let names = Names::load(Path::new(args.get(1).ok_or(usage)?));
|
||||
let creative = Creative::from_json(&serde_json::from_slice(&fs::read(
|
||||
@@ -0,0 +1,49 @@
|
||||
//! How the probe binary runs a probe. main.rs lists the probes and nothing else (tools/parity.py leaves it out of
|
||||
//! the harnesses' dependencies); code every probe relies on goes here.
|
||||
use std::process::ExitCode;
|
||||
|
||||
/// `probes! { a, b, }` declares the binary's `main`, which runs the probe module named by its first argument.
|
||||
macro_rules! probes {
|
||||
($($name:ident,)*) => {
|
||||
fn run(name: &str) -> Option<std::process::ExitCode> {
|
||||
use std::process::Termination;
|
||||
Some(match name {
|
||||
$(stringify!($name) => $name::main().report(),)*
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn main() -> std::process::ExitCode {
|
||||
dispatch::main(&[$(stringify!($name)),*], run)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The probe's command line as its own example saw it: the program, then the arguments after the probe's name.
|
||||
pub fn args() -> std::vec::IntoIter<String> {
|
||||
let mut args: Vec<String> = std::env::args().collect();
|
||||
if args.len() > 1 {
|
||||
args.remove(1);
|
||||
}
|
||||
args.into_iter()
|
||||
}
|
||||
|
||||
/// args(), as OsStrings.
|
||||
pub fn args_os() -> std::vec::IntoIter<std::ffi::OsString> {
|
||||
let mut args: Vec<_> = std::env::args_os().collect();
|
||||
if args.len() > 1 {
|
||||
args.remove(1);
|
||||
}
|
||||
args.into_iter()
|
||||
}
|
||||
|
||||
pub fn main(names: &[&str], run: fn(&str) -> Option<ExitCode>) -> ExitCode {
|
||||
let name = std::env::args().nth(1).unwrap_or_default();
|
||||
run(&name).unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
"usage: client_probe <name> [arguments...]\nprobes: {}",
|
||||
names.join(" ")
|
||||
);
|
||||
ExitCode::from(2)
|
||||
})
|
||||
}
|
||||
+2
-2
@@ -14,8 +14,8 @@ fn d(v: f64) -> String {
|
||||
format!("{:016x}", v.to_bits())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in BufReader::new(File::open(&args[1])?).lines().enumerate() {
|
||||
let c: Value = serde_json::from_str(&line?)?;
|
||||
+2
-2
@@ -10,8 +10,8 @@ use horizon_client::{
|
||||
};
|
||||
use std::{fmt::Write as _, fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: enchanting_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
//! posed model with `mobs::render::draw` under the case's living-entity root
|
||||
//! transform and writes each drawn part's packed vertex normals.
|
||||
//!
|
||||
//! cargo run --profile fast -p horizon-client --example entity_anim_fixture -- \
|
||||
//! cargo run --profile fast -p horizon-client --example probe -- entity_anim_fixture \
|
||||
//! RESOURCES VANILLA.jsonl OUT.jsonl
|
||||
use horizon_client::mesher::Vertex;
|
||||
use horizon_client::mobs::{
|
||||
@@ -288,8 +288,8 @@ fn entity_state(mob: &mut Mob, species: Species, case: &Value) {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().skip(1).collect();
|
||||
let root = PathBuf::from(&args[0]);
|
||||
let types = MobTypes::load(&root)?;
|
||||
let animations = MobData::load_animations(&root);
|
||||
+2
-2
@@ -61,8 +61,8 @@ fn species(id: &str) -> Species {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -53,8 +53,8 @@ fn line(s: &LootStack) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: entity_death_loot_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -13,8 +13,8 @@ fn d(v: f64) -> String {
|
||||
format!("{:016x}", v.to_bits())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in BufReader::new(File::open(&args[1])?).lines().enumerate() {
|
||||
let c: Value = serde_json::from_str(&line?)?;
|
||||
+2
-2
@@ -9,8 +9,8 @@ use horizon_client::{
|
||||
};
|
||||
use std::{collections::HashMap, fmt::Write as _, fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: environment_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -388,8 +388,8 @@ fn describe(m: &Mob, all: &[Mob], regs: &SpawnRegistries) -> String {
|
||||
t.join(" ")
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: finalize_spawn_fixture RESOURCES INPUT OUTPUT HALLOWEEN")?,
|
||||
+2
-2
@@ -11,8 +11,8 @@ use std::{
|
||||
io::{BufRead, BufReader, BufWriter, Write},
|
||||
};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for line in input.lines() {
|
||||
+2
-2
@@ -4,8 +4,8 @@
|
||||
use horizon_client::{enchant::Enchantments, item_data::parse_stack, item_tooltip::firework_lines};
|
||||
use std::{error::Error, fmt::Write, path::PathBuf};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = std::fs::read_to_string(&args[1])?;
|
||||
let root = input
|
||||
.lines()
|
||||
+2
-2
@@ -458,8 +458,8 @@ impl HandWorld for ResetWorld<'_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -50,8 +50,8 @@ impl LimiterClock for Script {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -291,8 +291,8 @@ fn key(c: &Value, out: &mut impl Write) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let mut out = BufWriter::new(File::create(&args[1])?);
|
||||
for line in BufReader::new(File::open(&args[0])?).lines() {
|
||||
let c: Value = serde_json::from_str(&line?)?;
|
||||
+2
-2
@@ -13,8 +13,8 @@ use horizon_client::{
|
||||
use serde_json::Value;
|
||||
use std::{fmt::Write as _, fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: ghost_recipe_fixture RESOURCES CASES OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let cases = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
use horizon_client::command::args::GameMode;
|
||||
use horizon_client::items::{ItemStack, take_held_drop};
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
for mode in [
|
||||
GameMode::Survival,
|
||||
GameMode::Creative,
|
||||
+2
-2
@@ -10,8 +10,8 @@ use serde_json::Value;
|
||||
use std::path::Path;
|
||||
use std::{fmt::Write as _, fs};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: hotbar_fixture RESOURCES CASES OUTPUT";
|
||||
let items = Items::catalog(Path::new(args.first().and(args.get(1)).ok_or(usage)?))?;
|
||||
let known = |id: &str| items.get(id).is_some();
|
||||
+2
-2
@@ -20,8 +20,8 @@ type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
#[path = "hud_fixture/kinds.rs"]
|
||||
mod kinds;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: hud_fixture RESOURCES INPUTS OUTPUT".into());
|
||||
};
|
||||
+1
@@ -306,6 +306,7 @@ fn chat(c: &Value, h: i32, atlas: &HudAtlas) -> Vec<GuiDraw> {
|
||||
height_focused: option("chatHeightFocused"),
|
||||
height_unfocused: option("chatHeightUnfocused"),
|
||||
line_spacing: option("chatLineSpacing"),
|
||||
colors: c["chatColors"].as_bool().unwrap_or(true),
|
||||
};
|
||||
for m in c["messages"].as_array().into_iter().flatten() {
|
||||
// GuiMessageTag indicator colours: systemSinglePlayer and chatError.
|
||||
+2
-2
@@ -11,8 +11,8 @@ fn number(v: &Value) -> f32 {
|
||||
fn bits(v: f32) -> u32 {
|
||||
if v.is_nan() { 0x7fc00000 } else { v.to_bits() }
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let mut out = BufWriter::new(File::create(&args[1])?);
|
||||
for line in BufReader::new(File::open(&args[0])?).lines() {
|
||||
let f: Value = serde_json::from_str(&line?)?;
|
||||
+2
-2
@@ -82,8 +82,8 @@ impl TargetUseWorld for World {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let input = std::io::BufReader::new(std::fs::File::open(&args[1])?);
|
||||
let mut out = std::io::BufWriter::new(std::fs::File::create(&args[2])?);
|
||||
for (i, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -14,8 +14,8 @@ fn unhex(s: &str) -> Vec<u8> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let cases = std::fs::read_to_string(&args[1]).unwrap();
|
||||
let mut out = String::new();
|
||||
let mut games: Vec<LanGame> = Vec::new();
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
//! server with Horizon's light engine and compare every SkyLight/BlockLight
|
||||
//! value with the arrays vanilla stored.
|
||||
//!
|
||||
//! cargo run --profile fast -p horizon-client --example light_parity -- \
|
||||
//! cargo run --profile fast -p horizon-client --example probe -- light_parity \
|
||||
//! RESOURCES DIMENSION_DIR [--nether] [--chunks X0 Z0 X1 Z1]
|
||||
use horizon_client::{
|
||||
assets::Assets,
|
||||
@@ -21,8 +21,8 @@ use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
type Arrays = HashMap<i32, (Option<Vec<u8>>, Option<Vec<u8>>)>;
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().skip(1).collect();
|
||||
let root = PathBuf::from(
|
||||
args.first()
|
||||
.ok_or("usage: light_parity RESOURCES DIMENSION_DIR")?,
|
||||
@@ -0,0 +1,178 @@
|
||||
//! Every horizon-client parity probe in one binary: `probe <name> [arguments]` runs `<name>.rs` as its own
|
||||
//! example did (tools/test_*_parity.py, tools/oracle_harness.py, tools/audio_harness.py). Linking ~80 examples,
|
||||
//! each with the whole client in it, was most of the parity job's probe build; one binary builds it once.
|
||||
//!
|
||||
//! This file only lists the probes, so that adding one reruns no harness: tools/parity.py leaves it out of
|
||||
//! their dependencies. How a probe runs is in dispatch.rs.
|
||||
#[macro_use]
|
||||
mod dispatch;
|
||||
|
||||
use dispatch::{args, args_os};
|
||||
|
||||
mod ambient_fixture;
|
||||
mod arrow_probe;
|
||||
mod audio_attributes_fixture;
|
||||
/// Sound-engine fakes the audio probes share.
|
||||
mod audio_common;
|
||||
mod auto_jump_probe;
|
||||
mod block_entity_anim_fixture;
|
||||
mod block_entity_render_fixture;
|
||||
mod block_entity_tickers_fixture;
|
||||
mod block_particles_fixture;
|
||||
mod block_transform_fixture;
|
||||
mod breaking_fixture;
|
||||
mod camera_probe;
|
||||
mod cauldron_fixture;
|
||||
mod chat_screen_fixture;
|
||||
mod cloud_fixture;
|
||||
mod command_parse_fixture;
|
||||
mod container_screen_probe;
|
||||
mod creative_search_fixture;
|
||||
mod emitter_particles_probe;
|
||||
mod enchanting_fixture;
|
||||
mod entity_anim_fixture;
|
||||
mod entity_components_probe;
|
||||
mod entity_death_loot_fixture;
|
||||
mod entity_particles_probe;
|
||||
mod environment_fixture;
|
||||
mod finalize_spawn_fixture;
|
||||
mod fire_starter_sound_probe;
|
||||
mod firework_tooltip_fixture;
|
||||
mod first_person_probe;
|
||||
mod frame_limiter_probe;
|
||||
mod game_loop_probe;
|
||||
mod ghost_recipe_fixture;
|
||||
mod held_drop_fixture;
|
||||
mod hotbar_fixture;
|
||||
mod hud_fixture;
|
||||
mod input_probe;
|
||||
mod interaction_input_fixture;
|
||||
mod lan_probe;
|
||||
mod light_parity;
|
||||
mod marker_particles_probe;
|
||||
mod menu_fixture;
|
||||
mod mipmap_probe;
|
||||
mod mob_ai_probe;
|
||||
mod mob_attributes_fixture;
|
||||
mod music_fixture;
|
||||
mod natural_spawn_fixture;
|
||||
mod options_probe;
|
||||
mod pack_resources_fixture;
|
||||
mod pack_screen_fixture;
|
||||
mod pack_selection_fixture;
|
||||
mod particle_providers_probe;
|
||||
mod pick_block_data_fixture;
|
||||
mod place_recipe_fixture;
|
||||
mod player_sync_fixture;
|
||||
mod raid_fixture;
|
||||
mod random_tick_sections_probe;
|
||||
mod recipe_book_fixture;
|
||||
mod recipe_book_render_fixture;
|
||||
mod recipe_book_view_fixture;
|
||||
mod recipe_fixture;
|
||||
mod scene_collision_probe;
|
||||
mod scene_motion_probe;
|
||||
mod scoreboard_fixture;
|
||||
mod screen_layout_fixture;
|
||||
mod section_mesh_fixture;
|
||||
mod server_files_probe;
|
||||
mod situational_music_fixture;
|
||||
mod skin_image_fixture;
|
||||
mod sound_engine_fixture;
|
||||
mod sound_event_fixture;
|
||||
mod spawn_rules_fixture;
|
||||
mod sprint_probe;
|
||||
mod subtitle_fixture;
|
||||
mod tab_list_fixture;
|
||||
mod team_rules_fixture;
|
||||
mod toggle_keys_probe;
|
||||
mod tooltip_display_fixture;
|
||||
mod trading_fixture;
|
||||
mod translucency_fixture;
|
||||
mod weather_fixture;
|
||||
mod world_border_render_fixture;
|
||||
mod world_options_fixture;
|
||||
|
||||
probes! {
|
||||
ambient_fixture,
|
||||
arrow_probe,
|
||||
audio_attributes_fixture,
|
||||
auto_jump_probe,
|
||||
block_entity_anim_fixture,
|
||||
block_entity_render_fixture,
|
||||
block_entity_tickers_fixture,
|
||||
block_particles_fixture,
|
||||
block_transform_fixture,
|
||||
breaking_fixture,
|
||||
camera_probe,
|
||||
cauldron_fixture,
|
||||
chat_screen_fixture,
|
||||
cloud_fixture,
|
||||
command_parse_fixture,
|
||||
container_screen_probe,
|
||||
creative_search_fixture,
|
||||
emitter_particles_probe,
|
||||
enchanting_fixture,
|
||||
entity_anim_fixture,
|
||||
entity_components_probe,
|
||||
entity_death_loot_fixture,
|
||||
entity_particles_probe,
|
||||
environment_fixture,
|
||||
finalize_spawn_fixture,
|
||||
fire_starter_sound_probe,
|
||||
firework_tooltip_fixture,
|
||||
first_person_probe,
|
||||
frame_limiter_probe,
|
||||
game_loop_probe,
|
||||
ghost_recipe_fixture,
|
||||
held_drop_fixture,
|
||||
hotbar_fixture,
|
||||
hud_fixture,
|
||||
input_probe,
|
||||
interaction_input_fixture,
|
||||
lan_probe,
|
||||
light_parity,
|
||||
marker_particles_probe,
|
||||
menu_fixture,
|
||||
mipmap_probe,
|
||||
mob_ai_probe,
|
||||
mob_attributes_fixture,
|
||||
music_fixture,
|
||||
natural_spawn_fixture,
|
||||
options_probe,
|
||||
pack_resources_fixture,
|
||||
pack_screen_fixture,
|
||||
pack_selection_fixture,
|
||||
particle_providers_probe,
|
||||
pick_block_data_fixture,
|
||||
place_recipe_fixture,
|
||||
player_sync_fixture,
|
||||
raid_fixture,
|
||||
random_tick_sections_probe,
|
||||
recipe_book_fixture,
|
||||
recipe_book_render_fixture,
|
||||
recipe_book_view_fixture,
|
||||
recipe_fixture,
|
||||
scene_collision_probe,
|
||||
scene_motion_probe,
|
||||
scoreboard_fixture,
|
||||
screen_layout_fixture,
|
||||
section_mesh_fixture,
|
||||
server_files_probe,
|
||||
situational_music_fixture,
|
||||
skin_image_fixture,
|
||||
sound_engine_fixture,
|
||||
sound_event_fixture,
|
||||
spawn_rules_fixture,
|
||||
sprint_probe,
|
||||
subtitle_fixture,
|
||||
tab_list_fixture,
|
||||
team_rules_fixture,
|
||||
toggle_keys_probe,
|
||||
tooltip_display_fixture,
|
||||
trading_fixture,
|
||||
translucency_fixture,
|
||||
weather_fixture,
|
||||
world_border_render_fixture,
|
||||
world_options_fixture,
|
||||
}
|
||||
+2
-2
@@ -22,8 +22,8 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(".local/horizon-client/26.3");
|
||||
let assets = Assets::load(root)?;
|
||||
let facts = BlockFacts::load(root, assets.registry)?;
|
||||
+6
-4
@@ -58,11 +58,12 @@ fn state(menu: &Menu) -> String {
|
||||
.map(|(slot, stack)| format!("{slot}:{}", canon_stack(stack.as_ref())))
|
||||
.collect();
|
||||
let line = format!(
|
||||
"{} | {} |{data} | {} | {}",
|
||||
"{} | {} |{data} | {} | {} | {}",
|
||||
slots.join(" "),
|
||||
canon_stack(menu.carried.as_ref()),
|
||||
menu.drops.join(";"),
|
||||
equipped.join(";")
|
||||
equipped.join(";"),
|
||||
menu.player_sounds.join(";")
|
||||
);
|
||||
if menu.kind() != Kind::Lectern {
|
||||
return line;
|
||||
@@ -74,8 +75,8 @@ fn state(menu: &Menu) -> String {
|
||||
format!("{line} | inv{items}")
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: menu_fixture RESOURCES INPUT OUTPUT")?,
|
||||
@@ -171,6 +172,7 @@ fn main() -> horizon_client::Result<()> {
|
||||
});
|
||||
menu.drops.clear();
|
||||
menu.equipped.clear();
|
||||
menu.player_sounds.clear();
|
||||
out += &format!("init {}\n", state(&menu));
|
||||
for op in case["ops"].as_array().ok_or("ops")? {
|
||||
let slot = op[0].as_i64().unwrap_or(0) as i32;
|
||||
+2
-2
@@ -4,8 +4,8 @@
|
||||
//! rows like VanillaMipmapOracle.
|
||||
use std::{fmt::Write as _, fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().skip(1).collect();
|
||||
let input = fs::read_to_string(&args[0])?;
|
||||
let mut lines = input.lines();
|
||||
let root = Path::new(lines.next().ok_or("no resources root")?);
|
||||
+79
-2
@@ -293,6 +293,47 @@ fn spawn_seed(index: usize) -> i64 {
|
||||
1000 + 7919 * index as i64
|
||||
}
|
||||
|
||||
/// `Villager.spawnGolemIfNeeded` for villager `a`, the game's way: the golem
|
||||
/// draws from the level's random and joins the scenario's mobs next tick,
|
||||
/// seeded as the oracle seeds what a tick spawned.
|
||||
fn summon_golem(
|
||||
mobs: &mut [Mob],
|
||||
a: usize,
|
||||
needed: usize,
|
||||
w: &MobWorld,
|
||||
types: &MobTypes,
|
||||
born: &mut Vec<Mob>,
|
||||
level_random: &mut LegacyRandom,
|
||||
) {
|
||||
use horizon_client::mobs::{villager, villager_brain};
|
||||
let Some(near) = villager::golem_summoners(mobs, a, w.game_time, needed) else {
|
||||
return;
|
||||
};
|
||||
let kind = Arc::new(
|
||||
types
|
||||
.types
|
||||
.get("minecraft:iron_golem")
|
||||
.expect("iron golem")
|
||||
.clone(),
|
||||
);
|
||||
let index = mobs.len() + born.len();
|
||||
let p = mobs[a].position;
|
||||
let start = [p.x.floor() as i32, p.y.floor() as i32, p.z.floor() as i32];
|
||||
let golem = villager::summon_golem(w, start, level_random, |random, at, yaw| {
|
||||
let mut m = Mob::new(100_000 + index as u32, kind.clone(), at, yaw);
|
||||
villager::finalize_summoned_golem(&mut m, random);
|
||||
m
|
||||
});
|
||||
let Some(mut golem) = golem else {
|
||||
return;
|
||||
};
|
||||
golem.random = LegacyRandom::new(spawn_seed(index));
|
||||
born.push(golem);
|
||||
for j in near {
|
||||
villager_brain::golem_detected(&mut mobs[j], w.game_time);
|
||||
}
|
||||
}
|
||||
|
||||
/// Villager events that act at once in vanilla (`TradeWithVillager` and
|
||||
/// `VillagerMakeLove` write the other villager directly).
|
||||
fn villager_events(
|
||||
@@ -304,6 +345,7 @@ fn villager_events(
|
||||
items: &Items,
|
||||
born: &mut Vec<Mob>,
|
||||
day_time: i64,
|
||||
level_random: &mut LegacyRandom,
|
||||
) {
|
||||
use horizon_client::mobs::villager;
|
||||
let index = |mobs: &[Mob], id: u32| {
|
||||
@@ -314,6 +356,7 @@ fn villager_events(
|
||||
while i < events.len() {
|
||||
match events[i] {
|
||||
MobEvent::VillagerMeet { mob, other } => {
|
||||
events.remove(i);
|
||||
if let (Some(a), Some(b)) = (index(mobs, mob), index(mobs, other)) {
|
||||
let meeting = villager::meet(mobs, a, b, w.game_time, |item| {
|
||||
items.get(item).map_or(64, |i| i.max_stack)
|
||||
@@ -322,8 +365,16 @@ fn villager_events(
|
||||
meeting.thrown.is_empty(),
|
||||
"villagers toss items: not modelled here"
|
||||
);
|
||||
if meeting.gossiped {
|
||||
summon_golem(mobs, a, 5, w, types, born, level_random);
|
||||
}
|
||||
}
|
||||
}
|
||||
MobEvent::GolemCheck { mob, needed } => {
|
||||
events.remove(i);
|
||||
if let Some(a) = index(mobs, mob) {
|
||||
summon_golem(mobs, a, needed, w, types, born, level_random);
|
||||
}
|
||||
}
|
||||
MobEvent::VillagerBirth {
|
||||
parent,
|
||||
@@ -759,8 +810,8 @@ fn villager(m: &Mob) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().skip(1).collect();
|
||||
if args.len() != 3 {
|
||||
return Err("usage: mob_ai_probe RESOURCES SCENARIOS OUTPUT".into());
|
||||
}
|
||||
@@ -1167,6 +1218,7 @@ fn main() -> horizon_client::Result<()> {
|
||||
&items,
|
||||
&mut born,
|
||||
s.time,
|
||||
&mut scratch,
|
||||
);
|
||||
horizon_client::mobs::warden::hear_mob_events(&mut mobs, &events, from, &w);
|
||||
// Melee hits on other mobs land during the attacker's tick
|
||||
@@ -1323,6 +1375,31 @@ fn main() -> horizon_client::Result<()> {
|
||||
world.set(at[0], at[1], at[2], registry.resolve(&st)?)?;
|
||||
}
|
||||
}
|
||||
// Doors villagers opened or closed (DoorBlock.setOpen), both halves.
|
||||
let doors: Vec<([i32; 3], bool)> = events
|
||||
.iter()
|
||||
.filter_map(|e| match e {
|
||||
MobEvent::SetDoorOpen { pos, open } => Some((*pos, *open)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
for (at, open) in doors {
|
||||
let Some(half) = registry
|
||||
.state(world.block(at[0], at[1], at[2]))
|
||||
.and_then(|s| s.properties.get("half").cloned())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let other = if half == "lower" { 1 } else { -1 };
|
||||
for y in [at[1], at[1] + other] {
|
||||
if let Some(mut st) = registry.state(world.block(at[0], y, at[2])).cloned()
|
||||
&& st.properties.contains_key("open")
|
||||
{
|
||||
st.properties.insert("open".to_owned(), open.to_string());
|
||||
world.set(at[0], y, at[2], registry.resolve(&st)?)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
mobs.append(&mut born);
|
||||
mobs.append(&mut added);
|
||||
for e in &heart_events {
|
||||
+2
-2
@@ -6,8 +6,8 @@ use horizon_client::mobs::{Mob, MobTypes};
|
||||
use horizon_core::geometry::Vec3;
|
||||
use std::{fmt::Write as _, fs, path::Path, sync::Arc};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: mob_attributes_fixture RESOURCES OUTPUT")?,
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
//! Replays `tools/test_music_parity.py` scripts through Horizon's
|
||||
//! `MusicManager` over its `SoundEngine`: `music_fixture ROOT INPUT OUTPUT`.
|
||||
#[path = "audio_common/mod.rs"]
|
||||
mod common;
|
||||
use crate::audio_common as common;
|
||||
use common::{Fake, describe, f, flush};
|
||||
use horizon_client::music::{Music, MusicFrequency, MusicManager};
|
||||
use horizon_client::sound_engine::{Bound, MUSIC, SoundEngine, TickContext};
|
||||
@@ -21,8 +20,8 @@ fn music(spec: &str) -> Option<Music> {
|
||||
))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut engine = SoundEngine::new(SoundRegistry::load(std::path::Path::new(&args[1])));
|
||||
engine.listening = true;
|
||||
let mut backend = Fake::default();
|
||||
+2
-2
@@ -508,8 +508,8 @@ fn yaw_text(entity: &str, v: f32) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: natural_spawn_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -7,8 +7,8 @@ use horizon_client::{
|
||||
};
|
||||
use std::{fs, io::Write};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let mut names: Vec<_> = fs::read_dir(&args[0])?
|
||||
.map(|e| e.map(|e| e.path()))
|
||||
.collect::<std::io::Result<_>>()?;
|
||||
+2
-2
@@ -30,8 +30,8 @@ fn types(root: &std::path::Path, file: PathBuf, key: &str) -> String {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let input = fs::read_to_string(&args[1])?;
|
||||
let mut lines = input.lines();
|
||||
let root: Vec<&str> = lines.next().ok_or("empty input")?.split(' ').collect();
|
||||
+2
-2
@@ -66,8 +66,8 @@ pub fn encode(draws: &[Draw]) -> Value {
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: pack_screen_fixture RESOURCES CASES OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -35,8 +35,8 @@ fn lists(m: &SelectionModel) -> Value {
|
||||
json!({"unselected": side(false), "selected": side(true)})
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [inputs, output] = args.as_slice() else {
|
||||
return Err("usage: pack_selection_fixture INPUTS OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -140,8 +140,8 @@ fn world(assets: &Assets, facts: &BlockFacts, floor: bool, water: bool) -> Resul
|
||||
Ok(world)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = &Path::new(".local/horizon-client").join(horizon_core::VANILLA_VERSION);
|
||||
let assets = Assets::load(root)?;
|
||||
let facts = BlockFacts::load(root, assets.registry)?;
|
||||
+2
-2
@@ -78,8 +78,8 @@ fn case(line: &str) -> Option<String> {
|
||||
Some(out)
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = fs::read_to_string(
|
||||
args.get(1)
|
||||
.ok_or("usage: pick_block_data_fixture INPUT OUTPUT")?,
|
||||
+2
-2
@@ -28,8 +28,8 @@ fn state(menu: &Menu) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: place_recipe_fixture RESOURCES CASES ORDERS OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let cases = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -8,8 +8,8 @@ fn number(value: &Value) -> f64 {
|
||||
f64::from_bits(u64::from_str_radix(value.as_str().unwrap(), 16).unwrap())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let input = std::io::BufReader::new(std::fs::File::open(&args[1])?);
|
||||
let mut out = std::io::BufWriter::new(std::fs::File::create(&args[2])?);
|
||||
for line in input.lines() {
|
||||
+2
-2
@@ -459,8 +459,8 @@ fn run_codec(c: &BTreeMap<&str, &str>) -> Result<String, String> {
|
||||
Ok(log.join(" ; "))
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: raid_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -51,8 +51,8 @@ impl LevelAccess for Air {
|
||||
fn emit(&mut self, _: LevelEvent) {}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = std::fs::read_to_string(&args[1])?;
|
||||
let root = input
|
||||
.lines()
|
||||
+2
-2
@@ -57,8 +57,8 @@ fn compound(tag: &Tag) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: recipe_book_fixture RESOURCES CASES OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let cases = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -30,8 +30,8 @@ fn round(v: f32) -> f32 {
|
||||
(v * 1e4).round() / 1e4
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: recipe_book_render_fixture RESOURCES CASES OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let cases = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -15,8 +15,8 @@ use horizon_client::{
|
||||
use serde_json::Value;
|
||||
use std::{fmt::Write as _, fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: recipe_book_view_fixture RESOURCES CASES OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let cases = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -12,8 +12,8 @@ use horizon_client::{
|
||||
};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: recipe_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+3
-2
@@ -28,8 +28,8 @@ fn vector(value: &Value) -> Result<Vec3> {
|
||||
};
|
||||
Ok(Vec3::new(number(0)?, number(1)?, number(2)?))
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
if args.len() != 3 {
|
||||
return Err("usage: scene_collision_probe RESOURCES FIXTURE_DIRECTORY RADIUS".into());
|
||||
}
|
||||
@@ -78,6 +78,7 @@ fn main() -> Result<()> {
|
||||
let mut selected = collisions::EntityCollisions {
|
||||
blocks: scene,
|
||||
entities: &entities,
|
||||
border: None,
|
||||
};
|
||||
let movement = world_movement::resolve_world_movement(
|
||||
&mut selected,
|
||||
+2
-2
@@ -233,8 +233,8 @@ fn snapshot(out: &mut impl Write, player: &PlayerMotion) -> Result<()> {
|
||||
writeln!(out, "events {}", events.join(" | "))?;
|
||||
Ok(())
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
if args.len() != 3 {
|
||||
return Err(
|
||||
"usage: scene_motion_probe RESOURCES FIXTURE_DIRECTORY --describe|REFERENCE".into(),
|
||||
+2
-2
@@ -370,8 +370,8 @@ fn score_json(sc: &sb::Score) -> Value {
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let registries: Value =
|
||||
serde_json::from_str(&fs::read_to_string(&args[1]).expect("registries")).expect("json");
|
||||
let list = |k: &str| -> Vec<String> {
|
||||
+2
-2
@@ -60,8 +60,8 @@ fn draw_json(d: &ScreenDraw) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: screen_layout_fixture RESOURCES INPUT OUTPUT";
|
||||
let banners = Banners::load(Path::new(args.get(1).ok_or(usage)?));
|
||||
let input = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -170,8 +170,8 @@ fn scene(
|
||||
}
|
||||
Ok(json!({"name": row["name"], "quads": quads}))
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
if args.len() != 3 {
|
||||
return Err(
|
||||
"usage: section_mesh_fixture RESOURCES (INPUT.jsonl | facts) OUTPUT.jsonl".into(),
|
||||
+2
-2
@@ -11,8 +11,8 @@ use horizon_client::server::{
|
||||
use horizon_protocol::crypto::uuid_string;
|
||||
use std::{fmt::Write as _, path::Path};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = std::env::args().skip(1);
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = crate::args().skip(1);
|
||||
let root = std::path::PathBuf::from(args.next().ok_or("CASES OUTPUT")?);
|
||||
let output = args.next().ok_or("OUTPUT")?;
|
||||
let mut cases: Vec<_> = std::fs::read_dir(&root)?
|
||||
+2
-2
@@ -5,8 +5,8 @@ use horizon_client::music::{BackgroundMusic, Music, MusicTables, Situation};
|
||||
use horizon_client::sound_events::normalize;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let tables = MusicTables::load(std::path::Path::new(&args[1]));
|
||||
let input = std::fs::read_to_string(&args[2]).expect("input");
|
||||
let mut out = std::io::BufWriter::new(std::fs::File::create(&args[3]).expect("output"));
|
||||
+2
-2
@@ -9,8 +9,8 @@ use std::{
|
||||
};
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [inputs, output] = args.as_slice() else {
|
||||
return Err("usage: skin_image_fixture INPUTS OUTPUT".into());
|
||||
};
|
||||
+3
-4
@@ -1,8 +1,7 @@
|
||||
//! Replays `tools/test_sound_engine_parity.py` scripts through Horizon's
|
||||
//! `SoundEngine` with a backend recording what an OpenAL source would hold:
|
||||
//! `sound_engine_fixture ROOT INPUT OUTPUT`.
|
||||
#[path = "audio_common/mod.rs"]
|
||||
mod common;
|
||||
use crate::audio_common as common;
|
||||
use common::{Fake, d, describe, f, flush, result_name};
|
||||
use horizon_client::sound_engine::{
|
||||
Attenuation, Backend, CartSound, InstanceId, SoundEngine, SoundInstance, TickContext,
|
||||
@@ -12,8 +11,8 @@ use horizon_core::random::LegacyRandom;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut engine = SoundEngine::new(SoundRegistry::load(std::path::Path::new(&args[1])));
|
||||
engine.listening = true;
|
||||
let mut backend = Fake::default();
|
||||
+2
-2
@@ -9,8 +9,8 @@ fn bits(v: f32) -> String {
|
||||
format!("{:08x}", v.to_bits())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let registry = SoundRegistry::load(std::path::Path::new(&args[1]));
|
||||
let mut engine = SoundEngine::new(registry);
|
||||
let input = std::fs::read_to_string(&args[2]).expect("input");
|
||||
+2
-2
@@ -136,8 +136,8 @@ fn reason(name: &str) -> Reason {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let root = Path::new(
|
||||
args.get(1)
|
||||
.ok_or("usage: spawn_rules_fixture RESOURCES INPUT OUTPUT")?,
|
||||
+2
-2
@@ -20,8 +20,8 @@ fn keys(mask: u64) -> Keys {
|
||||
analog: None,
|
||||
}
|
||||
}
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let mut out = BufWriter::new(File::create(&args[1])?);
|
||||
for line in BufReader::new(File::open(&args[0])?).lines() {
|
||||
let f: Value = serde_json::from_str(&line?)?;
|
||||
+2
-2
@@ -21,8 +21,8 @@ fn pose(m: [f32; 6]) -> Value {
|
||||
json!(m)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: subtitle_fixture RESOURCES INPUTS OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -53,8 +53,8 @@ fn runs(t: &Text) -> Value {
|
||||
out.into_iter().map(|(r, k)| json!([r, k])).collect()
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = std::env::args_os().skip(1).map(PathBuf::from).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<PathBuf> = crate::args_os().skip(1).map(PathBuf::from).collect();
|
||||
let [root, inputs, output] = args.as_slice() else {
|
||||
return Err("usage: tab_list_fixture RESOURCES INPUTS OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -8,8 +8,8 @@ use horizon_client::scoreboard::{self as sb, CollisionRule, NameView, Scoreboard
|
||||
use serde_json::{Value, json};
|
||||
use std::{fs, io::Write};
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut out = std::io::BufWriter::new(fs::File::create(&args[2]).expect("output"));
|
||||
for line in fs::read_to_string(&args[1]).expect("inputs").lines() {
|
||||
let c: Value = serde_json::from_str(line).expect("case");
|
||||
+2
-2
@@ -11,8 +11,8 @@ use std::{
|
||||
io::{BufRead, BufReader, BufWriter, Write},
|
||||
};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let input = BufReader::new(File::open(&args[1])?);
|
||||
let mut out = BufWriter::new(File::create(&args[2])?);
|
||||
for (n, line) in input.lines().enumerate() {
|
||||
+2
-2
@@ -3,8 +3,8 @@ use horizon_client::{item_tooltip::TooltipDisplay, items::ItemStack};
|
||||
use horizon_world::nbt::Tag;
|
||||
use std::{error::Error, fmt::Write};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut output = String::new();
|
||||
for line in std::fs::read_to_string(&args[1])?.lines() {
|
||||
let fields: Vec<&str> = line.split('\t').collect();
|
||||
+2
-2
@@ -231,8 +231,8 @@ fn prepare(m: &mut Merchant, gossips: &mut Gossips, kv: &HashMap<String, String>
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> horizon_client::Result<()> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let usage = "usage: trading_fixture RESOURCES INPUT VANILLA_OUTPUT OUTPUT";
|
||||
let root = Path::new(args.get(1).ok_or(usage)?);
|
||||
let input = fs::read_to_string(args.get(2).ok_or(usage)?)?;
|
||||
+2
-2
@@ -14,8 +14,8 @@ struct Case {
|
||||
cameras: Vec<[f64; 3]>,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().skip(1).collect();
|
||||
let [input, output] = args.as_slice() else {
|
||||
return Err("usage: translucency_fixture INPUT OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -8,8 +8,8 @@ fn bits(value: f32) -> String {
|
||||
format!("{:x}", value.to_bits())
|
||||
}
|
||||
}
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args: Vec<_> = crate::args().collect();
|
||||
let mut output = String::new();
|
||||
let mut parameters = weather::ParameterCache::default();
|
||||
for (case, line) in fs::read_to_string(&args[1])?.lines().enumerate() {
|
||||
+2
-2
@@ -24,8 +24,8 @@ fn doubles(v: &[f64]) -> Value {
|
||||
v.iter().map(|f| f.to_bits() as i64).collect()
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
pub fn main() -> Result<()> {
|
||||
let args: Vec<String> = crate::args().skip(1).collect();
|
||||
let [inputs, output] = args.as_slice() else {
|
||||
return Err("usage: world_border_render_fixture INPUTS OUTPUT".into());
|
||||
};
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
use horizon_protocol::{buf::Reader, packets::play::*};
|
||||
use std::{error::Error, fmt::Write};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
pub fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args: Vec<String> = crate::args().collect();
|
||||
let mut output = String::new();
|
||||
for line in std::fs::read_to_string(&args[1])?.lines() {
|
||||
let fields: Vec<&str> = line.split('\t').collect();
|
||||
Loaded 100 of 770 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user