Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1169ce6fe | ||
|
|
245ab9b4f6 | ||
|
|
61e99d5df7 | ||
|
|
59f2388a0f | ||
|
|
5b0ae21c96 | ||
|
|
097ccd28b0 | ||
|
|
31d77513fe | ||
|
|
5ba617927f | ||
|
|
7257e32237 | ||
|
|
18102bf315 | ||
|
|
7ec0a0516d | ||
|
|
c3839da0ef | ||
|
|
2f677e9337 | ||
|
|
8295b4c1ef | ||
|
|
cacc3360e0 | ||
|
|
964325b819 | ||
|
|
9ce6a3f9a0 | ||
|
|
693205032b | ||
|
|
e8b243b60d | ||
|
|
409cac606e | ||
|
|
d4463c5a82 | ||
|
|
e001cceadd | ||
|
|
2b62bd35d9 | ||
|
|
219c9302d9 | ||
|
|
e9f25bb1d7 | ||
|
|
bb97027039 | ||
|
|
27bfc9da13 | ||
|
|
fa61a38111 | ||
|
|
169ac59750 | ||
|
|
7c850a3056 | ||
|
|
e3ee0a7c45 | ||
|
|
3f115b7e06 | ||
|
|
a864f877ec | ||
|
|
41874a0e0c | ||
|
|
48ed3ea061 | ||
|
|
8e5a70b52b | ||
|
|
d31c2d7992 | ||
|
|
9f691e7e83 | ||
|
|
c5d504a734 | ||
|
|
6c2a827c34 | ||
|
|
90f06bd473 | ||
|
|
3395149802 | ||
|
|
3fc6964447 | ||
|
|
3749d679bd | ||
|
|
d933c333e6 | ||
|
|
c86a73887a | ||
|
|
83c4269800 | ||
|
|
89d90c3376 | ||
|
|
6b71454d1b | ||
|
|
57f7902809 | ||
|
|
7c2b9f3b80 | ||
|
|
2a4307638f | ||
|
|
5108050b31 | ||
|
|
706f3a6cb1 | ||
|
|
6d05ae816f | ||
|
|
f5487d5b08 | ||
|
|
4ede2e8aa7 | ||
|
|
9e1a2b70a8 | ||
|
|
969533780c | ||
|
|
31e019dff8 | ||
|
|
cccfc99d37 | ||
|
|
9c12738fb0 | ||
|
|
6d9e3a2064 | ||
|
|
9f7346e2e5 | ||
|
|
a04b258daf | ||
|
|
1b4ab4efe8 | ||
|
|
0eee668de4 | ||
|
|
a5fdef87fb | ||
|
|
44fa384ad6 | ||
|
|
f25ae007a7 | ||
|
|
181b9af7de | ||
|
|
c6c309d01b | ||
|
|
a258ef03d9 | ||
|
|
acf5d8896a | ||
|
|
4dcb8fed29 | ||
|
|
f56752d74f | ||
|
|
455a8b800f | ||
|
|
238d9cd1f4 | ||
|
|
ddab3fa269 | ||
|
|
a301fcc469 | ||
|
|
c1ce388d41 | ||
|
|
8bbf748e1f | ||
|
|
50c23cb7d9 | ||
|
|
8d5c1ed7a3 | ||
|
|
b6c1af58cd | ||
|
|
3cf1b6aa8f | ||
|
|
a11db16db3 | ||
|
|
dca26bf044 | ||
|
|
95b8f15c6b | ||
|
|
be6b796a20 | ||
|
|
90e26686bd | ||
|
|
2cd564f16b | ||
|
|
c64087836d | ||
|
|
40f3d42984 | ||
|
|
9a7b8a0ffc | ||
|
|
b571298b58 | ||
|
|
fefd3e8c6b | ||
|
|
4364dbfba3 | ||
|
|
8c837ede87 | ||
|
|
36b3c994e6 | ||
|
|
1ab3acaf70 | ||
|
|
ca4f82c665 | ||
|
|
bcf749c4d8 | ||
|
|
ff69e902c8 | ||
|
|
97170b869d | ||
|
|
e09a094d25 | ||
|
|
c5ba9aaf03 | ||
|
|
f7709827f6 | ||
|
|
72250afe73 | ||
|
|
602a58cfd1 | ||
|
|
f8a41e6c8b | ||
|
|
5495b461fd | ||
|
|
d1e80f8485 | ||
|
|
65aaaafe56 | ||
|
|
634fc6cb7a | ||
|
|
fb9a47061c | ||
|
|
0cebbbfad8 | ||
|
|
52069c3e49 | ||
|
|
8479dec66f | ||
|
|
f489d26358 | ||
|
|
4904b24c69 | ||
|
|
38421f5a8d | ||
|
|
3488a88696 | ||
|
|
2708b6a02f | ||
|
|
aaf6ccefcc | ||
|
|
b0e3d98b52 | ||
|
|
803907aaa5 | ||
|
|
ec056f9f02 | ||
|
|
63f2fa9f01 | ||
|
|
1ec378ac96 | ||
|
|
04c0ee173a | ||
|
|
3516095141 | ||
|
|
0eb6ca75c3 | ||
|
|
26079e71ed | ||
|
|
7d2b14f53e | ||
|
|
b9bd159dcf | ||
|
|
52980b81e0 | ||
|
|
4fbe64e376 | ||
|
|
5aacb47cd4 | ||
|
|
ff18bb42d5 | ||
|
|
9121109717 | ||
|
|
0faf62da1c | ||
|
|
5b03ea2d0c | ||
|
|
5dad8648b3 | ||
|
|
7f1bb6920b | ||
|
|
7bd4f6207b | ||
|
|
1d4cb83ca2 | ||
|
|
37f573d08f | ||
|
|
847fd2dcbe | ||
|
|
2c41bdf9fd | ||
|
|
7704c01acf | ||
|
|
c2f369fb2e | ||
|
|
c13658c430 | ||
|
|
5c1b79862e | ||
|
|
8366f89925 | ||
|
|
2917b77de1 | ||
|
|
b75251443c | ||
|
|
5d26a0bde3 | ||
|
|
7339aa2992 | ||
|
|
0096a8a835 | ||
|
|
5728b12cbb | ||
|
|
830bc7884b | ||
|
|
7e795012ed | ||
|
|
666479ad05 | ||
|
|
b498e0a5fc | ||
|
|
ebcadb8dd6 | ||
|
|
b1ad307e93 | ||
|
|
395b1422e0 | ||
|
|
1910ab8709 | ||
|
|
08ca24a176 | ||
|
|
b27aeaa93f | ||
|
|
ae217daafd | ||
|
|
d6501160e1 | ||
|
|
c3669e5412 | ||
|
|
0e7ed706b6 | ||
|
|
678eb2d1af | ||
|
|
55e203b1cd | ||
|
|
e9f14ea77f | ||
|
|
190d8f9a60 | ||
|
|
bbe01b52ad | ||
|
|
0d8411b352 | ||
|
|
890d330600 | ||
|
|
7fd746624a | ||
|
|
7ce014f8a9 | ||
|
|
f6dade0df2 |
No files matched your search
@@ -36,6 +36,21 @@ Submitting a project, through the form or a pull request, means you confirm that
|
||||
You alone are responsible for what you publish and for any claim about it. The Horizon project may refuse, hide or
|
||||
remove any project, at any time, without having to give a reason.
|
||||
|
||||
## Licences reviewers can read
|
||||
|
||||
Reviewers read a project's source before each version is listed; that is how they check it holds nothing harmful.
|
||||
They may only read source under a licence that lets them, so a new project, and every new version of a listed one,
|
||||
needs source under one of:
|
||||
|
||||
- MIT, MIT-0, BSD-2-Clause, BSD-3-Clause, 0BSD, Apache-2.0, ISC, zlib, Unlicense or CC0-1.0;
|
||||
- or any licence, with a written grant from its authors that lets the Horizon reviewers read the source to review it
|
||||
(say so in the pull request, with a link to the grant).
|
||||
|
||||
Source under GPL, LGPL, MPL or all rights reserved, without such a grant, can't be reviewed, so it can't be listed or
|
||||
updated. The projects already listed under other licences when this rule was written (classic_zoom,
|
||||
distant_horizons, fly_speed, serverify) stay listed as they are; their next version needs a licence above or a
|
||||
grant. A port also has to follow promise 2 above.
|
||||
|
||||
## Copyright and takedowns
|
||||
|
||||
If a project in this registry uses your work without your permission:
|
||||
|
||||
@@ -18,8 +18,8 @@ and the launcher to have shipped first.
|
||||
|
||||
**Who is responsible.** Except the projects marked Official (made by the Horizon project), everything here is made and
|
||||
owned by its own authors, not by the Horizon project or its maintainers. A listing is not an endorsement. See the
|
||||
[mod policy](MOD-POLICY.md): what authors promise when they submit (ports of other mods included) and how to have
|
||||
a project taken down.
|
||||
[mod policy](MOD-POLICY.md): what authors promise when they submit (ports of other mods included), the licences
|
||||
whose source reviewers can read, and how to have a project taken down.
|
||||
|
||||
## Submit
|
||||
|
||||
@@ -41,8 +41,9 @@ cargo install --git https://github.com/horizon-rust/horizon cargo-horizon-mod
|
||||
cargo horizon-mod check target/horizon-mod/my_mod.hmod
|
||||
```
|
||||
|
||||
**Updates** come the same way: the form adds a version to your entry. Only an entry's `owners` publish its updates
|
||||
without a reviewer's extra look. A published file never changes: publish a new version.
|
||||
**Updates** come the same way: the form adds a version to your entry, and a reviewer reads it before it is
|
||||
published. Only an entry's `owners` can add versions, and every version of a native mod is reviewed, owner or
|
||||
not: its code runs with the player's account permissions. A published file never changes: publish a new version.
|
||||
|
||||
**Signing** is optional and recommended: put your [minisign](https://jedisct1.github.io/minisign/) public key in your
|
||||
entry, and every later version must be signed with it, so nobody else can publish an update in your name.
|
||||
@@ -65,7 +66,7 @@ why.
|
||||
| `.github/workflows/publish.yml` | On merge: releases, then `index.json` on Pages |
|
||||
| `.github/workflows/cleanup.yml` | Weekly: staging files nobody needs any more |
|
||||
| `.github/workflows/native.yml` | Horizon's native mods: each changed one's tests, `.hnmod` and game check, all of them together, and weekly on the newest Nightly |
|
||||
| `native/<name>/` | Horizon's own native mods (Zoom, FPS Counter, Keystrokes, Minimap, Recipes): the source of their `.hnmod` files |
|
||||
| `native/<name>/` | Horizon's own native mods (Zoom, FPS Counter, Keystrokes, Minimap, Recipes, Coordinates HUD): the source of their `.hnmod` files |
|
||||
| `native/tools/` | Shared by them: apply on Horizon, check, build, package, prove (`native/tools/native.py`) |
|
||||
| `scripts/` | What the workflows share |
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 975 B |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 855 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 644 B |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 140 KiB |
@@ -0,0 +1,45 @@
|
||||
id = "appleskin"
|
||||
kind = "native-mod"
|
||||
name = "AppleSkin"
|
||||
summary = "Shows how much HP, hunger, and saturation will be restored."
|
||||
description = """
|
||||
AppleSkin for Horizon, a native mod.
|
||||
|
||||
Renders saturation, exhaustion, and held-food values over the hunger bar, as the original AppleSkin does.
|
||||
|
||||
Based on AppleSkin by squeek502. See the LICENSE in the source for the
|
||||
original copyright and licence notices."""
|
||||
authors = ["soufi"]
|
||||
owners = ["soufied"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/soufied/AppleSkin-Horizon"
|
||||
icon = "icons/appleskin.png"
|
||||
key = "RWT6eNq4e5WfVDA2lzOOi6XCm/+jJgilqT1+HUUM33ie5MCjcRfSg760"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.1"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "appleskin-0.1.1.hnmod"
|
||||
sha256 = "182117d2a9767bc22a7c6652efd24551990cea015193784f20aeb8a7ba35b4ac"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUT6eNq4e5WfVPcAN+WeTYujFNeWw6oMKKV7nXxfIfyeqg83qrFNNA/LYfOrmxwV0DgO+tf5Sk5piJjS7hEtyKhl9rs0VpBOfgg=
|
||||
trusted comment: timestamp:1793418678\tfile:appleskin-0.1.1.hnmod\thashed
|
||||
gK9BQoCtM8sRPSvSiBzAT2IE8nZlCDfUa7tWCG7cG/v7H41E+4DnflE0KtAPdqi/9+MQT3ONmT4qbGFVio58BA=="""
|
||||
changelog = """
|
||||
dumped to 0.1.1
|
||||
added icon"""
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "appleskin-1.0.0.hnmod"
|
||||
sha256 = "3c25b916f74f47faf40070a8654c546d15cb79ac3947f140e257f4cb041aeb96"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUT6eNq4e5WfVEMHvcSGm73mmamWosNGGcdt7Qn05wqgRuAlDj/DyzH66lS2u8nvB43GnZJ7xCmgoM5xArHJuN9kD30iIKj0zws=
|
||||
trusted comment: timestamp:1793368049\tfile:appleskin-1.0.0.hnmod\thashed
|
||||
gjEf247x8XwHpOI2Ra3ngk6umC/mFZiHOCfZyzxg5IFJ7CNJVpofnw/l7ITtePPeyi4r3+0D6FvmmhtuiqVAAg=="""
|
||||
changelog = "First release. AppleSkin for Horizon as a native mod: saturation, exhaustion and the food in your hand, drawn over the food bar."
|
||||
@@ -0,0 +1,29 @@
|
||||
id = "appleskin_horizon"
|
||||
kind = "native-mod"
|
||||
name = "AppleSkin"
|
||||
summary = "1:1 Minecraft Java parity food value preview & saturation HUD overlay."
|
||||
description = """
|
||||
1:1 Minecraft Java parity port of AppleSkin for the native Horizon Rust client.
|
||||
|
||||
Features
|
||||
Saturation Overlay: Golden border and glow around active saturation drumsticks matching original icons.png pixel art.
|
||||
Food Value Preview: Pulsing preview drumsticks and preview saturation border when holding edible items.
|
||||
Clean Integration: Easily toggled via Options > Mods > AppleSkin."""
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/appleskin"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "appleskin_horizon-1.0.0.hnmod"
|
||||
sha256 = "38a729f1aad00f6148f29578a2725cb5e7f9aea79a870fcf3cee76f39838c5ff"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTNzxiQEELascXv6v/RXLycX9k/IkVf5ggI7lL2qjyDEVxdDl5nPxbdCJ3epwwHIE6D8ZHw6QGXCFQjRz3I6Z/UA0=\r
|
||||
trusted comment: timestamp:1793440355\tfile:appleskin_horizon-1.0.0.hnmod\thashed\r
|
||||
6kGj1vQ1DJypzS0iDdvwksQ2FFAB1jBcycZL83OgBgQgUzbQzKRhGtleKwqAuIrRLdpQO93ale4hSMAv1z/EDg=="""
|
||||
changelog = "Initial release for Horizon 26.3."
|
||||
@@ -0,0 +1,30 @@
|
||||
id = "armor_status"
|
||||
kind = "native-mod"
|
||||
name = "Armor Status"
|
||||
summary = "Displays equipped armor & held items with authentic Java durability colors."
|
||||
description = """
|
||||
A native ArmorStatusHUD mod for the Horizon Rust client.
|
||||
|
||||
Features
|
||||
Displays all 4 armor slots plus main and off-hand items on the HUD.
|
||||
Authentic Java durability color coding (Green > Yellow > Orange > Red).
|
||||
Item count display for non-damageable held items (torches, food, blocks).
|
||||
Default position: Bottom Right (freely customizable in Options > Mods)."""
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/armor-status"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "armor_status-1.0.0.hnmod"
|
||||
sha256 = "82c8672fa2c43d7946a26a560fd56fdd8f34beecf4bcb459c2d508b3d09eeee6"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTN+dR+lW2uDL5+FJfKRnHJvelJnWmhWGQeS/p0lNFVDFfq3BjZ2LCuNEtza8cZvcuKuuYF5asmxsnbtB/MMykYQA=\r
|
||||
trusted comment: timestamp:1793439927\tfile:armor_status-1.0.0.hnmod\thashed\r
|
||||
LTwf1kuPLucJIBfHPdx1nsp0YuHSlxbFG6PYKG2HnMxMf4acAsZbWR0QdQnzkn+7Oc/T60iQPh3X14RBST3+Bg=="""
|
||||
changelog = "Initial release for Horizon 26.3."
|
||||
@@ -0,0 +1,32 @@
|
||||
id = "astral_cruiser"
|
||||
kind = "native-mod"
|
||||
name = "Astral Cruiser"
|
||||
summary = "A huge pilotable starship with a walkable interior, lasers, dash and live portals between dimensions."
|
||||
description = """
|
||||
A huge starship you fly yourself, with a large walkable interior that moves with it.
|
||||
|
||||
- **Flight:** WASD with the ship following your view, and F5 views including the ship's own.
|
||||
- **Weapons:** turrets, nose guns and two beams.
|
||||
- **Travel:** coordinate dash and jump. Long dashes show only a small strip of far terrain around the ship.
|
||||
- **Portals:** a portal shows the real destination dimension live, and you cross it aboard or on foot.
|
||||
- **Start:** `/astral spawn`, then `/astral board`. N opens the control panel; keys are in Options > Mods > Settings.
|
||||
|
||||
**What it does as a native mod.** It is compiled into the game with no sandbox. It changes the game's rendering, ticking and chunk loading for the ship and portals, and registers a thread-exit callback in builds made with MinGW so the allocator frees finished threads' memory.
|
||||
|
||||
**What it does not do.** It adds no network access of its own beyond the game's own, and it reads no accounts or files outside the game's data. It keeps the ship in the world's own folder (`astral_cruiser/ship.json`). It holds no Minecraft code or assets.
|
||||
|
||||
Weapons hurt the mobs they hit. With blasting turned on in the control panel (off by default), the nose guns and beams also blow up the blocks they hit. Portals can hang in the air, so a player on foot falls if there is no ground at the exit, including into the End's void.
|
||||
|
||||
Built for this Horizon commit only: `68ac6f647e7022b2c696e81863d7cface28c9416`."""
|
||||
authors = ["repositorykreml1n"]
|
||||
owners = ["repositorykreml1n"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/repositorykreml1n/astral-cruiser"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-11-01"
|
||||
game = "26.3"
|
||||
file = "astral_cruiser-0.1.0.hnmod"
|
||||
sha256 = "69100219f92307f9190712da2854bfd43f15cf81773d89d89d6dd22411caa2f2"
|
||||
changelog = "First release, built for Horizon 68ac6f6."
|
||||
@@ -0,0 +1,34 @@
|
||||
id = "basic_hud"
|
||||
kind = "native-mod"
|
||||
name = "The Basic HUD"
|
||||
summary = "Effect timers, potions, golden apples and totems carried, totems used by each player, and armour, elytra and shield durability."
|
||||
description = """
|
||||
A small HUD box in a corner of the screen.
|
||||
|
||||
## What it shows
|
||||
|
||||
- Active effects with their time left. Potion effects are pinned by default; any other effect can be pinned on the mod's settings page, or all of them shown at once.
|
||||
- Potions of each kind, golden apples, enchanted golden apples and totems in your inventory.
|
||||
- Totems each player has used, above that player's name. Your own count is in the box.
|
||||
- Durability of worn armour, elytra and a held shield.
|
||||
|
||||
The count of a player's totems resets when they die or when you leave the world.
|
||||
|
||||
## What it does not do
|
||||
|
||||
- It builds on one Horizon commit only, 68ac6f6 (Minecraft 26.3). Counting totems and writing above a player have no hook point, so it hooks two of the game's own functions (totem_event, name_tag_geometry). The rest uses hook points but reads the game's internal data.
|
||||
- It knows only what the client is told: a totem used out of your sight is not counted.
|
||||
- Its own texts are in English. Effect and item names follow the game's language.
|
||||
- Tested on Windows in single player and over LAN with two clients, not on a dedicated server."""
|
||||
authors = ["repositorykreml1n"]
|
||||
owners = ["repositorykreml1n"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/repositorykreml1n/the-basic-hud"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-11-01"
|
||||
game = "26.3"
|
||||
file = "basic_hud-0.1.0.hnmod"
|
||||
sha256 = "fe2c5d9da681b4f575bff867df70d6e2f61614b0215a206fb7a0c3b0027db994"
|
||||
changelog = "First release."
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "BiomeCompass"
|
||||
summary = "Craft a Biome Compass, pick a biome and its needle points to the nearest one."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
Craft a **Biome Compass** (a compass with a sapling on each of its four sides, any kinds), right-click it and pick a biome from the list (with a search box). The world generator is searched around you, a little every tick, and the compass's needle then points to the nearest one, with its distance and direction on the action bar.
|
||||
|
||||
@@ -16,7 +16,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/biomecompass"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/biomecompass/main/icon.png"
|
||||
icon = "icons/biomecompass.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.2.2"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
id = "blockscope"
|
||||
kind = "mod"
|
||||
kind = "native-mod"
|
||||
name = "Blockscope"
|
||||
summary = "The block under your crosshair: its name, id, distance and icon, with reach, placement and opacity on its own settings page. A Jade-style tooltip for Horizon."
|
||||
description = "Jade-style block info for Horizon: the block under your crosshair, its name in your language, its block id, how far it is and its icon."
|
||||
@@ -7,7 +7,15 @@ authors = ["Domanffe"]
|
||||
owners = ["Domanffe"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/Domanffe/blockscope"
|
||||
icon = "https://raw.githubusercontent.com/Domanffe/blockscope/main/docs/icon.png"
|
||||
icon = "https://horizon-rust.github.io/horizon-mods/icons/blockscope.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.3.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "blockscope-0.3.0.hnmod"
|
||||
sha256 = "ba4a1c887ab26a2a9189c671cbdbea3ce2ed212a6e3d32f1fffaa60386198358"
|
||||
changelog = "Native: the WebAssembly mod rewritten as a mixin bundle for the launcher's native mods, with hardness and the tool's icon, block states, crop growth, a container's slots and a creature's health, each on its own switch. Its settings carry over from 0.2.0."
|
||||
|
||||
[[versions]]
|
||||
version = "0.2.0"
|
||||
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "Carry Block"
|
||||
summary = "Sneak and right-click with an empty hand to pick up a chest (with its items) or a small mob, carry it and put it down."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
Sneak and right-click with an empty hand to pick up a block with its contents (chests, furnaces, barrels...) or a small, friendly mob, and carry it; right-click to put it down where you want, with everything it held.
|
||||
|
||||
@@ -17,7 +17,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/carryblock"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/carryblock/main/icon.png"
|
||||
icon = "icons/carryblock.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.2"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "chatheads"
|
||||
kind = "native-mod"
|
||||
name = "ChatHeads"
|
||||
summary = "A player's head left of every chat line they wrote."
|
||||
description = """
|
||||
Each chat line from a player gets their 8x8 skin face in the strip to its left, like the Chat Heads Java mod. Lines without a player (system messages, /me, wrapped continuations) stay as they are; the face fades with its line.
|
||||
|
||||
Settings: Options > Mods > ChatHeads > Settings (on or off).
|
||||
|
||||
Known limit: the chat's hit-test does not know about the 10 px indent, so clicking a link in chat lands 10 px left of its pixels."""
|
||||
authors = ["Domanffe"]
|
||||
owners = ["Domanffe"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/Domanffe/chatheads"
|
||||
icon = "https://horizon-rust.github.io/horizon-mods/icons/chatheads.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "chatheads-0.1.0.hnmod"
|
||||
sha256 = "c20605c24e29a762b9aea85cba1b0cc7955955a40a031efae70a5b01e4e79df4"
|
||||
changelog = "First release: a native mod for Horizon 26.3. Every chat line from a player gets their 8x8 skin face in the strip to its left; system lines, /me and wrapped continuations get none. Settings in Options > Mods."
|
||||
@@ -1,5 +1,5 @@
|
||||
id = "classic_zoom"
|
||||
kind = "mod"
|
||||
kind = "native-mod"
|
||||
name = "Classic Zoom"
|
||||
summary = "Hold V to zoom 3x, scroll for more, release to snap back. Instant, no settings, inspired by WI Zoom."
|
||||
description = """
|
||||
@@ -32,14 +32,29 @@ Both can be installed at once: they use different keys.
|
||||
- Written from scratch for Horizon's mod API. Not affiliated with Wurst-Imperium.
|
||||
- Some servers forbid zoom mods: check the rules before you join.
|
||||
|
||||
**Now a native mod (2.0.0)**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's permissions, so read the source before you build it: it is one small bundle on Horizon's native hook points (key, wheel, zoom, mods list). Tested against Horizon `6f8c7a0e5d531d3834c4d0be4659a1db8e7e5c2a` with Horizon Mixins `0d6b103c70633d8fd9443d8d0acd3aadaacedb06`. A key set in 1.0.0 carries over.
|
||||
|
||||
Source and issues: [github.com/SU4G3/classic-zoom](https://github.com/SU4G3/classic-zoom)"""
|
||||
authors = ["Surge"]
|
||||
owners = ["SU4G3"]
|
||||
license = "GPL-3.0-or-later"
|
||||
source = "https://github.com/SU4G3/classic-zoom"
|
||||
icon = "https://github.com/SU4G3/classic-zoom/blob/main/.github/icon.png?raw=true"
|
||||
icon = "icons/classic_zoom.png"
|
||||
key = "RWTOxMcIG6MtC0QQnhWEMC+nLKJ6+u4trV/rF+4juSRuow8W4b5P+CPS"
|
||||
|
||||
[[versions]]
|
||||
version = "2.0.0"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "classic_zoom-2.0.0.hnmod"
|
||||
sha256 = "a8bdeba615ed31b9bd10280fcf8ba04a31935bc65fff429fc0e83d1c8090dac9"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUTOxMcIG6MtCyXVhFrgrbWwg3pEBeR8iQ6g3w8MlWbzunH02kAF3swud3hq59EQvuoNpQxj7eTNRy6IJ4l+++7H1EazgGLV3AY=
|
||||
trusted comment: timestamp:1793286240\tfile:classic_zoom-2.0.0.hnmod\thashed
|
||||
bbYFmm0wap7Mgnt+wxSMkC/FqklbuAZage02x4Kt5Mi2mzknFbhWij/6sOx5ojRAquDT1XLRpRd2UrrAy4x4Bg=="""
|
||||
changelog = "Now a native mod (WebAssembly code mods are going away). Same zoom: V by default, 3x, x1.1 per wheel step within 1x-10x, instant, slower turning while zoomed; a key set in 1.0.0 carries over. Pinned to Horizon 6f8c7a0 and Horizon Mixins 0d6b103."
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-29"
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
id = "coords_hud"
|
||||
kind = "mod"
|
||||
kind = "native-mod"
|
||||
name = "Coordinates HUD"
|
||||
summary = "Your coordinates, facing and the time of day in a corner of the screen."
|
||||
summary = "Your coordinates and facing in a corner of the screen."
|
||||
description = """
|
||||
The SDK's example mod. It draws your block position, the direction you face and the time of day
|
||||
in the top-left corner, every frame.
|
||||
Your block position and the direction you face in the top-left corner of the screen.
|
||||
|
||||
- `/where` puts your coordinates and dimension in chat.
|
||||
- `/coords` hides or shows the panel.
|
||||
- `/coords` hides or shows the box, and the game keeps your choice (also Options > Mods > Coordinates HUD > Settings).
|
||||
|
||||
It reads the game (position, health, time), draws on the HUD and writes to chat: nothing else.
|
||||
It reads the player's position, draws on the HUD and writes to chat: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(install it on the launcher's Mods page, then press Build there). The time of
|
||||
day line is gone, since Horizon's hook points don't give the game's clock yet. Turn it off in Options > Mods: it
|
||||
rests at once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/coords-hud](https://github.com/horizon-rust/horizon-mods/tree/main/native/coords-hud).
|
||||
"""
|
||||
authors = ["Horizon"]
|
||||
owners = ["ludovic111"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/horizon-rust/horizon/tree/main/crates/horizon-mod-sdk/examples/coords-hud"
|
||||
source = "https://github.com/horizon-rust/horizon-mods/tree/main/native/coords-hud"
|
||||
icon = "icons/coords_hud.png"
|
||||
|
||||
[[versions]]
|
||||
version = "2.0.0"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "coords_hud-2.0.0.hnmod"
|
||||
sha256 = "432376fad3062b3517e274d3b8c0d0b52fc5d6de2aee20a0b340c8cab5a8cf08"
|
||||
changelog = "Native: built into the game by the launcher on Horizon's native hook points; /coords is kept; turn it off in Options > Mods. The time of day line is gone for now."
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-24"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
id = "crosshair_indicator"
|
||||
kind = "native-mod"
|
||||
name = "Crosshair Indicator"
|
||||
summary = "Dynamic target reach awareness: visual feedback on your crosshair when hovering over an entity in attack range."
|
||||
description = """
|
||||
Crosshair Indicator
|
||||
|
||||
A native Horizon mod by CayMac that ports the popular Java Crosshair Indicator mod into Horizon:
|
||||
|
||||
Dynamic Target Reach Awareness: Real-time visual feedback directly on your crosshair when hovering over an entity in attack reach (<= 3.0 blocks).
|
||||
Iconic PvP Target Reticle: Default crisp white corner brackets [ + ] hugging the crosshair, matching classic competitive PvP clients.
|
||||
Multiple Styles: Choose between Brackets [ + ], Center Dot, Diamond, and Tactical Chevron.
|
||||
Custom Color Themes: Classic White (Default), Dynamic (Green/Orange cooldown awareness), Combat Red, Pink Aesthetic, Diamond Cyan, and Gold.
|
||||
Cooldown Bar: Optional subtle weapon cooldown progress indicator below the crosshair.
|
||||
Configurable: Easily customize styles, themes, and keybinds in Options > Mods > Crosshair Indicator."""
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/crosshair-indicator"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "crosshair_indicator-1.0.0.hnmod"
|
||||
sha256 = "96beba1f7c94fca492b552fb12af0d20047dc1799f0801607841d56b12786226"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTNz67XDjUwaJ8if7+jDk+qXnJLdhtyjh8mk04UuZ2bme/Tzcpi1Od4ppYmvqzfZ+rEAeG2hb9Lytn+J2nFy1u8gc=\r
|
||||
trusted comment: timestamp:1793461576\tfile:crosshair_indicator-1.0.0.hnmod\thashed\r
|
||||
zF7EJHDjJPwVG+cYcSgvGJv4kjjYRMdMZipUQyABH0DEMIZ2Fe13hb2nbYYRZlNDG1j4kjhgEYQTODFiAlaCBQ=="""
|
||||
changelog = "Initial release for 26.3 Horizon."
|
||||
@@ -0,0 +1,33 @@
|
||||
id = "crossversion"
|
||||
kind = "native-mod"
|
||||
name = "CrossVersion"
|
||||
summary = "Allows connecting to older servers"
|
||||
description = """
|
||||
A native Horizon mod that lets the 26.3 client join servers that speak an older Minecraft protocol.
|
||||
|
||||
Horizon talks exactly one protocol (777, Minecraft 26.3). This mod watches a join, asks the server what protocol it speaks in its status reply, and — if it is not 26.3 — starts a ViaProxy instance on a loopback port and points the join at it. The proxy speaks 26.3 to Horizon and the server's own version to the server. Nothing else in the client changes, and a join to a 26.3 server never starts anything.
|
||||
|
||||
Horizon client ──26.3──▶ 127.0.0.1:<port> ViaProxy ──server's version──▶ the server
|
||||
|
||||
Tested against a vanilla 1.20.1 server (protocol 763) and a 1.21.1 server (767): world load, chunks, entities, chat and the tab list all work. ViaProxy itself covers servers from 1.0 to 26.3. An online-mode 1.20.1 server accepts the player's own account through the proxy.
|
||||
|
||||
Signed chat works too: from Horizon's Nightly 2026-11-01 on, the client holds a chat key pair and signs its messages, so online-mode servers with enforce-secure-profile=true accept them through the proxy (<JustKarkat> …, not [Not Secure]). On Horizon before that nightly (the mod's 0.1.x pinned an earlier commit) secure-profile servers refused the chat and said "Chat disabled due to missing profile public key" — the client's gap, not the proxy's."""
|
||||
authors = ["JustKarkat"]
|
||||
owners = ["JustKarkat"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/JustKarkat/horizon-crossversion"
|
||||
icon = "https://github.com/JustKarkat/horizon-crossversion/blob/master/icon.png?raw=true"
|
||||
key = "RWTcPJHJYjPW0pV3lPwr45crCu0wJxW5HbDLc3fr3Eom1TzxO++kHOo4"
|
||||
|
||||
[[versions]]
|
||||
version = "0.4.0"
|
||||
published = "2026-11-02"
|
||||
game = "26.3"
|
||||
file = "crossversion-0.4.0.hnmod"
|
||||
sha256 = "5cf5ed0c16636a72da77d00f25923b2dc9938b66bcba2fc3571f2220f99f3f30"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUTcPJHJYjPW0sufgxegROTP9Mp0mOnggtNsendRR9PUL9gvOQAXIpX+gOSNinE/Xsze7pzBkvi7kgWqmR3hAeM/GZ8Wal97CQU=
|
||||
trusted comment: timestamp:1793593673\tfile:crossversion-0.4.0.hnmod\thashed
|
||||
NErBRO3f7O8sN/aQHf7Fsrqanubwgo9rCm/kuxSP0Oux21LiX6jcuMxeMykUmjtWP6AJDptFjdyAHlA7m0P9Dw=="""
|
||||
changelog = "Initial push for CrossVersion"
|
||||
@@ -0,0 +1,33 @@
|
||||
id = "distant_horizons"
|
||||
kind = "native-mod"
|
||||
name = "Distant Horizons for Horizon Client"
|
||||
summary = "See far past your render distance: Distant Horizons' level-of-detail terrain, ported to Rust as a native mod."
|
||||
description = """
|
||||
An unofficial Rust port of [Distant Horizons](https://gitlab.com/distant-horizons-team/distant-horizons) by James Seibel and contributors: the world past your render distance, drawn at lower detail the farther it is.
|
||||
|
||||
- Far terrain built from the chunks you visit, and in single player from the world generator, out to 64–1024 chunks.
|
||||
- Detail drops with distance by Distant Horizons' own rule, with its five quality presets.
|
||||
- LODs are kept on disk per world, so they load at once next time.
|
||||
- Drawn by Horizon's far-terrain renderer with block textures and biome tints.
|
||||
|
||||
Settings: Options > Mods > Distant Horizons. In chat: `/dh` for status, `/dh distance 512`, `/dh quality high`, `/dh debug on` and more (Tab completes them).
|
||||
|
||||
Native source mod: install it on the launcher's Mods page, press Build there and confirm the native-code warning. The launcher downloads its own Rust and builds a separate game (10–30 minutes the first time). It runs with your account's permissions.
|
||||
|
||||
Pinned to Horizon nightly `d009ebd140476b5bdc958c00f56a75e82abec691` (2026-10-29) and Horizon Mixins `0d6b103c70633d8fd9443d8d0acd3aadaacedb06`; the launcher builds these exact revisions. Other Horizon revisions have not been validated. It builds together with Horizon's official native mods; it can't be built with a native mod pinned to a different Horizon commit. Turn Video Settings > LOD Distance off: Horizon's own far terrain draws in the same place.
|
||||
|
||||
Known limits: heavy at 256+ chunks (about 30–40 fps on an Apple M5 MacBook Pro); water at LOD edges can show see-through walls.
|
||||
|
||||
LGPL-3.0, as Distant Horizons; its copyright notices are kept. Not made or endorsed by the Distant Horizons team. No Minecraft code or assets are included. Ported by Deniz Şahin with Claude (Anthropic)."""
|
||||
authors = ["denizsahin7744", "Deniz7744"]
|
||||
owners = ["denizsahin7744"]
|
||||
license = "LGPL-3.0-only"
|
||||
source = "https://github.com/denizsahin7744/distant-horizons-for-horizon-client"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "distant_horizons-0.1.0.hnmod"
|
||||
sha256 = "c53a2501f14efb624839329aac6999ddf8c64a399d41bec42a0c878902feea81"
|
||||
changelog = "First release: pinned to Horizon nightly d009ebd and Horizon Mixins 0d6b103."
|
||||
@@ -0,0 +1,46 @@
|
||||
id = "eatinganimation"
|
||||
kind = "native-mod"
|
||||
name = "Eating Animation"
|
||||
summary = "While you eat food, or drink a potion or milk, the item in your hand shows its bitten frames."
|
||||
description = """
|
||||
It is a port of [Eating Animation](https://github.com/Theoness1/EatingAnimation) for Horizon.
|
||||
|
||||
While you eat food, or drink a potion or milk, the item in your hand shows its bitten frames.
|
||||
|
||||
The frames come from a resource pack you build from your own copy of the EatingAnimation download with `tools/make_frame_pack.py`, and drop into Horizon's `resourcepacks/` folder.
|
||||
|
||||
~~Or you can just download it from GitHub Releases...~~"""
|
||||
authors = ["soufi"]
|
||||
owners = ["soufied"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/soufied/EatingAnimation-Horizon"
|
||||
icon = "icons/eatinganimation.png"
|
||||
key = "RWT6eNq4e5WfVDA2lzOOi6XCm/+jJgilqT1+HUUM33ie5MCjcRfSg760"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.1"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "eatinganimation-0.1.1.hnmod"
|
||||
sha256 = "3b4d7ce3c9791facc862da7727c2c7c71025cd9bb3ee4cbeaf40f48c72bf5cb0"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUT6eNq4e5WfVC2NLoRuU8m5JDlH1mh8dNmGbAZUj6bB4grd487xtihz4OLxxJRyO7jzQHrOz6nAPjcZjT/o1RIxebtX+A3tPg8=
|
||||
trusted comment: timestamp:1793419092\tfile:eatinganimation-0.1.1.hnmod\thashed
|
||||
OeN+0r/c6BVNO4b82/T9jp/Wh9iGpvL/B0enoxWiIB31W+7E2OmKWhceMaIZqc4w3N3gn3D8+sFrDICK55WoDQ=="""
|
||||
changelog = """
|
||||
dumped to v0.1.1
|
||||
added icon"""
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "eatinganimation-0.1.0.hnmod"
|
||||
sha256 = "07ef4fde3ebbc4f132aab593b12187bce15e1a46689ab40bd3067c685aca85b9"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RUT6eNq4e5WfVJPSxJOh730W1FMzydyVRO2S58rux9xbEtEU+mDgsqWX65rscWaUH3zqOkLan6quW/u9nEZDgXrNz1n6IHnT5Aw=
|
||||
trusted comment: timestamp:1793371727\tfile:eatinganimation-0.1.0.hnmod\thashed
|
||||
qCCGAWAc39kDujbX9CsdXu/URjpNybAOxkomTi18GnzJhMLtsbj0ZfVJaVCSxnh0VvznGQvoH9/DEdRAxBAVBg=="""
|
||||
changelog = "First release. Eating Animation for Horizon as a native mod: the food, milk and potion in your hand show bitten frames while you eat or drink them."
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "Enchantment Hints"
|
||||
summary = "A short description under every enchantment in item tooltips, in English and Russian."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
Every enchantment on books and gear gets a one-line description in its tooltip: what it does, in plain words. Our own text for every 26.3 enchantment, in English and Russian.
|
||||
|
||||
@@ -15,7 +15,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/enchantmenthints"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/enchantmenthints/main/icon.png"
|
||||
icon = "icons/enchantmenthints.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
id = "fair_freecam"
|
||||
kind = "native-mod"
|
||||
name = "Fair Freecam"
|
||||
summary = "Fly the camera freely while your player stays where it is, with an optional fair play mode."
|
||||
description = """
|
||||
Press **F4** to leave your body and fly the camera anywhere. Your player stays where it is and you see it from outside. Press **F4** again to snap back.
|
||||
|
||||
**Controls while flying:**
|
||||
- **W A S D**: fly where you look
|
||||
- **Space / Shift**: up / down
|
||||
- **Ctrl**: 2.5x faster
|
||||
- **Mouse wheel**: change the speed
|
||||
|
||||
**Settings** (Options > Mods > Fair Freecam):
|
||||
- **Speed**: 2, 5, 10, 20, 40 or 80 blocks per second.
|
||||
- **Fair play**: the camera can't fly through blocks, so no peeking into caves or bases through walls. Glass, fences and doors stop it, grass and flowers don't.
|
||||
- **Allowed on servers**: turn it off to only use freecam in your own worlds.
|
||||
|
||||
While flying, your player doesn't move, attack, mine or use items.
|
||||
|
||||
Some servers don't allow freecam, so check their rules first."""
|
||||
authors = ["Lutziano888"]
|
||||
owners = ["Lutziano888"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/Lutziano888/horizon-freecam"
|
||||
icon = "icons/fair_freecam.png"
|
||||
|
||||
[[versions]]
|
||||
version = "1.2.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "fair_freecam-1.2.0.hnmod"
|
||||
sha256 = "4fdd0b3067a00d23fe30ee4d594293ef0705325bb5e6e5b292f90c1e8b8a5f8a"
|
||||
changelog = "First release as Fair Freecam (id fair_freecam), so it doesn't clash with other freecam mods."
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "fly_speed"
|
||||
kind = "native-mod"
|
||||
name = "Fly Speed"
|
||||
summary = "Allows you to change your fly speed"
|
||||
description = "Fly 0.1x to 20x your normal speed: /flyspeed, /flyspeed +1 to step, /flyspeed reset for 1x. Native Horizon mod."
|
||||
authors = ["ImmortalDev"]
|
||||
owners = ["ImmortalWhisper"]
|
||||
license = "All Rights Reserved"
|
||||
source = "https://github.com/ImmortalWhisper/Fly-Speed"
|
||||
key = "RWSy3RAfbzD2a0WMm0tQlVl+3GHigjwvwXKvzvnwfmoYrIAoIffbrSbP"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "fly_speed-0.1.0.hnmod"
|
||||
sha256 = "c50a3dcfd9ff68af00560f9cd330c4d18b3d9028113b6769ded54997d5267ddf"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUSy3RAfbzD2a/1H3F6VX9i5wllM8eP2z7FagPND9tqKj76TY2RNWvF/b4xYcqPLU7OLKAPDVY2+HglKTx9GKnAPPt0KQUYwmQQ=\r
|
||||
trusted comment: fly_speed-0.1.0.hnmod\r
|
||||
FcLZSTLhxoNvfQAXmKtGb96iTxdJgh2llOMq4GlGhJPgjrhCvllUHEsHWvXnk0sNKEJREKxQ3CVy8VmYcNQzBQ=="""
|
||||
changelog = "Created Mod"
|
||||
@@ -12,7 +12,7 @@ Horizon's own FPS counter, formerly an extra in Options > Horizon Extras.
|
||||
It reads the game's own frame counter and draws on the HUD: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(Settings → Game → Native mods (experimental), then Build). Your settings carry over from 1.0.0. Turn it off in
|
||||
(install it on the launcher's Mods page, then press Build there). Your settings carry over from 1.0.0. Turn it off in
|
||||
Options > Mods: it rests at once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/fps-overlay](https://github.com/horizon-rust/horizon-mods/tree/main/native/fps-overlay).
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "freecam"
|
||||
kind = "native-mod"
|
||||
name = "Freecam"
|
||||
summary = "Freecam mod ported for Horizon"
|
||||
description = "A rewrite for Horizon of the Freecam mod by the Freecam authors (https://github.com/MinecraftFreecam/Freecam, MIT; on Modrinth as freecam). Its licence notice is kept in the source."
|
||||
authors = ["hakergeniusz"]
|
||||
owners = ["hakergeniusz"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/hakergeniusz/freecam"
|
||||
key = "RWR4cJC6Jj3EWGi26o29Rs3hAIPWqf8koFdXV4bBLF/Tm84QPfRAYjO5"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "freecam-0.1.0.hnmod"
|
||||
sha256 = "6314ed87d3b58ed0244bed388201c64bffb8deab4f5ff7beed2a3791b391a6da"
|
||||
signature = """
|
||||
untrusted comment: signature from rsign secret key
|
||||
RUR4cJC6Jj3EWN7yDLuEFss9Xir36oWeHI3yyIK+PlIffoXzHXcZ4eBAN/UcOwGpniH+lJl9uU1vzg8yRe9i6SKNMFhI6qbHkAQ=
|
||||
trusted comment: freecam 0.1.0 for Horizon (Minecraft 26.3), built from github.com/hakergeniusz/freecam commit 78d8f05
|
||||
6sfFvM54vZFE+02rwu0EJVbCnv5dJAJ7PDEWp64QnyEjlWYEnzXDzDAyLzKdZAfXwtvX+igaCS2KJKCk5UY5CA=="""
|
||||
changelog = "Release."
|
||||
@@ -0,0 +1,27 @@
|
||||
id = "freecam_plus"
|
||||
kind = "native-mod"
|
||||
name = "Freecam+"
|
||||
summary = "Fly the camera anywhere while your player stays perfectly still."
|
||||
description = """
|
||||
Press U and your camera leaves your body. Fly it with WASD, Space and Shift, hold Ctrl to go faster and use the mouse wheel to change the speed. Your player does not move or turn, so the server sees you standing still. Through walls and speed can be changed in Options, Mods, Freecam.
|
||||
|
||||
Since this is a native mod it will not work in v0.2.97 as there are no native hooks possible. This works on all nightly releases and LIKELY on version upwards from v0.2.97."""
|
||||
authors = ["_idom_"]
|
||||
owners = ["umbx-dot"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/umbx-dot/horizon-freecam"
|
||||
icon = "icons/freecam_plus.png"
|
||||
key = "RWT9Ujo/oCprPGHHiSLHFNOJV1ZzoJdAU6EdZyiQcBwT2iMXfiYms4hD"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "freecam_plus-1.0.0.hnmod"
|
||||
sha256 = "264218191c32e7107982eab297b30a43076c5f1467d4e292cb844213258b5eb1"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUT9Ujo/oCprPAR7aucj7Ez3exPIc7MGDVH8ns9azj3ilxe+G4JTWb0PnF0YYxAm0FQJJs3DcmHxHjEEfiiWymsAnTG/cdggrQI=\r
|
||||
trusted comment: timestamp:1793450278\tfile:freecam_plus-1.0.0.hnmod\thashed\r
|
||||
/4Di5+zUUSOmYB56u/GDYran5upJjtmfdUff5uKER6lknPGYjsgeLfENH8trB+d8g2hhn70b5+lGxy9mrBfJBg=="""
|
||||
changelog = "Initial Release. "
|
||||
@@ -0,0 +1,19 @@
|
||||
id = "freelook"
|
||||
kind = "native-mod"
|
||||
name = "Freelook"
|
||||
summary = "Hold a key for a third person camera you can look around in"
|
||||
description = """
|
||||
Freelook is a Freelook/Perspective Mod for Fabric, allowing you to move your camera freely without changing your player's rotation.
|
||||
Camera distance can be adjusted by scrolling."""
|
||||
authors = ["Krzysix17"]
|
||||
owners = ["Krzysix17"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/Krzysix17/horizon-freelook"
|
||||
|
||||
[[versions]]
|
||||
version = "0.3.1"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "freelook-0.3.1.hnmod"
|
||||
sha256 = "9c0c92ce9f0fc8e7bc1bd34349e26d42b32b8abd2c7a09ec710936f9b6ce9aaf"
|
||||
changelog = "First release"
|
||||
@@ -0,0 +1,29 @@
|
||||
id = "fullbright"
|
||||
kind = "native-mod"
|
||||
name = "MoreGamma"
|
||||
summary = "Brightness past 100%: set your own gamma with /gamma, or toggle full brightness with /fullbright."
|
||||
description = """
|
||||
A native Horizon mod: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Uses only Horizon's native hook points (hooks 1); tested on Horizon 41672b1 and horizon-mixins 0d6b103.
|
||||
|
||||
See in the dark without torches or night vision. MoreGamma lets you set the brightness (gamma) far past the video settings' 100% "Bright" limit, with a chat command, and switch full brightness on and off.
|
||||
|
||||
- `/gamma <value>`: your own gamma. `1` is vanilla's "Bright", `15` is fullbright, up to `100`; `/gamma 1500%` works too.
|
||||
- `/gamma` shows the gamma in effect.
|
||||
- `/gamma reset` (or `off`) goes back to your video settings slider; `/gamma on` turns your last custom gamma on again.
|
||||
- `/fullbright` toggles full brightness (gamma 15).
|
||||
- Options → Mods → Fullbright: an on/off button, a button cycling 100/200/500/1000/1500%, and a toggle key you can bind.
|
||||
|
||||
Client-side: the commands are handled by your game before anything reaches a server, so it works in single player, on LAN and on servers. Your brightness slider and `options.txt` are never changed, so turning it off gives your own brightness back. Settings are remembered between sessions."""
|
||||
authors = ["bezi5kt"]
|
||||
owners = ["bezi5kt"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/bezi5kt/gamma-rust"
|
||||
icon = "icons/fullbright.png"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "fullbright-1.0.0.hnmod"
|
||||
sha256 = "573c5e04188e0b1a26eb42a8aeaeeefeb6fb334a096afaa834e71b8efa353ad7"
|
||||
changelog = "First release."
|
||||
@@ -0,0 +1,29 @@
|
||||
id = "fullbright_horizon"
|
||||
kind = "native-mod"
|
||||
name = "Fullbright"
|
||||
summary = "Toggle maximum 1000% gamma cave and night brightness with smooth fade via keybind G."
|
||||
description = """
|
||||
Maximum brightness and night illumination for the Horizon Rust client.
|
||||
|
||||
Features
|
||||
Press G (rebindable in Options > Mods > Fullbright) to immediately toggle 1000% Gamma cave and night illumination without shadows.
|
||||
Smooth 250ms brightness fade transition and HUD status notification.
|
||||
100% client-side lightmap modification, safe for multiplayer."""
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/fullbright"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "fullbright_horizon-1.0.0.hnmod"
|
||||
sha256 = "db6175eec1711dbc5ab2a2edc40eee9cbc4080ec1d706a3cef688e54ba9cb017"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTN70A+lNWzZF2M2MiOMfjOIqVnTGNY05bQXW47Ov/mHp8io8o9HZiOYQXOYbxhazjWOfGU3WWuRzqj05swkoG/QY=\r
|
||||
trusted comment: timestamp:1793440355\tfile:fullbright_horizon-1.0.0.hnmod\thashed\r
|
||||
mJGiv7YnJHRGreiX5K3mx6zwEtRTC4rAygoIC+rkp1tjUeazIwyehtojb6T+iQBQaq2p97PTor410KnbK675BA=="""
|
||||
changelog = "Initial release for Horizon 26.3."
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "inventory_profiles"
|
||||
kind = "native-mod"
|
||||
name = "Inventory Profiles"
|
||||
summary = "R-key & UI sorting (Category, A-Z, Count, ID), Auto-Refill depleted stacks, Tool Break Protection, and Quick-Stack to chests."
|
||||
description = "A 1:1 native Rust port of Inventory Profiles Next & Inventory Sorter for Horizon. Press R or click the UI sort buttons to merge partial stacks and sort chests or your inventory using 4 selectable modes: Category (Creative Tab), Alphabetical (A-Z), Stack Count (High-Low), or Item ID. Includes automatic hand stack refilling when placing blocks or consuming items, Tool Break Protection that swaps out low-durability tools before they break, and G-key Quick-Stacking to move matching items into open containers."
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/inventory-profiles"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "inventory_profiles-1.0.0.hnmod"
|
||||
sha256 = "1e5d1c75d05230172820b5bc016d7d3ac792adf473de7dbfb84394d8b795a633"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTNzTcNlnhp0xG8ZqxNqwzpSnc+ghT4/m+aR0dga48gdD04aioDSIPK5DBUtd4i2Vf+e4r7LKX3zb6T90aDdYJjgI=\r
|
||||
trusted comment: timestamp:1793443789\tfile:inventory_profiles-1.0.0.hnmod\thashed\r
|
||||
RcTkkWUMpp4nRQ4uXRFCD4m67ir4J0y3lo2nhOVUgriLIMndinAsVjnNsrfAoJLvKN9DO5vT/xp2+oW1iW7xAQ=="""
|
||||
changelog = "Initial release for 26.3 Horizon. "
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "Item New"
|
||||
summary = "Newly picked-up items glow in your hotbar and inventory until you look at them."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
Items you just got (picked up, crafted, taken from a chest, given) get a soft glow in the hotbar and in inventory and container screens, until you point at them or close the screen.
|
||||
|
||||
@@ -15,7 +15,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/itemnew"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/itemnew/main/icon.png"
|
||||
icon = "icons/itemnew.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.1"
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
id = "jei"
|
||||
kind = "native-mod"
|
||||
name = "JEI for Horizon"
|
||||
summary = "An item and recipe viewer for Horizon: every item beside container screens, with search, recipes and uses"
|
||||
description = """
|
||||
An item and recipe viewer for [Horizon](https://playhorizon.dev), the Rust reimplementation of Minecraft: Java Edition.
|
||||
|
||||
Horizon JEI is inspired by [JustEnoughItems (JEI)](https://github.com/mezz/JustEnoughItems). JEI serves as the reference specification, while this project is a completely new Rust implementation built around Horizon's native hook points.
|
||||
|
||||
**Version 0.1.0 — Core Viewer**
|
||||
|
||||
### Features
|
||||
|
||||
- **Item Browser:** Browse every item registered by the game through a paginated panel alongside container screens, with a search bar supporting JEI's search grammar: words, `"quoted phrases"`, `-exclusions`, `|` alternatives, `@namespace`, and `#tag`.
|
||||
- **Recipe Viewer:** Press **R** to view an item's recipes or **U** to see its uses. Both work over the item panel and container slots.
|
||||
- **Recipe Categories:** Dedicated tabs for crafting, furnace, blast furnace, smoker, campfire, stonecutter, smithing, and brewing, supporting all five of the game's recipe layouts, including cooking time and XP.
|
||||
- **Recipe Navigation:** Browse recipe history with **Back** and click recipe slots to open the corresponding item.
|
||||
- **Recipe Placement:** Use the **+** button to place a recipe into the open crafting grid, provided it is available in the recipe book.
|
||||
- **Item Giving:** Give items through Options → Mods → JEI or `/jei give`. In creative mode, left-click gives one item and right-click gives a full stack. In survival mode, clicking opens the recipe viewer instead.
|
||||
- **Localization:** English and Spanish interface translations. Item names are retrieved directly from the game and respect the player's language.
|
||||
- **Diagnostics:** `/jei` reports the game's recipe table sizes.
|
||||
|
||||
### Current Limitations
|
||||
|
||||
The 0.1.0 release focuses on the core viewer. Bookmarks, container slot click integration, tooltips, creative inventory integration, non-recipe categories (anvil, grindstone, composter, and fuel), and shift-click recipe placement are not yet supported.
|
||||
|
||||
Some of these features require native hook points that Horizon does not currently expose. See the [JEI parity matrix](https://github.com/enderliker/horizon-jei/blob/main/docs/jei-parity.md) for implementation details.
|
||||
|
||||
### Requirements & Security
|
||||
|
||||
Requires Horizon **26.3**, hook points version **2**, and the current Nightly build.
|
||||
|
||||
Horizon native mods are compiled directly into the game and are **not sandboxed**. Only build source code you trust.
|
||||
|
||||
Horizon JEI reads the game's tables, container interface, chat, and its own settings directory (`horizon-mods/.horizon-mod-data/jei/`). It does not write to any other location.
|
||||
|
||||
*Unofficial project. Not affiliated with mezz, Mojang, Microsoft, or the Horizon project.*"""
|
||||
authors = ["enderliker"]
|
||||
owners = ["enderliker"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/enderliker/horizon-jei"
|
||||
key = "RWRqzx718YYz/OHRM+pAnFWlDv8Rrgar5C4NszQg3EKJWQZWNel5Sslf"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "jei-0.1.0.hnmod"
|
||||
sha256 = "c5590e0d4618d435fc0c56abcc9cdabf253be694710068a3dd4643ac25466b5b"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key
|
||||
RURqzx718YYz/AZEFNcRh0lQFAgg8JsladNTOULcWqBnZFoFoApH0UvoQQkTk8wC/LfZpfJkrn7XRzSUOPUOfudUebBSHHdVYQ0=
|
||||
trusted comment: jei 0.1.0 for Horizon 26.3
|
||||
OqC3JuFFGuGNdxATsGIvM20nrld1ME2ks3tI2hfaMX2s5bCgwYjieUDk7FbDQD8zxd3KHqOYaUTz6T+njgUNCw=="""
|
||||
changelog = """
|
||||
The first playable Horizon JEI viewer, built on Horizon's native hook points (version 2).
|
||||
|
||||
### Item Browser & Search
|
||||
- Added an item panel alongside container screens, displaying every item known to the game with pagination.
|
||||
- Implemented JEI's search grammar:
|
||||
- Words and `"quoted phrases"`.
|
||||
- `-exclusions` and `|` alternatives.
|
||||
- `@namespace` and `#tag` filters.
|
||||
- `$tooltip` and `%creative tab` are not supported yet, pending access to the required data.
|
||||
|
||||
### Recipe & Usage Viewer
|
||||
- Press **R** to view an item's recipes and **U** to view its uses.
|
||||
- Works over the item panel and any slot in a container screen.
|
||||
- Clicking an item in the panel opens the same views.
|
||||
- Added recipe pages with dedicated tabs for:
|
||||
- Crafting
|
||||
- Furnace
|
||||
- Blast Furnace
|
||||
- Smoker
|
||||
- Campfire
|
||||
- Stonecutter
|
||||
- Smithing
|
||||
- Brewing
|
||||
- Supports all five of the game's recipe layouts, including cooking time and XP.
|
||||
- Added a **Back** button to navigate through viewing history.
|
||||
- Clicking a recipe slot opens that item's recipes.
|
||||
|
||||
### Recipe Placement
|
||||
- Added the **+** button to place recipes into the open crafting grid when the recipe book contains them.
|
||||
- The button remains disabled until the recipe is available in the recipe book.
|
||||
- Shift-click is not supported yet because the panel's action event does not expose modifier keys.
|
||||
|
||||
### Item Giving
|
||||
- Added item giving through **Options → Mods → JEI** or `/jei give`.
|
||||
- In creative mode, left-click gives one item and right-click gives a full stack.
|
||||
- In survival mode, clicking an item opens its recipes instead.
|
||||
|
||||
### Localization & Diagnostics
|
||||
- Added English and Spanish UI translations, configurable through the mod's **Language** setting.
|
||||
- Item names are retrieved directly from the game and always respect the player's language.
|
||||
- Added `/jei` to report the game's table sizes."""
|
||||
@@ -12,7 +12,7 @@ Horizon's own keystrokes overlay, formerly an extra in Options > Horizon Extras.
|
||||
It reads which keys you hold and your clicks, and draws on the HUD: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(Settings → Game → Native mods (experimental), then Build). Your settings carry over from 1.0.0. Turn it off in
|
||||
(install it on the launcher's Mods page, then press Build there). Your settings carry over from 1.0.0. Turn it off in
|
||||
Options > Mods: it rests at once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/keystrokes](https://github.com/horizon-rust/horizon-mods/tree/main/native/keystrokes).
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "light_overlay"
|
||||
kind = "native-mod"
|
||||
name = "Light Overlay"
|
||||
summary = "1:1 Light Overlay & MiniHUD (F7): visualizes mob-spawnable blocks with 3D Yellow (night spawn) and Red (always/cave spawn) crosses (X) or 3D light level numbers"
|
||||
description = "A 1:1 native Rust port of Light Overlay and MiniHUD's F7 Light Level Overlay for Horizon. Press F7 during gameplay to scan nearby spawnable block surfaces and render depth-tested 3D markers directly on block tops. Red markers indicate blocks where hostile mobs can spawn at any time (caves/indoor darkness), Yellow markers indicate blocks where hostile mobs can spawn at night, and optional Green markers show safe blocks. Supports Crosses (X), 3D Numbers (0-15), or Both, with configurable scan radius (8 to 20 blocks) and Modern (== 0) or Legacy (<= 7) spawn thresholds."
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/light-overlay"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "light_overlay-1.0.0.hnmod"
|
||||
sha256 = "b4aeb56b13d9c73df267a1dc7b1f588f4db39bfd55f7beaef97a014fffb5b076"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTNy4CWemZ33Twp2eJ5FybX79KHuEbkVXRfv1C8+lWasqO1vOdx2A+8oN9eTR9XIh+QKjjw6xwrkG1u2nDoYkk5ww=\r
|
||||
trusted comment: timestamp:1793444149\tfile:light_overlay-1.0.0.hnmod\thashed\r
|
||||
3mGbUejwekJoW98TqQVK9QKS0aXMamM9rfCVOEwot/Xq/ZbaT1kUdDJMo6mn0iJIeodvdAFd7TnDEoguj7jkCA=="""
|
||||
changelog = "Initial release for 26.3 Horizon. "
|
||||
@@ -1,26 +1,30 @@
|
||||
id = "lookat"
|
||||
kind = "mod"
|
||||
kind = "native-mod"
|
||||
name = "LookAt"
|
||||
summary = "The block under your crosshair as a vanilla tooltip: its icon, its name in your language and where it comes from. Reach up to 1024 blocks"
|
||||
summary = "The block or mob under your crosshair as a vanilla tooltip: icon, name in your language, health, the tool it needs and where it comes from"
|
||||
description = """
|
||||
The block under your crosshair at the top of the screen, drawn as a vanilla tooltip: its item's icon, its name in your language and the namespace it comes from.
|
||||
The block or entity under your crosshair at the top of the screen, drawn as a vanilla tooltip: its item's icon, its name in your language and the namespace it comes from.
|
||||
|
||||
**Settings** (Options → Mods → LookAt):
|
||||
- **Blocks**: up to 1024 blocks away, across distant terrain.
|
||||
- **Mobs and players**: name and health as hearts or numbers; boats, minecarts, armor stands, paintings and item frames (with what they hold).
|
||||
- **Harvest tool**: ✔ or ✘ with the tool a block needs.
|
||||
|
||||
- **Range**: Reach (5 blocks), 16, 64 or 1024 blocks, across distant terrain
|
||||
- **Position**: Top, Top left, Top right
|
||||
- **Background opacity**: 100%, 75%, 50%, 25%
|
||||
- **Item icon**, **Where it comes from**: on or off
|
||||
- **Position and distance**: the block's coordinates and how far it is
|
||||
**Settings** (Options → Mods → LookAt): range, position (top, top left, top right), size, background opacity, item icon, where it comes from, position and distance, entities, health, harvest tool. Boxes keep clear of F3, boss bars, the minimap and effect icons.
|
||||
|
||||
To make the box bigger, raise the game's GUI Scale.
|
||||
|
||||
**Blocks only for now**: the mod API can't see entities yet, so mobs show nothing."""
|
||||
**Now a native mod (0.2.1)**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's permissions, so read the source before you build it. Tested against Horizon `142388e1c136e622652ec7505af15d8ad195e041` with Horizon Mixins `0d6b103c70633d8fd9443d8d0acd3aadaacedb06`; the launcher builds these exact pinned revisions. Settings from 0.1.0 carry over."""
|
||||
authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/lookat"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/lookat/main/icon.png"
|
||||
icon = "icons/lookat.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.2.1"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "lookat-0.2.1.hnmod"
|
||||
sha256 = "6c15726116825b5955984223d0e1bccd5d18375005af243a061b2ba2b9139f33"
|
||||
changelog = "Now a native mod (WebAssembly code mods are going away). New: mobs, players and other entities under the crosshair with their health, the harvest tool a block needs, a size setting, and boxes that keep clear of F3, boss bars, the minimap and effect icons. Pinned to Horizon 142388e and Horizon Mixins 0d6b103."
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
id = "menu_panorama"
|
||||
kind = "resourcepack"
|
||||
name = "Menu Panorama"
|
||||
summary = "Put your own wallpaper behind the main menu in Horizon — Minecraft 26.3, rewritten in Rust."
|
||||
description = """
|
||||
Menu Panorama is a resource pack for **Horizon** — Minecraft: Java Edition 26.3, rewritten from scratch in **Rust**.
|
||||
|
||||
It replaces the six textures of the main-menu background with a picture you choose. It is a plain resource pack, not a Java mod: no mod loader, no Java, and no code from the pack is executed. Horizon loads it natively.
|
||||
|
||||
- **Any photo** in the `room` mode: the picture is shown whole on the four walls, with mirrored seams and soft colours above and below.
|
||||
- **A 360° equirectangular panorama** in the `360` mode: the sphere is cut into six cube faces, so the view stays seamless when the camera turns.
|
||||
- **Auto** picks the mode from the image's aspect ratio.
|
||||
|
||||
Build a pack in the browser with `panorama-maker.html`: drop an image, choose a face size, download the `.zip`. Everything runs locally; the picture never leaves the computer. `make_panorama.py` does the same from the command line.
|
||||
|
||||
The pack only changes `assets/minecraft/textures/gui/title/background/panorama_0..5.png`; gameplay, sounds and other textures are untouched. `pack.mcmeta` is made for Horizon 26.3 (resource format 97) and also declares formats 15–999, so the same file loads in Minecraft Java 1.21+. A demo pack is attached to every release.
|
||||
|
||||
MIT licensed. Source, the browser generator and the CLI are in the repository."""
|
||||
authors = ["form1t"]
|
||||
owners = ["form1t"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/form1t/menu-panorama"
|
||||
icon = "icons/menu_panorama.png"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "menu_panorama-1.0.0.zip"
|
||||
sha256 = "e0403b003e6c93dec683037202cebb47880025cfe21e2d8fc7818321ee362401"
|
||||
changelog = """
|
||||
First release.
|
||||
|
||||
- Demo sunset pack: six 1024×1024 faces and a 128×128 icon.
|
||||
- `panorama-maker.html`: browser generator with drag & drop, auto/room/360 modes and 512/1024/2048 face sizes.
|
||||
- `make_panorama.py`: CLI with the same modes, preview output and `--description`.
|
||||
- `pack.mcmeta` for Horizon 26.3: resource format 97, `pack_format` 34, formats 15–999.
|
||||
- MIT licence."""
|
||||
@@ -12,7 +12,7 @@ Horizon's own minimap, formerly an extra in Options > Horizon Extras.
|
||||
It shows a map in a corner of the screen: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(Settings → Game → Native mods (experimental), then Build). Your settings carry over from 1.0.0. Turn it off in
|
||||
(install it on the launcher's Mods page, then press Build there). Your settings carry over from 1.0.0. Turn it off in
|
||||
Options > Mods: it rests at once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/minimap](https://github.com/horizon-rust/horizon-mods/tree/main/native/minimap).
|
||||
"""
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
id = "mod_menu"
|
||||
kind = "mod"
|
||||
name = "Mod Menu"
|
||||
summary = "Browse installed mods, including native mods, with versions, enabled states, filters and search."
|
||||
description = """
|
||||
An independent, sandboxed mod browser by levzzz5154.
|
||||
|
||||
Press **M** while playing, run **`/modmenu`**, or open
|
||||
**Options → Mods → Mod Menu → Settings**. Use `/modmenu text` to search names,
|
||||
ids and mod types. Filter all/enabled/disabled mods, browse pages, select a row
|
||||
for details, and refresh after changing mods in the launcher.
|
||||
|
||||
Lists installed sandboxed, content and native source mods in the current instance.
|
||||
Enabled means the launcher's selected state, not proof a mod is running. This is
|
||||
a read-only menu: it does not toggle other mods, run commands, or start native builds.
|
||||
|
||||
**Requires a launcher with the schema-1 Mod Menu inventory feed**
|
||||
([Horizon #3112](https://github.com/horizon-rust/horizon/pull/3112)). On a launcher
|
||||
without it, the menu shows an explicit update message. The launcher supplies display
|
||||
metadata through this mod's own sandbox storage; the mod has no general filesystem
|
||||
or network access. Direct external `--dev-mod` paths and runtime failure status
|
||||
are not included in the feed.
|
||||
|
||||
Tested on Horizon nightly `83f15fa27` (Minecraft 26.3), mod API 0.1 / API level 0.
|
||||
Other Horizon revisions have unverified support. This `.hmod` does not require Rust,
|
||||
Git, Horizon Mixins or any native build to install.
|
||||
|
||||
Independently written, not a port of another project's Mod Menu. No Minecraft code
|
||||
or artwork is included. MIT licensed; source, tests and feed specification are linked below.
|
||||
"""
|
||||
authors = ["levzzz5154"]
|
||||
owners = ["levzzz5154"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/levzzz5154/horizon-mod-menu"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.1"
|
||||
published = "2026-10-28"
|
||||
game = "26.3"
|
||||
file = "mod_menu-0.1.1.hmod"
|
||||
sha256 = "3833b79bbb9607c5cab6dbdc4a6d3e31754c2ed183b1c6bf431f3615b93ef3b5"
|
||||
changelog = "First release: installed mods, enabled states, native/content/sandboxed types, paging, filters, search and refresh. Requires the launcher inventory feed."
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "Mouse Tricks"
|
||||
summary = "Inventory mouse tricks: drag to spread or gather, the wheel moves items one by one, and R sorts."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
- **Right-drag**: one item into each slot you pass.
|
||||
- **Left-drag**: gather the same items; with Shift, quick-move many stacks.
|
||||
@@ -15,7 +15,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/mousetricks"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/mousetricks/main/icon.png"
|
||||
icon = "icons/mousetricks.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.2.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
id = "recipes"
|
||||
kind = "mod"
|
||||
kind = "native-mod"
|
||||
name = "Recipes"
|
||||
summary = "Every item beside your inventory, with its recipes and uses."
|
||||
description = """
|
||||
@@ -13,11 +13,25 @@ Horizon's own recipe viewer.
|
||||
- On servers that are not Horizon, it shows this game's own 26.3 recipes. Which recipes you know, and what + can fill, follow the server's recipe book.
|
||||
|
||||
It reads the game's items and recipes, hears its own keys and your clicks on the panel, and places recipes or gives items only when you ask: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(install it on the launcher's Mods page, then press Build there). It needs Horizon's native hook points version 2, in the
|
||||
Nightlies from 4baa571 on. Your settings and keys carry over from 1.0.0. Turn it off in Options > Mods: it rests at
|
||||
once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/recipes](https://github.com/horizon-rust/horizon-mods/tree/main/native/recipes).
|
||||
"""
|
||||
authors = ["Horizon"]
|
||||
owners = ["ludovic111"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/horizon-rust/horizon/tree/main/mods/official/recipes"
|
||||
source = "https://github.com/horizon-rust/horizon-mods/tree/main/native/recipes"
|
||||
|
||||
[[versions]]
|
||||
version = "2.0.0"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "recipes-2.0.0.hnmod"
|
||||
sha256 = "51fddf300709404170061355afdf0b407f28eb928bcc0a9133c241cd63f4a0ed"
|
||||
changelog = "Native: built into the game by the launcher on Horizon's native hook points (version 2); settings and keys carry over; turn it off in Options > Mods."
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
id = "rightharvest"
|
||||
kind = "native-mod"
|
||||
name = "RightClickHarvest"
|
||||
summary = "Right-click a ripe crop to pick it and sow it again."
|
||||
description = """
|
||||
With an empty hand, right-click a ripe wheat, carrot, potato, beetroot or nether wart: the crop is harvested with the game's own drops, sound and statistics, and sown again from a seed in your inventory.
|
||||
|
||||
No settings: turn it off in Options > Mods."""
|
||||
authors = ["Domanffe"]
|
||||
owners = ["Domanffe"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/Domanffe/rightharvest"
|
||||
icon = "https://horizon-rust.github.io/horizon-mods/icons/rightharvest.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "rightharvest-0.1.0.hnmod"
|
||||
sha256 = "a43870a89827c1d0fa861a663aa1781819b236f994191abf971c98125a3a4653"
|
||||
changelog = "First release: a native mod for Horizon 26.3. With an empty hand, right-click a ripe crop to harvest it with the game's own drops and sow it again from a seed you carry."
|
||||
@@ -0,0 +1,56 @@
|
||||
id = "serverify"
|
||||
kind = "native-mod"
|
||||
name = "Serverify"
|
||||
summary = "Find Minecraft servers and add them to your Multiplayer list, from a page in your web browser."
|
||||
description = """
|
||||
Serverify is a server browser. Press **F8** (or type `/serverify web`, or press the button on the mod's settings page) and your web browser opens a page with a search box, a category menu and cards showing each server's picture, address, player count and country. Press **Add** and the server goes to the top of your Multiplayer list. Then join it from Horizon's own Multiplayer screen.
|
||||
|
||||
It is the Horizon version of [Serverify](https://github.com/Louchatfroff/serverify), the server browser for Fabric, Quilt, Forge and NeoForge, by the same author.
|
||||
|
||||
## What it does
|
||||
|
||||
- Opens a server browser page in your web browser: search, 22 categories, an offline-mode filter and an **Add** button.
|
||||
- Adds servers to `servers.dat` in the game folder, with the name cleaned of colour codes.
|
||||
- Adds chat commands: `/serverify web`, `list [category]`, `search <words>`, `next`, `prev`, `add <number>` and `categories`.
|
||||
- Adds a row in Options > Mods with a rebindable key (F8 by default) and a settings page with two buttons: open the browser, and **Offline-mode servers only** (on by default).
|
||||
|
||||
Horizon cannot join servers that check Minecraft accounts yet, which is most public servers, so by default the page shows servers that accept offline-mode players. Turn the filter off to see all of them.
|
||||
|
||||
## What it contacts
|
||||
|
||||
- **Modrinth.** The game asks `api.modrinth.com` for the server list and `cdn.modrinth.com` for server pictures, only when you look for servers.
|
||||
- **Three listing sites.** With the offline-mode filter off (and for top-mc-servers.net's list of cracked servers when it is on), the game fetches public pages of `top-mc-servers.net`, `minecraftservers.org` and `minecraft-mp.com`, and their server pictures. The game builds those addresses itself. The page reads the fetched pages with the browser's own HTML parser.
|
||||
- **A page on your computer.** The first time you open the page, the mod starts a small web server on `127.0.0.1` (this computer only, never the network) with a random secret in its address, made for each session. The page talks only to that server. A request with another host name, another origin or no secret is refused. The server can show the list, send a picture and add one server to your Multiplayer list.
|
||||
- It sends no data about you, and makes no request at any other time.
|
||||
|
||||
## What it does not do
|
||||
|
||||
- It does not run any code from the sites it reads, and it does not send your data anywhere.
|
||||
- It does not change anything but `servers.dat` (one entry at a time) and its own settings in `horizon-mods/.horizon-mod-data/serverify/`.
|
||||
- It does not draw screens or buttons in the game: Horizon's hook points have none, so the screen is your web browser.
|
||||
- It cannot make Horizon join servers that check Minecraft accounts.
|
||||
- Adding a server rewrites `servers.dat`, which drops the hidden direct-join entries Horizon keeps. Your saved servers stay.
|
||||
|
||||
## Install
|
||||
|
||||
Install it from the launcher's Mods page, then press Build there, and play that instance. Guide: https://github.com/Louchatfroff/serverify/tree/main/horizon/serverify#readme
|
||||
|
||||
Native mods are not sandboxed. The source is public and licensed GPL-3.0-only: https://github.com/Louchatfroff/serverify/tree/main/horizon/serverify"""
|
||||
authors = ["Louchatfroff"]
|
||||
owners = ["Louchatfroff"]
|
||||
license = "GPL-3.0-only"
|
||||
source = "https://github.com/Louchatfroff/serverify"
|
||||
icon = "icons/serverify.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "serverify-0.1.0.hnmod"
|
||||
sha256 = "f9ad0777f8fc7ea532f799da8a9eb72df2348c8d6bb5dc104f81b6ab47209501"
|
||||
changelog = """
|
||||
First release for Horizon, ported from the Java Edition mod of the same name.
|
||||
|
||||
- A server browser page in your web browser (F8, `/serverify web`, or the settings button).
|
||||
- Chat commands to list, search and add servers.
|
||||
- An offline-mode filter, on by default, because Horizon cannot join servers that check Minecraft accounts yet."""
|
||||
@@ -0,0 +1,31 @@
|
||||
id = "shulker_peek"
|
||||
kind = "native-mod"
|
||||
name = "ShulkerPeek"
|
||||
summary = "A shulker box's contents as a 9 x 3 grid in its tooltip."
|
||||
description = """
|
||||
Hover a shulker box to see what's inside: its 27 slots appear as a 9 x 3 grid right in the tooltip, laid out exactly like the box's own screen, with item icons and stack counts.
|
||||
|
||||
- Works with the plain shulker box and all 16 dyed ones, whether empty, partly filled or full.
|
||||
- Works on every screen with item tooltips: your inventory, chests and other containers, the creative inventory, the item panel, chat item links and trading.
|
||||
- Keeps the tooltip's usual lines (name, lore, "64 x Diamond"...); the grid goes underneath.
|
||||
- Respects hidden tooltips: a box whose `minecraft:tooltip_display` hides its contents stays hidden.
|
||||
- Settings in Options > Mods > ShulkerPeek > Settings: show the grid always or only while holding Shift, show a grid for empty boxes, and tint the grid with the box's dye colour.
|
||||
- Uses your resource pack's own shulker box texture.
|
||||
|
||||
Works in single player and on LAN worlds you host. Horizon currently leaves a box's contents out of what its built-in server sends to the game window, which is why even the "64 x Diamond" lines are missing there. ShulkerPeek sends the contents the way a vanilla server does. On vanilla servers the grid works too; on other Horizon servers without the mod, boxes look empty.
|
||||
|
||||
It never changes items, inventories or worlds. Turn it off any time in Options > Mods.
|
||||
|
||||
This is a native mod built for Horizon Nightly 2026-10-29 (`5e391eb`). It builds together with Horizon's official native mods (FPS Counter, Zoom, Minimap, Recipes and others)."""
|
||||
authors = ["vstxx"]
|
||||
owners = ["vstxx"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/vstxx/shulkerpeek"
|
||||
icon = "icons/shulker_peek.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
published = "2026-10-29"
|
||||
game = "26.3"
|
||||
file = "shulker_peek-0.1.0.hnmod"
|
||||
sha256 = "e4e33cb698d91042b2ed2f93a1c935f279d16d83988115d53c0f33530cabeab5"
|
||||
@@ -3,7 +3,7 @@ kind = "native-mod"
|
||||
name = "SmartF3"
|
||||
summary = "A tidier, configurable F3 debug screen: the same information in modules you can colour, reorder and turn off."
|
||||
description = """
|
||||
**A native Horizon mod**: the launcher builds it into the game (Settings → Game → Native mods, then Build). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
**A native Horizon mod**: the launcher builds it into the game (install it on the launcher's Mods page, then press Build there). Native mods are not sandboxed and run with your account's rights, so read the source before you build it. Pinned to Horizon 142388e and horizon-mixins 0d6b103.
|
||||
|
||||
The F3 debug screen, grouped into 14 modules: FPS, server, coordinates, chunk, facing, world, biome, light, chart keys, system, rendering, and the targeted block, fluid and entity.
|
||||
|
||||
@@ -16,7 +16,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/smartf3"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/smartf3/main/icon.png"
|
||||
icon = "icons/smartf3.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "status_effect_hud"
|
||||
kind = "native-mod"
|
||||
name = "Status Effect HUD"
|
||||
summary = "1:1 Status Effect Bars & Inventory HUD+ Potion HUD: displays active potion/beacon effects with icons, Roman numeral amplifiers, color-coded mm:ss countdown time"
|
||||
description = "A 1:1 native Rust port of Status Effect Bars and Inventory HUD+ (Potion HUD) for Horizon. Renders all active potion and beacon status effects directly on the HUD during gameplay with their official mob_effect sprites, translated effect names, and Roman numeral potency levels (II, III, IV). Includes color-coded mm:ss countdown timers (White for >30s, Yellow for 10-30s, Flashing Red for <=10s urgent expiration warning, and Aqua infinity symbol for permanent effects) alongside smooth duration progress bars colored in each effect's authentic vanilla potion color."
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/status-effect-hud"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "status_effect_hud-1.0.0.hnmod"
|
||||
sha256 = "afa30125bb8b402892f1719e550b66d4eb4d7264895f71bb9c98a4caf5c7b432"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTNzV+wcfmnupP9b3ECNs7/D2jW8vAV9eAd1rxLpETdSVxvuPpnbTPB/W9APouT8uLbsZLrB9wFsOoBtrhuUPmCw0=\r
|
||||
trusted comment: timestamp:1793443789\tfile:status_effect_hud-1.0.0.hnmod\thashed\r
|
||||
MkNOcfvQQP8dWwvaSdoGIasz6tYOCB13U0OVFIApxz9VzhCUGRZXTYaSitlSSoBfGqYCQk87zvliwvklR0lbDQ=="""
|
||||
changelog = "Initial release for 26.3 Horizon. "
|
||||
@@ -0,0 +1,23 @@
|
||||
id = "toggle_sprint"
|
||||
kind = "native-mod"
|
||||
name = "Toggle Sprint"
|
||||
summary = "1:1 Better Sprinting & Lunar ToggleSprint HUD: toggle sprint and toggle sneak with [Sprinting (Toggled)] / [Key Held] / [Flying] status HUD and configurable Cre"
|
||||
description = "A 1:1 native Rust port of Better Sprinting and the Lunar/Badlion ToggleSprint HUD for Horizon. Allows toggling continuous sprint (V or vanilla Sprint key) and sneak (C) without holding keys down, while automatically pausing toggled sneak inside inventory and chest screens so Shift-clicking items works normally. Renders the classic movement status HUD ([Sprinting (Toggled)], [Sprinting (Key Held)], [Sneaking (Toggled)], [Sneaking (Key Held)], [Flying (2.0x Boost)], [Swimming], [Gliding (Elytra)], [Riding]) and includes a configurable Creative Fly Speed Boost multiplier (1.0x to 4.0x)."
|
||||
authors = ["CayMac"]
|
||||
owners = ["CayMac97"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/CayMac97/toggle-sprint"
|
||||
key = "RWS411U2KXdTN4/y5bQhqBYxNlZvCtSZ5lNy46eeSAcgy0cxSJo2+Sm3"
|
||||
|
||||
[[versions]]
|
||||
version = "1.0.0"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "toggle_sprint-1.0.0.hnmod"
|
||||
sha256 = "b2a4190f9c19adbceae4a639342b7630bfc3047339eabf57673b7807db5edc6a"
|
||||
signature = """
|
||||
untrusted comment: signature from minisign secret key\r
|
||||
RUS411U2KXdTN3mUUTEw+mmiuQhcddYpNrjRnGA43/GS3y/qgY1EnL0kGp4NTBouTlVJbiThEkQfOrqIjnwlshUB18PrQloxAAw=\r
|
||||
trusted comment: timestamp:1793443789\tfile:toggle_sprint-1.0.0.hnmod\thashed\r
|
||||
2kNF92yIivWMWhgUH7ypwU3pciKG3ouiHhpZrQmX8fWZHay2da9HgdOYFAUp5KaHJ1NAgBuwL1zMfwVf61X+Cw=="""
|
||||
changelog = "Initial release for 26.3 Horizon. "
|
||||
@@ -16,7 +16,7 @@ authors = ["d3grando"]
|
||||
owners = ["d3grando"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/d3grando/treefall"
|
||||
icon = "https://raw.githubusercontent.com/d3grando/treefall/main/icon.png"
|
||||
icon = "icons/treefall.png"
|
||||
|
||||
[[versions]]
|
||||
version = "0.3.0"
|
||||
|
||||
@@ -7,16 +7,15 @@ An unofficial Rust port by levzzz5154. Mines connected veins, including diagonal
|
||||
through Horizon's player-mining code, preserving loot, XP, tool wear and server block events.
|
||||
Includes per-player toggles, configurable block/tool groups, a block limit and cooldown.
|
||||
|
||||
Native source mod: enable Settings → Game → Native mods (experimental), choose Build,
|
||||
Native source mod: install it on the launcher's Mods page, press Build there,
|
||||
and confirm the native-code warning. A supported launcher downloads its own Rust toolchain
|
||||
and builds a separate game using Horizon Mixins. Requires Git and Horizon's platform build
|
||||
dependencies, and runs with your account's permissions.
|
||||
|
||||
Tested against Horizon nightly `83f15fa276c44711276b6ceb5f0fe0c9c534dc66`
|
||||
(`nightly/build-2026-10-28-3`) with Horizon Mixins 0.5.0 at
|
||||
`0500ff24aa5933fca95a877ef41125353c4b4fe3`. The launcher builds these exact pinned revisions.
|
||||
Other Horizon revisions have not been validated. Ordinary Play does not compile mods;
|
||||
rebuild after changing the enabled native-mod combination.
|
||||
Each version is pinned to one Horizon Nightly and Horizon Mixins revision, named in its
|
||||
changelog; the launcher builds those exact revisions. Other Horizon revisions have not
|
||||
been validated. Ordinary Play does not compile mods; rebuild after changing the enabled
|
||||
native-mod combination.
|
||||
|
||||
Use `/veinminer toggle`, `/veinminer on`, `/veinminer off` or `/veinminer status`.
|
||||
`/veinminer reload` requires operator permission. Survival mining only; install on the
|
||||
@@ -37,3 +36,11 @@ game = "26.3"
|
||||
file = "veinminer-0.3.0.hnmod"
|
||||
sha256 = "ec308c02c65bad64043828a19ef6254d1eb9d422bb1123cd065cb9e6e7b126c8"
|
||||
changelog = "Native launcher bundle, pinned to nightly 83f15fa27 and Horizon Mixins 0.5.0."
|
||||
|
||||
[[versions]]
|
||||
version = "0.3.2"
|
||||
published = "2026-10-31"
|
||||
game = "26.3"
|
||||
file = "veinminer-0.3.2.hnmod"
|
||||
sha256 = "31a4249da1b35972ae8b34201373c86352f4adc2f5cb3e015749d1fbfecf00a0"
|
||||
changelog = "Pinned to Nightly 2026-10-31 (d91cab6) and Horizon Mixins 4342a0b. Reads each level's height from the loaded world, so data-pack dimension heights are respected."
|
||||
@@ -0,0 +1,19 @@
|
||||
id = "worldedit"
|
||||
kind = "native-mod"
|
||||
name = "WorldEdit"
|
||||
summary = "working port of java world edit"
|
||||
description = """
|
||||
//we for commands
|
||||
|
||||
working schematics."""
|
||||
authors = ["_cykoo_"]
|
||||
owners = ["XnotCykoX"]
|
||||
license = "MIT"
|
||||
source = "https://github.com/XnotCykoX/WorldEdit-Horizon"
|
||||
|
||||
[[versions]]
|
||||
version = "1.2.1"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "worldedit-1.2.1.hnmod"
|
||||
sha256 = "b2bb3019ecd4d5392644c54c70a87d6c3277538a6e18d0c311f3a051f7d2f015"
|
||||
@@ -0,0 +1,33 @@
|
||||
id = "xtoxray"
|
||||
kind = "native-mod"
|
||||
name = "X To Xray"
|
||||
summary = "Opensource Xraymod"
|
||||
description = """
|
||||
Press X To Xray!
|
||||
Does Not Work On Servers.
|
||||
|
||||
Instalation:
|
||||
1. Download Horizon
|
||||
2. Get Horizon Working
|
||||
3. Add The Mod Trough The Horizon Launcher
|
||||
4. Start Xraying
|
||||
"""
|
||||
authors = ["1_st_Cat"]
|
||||
owners = ["RealCat1st"]
|
||||
license = "Apache-2.0"
|
||||
source = "https://github.com/RealCat1st/XToXrayRust"
|
||||
icon = "icons/xtoxray.png"
|
||||
key = "RWQVF+EFGGnX6eUNms+cP5AceLvx9b0rFYYXCty7so4MVbJ1SNpi9zNK"
|
||||
|
||||
[[versions]]
|
||||
version = "2026.29.0"
|
||||
published = "2026-10-30"
|
||||
game = "26.3"
|
||||
file = "xtoxray-2026.29.0.hnmod"
|
||||
sha256 = "3446a4a70a2b87ef6e9de00ce8a255aa83c2e44ccd5acc9f14887662ed55f27c"
|
||||
signature = """
|
||||
untrusted comment: signature from rsign secret key
|
||||
RUQVF+EFGGnX6cZkn/iGZ9FUHXC45MU+8uuj7l7eRkZ+bR/x7S8s2U34F7nv/f6jKXdzeLZi3QoSA5g5oXqP99/KlGgd/19ygwY=
|
||||
trusted comment: timestamp:1793375231\tfile:xtoxray-2026.29.0.hnmod\tprehashed
|
||||
2h6QOc/dnek1KMCGL2jerhCObc9pECmShr0kKYJhEEFz52Hhb4C3vmjc9vuwE3CftUHs+StHkalHQVLVQy8eCg=="""
|
||||
changelog = "Release"
|
||||
@@ -13,7 +13,7 @@ Horizon's own zoom, formerly an extra in Options > Horizon Extras.
|
||||
It hears its own key and the mouse wheel while you hold it, and zooms the camera: nothing else.
|
||||
|
||||
Now a native mod (2.0.0): built into the game by the launcher, on the Horizon you play, like any native mod
|
||||
(Settings → Game → Native mods (experimental), then Build). Your settings carry over from 1.0.0. Turn it off in
|
||||
(install it on the launcher's Mods page, then press Build there). Your settings carry over from 1.0.0. Turn it off in
|
||||
Options > Mods: it rests at once, and the next build leaves it out. Its source is
|
||||
[horizon-mods/native/zoom](https://github.com/horizon-rust/horizon-mods/tree/main/native/zoom).
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "horizon-mod-coords-hud"
|
||||
version = "2.0.0"
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "horizon-mod-coords-hud"
|
||||
version = "2.0.0"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
publish = false
|
||||
description = "Horizon's Coordinates HUD, a native mod: your position and facing in a corner of the screen."
|
||||
|
||||
# The mod's logic and its tests: the same file the bundle adds to the game.
|
||||
[lib]
|
||||
path = "mixins/coords_hud/runtime.rs"
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Ludovic Marie and the Horizon contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Coordinates HUD (Horizon native mod)
|
||||
|
||||
Your block position and the direction you face in a box in the top-left corner of the screen.
|
||||
|
||||
- `/where` puts your coordinates and dimension in chat.
|
||||
- `/coords` hides or shows the box, and the game keeps your choice (also Options > Mods > Coordinates HUD > Settings).
|
||||
|
||||
It is a [horizon-mixins](https://github.com/horizon-rust/horizon-mixins) bundle (`mixins/coords_hud/`) that the Horizon
|
||||
launcher builds into the game. It is a small example mod.
|
||||
The time of day line is gone: Horizon's hook points don't give the game's clock yet.
|
||||
|
||||
## Install
|
||||
|
||||
In the Horizon launcher: Mods → Coordinates HUD → Install, then **Build** on the same page (once built, switch it
|
||||
on or off in the game under Options → Mods). The
|
||||
launcher downloads its own Rust and builds the game with your native mods; see Horizon's
|
||||
[native mods](https://github.com/horizon-rust/horizon/blob/main/docs/native-mods.md).
|
||||
|
||||
## Made on the hook points
|
||||
|
||||
The bundle hooks only Horizon's native hook points (`crates/horizon-client/src/game/native_hooks.rs`), which keep
|
||||
their names and signatures across releases. `compatibility.json` names the version it needs (`"hooks": 1`), so the
|
||||
launcher builds it on any Horizon with that version or a later one, together with any other mod. `horizon_revision` is
|
||||
only the commit it was last tested on.
|
||||
|
||||
| File | What it is |
|
||||
|---|---|
|
||||
| `mixins/coords_hud/horizon-mixin.toml` | The bundle: one module and the HEAD hooks |
|
||||
| `mixins/coords_hud/runtime.rs` | The mod's logic and state, added to the game as `game::official_coords_hud`; also this crate's library, for its tests |
|
||||
| `mixins/coords_hud/*.rs` | One small helper per hook |
|
||||
| `proof.py` (with `../tools/game.py`) | The proof: the built game driven with `horizon-ctl --offscreen` on fresh, temporary data |
|
||||
|
||||
## Build and prove
|
||||
|
||||
```sh
|
||||
(cd native/coords-hud && cargo test) # the logic
|
||||
python3 native/tools/native.py check coords-hud # apply on the tested Horizon and cargo check the game
|
||||
python3 native/tools/native.py check all # with the other native mods, as a player's set
|
||||
python3 native/tools/native.py package coords-hud # native/target/coords_hud-<version>.hnmod for the registry
|
||||
python3 native/tools/native.py proof coords-hud --resources /path/to/.local/horizon-client/26.3
|
||||
```
|
||||
|
||||
The proof needs resources prepared from your own Minecraft 26.3 (`horizon-prepare`); none are in this repository.
|
||||
It checks the row and the settings page in Options > Mods, that the box shows in the top left, that `/coords` hides it
|
||||
and writes `horizon-mods/.horizon-mod-data/coords_hud/shown`, and takes a screenshot of `/where`'s line in chat.
|
||||
|
||||
License: MIT.
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"game": "26.3",
|
||||
"hooks": 1,
|
||||
"horizon_repository": "https://github.com/horizon-rust/horizon",
|
||||
"horizon_revision": "4baa571566e39bfd6594988d3bb2bc85440c30e7",
|
||||
"horizon_mixins_repository": "https://github.com/horizon-rust/horizon-mixins",
|
||||
"horizon_mixins_revision": "0d6b103c70633d8fd9443d8d0acd3aadaacedb06"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// A click on the mod's settings page: show or hide the box, and keep it.
|
||||
fn official_coords_hud_click(game: &mut crate::game::Game<'_>, mod_id: &str, button: usize) {
|
||||
use crate::game::official_coords_hud as m;
|
||||
if mod_id != m::ID || button != 0 {
|
||||
return;
|
||||
}
|
||||
let shown = !m::shown(|| game.native_setting(m::ID, "shown"));
|
||||
m::set_shown(shown);
|
||||
game.native_set_setting(m::ID, "shown", if shown { "true" } else { "false" });
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// /where puts the position in chat; /coords hides or shows the box.
|
||||
fn coords_hud_command(game: &mut crate::game::Game<'_>, command: &str, ran: &mut bool) {
|
||||
use crate::game::official_coords_hud as m;
|
||||
let name = command.split(' ').next().unwrap_or("");
|
||||
if !game.native_on(m::ID) || !matches!(name, "where" | "coords") {
|
||||
return;
|
||||
}
|
||||
*ran = true;
|
||||
if name == "coords" {
|
||||
let shown = !m::shown(|| game.native_setting(m::ID, "shown"));
|
||||
m::set_shown(shown);
|
||||
game.native_set_setting(m::ID, "shown", if shown { "true" } else { "false" });
|
||||
game.native_chat(if shown { "Coordinates panel shown" } else { "Coordinates panel hidden" });
|
||||
return;
|
||||
}
|
||||
match game.native_player() {
|
||||
Some(p) => game.native_chat(&m::where_line(p.x, p.y, p.z, p.dimension)),
|
||||
None => game.native_chat("Not in a world"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
[mod]
|
||||
id = "coords_hud"
|
||||
version = "2.0.0"
|
||||
priority = 100
|
||||
|
||||
# The commit it was tested on. It uses only the native hook points (hooks 1 in
|
||||
# compatibility.json): the launcher builds it on any Horizon that has them.
|
||||
[compatibility]
|
||||
horizon_revision = "4baa571566e39bfd6594988d3bb2bc85440c30e7"
|
||||
|
||||
[[module]]
|
||||
id = "runtime"
|
||||
file = "crates/horizon-client/src/game.rs"
|
||||
name = "official_coords_hud"
|
||||
source = "runtime.rs"
|
||||
|
||||
[[injection]]
|
||||
id = "hud"
|
||||
kind = "HEAD"
|
||||
target = "horizon_client::game::native_hooks::Game<'_>::native_hud"
|
||||
helper = "hud.rs"
|
||||
bindings = [
|
||||
{ name = "game", ty = "&mut crate::game::Game<'_>", value = "&mut *self" },
|
||||
{ name = "batch", ty = "&mut horizon_client::hud::HudBatch", value = "&mut *batch" },
|
||||
{ name = "corners", ty = "&mut horizon_client::extras_hud::Corners", value = "&mut *corners" },
|
||||
]
|
||||
|
||||
[[injection]]
|
||||
id = "command"
|
||||
kind = "HEAD"
|
||||
target = "horizon_client::game::native_hooks::Game<'_>::native_command"
|
||||
helper = "command.rs"
|
||||
bindings = [
|
||||
{ name = "game", ty = "&mut crate::game::Game<'_>", value = "&mut *self" },
|
||||
{ name = "command", ty = "&str", value = "command" },
|
||||
{ name = "ran", ty = "&mut bool", value = "&mut *ran" },
|
||||
]
|
||||
|
||||
[[injection]]
|
||||
id = "list"
|
||||
kind = "HEAD"
|
||||
target = "horizon_client::game::native_hooks::Game<'_>::native_mods"
|
||||
helper = "list.rs"
|
||||
bindings = [
|
||||
{ name = "mods", ty = "&mut Vec<crate::game::native_hooks::NativeMod>", value = "&mut *mods" },
|
||||
]
|
||||
|
||||
[[injection]]
|
||||
id = "settings"
|
||||
kind = "HEAD"
|
||||
target = "horizon_client::game::native_hooks::Game<'_>::native_settings"
|
||||
helper = "settings.rs"
|
||||
bindings = [
|
||||
{ name = "game", ty = "&mut crate::game::Game<'_>", value = "&mut *self" },
|
||||
{ name = "mod_id", ty = "&str", value = "mod_id" },
|
||||
{ name = "buttons", ty = "&mut Vec<String>", value = "&mut *buttons" },
|
||||
]
|
||||
|
||||
[[injection]]
|
||||
id = "click"
|
||||
kind = "HEAD"
|
||||
target = "horizon_client::game::native_hooks::Game<'_>::native_settings_click"
|
||||
helper = "click.rs"
|
||||
bindings = [
|
||||
{ name = "game", ty = "&mut crate::game::Game<'_>", value = "&mut *self" },
|
||||
{ name = "mod_id", ty = "&str", value = "mod_id" },
|
||||
{ name = "button", ty = "usize", value = "button" },
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
// The box in the top-left corner, drawn as the WebAssembly mods' panels were;
|
||||
// the debug screen takes that corner.
|
||||
fn coords_hud(
|
||||
game: &mut crate::game::Game<'_>,
|
||||
batch: &mut horizon_client::hud::HudBatch,
|
||||
corners: &mut horizon_client::extras_hud::Corners,
|
||||
) {
|
||||
use crate::game::official_coords_hud as m;
|
||||
use horizon_client::extras::Corner;
|
||||
// Turned off in Options > Mods: nothing until the next build leaves it out.
|
||||
if !game.native_on(m::ID) || !game.native_corner_shown(Corner::TopLeft) {
|
||||
return;
|
||||
}
|
||||
if !m::shown(|| game.native_setting(m::ID, "shown")) {
|
||||
return;
|
||||
}
|
||||
let Some(p) = game.native_player() else {
|
||||
return;
|
||||
};
|
||||
let lines = m::lines(p.x, p.y, p.z, p.yaw);
|
||||
let w = lines.iter().map(|l| game.native_text_width(l)).fold(0.0, f32::max) + 4.0;
|
||||
let h = 10.0 * lines.len() as f32 + 2.0;
|
||||
let (x, y) = corners.place(Corner::TopLeft, w, h);
|
||||
game.native_fill(batch, [x, y, w, h], m::BACKGROUND);
|
||||
for (i, line) in lines.iter().enumerate() {
|
||||
game.native_text(batch, line, [x + 2.0, y + 2.0 + 10.0 * i as f32], m::INK, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// The mod's row in Options > Mods.
|
||||
fn official_coords_hud_listed(mods: &mut Vec<crate::game::native_hooks::NativeMod>) {
|
||||
use crate::game::official_coords_hud as m;
|
||||
mods.push(crate::game::native_hooks::NativeMod {
|
||||
id: m::ID.into(),
|
||||
title: format!("{} {}", m::NAME, m::VERSION),
|
||||
description: m::DESCRIPTION.into(),
|
||||
keys: Vec::new(),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Horizon's Coordinates HUD, formerly the WebAssembly SDK's example mod: the
|
||||
// block position and the direction the player faces in a box in the top-left
|
||||
// corner, `/where` to put the position in chat and `/coords` to hide or show
|
||||
// the box. This file is both the mod's Cargo library (its tests) and the
|
||||
// module the bundle adds to the game.
|
||||
|
||||
/// The mod's id (its settings folder), name and version.
|
||||
pub const ID: &str = "coords_hud";
|
||||
pub const NAME: &str = "Coordinates HUD";
|
||||
pub const VERSION: &str = "2.0.0";
|
||||
pub const DESCRIPTION: &str = "Your coordinates and facing in a corner of the screen. /where puts them in chat, /coords hides or shows the box.";
|
||||
/// The WebAssembly mods' panel: translucent black, white text with a shadow.
|
||||
pub const BACKGROUND: u32 = 0x7800_0000;
|
||||
pub const INK: u32 = 0xFF_FFFF;
|
||||
|
||||
/// Direction.fromYRot: yaw 0 faces south, 90 west.
|
||||
pub fn facing(yaw: f32) -> &'static str {
|
||||
let i = (yaw / 90.0 + 0.5).floor() as i32 & 3;
|
||||
["South (+Z)", "West (-X)", "North (-Z)", "East (+X)"][i as usize]
|
||||
}
|
||||
|
||||
/// The box's lines, as the WebAssembly mod wrote them.
|
||||
pub fn lines(x: f64, y: f64, z: f64, yaw: f32) -> [String; 2] {
|
||||
[
|
||||
format!("XYZ {x:.1} / {y:.1} / {z:.1}"),
|
||||
format!("Facing {}", facing(yaw)),
|
||||
]
|
||||
}
|
||||
|
||||
/// `/where`'s line: `12, 70, -4 in minecraft:the_nether`.
|
||||
pub fn where_line(x: f64, y: f64, z: f64, dimension: &str) -> String {
|
||||
format!(
|
||||
"{:.0}, {:.0}, {:.0} in {dimension}",
|
||||
x.floor(),
|
||||
y.floor(),
|
||||
z.floor()
|
||||
)
|
||||
}
|
||||
|
||||
/// The stored `shown` value: shown unless it says `false`.
|
||||
pub fn read_shown(stored: Option<String>) -> bool {
|
||||
stored.is_none_or(|v| v.trim() != "false")
|
||||
}
|
||||
|
||||
pub fn shown_label(shown: bool) -> String {
|
||||
format!("Shown: {}", if shown { "ON" } else { "OFF" })
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// Whether the box shows, read once from its file, then kept.
|
||||
static SHOWN: std::cell::Cell<Option<bool>> = const { std::cell::Cell::new(None) };
|
||||
}
|
||||
|
||||
/// Whether the box shows, read once through `get` (the `shown` file).
|
||||
pub fn shown(get: impl FnOnce() -> Option<String>) -> bool {
|
||||
SHOWN.with(|s| {
|
||||
let found = s.get().unwrap_or_else(|| read_shown(get()));
|
||||
s.set(Some(found));
|
||||
found
|
||||
})
|
||||
}
|
||||
|
||||
/// Replaces it (`/coords` or the settings page changed it).
|
||||
pub fn set_shown(shown: bool) {
|
||||
SHOWN.with(|s| s.set(Some(shown)));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn facing_follows_vanilla_yaw() {
|
||||
assert_eq!(facing(0.0), "South (+Z)");
|
||||
assert_eq!(facing(90.0), "West (-X)");
|
||||
assert_eq!(facing(-180.0), "North (-Z)");
|
||||
assert_eq!(facing(-90.0), "East (+X)");
|
||||
assert_eq!(facing(314.0), "East (+X)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lines_read_as_the_webassembly_mods() {
|
||||
assert_eq!(
|
||||
lines(12.5, 64.0, -3.25, 180.0),
|
||||
["XYZ 12.5 / 64.0 / -3.2", "Facing North (-Z)"]
|
||||
);
|
||||
assert_eq!(
|
||||
where_line(12.5, 70.2, -3.25, "minecraft:the_nether"),
|
||||
"12, 70, -4 in minecraft:the_nether"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shown_unless_stored_false() {
|
||||
assert!(read_shown(None));
|
||||
assert!(read_shown(Some("true".into())));
|
||||
assert!(!read_shown(Some("false\n".into())));
|
||||
assert_eq!(shown_label(false), "Shown: OFF");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// The mod's settings page: one button, the box shown or hidden.
|
||||
fn official_coords_hud_page(game: &mut crate::game::Game<'_>, mod_id: &str, buttons: &mut Vec<String>) {
|
||||
use crate::game::official_coords_hud as m;
|
||||
if mod_id != m::ID {
|
||||
return;
|
||||
}
|
||||
buttons.push(m::shown_label(m::shown(|| game.native_setting(m::ID, "shown"))));
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Coordinates HUD in a running modded game: its row and settings page in Options > Mods, the box in the top
|
||||
left, /coords hiding and showing it (and keeping that), and /where's line in chat (screenshots)."""
|
||||
import json
|
||||
import time
|
||||
from game import Game, difference
|
||||
|
||||
DATA = "horizon-mods/.horizon-mod-data/coords_hud"
|
||||
TOP_LEFT, CHAT = (0.0, 0.0, 0.25, 0.1), (0.0, 0.7, 0.5, 0.95)
|
||||
|
||||
|
||||
def typed(g, line):
|
||||
"""As the player types it: T opens the chat box, then the line and Enter."""
|
||||
g.run("key", "t", "tap")
|
||||
time.sleep(0.5)
|
||||
g.run("type", line)
|
||||
g.run("key", "enter", "tap")
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def run(ctl, resources, out):
|
||||
with Game(ctl, resources, out) as g:
|
||||
g.run("options", "mods")
|
||||
assert "Coordinates HUD 2.0.0: ON" in g.labels(), g.labels()
|
||||
g.run("click", g.ids()["Settings"])
|
||||
page = g.labels()
|
||||
assert "Shown: ON" in page, page
|
||||
g.run("click", g.ids()["Shown: ON"])
|
||||
clicked = (g.home / DATA / "shown").read_text()
|
||||
g.run("click", g.ids()["Shown: OFF"])
|
||||
g.play()
|
||||
g.run("command", "tp @s ~ ~ ~ 0 10")
|
||||
time.sleep(2)
|
||||
shown = g.shot("1-shown")
|
||||
typed(g, "/coords")
|
||||
hidden_file = (g.home / DATA / "shown").read_text()
|
||||
time.sleep(4)
|
||||
hidden = g.shot("2-hidden")
|
||||
typed(g, "/coords")
|
||||
typed(g, "/where")
|
||||
where = g.shot("3-where")
|
||||
results = {
|
||||
"page": page,
|
||||
"shown_file_after_click": clicked,
|
||||
"shown_file_after_coords": hidden_file,
|
||||
"shown_file_at_end": (g.home / DATA / "shown").read_text(),
|
||||
"diff_top_left_hidden": round(difference(shown, hidden, TOP_LEFT), 1),
|
||||
"diff_top_left_shown_again": round(difference(shown, where, TOP_LEFT), 1),
|
||||
"diff_chat_where": round(difference(hidden, where, CHAT), 1),
|
||||
}
|
||||
print(json.dumps(results, indent=2))
|
||||
assert clicked == "false" and hidden_file == "false", results
|
||||
assert results["shown_file_at_end"] == "true", results
|
||||
assert results["diff_top_left_hidden"] > 4, results
|
||||
assert results["diff_top_left_shown_again"] < results["diff_top_left_hidden"], results
|
||||
# native_chat lines are the client's; chat-log reads the server's chat here: see 3-where.png.
|
||||
print(json.dumps({"proof": "coords_hud", "ok": True, **results}, indent=2))
|
||||
@@ -3,11 +3,12 @@
|
||||
Horizon's official FPS counter: frames per second in a box in a corner of the screen, and, if you like, the slowest frame and the 1% low of the last 5 seconds. Its settings page (Options > Mods > FPS Counter > Settings) picks the corner and the lows.
|
||||
|
||||
It is a [horizon-mixins](https://github.com/horizon-rust/horizon-mixins) bundle (`mixins/fps_overlay/`) that the Horizon
|
||||
launcher builds into the game. It replaces the WebAssembly FPS Counter 1.x and keeps its settings: the same files (`horizon-mods/.horizon-mod-data/fps_overlay/corner`, `lows`).
|
||||
launcher builds into the game. It keeps the settings of earlier versions: the same files (`horizon-mods/.horizon-mod-data/fps_overlay/corner`, `lows`).
|
||||
|
||||
## Install
|
||||
|
||||
In the Horizon launcher: Mods → FPS Counter → Install, then Settings → Game → Native mods (experimental) → Build. The
|
||||
In the Horizon launcher: Mods → FPS Counter → Install, then **Build** on the same page (once built, switch it
|
||||
on or off in the game under Options → Mods). The
|
||||
launcher downloads its own Rust and builds the game with your native mods; see Horizon's
|
||||
[native mods](https://github.com/horizon-rust/horizon/blob/main/docs/native-mods.md).
|
||||
|
||||
@@ -38,6 +39,6 @@ python3 native/tools/native.py proof fps-overlay --resources /path/to/.local/hor
|
||||
```
|
||||
|
||||
The proof needs resources prepared from your own Minecraft 26.3 (`horizon-prepare`); none are in this repository.
|
||||
It seeds the WebAssembly mod's settings (bottom right, lows on) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the box to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
It seeds an earlier version's settings (bottom right, lows on) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the box to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
|
||||
License: MIT.
|
||||
@@ -3,11 +3,12 @@
|
||||
Horizon's official Keystrokes: your movement keys, mouse buttons and space bar in a corner, lit while held, with clicks per second. Its settings page (Options > Mods > Keystrokes > Settings) picks the corner and the clicks per second.
|
||||
|
||||
It is a [horizon-mixins](https://github.com/horizon-rust/horizon-mixins) bundle (`mixins/keystrokes/`) that the Horizon
|
||||
launcher builds into the game. It replaces the WebAssembly Keystrokes 1.x and keeps its settings: the same files (`horizon-mods/.horizon-mod-data/keystrokes/corner`, `cps`).
|
||||
launcher builds into the game. It keeps the settings of earlier versions: the same files (`horizon-mods/.horizon-mod-data/keystrokes/corner`, `cps`).
|
||||
|
||||
## Install
|
||||
|
||||
In the Horizon launcher: Mods → Keystrokes → Install, then Settings → Game → Native mods (experimental) → Build. The
|
||||
In the Horizon launcher: Mods → Keystrokes → Install, then **Build** on the same page (once built, switch it
|
||||
on or off in the game under Options → Mods). The
|
||||
launcher downloads its own Rust and builds the game with your native mods; see Horizon's
|
||||
[native mods](https://github.com/horizon-rust/horizon/blob/main/docs/native-mods.md).
|
||||
|
||||
@@ -38,6 +39,6 @@ python3 native/tools/native.py proof keystrokes --resources /path/to/.local/hori
|
||||
```
|
||||
|
||||
The proof needs resources prepared from your own Minecraft 26.3 (`horizon-prepare`); none are in this repository.
|
||||
It seeds the WebAssembly mod's settings (bottom right, no clicks per second) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the keys to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
It seeds an earlier version's settings (bottom right, no clicks per second) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the keys to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
|
||||
License: MIT.
|
||||
@@ -3,11 +3,12 @@
|
||||
Horizon's official Minimap: a map of the terrain around you in a corner, in map colours, square or round, north up or turning with you, drawn by Horizon's own minimap. Its settings page (Options > Mods > Minimap > Settings) picks the corner, size, shape, zoom and turning.
|
||||
|
||||
It is a [horizon-mixins](https://github.com/horizon-rust/horizon-mixins) bundle (`mixins/minimap/`) that the Horizon
|
||||
launcher builds into the game. It replaces the WebAssembly Minimap 1.x and keeps its settings: the same files (`horizon-mods/.horizon-mod-data/minimap/corner`, `size`, `shape`, `zoom`, `rotate`).
|
||||
launcher builds into the game. It keeps the settings of earlier versions: the same files (`horizon-mods/.horizon-mod-data/minimap/corner`, `size`, `shape`, `zoom`, `rotate`).
|
||||
|
||||
## Install
|
||||
|
||||
In the Horizon launcher: Mods → Minimap → Install, then Settings → Game → Native mods (experimental) → Build. The
|
||||
In the Horizon launcher: Mods → Minimap → Install, then **Build** on the same page (once built, switch it
|
||||
on or off in the game under Options → Mods). The
|
||||
launcher downloads its own Rust and builds the game with your native mods; see Horizon's
|
||||
[native mods](https://github.com/horizon-rust/horizon/blob/main/docs/native-mods.md).
|
||||
|
||||
@@ -38,6 +39,6 @@ python3 native/tools/native.py proof minimap --resources /path/to/.local/horizon
|
||||
```
|
||||
|
||||
The proof needs resources prepared from your own Minecraft 26.3 (`horizon-prepare`); none are in this repository.
|
||||
It seeds the WebAssembly mod's settings (bottom right, round, 2 blocks per pixel) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the map to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
It seeds an earlier version's settings (bottom right, round, 2 blocks per pixel) in a temporary game folder, then checks that Options > Mods shows them, and that the Corner button moves the map to the top left and writes the same file. CI runs `cargo test`, packages the `.hnmod` and checks the game on the tested commit, and every Monday on the newest Nightly.
|
||||
|
||||
License: MIT.
|
||||
@@ -7,13 +7,14 @@ Settings): a click on an item in the panel gives you one, a right click a stack.
|
||||
Options > Mods.
|
||||
|
||||
It is a [horizon-mixins](https://github.com/horizon-rust/horizon-mixins) bundle (`mixins/recipes/`) that the Horizon
|
||||
launcher builds into the game. It replaces the WebAssembly Recipes 1.x and keeps its settings: the same file
|
||||
launcher builds into the game. It keeps the settings of earlier versions: the same file
|
||||
(`horizon-mods/.horizon-mod-data/recipes/give`) and the same keys (`key.recipes.recipe`, `key.recipes.uses` in
|
||||
`horizon-mods.txt`).
|
||||
|
||||
## Install
|
||||
|
||||
In the Horizon launcher: Mods → Recipes → Install, then Settings → Game → Native mods (experimental) → Build. The
|
||||
In the Horizon launcher: Mods → Recipes → Install, then **Build** on the same page (once built, switch it
|
||||
on or off in the game under Options → Mods). The
|
||||
launcher downloads its own Rust and builds the game with your native mods; see Horizon's
|
||||
[native mods](https://github.com/horizon-rust/horizon/blob/main/docs/native-mods.md).
|
||||
|
||||
@@ -44,7 +45,7 @@ python3 native/tools/native.py proof recipes --resources /path/to/.local/horizon
|
||||
```
|
||||
|
||||
The proof needs resources prepared from your own Minecraft 26.3 (`horizon-prepare`); none are in this repository.
|
||||
It seeds the WebAssembly mod's setting ("Click gives items" on) in a temporary game folder, checks that Options > Mods
|
||||
It seeds an earlier version's setting ("Click gives items" on) in a temporary game folder, checks that Options > Mods
|
||||
shows the mod, its keys and the setting, then opens the inventory: the panel shows items, a click on one in creative
|
||||
mode gives it, and with the setting turned off the same click opens its recipe page.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"game": "26.3",
|
||||
"hooks": 2,
|
||||
"horizon_repository": "https://github.com/horizon-rust/horizon",
|
||||
"horizon_revision": "8f91683323ac1165e7d76b3037e18f30fe647205",
|
||||
"horizon_revision": "4baa571566e39bfd6594988d3bb2bc85440c30e7",
|
||||
"horizon_mixins_repository": "https://github.com/horizon-rust/horizon-mixins",
|
||||
"horizon_mixins_revision": "0d6b103c70633d8fd9443d8d0acd3aadaacedb06"
|
||||
}
|
||||
@@ -6,7 +6,7 @@ priority = 100
|
||||
# The commit it was tested on. It uses only the native hook points (hooks 2 in
|
||||
# compatibility.json): the launcher builds it on any Horizon that has them.
|
||||
[compatibility]
|
||||
horizon_revision = "8f91683323ac1165e7d76b3037e18f30fe647205"
|
||||
horizon_revision = "4baa571566e39bfd6594988d3bb2bc85440c30e7"
|
||||
|
||||
[[module]]
|
||||
id = "runtime"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
__pycache__/
|
||||
target/
|
||||
@@ -0,0 +1,107 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "horizon-mod-smp"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.154"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "horizon-mod-smp"
|
||||
version = "0.29.0"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
publish = false
|
||||
description = "The official Horizon server's SMP, a native server mod: economy (and next, market, trades, claims)."
|
||||
|
||||
# The mod's rules and their tests: the same files the bundle adds to the game
|
||||
# (as game::smp_store, game::smp_economy), under the same names.
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Ludovic Marie and the Horizon contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,414 @@
|
||||
# SMP (Horizon native server mod)
|
||||
|
||||
The official Horizon server's survival layer ([design](https://github.com/horizon-rust/horizon/blob/main/docs/smp.md)).
|
||||
It is **not** part of Horizon's own server: only a server that builds this mod into its engine has it. It isn't listed
|
||||
in the registry.
|
||||
|
||||
Players install nothing: it speaks only what a stock Horizon client already shows (commands with completions, chat
|
||||
lines, vanilla chest menus the server fills with ordinary items (the trade menu); later sounds, titles, the action
|
||||
bar, boss bars and the sidebar).
|
||||
|
||||
This version: the economy with its Treasury and taxes, the auction house, the bank, the server market and its `/shop` menu, player trades, the coinflip, the lottery, places (spawn, homes, warps,
|
||||
teleport requests, the rules), land claims, and the scoreboard (a sidebar with your balance, playtime and the richest players, the Tab list's
|
||||
header and footer).
|
||||
|
||||
| Command | Does |
|
||||
|---|---|
|
||||
| `/balance [player]`, `/bal` | your balance, or another player's |
|
||||
| `/pay <player> <amount>` | gives money to a player who has an account (anyone who has played since the mod was on) |
|
||||
| `/baltop [page]` | the richest players, 10 a page |
|
||||
| `/eco take <player> <amount> [reason]`, `/money take ...` | operators of level 3: a cheat's gains go into the Treasury, logged with the reason. Nobody gives or sets money (`/eco give` and `/eco set` say so) |
|
||||
| `/treasury`, `/treasury log` | the Treasury's balance, its income by tax and its spending (today and since it opened), its last movements |
|
||||
| `/treasury pay <player> <amount> <reason>` | operators of level 3: pays a player from the Treasury (an event prize, a bug refund, a grant), never more than it holds; everyone sees it |
|
||||
| `/jobs`, `/jobs deliver <n>` | the day's contracts: deliver items the state asks for, paid from the Treasury |
|
||||
| `/futures`, `/futures long\|short <item> <margin> [leverage]`, `/futures close <n>`, `/futures info <item>`, `/futures list` | perpetual futures on the market's prices: a chest menu of your positions (profit green, loss red, liquidation price), leverage up to 10x |
|
||||
| `/eco stats` | the money supply and where it sits, what the server made and destroyed today, taxes and fees, how evenly money is spread |
|
||||
| `/bank`, `/bank deposit <amount\|all>`, `/bank withdraw <amount\|all>` | your savings, which earn a small interest from the Treasury each night |
|
||||
| `/ah` | the auction house: a chest menu of listings by category, cheapest a unit first; click one to buy it or bid; your listings (click to take one back) and your mail |
|
||||
| `/ah sell <price> [count]` | lists the stack in your hand (or part of it) at a fixed price, for `listing_hours` (48); the listing fee (1%, at least 1 coin) goes to the Treasury |
|
||||
| `/ah auction <start> [hours]` | auctions the stack in your hand from a starting bid, for 1 to 24 hours (12) |
|
||||
| `/ah bid <listing> <amount>`, `/ah buy <listing>` | bids (the money is held until someone bids more or it ends), buys a fixed-price listing |
|
||||
| `/ah cancel <listing>`, `/ah claim`, `/ah search <words>`, `/ah mine`, `/ah mail` | takes back a listing nobody bid on; gives you your mail; the menu on a search, your listings, your mail |
|
||||
| `/eco taxes`, `/taxes` | the tax code and your own bill on Monday; `/eco taxes pay` pays land tax you owe |
|
||||
| `/shop` | the market as a chest menu: categories, a click buys one, a shift-click 64, a click on a stack of yours sells it, "Sell all" |
|
||||
| `/market [item]` | the moving market as a chest menu: categories, each item's price, its move over 1 h and 24 h and its volume; an item's page buys or sells 1, 16 or 64, sells all you carry, and gives its price chart as a map |
|
||||
| `/worth [item]` | an item's price, the same to buy and to sell (the one in your hand without a name), and what you may still sell today |
|
||||
| `/sell hand [count]`, `/sell <item> [count]`, `/sell all` | sells to the market: the stack in your hand, an item, or everything it buys |
|
||||
| `/buy <item> [count]` | buys from the market, only what fits in your inventory |
|
||||
| `/trade <player>` | asks a player to trade (60 s to answer) |
|
||||
| `/trade accept [player]`, `/trade deny [player]` | answers a request |
|
||||
| `/trade money <amount>` | the money you add to your offer (0: none) |
|
||||
| `/trade cancel` | ends your trade, or withdraws your request |
|
||||
| `/coinflip <amount> [player]` | stakes an amount for anyone (or one player) to match; off unless `gambling.enabled` |
|
||||
| `/lottery`, `/lottery buy <tickets>` | the pot, your tickets and the time to the draw; buys tickets (off unless `gambling.enabled`) |
|
||||
| `/casino`, `/casino roulette\|slots\|crash\|blackjack` | the casino's lobby menu, or a game's table (needs `gambling.enabled` and `casino.enabled`) |
|
||||
| `/casino help`, `/casino top`, `/casino stats` | every game's odds and house edge and the limits; today's biggest wins; what you bet, won and may still lose today |
|
||||
| `/coinflip accept <player>`, `/coinflip cancel`, `/coinflip list` | takes an offer (a fair coin decides, the winner gets both stakes), withdraws yours, lists those waiting |
|
||||
| `/spawn` | to the server's spawn; `/setspawn` (operators of level 3) sets it where you stand |
|
||||
| `/home [name]`, `/sethome [name]`, `/delhome [name]`, `/homes` | your homes (`home` when unnamed): go, set or move one where you stand, delete, list |
|
||||
| `/warp <name>`, `/warps` | to a warp, the list; `/setwarp <name>`, `/delwarp <name>` for operators of level 3 |
|
||||
| `/tpa <player>`, `/tpaccept [player]`, `/tpdeny [player]` | asks to go to a player (60 s to answer); answers a request |
|
||||
| `/rules` | the server's rules |
|
||||
| `/back` | back to where you died, or where your last teleport took you from (warmup and cooldown as any teleport) |
|
||||
| `/afk` | marks you away from the keyboard until you move, turn or run a command |
|
||||
| `/playtime [player]` | how long you (or a player who is on) have played here |
|
||||
| `/claim`, `/claim info`, `/unclaim` | claims the chunk you stand in (all its height), says whose it is, frees it (operators of level 3: anyone's) |
|
||||
| `/claim show` | draws the border of the chunk you stand in for 10 s, for you only: green yours or a trusting owner's, red someone else's, white free |
|
||||
| `/claims` | your chunks, how many you may hold, and who you trust |
|
||||
| `/trust <player>`, `/untrust <player>` | lets a player (or no longer) build and use things on all your land |
|
||||
| `/nick <name>`, `/nick off`, `/nick` | operators of level 3 (with `ops_only`, the default): another name for you in chat and the Tab list, shown as `~name` (hovering it gives your real one); `/nick off` (anyone with a nickname) takes it off; `/nick` alone says how |
|
||||
| `/nick <player> <name\|off>` | operators of level 3: sets or takes off a player's nickname |
|
||||
| `/realname <nick>` | who goes by that nickname |
|
||||
| `/invsee <player>`, `/endersee <player>` | operators of level 3: the player's inventory (main, hotbar, armour, off hand) or ender chest in a chest menu, on or off the server; click one of theirs to take it, one of yours to give it; every move in `audit.log`, a summary in `staff.log` |
|
||||
| `/sidebar off`, `/sidebar on`, `/sidebar` | hides the scoreboard sidebar for you (remembered), shows it again |
|
||||
|
||||
The market trades only plain items (not worn, named or enchanted), and only with players in survival or adventure
|
||||
mode. Items move first, then money, both logged; a sale the log refuses gives the items back, and a purchase checks the
|
||||
money and the room before anything moves.
|
||||
|
||||
**No way to get rich from the market.** The market makes money only from what players gather, and only so much a day:
|
||||
- One price per item, to buy and to sell (since 0.29): a config that still has two (`buy` 400, `sell` 100) gets
|
||||
their geometric mean (200) at load, logged ("one price now"); `buy` or `sell` 0 still closes that side. A trade
|
||||
of N items is priced along the curve it moves the price on (below), so buying N and selling them back gives back
|
||||
exactly what was paid, less the tax: a round trip never earns (tested for 1, 64 and past the minute's band, and
|
||||
over thousands of random trades with the drift in between).
|
||||
- No chain of recipes turns what the market sells into something it buys for more: the cheapest way to get each item
|
||||
from the market (bought, or crafted, smelted, cut from bought items, through any number of recipes) is worked out,
|
||||
and an item the market would buy for more than that isn't bought. The tests walk every vanilla recipe
|
||||
(`SMP_VANILLA_DATA=<.local/horizon-client/26.3/data/minecraft> cargo test`); the server checks the iron, gold,
|
||||
copper, diamond, emerald, coal, redstone, lapis, wheat, wood and food chains at each start.
|
||||
- Items a recipe links (an ingot and its block, wheat and hay...) share one moving price, the block moving it as
|
||||
its 9 ingots do, so crafting never beats the market however prices move; the vanilla-recipe test checks every item
|
||||
at the worst drift (what makes it at 0.6 times its price, it at 1.6) too.
|
||||
- Each player sells at most `daily_sell_coins` (2,000 coins) and `daily_sell_items` (640 of each item) a UTC day,
|
||||
`/worth` and the shop show what is left, and `market.json` keeps the day's count across restarts.
|
||||
- Money received with `/pay` counts toward the receiver's same `daily_sell_coins`: selling up to the limit on alts
|
||||
and paying it all to a main is refused once the main's limit is reached ("can only receive N more today").
|
||||
Trades (`/trade`) and auction house sales are not counted.
|
||||
- Amounts are checked: no price above 1,000,000,000,000, no sum that overflows.
|
||||
- The coinflip and the lottery give the winner the stakes (less `fee_percent`, 0 by default): they move money
|
||||
between players and never make any.
|
||||
|
||||
Default prices (coins; "buy only": the market sells it but doesn't buy it, "sell only" the other way):
|
||||
|
||||
| Category | Items |
|
||||
|---|---|
|
||||
| Farming | wheat 2, carrot 2, potato 2, beetroot 2, sugar cane 2, pumpkin 5, melon slice 1, cactus 2; buy only: wheat seeds 2, bone meal 3 |
|
||||
| Mining | coal 4, copper ingot 3, iron ingot 15, gold ingot 20, redstone 2, lapis 4, quartz 4, emerald 40, diamond 200 |
|
||||
| Wood | the eight logs 2 |
|
||||
| Mob drops | bone 2, string 2, gunpowder 4, spider eye 2, slime ball 4, blaze rod 15, leather 3, feather 1; sell only: rotten flesh 1 |
|
||||
| Building (buy only) | cobblestone 1, stone 2, dirt 1, sand 2, gravel 2, glass 3, bricks 4, stone bricks 3 |
|
||||
| Food (buy only) | bread 5, cooked beef 6, cooked porkchop 6, cooked chicken 5, baked potato 4, apple 4, golden carrot 40 |
|
||||
| Tools (buy only) | torch 1, ladder 2, crafting table 4, chest 6, furnace 6 |
|
||||
|
||||
A `config.json` still holding the 18 prices of versions 0.1 to 0.11, never edited, gets these at the first start of
|
||||
0.12.0; edited prices are kept. Only items that stack to 64 belong in the market: a shift-click buys 64, and what
|
||||
doesn't fit falls at the player's feet for them.
|
||||
|
||||
**/invsee and /endersee.** For operators of level 3 (luzW, bunchy7s...). The menu shows the main inventory in its
|
||||
first three rows, the hotbar in the fourth, then the armour (head to feet) and the off hand; the ender chest fills
|
||||
three rows. A click on one of the player's stacks moves it whole into the operator's inventory; a click on one of the
|
||||
operator's own moves it into the player's (main inventory or ender chest, where it fits whole). A stack moves only if
|
||||
it is still exactly what the menu showed: the game checks it and moves it, or nothing (no copy, no loss). A player who
|
||||
isn't on is read from and written to their saved file; while they log in or are dead nothing moves and the menu says
|
||||
why. The menu is read again once a second while open; nothing runs when none is open. Each move is in `audit.log`
|
||||
before it is made (`invsee_take`, `invsee_put`: operator, player, inventory, item, count; a refused one again with
|
||||
its reason); closing the menu writes one line to the server log (`[smp] staff: ...`), `staff.log`, and the chat of
|
||||
the other operators on. Needs horizon#6106 (`native_inventory`, `native_move_stack`).
|
||||
|
||||
**Nicknames.** With `ops_only` (the default since 0.22) only operators of level 3 set nicknames: their own, or a
|
||||
player's with `/nick <player> <name>`; a player may take off the one given to them (`/nick off`). At each start, a
|
||||
nickname a player who isn't an operator picked themselves is taken off and logged (`for operators only`). 3 to 16 letters, digits or `_`, shown with a `~` in front (`~Rocky`) so a nickname never passes for
|
||||
a real name. Names are compared case-insensitively with `_` dropped and look-alikes folded (`0`→o, `1`/`i`→l, `3`→e,
|
||||
`4`→a, `5`→s, `7`→t, `8`→b, `9`→g). Refused: a nickname equal to, or containing (from 4 letters), the name of anyone
|
||||
who has played here (the economy's accounts and `usercache.json`), an operator (`ops.json`), the Team (`protected`)
|
||||
or another player's nickname; one that reads as a reserved word (`reserved`: server, console, admin, mod, owner,
|
||||
staff, op, horizon, kira, notch, mojang, herobrine...); one the server's chat filter refuses. A player needs
|
||||
`min_playtime_minutes` of play before their first nickname (operators don't). At each start, nicknames that break
|
||||
these rules are taken off, each logged (`[smp] nickname X of <uuid> taken off: why`). The change is made at the next
|
||||
second. The nickname shows in chat (messages, `/me`, `/msg`) and the Tab list, and hovering it gives the real name;
|
||||
the real name stays everywhere else: the server's log, the anticheat, selectors, the Discord bridge. `/pay`, `/tpa`,
|
||||
`/trade`, `/playtime`, `/tpaccept`, `/tpdeny` and `/eco` take a nickname (with or without `~`) wherever they take a
|
||||
player's name. The player's profile (name, UUID) never changes.
|
||||
`config.json`'s `nicks`: `enabled`, `ops_only` (true), `cooldown_seconds` (600), `min_playtime_minutes` (60), `protected` (the Team's
|
||||
names), `reserved` (the words above).
|
||||
|
||||
**Moving prices** (`market.dynamic`, on by default since 0.26). Each item has one price: its base price (`items`)
|
||||
times a factor that supply and demand move as each trade happens. Every item bought raises the log of the factor by
|
||||
`1% / depth`, every item sold lowers it as much, where the depth follows the item's rarity (400 / its price, between
|
||||
2 and 400: a diamond moves 50 times faster per item than cobblestone; `depth` overrides it per item). A trade of N is
|
||||
worth the area under that curve (`price / step × (e^(N × step) - 1)`), rounded up to whole coins when buying and down
|
||||
when selling: one diamond at 200 costs 201 and sells for 199, 64 cobblestone at 1 cost 65, and a sale walks back the
|
||||
exact path of the purchase. All trades together move an item at most `max_minute_move_percent` (5%) a minute from
|
||||
where it started that minute: past that, a purchase is cut short and a sale keeps the rest ("sell them in a
|
||||
minute"). The factor goes back to 1 with a half-life of `half_life_hours` (6) and stays within `min_factor` (0.6)
|
||||
and `max_factor` (1.6), where the rest of a trade goes at that price. A `tax_percent` (2%) of each sale and purchase
|
||||
goes to the Treasury, on its own line of the receipt ("Sold 3 diamond at 198 coins each: 595 coins." then "Tax 2%:
|
||||
-12 coins. You get 583 coins."). Items a player bought from the market in the last `round_trip_hours` (24) can't be
|
||||
sold back to it. (`max_trade_impact_percent` and `max_player_impact_percent` are no longer used: the curve and the
|
||||
minute's band do their work.) History: one point a minute for 24 hours and one an hour for 30 days (the mid price, the
|
||||
items traded and those sold), in `market_prices.json`, written by a thread every 5 minutes and when the world closes.
|
||||
At the first minute of each UTC day, the day's three biggest risers and fallers (at least 1%) and news from real
|
||||
activity ("Diamond supply up 40% today", sales against the day before's, at least `news_percent` and
|
||||
`news_min_volume`) go to everyone's chat and to `web/market.json` for Kira to post. `enabled: false` keeps the
|
||||
fixed prices of 0.23. For other mods (the futures): `Market::spot`, `twap(id, minutes, now)`, `mark_price(id, now)`
|
||||
(the 10-minute TWAP from at least 5 points), `volume(id, now, hours)`, `history(id, Span)`.
|
||||
|
||||
**`/market`.** A 6-row chest menu: the shop's categories and the day's movers; a category's items, each with its
|
||||
price, its change over 1 h and 24 h (green ▲, red ▼) and what was traded in 24 h; an item's page with its
|
||||
base price, the tax and what you may still sell today, buttons to buy or sell 1, 16 and 64 (what they come to
|
||||
along the curve, and the tax), sell all of it you carry, and the price chart over 24 hours or 7 days, given as a filled map (128 × 128,
|
||||
drawn by the server: the curve green when it rose, red when it fell, the price, the change, the low and high). A
|
||||
chart map is drawn again each minute for whoever carries it, and once a minute the open menus follow the prices.
|
||||
`/market <item>` opens the item's page. `/worth` adds the item's moves and volume.
|
||||
|
||||
**The shop.** `/shop` opens a 6-row chest menu on the market's prices: the categories of `config.json`'s `shop` (an
|
||||
item in none goes under "Other"), each item named with its prices. A click buys one, a shift-click 64; a click on a
|
||||
stack in your own inventory, below the menu, sells it; "Sell all" sells everything the market buys. The bottom row
|
||||
shows your balance and today's selling limit. It goes through the market's own rules (survival or adventure only,
|
||||
items then money, logged, the daily limits); the items move by the console's `clear` and `give`, measured on the
|
||||
inventory before and after, so the money follows what really moved.
|
||||
|
||||
**Trades.** Once accepted, both players see a 6-row chest menu: their own offer on the left (16 stacks), the other's
|
||||
on the right, each side's money, their confirm and cancel buttons, and whether the other has confirmed. A click on a
|
||||
stack in your inventory, below the menu, adds it to your offer; a click on it in your offer takes it back. The menu
|
||||
moves nothing: offered stacks stay in their owners' inventories, the menu shows copies, and a stack that changes
|
||||
(used, dropped, grown by a pickup) leaves the offer. Any change clears both confirmations. When both have confirmed,
|
||||
the server checks that each still holds exactly what they offer, has room for what they get and has the money, logs
|
||||
the trade, and swaps everything in one step, or nothing (and both must confirm again). Closing the menu,
|
||||
`/trade cancel`, leaving, dying or the other player leaving ends the trade with nothing moved. Survival and
|
||||
adventure players only.
|
||||
|
||||
**Coinflips.** Off by default: the owner turns them on in `config.json` (`gambling`: `enabled`, `min_bet` 10,
|
||||
`max_bet` 1000, `cooldown_seconds` 30, `offer_seconds` 60, `fee_percent` 0). A stake is held from the offer, in
|
||||
`economy.json` with the balances, until the coin falls; an offer cancelled, not taken in time, or whose player
|
||||
left gives it back, and so does the next start for one the server stopped with. The coin is a fresh random key from
|
||||
the system, never the world's random. Only the in-game currency is staked and won.
|
||||
|
||||
**The lottery.** Part of `gambling` (`ticket_price` 10, `max_tickets` 100 a player a draw, `lottery_seconds` 3600
|
||||
from a round's first ticket to its draw). Tickets are held like coinflip stakes; at the draw one ticket is picked at
|
||||
random among all sold (more tickets, more chances), its owner gets the pot (less `fee_percent`), and everyone hears
|
||||
it. A round with a single player, or one the server stopped with, gives every ticket back.
|
||||
|
||||
**The casino.** On with `gambling.enabled` (and `casino.enabled`, true by default). Every game is a chest menu any
|
||||
stock client can play, animated by changing its items at most 5 times a second for each open menu (and only while a
|
||||
round moves), with note-block sounds, titles and the action bar for results, fireworks and a line for everyone on a
|
||||
jackpot:
|
||||
|
||||
- European roulette: one zero, red/black, odd/even, 1-18/19-36 pay 1 to 1, dozens and columns 2 to 1, a number 35 to
|
||||
1; house edge 2.70% on every bet. The wheel turns and slows down on the drawn pocket.
|
||||
- Slots: 3 reels of 32 stops with item symbols, one payline, a published paytable (three Nether Stars 500x down to
|
||||
three Berries 6x, two Berries 2x); 94.2% paid back (house edge 5.8%), one pull in 4.5 pays.
|
||||
- Crash: one shared round; bet in the 10 s before take-off, then cash out (or set an automatic cash-out) before it
|
||||
crashes. P(crash at x or more) = 96% / x, capped at 100x: 96% paid back whatever you do. Each player in the round
|
||||
sees the multiplier in their own boss bar and the action bar.
|
||||
- Blackjack: 6 decks shuffled each hand, the dealer stands on all 17s and peeks, blackjack pays 3 to 2, double on the
|
||||
first two cards, no split; about 1% house edge with basic strategy.
|
||||
|
||||
Every draw is made by the server (ChaCha20 keyed from the system) before the animation starts. Bets go from `min_bet`
|
||||
10 to `max_bet` 1000; a player may lose at most `daily_loss_cap` (10,000) a day (UTC, all games together) and win at most
|
||||
`daily_win_cap` (10,000) net (once reached, no new bet until 00:00 UTC; the round that crosses it is paid in full), and
|
||||
`cooldown_ms` (2000) passes between the end of a round and their next bet. A bet is held like a coinflip stake;
|
||||
closing the menu or leaving never loses a round: a spin or a pull ends and is paid, a blackjack hand stands, a crash
|
||||
bet is cashed out when its player leaves in flight (or given back before take-off). Wins are paid from the casino's
|
||||
pot (`economy.json`'s pool `casino`), never with new money: a win larger than the pot is paid up to it. Once an hour
|
||||
the pot above `float` (20,000) goes to the Treasury (`casino_profit`); below it, the Treasury tops it up with what it
|
||||
holds (`casino_float`). A win of `jackpot_multiple` (50) times the stake, or of `announce_profit` (5000) coins, is
|
||||
told to everyone. Settings in `config.json`'s `casino`, also `crash_edge_percent` (4) and `crash_max` (100).
|
||||
|
||||
**Places.** A teleport waits `warmup_seconds` (3) in `config.json`'s `places`; a player who moves or is hurt meanwhile
|
||||
stays where they are, and `cooldown_seconds` (10) passes between two of one player's teleports. `/tpa` takes the
|
||||
asker to where the other player is when the warmup ends. Homes grow with the time played on the server since the mod
|
||||
was on (`homes`: `[hours, homes]`, by default 1 home, 2 from 5 hours, 3 from 20, 5 from 100). `rules` holds `/rules`'
|
||||
lines. Teleports are vanilla's `tp`, run as the server (`execute in <level> run tp`), so they cross levels and land
|
||||
as any teleport does. Teleports cost a fee to the Treasury (`places.fees`: `spawn` 0, `home` 5, `warp` 10, `back` 10,
|
||||
`tpa` 10, paid by the one who moves), logged as `travel_fee`. It is checked when the command runs and paid when the
|
||||
teleport happens: one called off (moved, hurt, the money spent meanwhile) costs nothing and leaves `/back` and the
|
||||
cooldown as they were. The spawn stays free so a lost or new player can always get back.
|
||||
|
||||
**Claims.** In a claimed chunk, only its owner, the players they trust and operators of level 3 break blocks or right
|
||||
click blocks: doors, chests, levers, buttons, placing a block, a bucket or flint on a block. Anyone else's click does
|
||||
nothing, and the action bar says whose land it is. The chunks a player may hold grow with the time played here
|
||||
(`claims.chunks`: `[hours, chunks]`, by default 4, 16 from 5 hours, 36 from 20, 64 from 100); `claims.enabled`
|
||||
turns them off. The world stays out too: no water or lava flows, no fire spreads or burns, and no piston pushes into
|
||||
a claim from land that isn't its owner's (or a player's they trust), and explosions break no claimed block, whoever
|
||||
lit them. Buckets are guarded where they fill or empty, and hitting the claim's item frames, armour stands,
|
||||
paintings, boats, minecarts and animals does nothing for others (`claims.protected_entities`, entity ids; monsters
|
||||
and players aren't in it). Not guarded yet: right clicking an entity (rotating a frame's item, an armour stand's
|
||||
items, shearing, leads), which waits for Horizon's hook (#4648). The server's `spawn-protection` (vanilla's) guards
|
||||
the spawn.
|
||||
|
||||
**The scoreboard.** A sidebar on the right, titled `board.title` ("Horizon SMP"): your own block first (your name, or
|
||||
your nickname; your balance, `125.4k`, `3.2M`; your playtime, `2h 05m`; the players online), then the `board.top` (3)
|
||||
richest players with their balance, then `board.footer` (`play.playhorizon.dev`, empty for none). The ranking is
|
||||
built once for everyone, only when a balance changed (at most every `board.min_seconds`, 5) or every
|
||||
`board.refresh_seconds` (60); each player's own lines are looked at on the same `board.refresh_seconds`, and a
|
||||
sidebar is sent only to the players whose lines changed and to newcomers: nothing runs per tick per player. The Tab
|
||||
list shows `board.tab_header` and `board.tab_footer` (`{server}`, `{tps}`, `{players}` filled in, every
|
||||
`board.tab_refresh_seconds`, 5). `board.sidebar` and `board.tab` turn either off; `board.server_name` names the Tab
|
||||
list. A server that kept 0.13's defaults (`Richest players`, the top 10) gets these at its first start of 0.14. The
|
||||
sidebar uses one scoreboard objective of its own (`horizon:native_sidebar`) and leaves the world's scoreboard alone.
|
||||
|
||||
**Presence.** A player's first join is announced to everyone (`presence.first_join`, empty for none) and they read
|
||||
`presence.welcome` and the rules. Each player gets `presence.daily_reward` (50) once a day (UTC) after
|
||||
`presence.reward_after_minutes` (10) of play that day, logged as `daily_reward` (0 turns it off). Only seconds with a
|
||||
move, a turn or a command in the minute before count, so an alt that logs in and stands still gets nothing (on
|
||||
2026-11-01, 1,242 players got the reward; 323 of them had played 10 minutes in all). The count isn't kept over a
|
||||
restart. A player who hasn't moved, turned or run a command for `presence.afk_minutes` (5),
|
||||
or typed `/afk`, is AFK: they don't count for sleeping (vanilla's `players_sleeping_percentage`) until they move or
|
||||
get in a bed; `presence.afk_announce` tells everyone instead of only them. A player runs at most
|
||||
`presence.spam_commands` (8) of the SMP's commands in `presence.spam_seconds` (5); operators of level 3 aren't
|
||||
limited. All of it is looked at once a second.
|
||||
|
||||
**The auction house.** Players sell to players: a listing is a fixed price or a timed auction. The listed items
|
||||
leave the seller's inventory at once; what doesn't sell, what an auction's winner gets, and what didn't fit in a
|
||||
buyer's inventory wait in the player's mail (`/ah claim`, or the menu's mail page; as much as fits, the rest stays).
|
||||
A purchase takes the whole listing: the listing leaves first, the items move, then the money (the seller gets the
|
||||
price less VAT, which goes to the Treasury); of two players who buy at once (the game runs every click on one
|
||||
thread), the second finds it gone. Bids wait in the `auction` pool: a higher bid gives the last one back at once,
|
||||
raising one's own only holds the difference, and a bid in the last `snipe_seconds` (60) moves the end back to
|
||||
60 seconds away. When an auction ends, the seller is paid (less VAT) and the items go to the winner's mail. Sellers
|
||||
and outbid players who are offline find a note when they come back. Everything (listings, bids, mail, notes) is
|
||||
written in `economy.json` with the balances, in one step: a crash can't keep the money and lose the items, or the
|
||||
reverse. Only plain items for now (not worn, named or enchanted); whole stacks with their enchantments wait for
|
||||
Horizon's `native_give_stack` to be stamped. Survival and adventure players only. `config.json`'s `auction`:
|
||||
`enabled`, `listing_fee_percent` (1), `max_listings` (8 a player), `listing_hours` (48), `auction_hours` (12),
|
||||
`auction_hours_max` (24), `bid_step_percent` (5: the smallest raise), `snipe_seconds` (60). Ended listings are
|
||||
looked at once a second (a pass over the open listings).
|
||||
|
||||
**The Treasury and taxes.** Nobody can make money, operators included: money enters the game only through the daily
|
||||
reward and what the market buys from players (later, paid contracts, from the Treasury). Every tax, fee and house edge
|
||||
goes into the Treasury, a pool in `economy.json` that belongs to no player (not in `/baltop` or the sidebar), and
|
||||
operators pay only from it (`/treasury pay`, with a reason everyone sees, logged as `grant`). A refund for a bug is
|
||||
such a payment, never new money. `/treasury` shows its balance, its income by kind and its spending; `/treasury log`
|
||||
its last 50 movements. The tax code (`config.json`'s `taxes`):
|
||||
- VAT (`vat_percent`, 5): on sales between players (the auction house, next), paid by the seller from the price.
|
||||
- Land tax, every Monday 00:00 UTC: `land_tax_per_chunk` (5 coins) a week per claimed chunk past the first
|
||||
`land_free_chunks` (4). What a player can't pay is owed: no new claim until it's paid (`/eco taxes pay`, or the
|
||||
next Monday's collection). Nothing is ever unclaimed for it.
|
||||
- Wealth tax, every Monday: `wealth_brackets` `[from, percent]`, by default 1% of a balance's part above 50,000,
|
||||
2% above 250,000 and 3% above 1,000,000 a week, on the balance and bank savings together (paid from the
|
||||
balance). On 2026-11-01 the richest player held 11,804 coins: nobody pays it
|
||||
yet; it keeps fortunes from growing without bound as the economy does.
|
||||
- Games of chance: the coinflip's and the lottery's `fee_percent` goes to the Treasury.
|
||||
The week's collection is looked at once a second (one comparison) and runs once a week; a restart never collects
|
||||
twice (the week collected is kept with the balances). `enabled: false` turns the weekly taxes off.
|
||||
|
||||
**The bank.** `/bank` shows your savings; `/bank deposit <amount|all>` and `/bank withdraw <amount|all>` move coins
|
||||
between your wallet and the bank (the `bank` pool), free and at any time. Interest (`bank.daily_basis_points`, 10:
|
||||
0.1% a day) is paid at 00:00 UTC from the Treasury, on the lowest amount saved since the last payment (a deposit made
|
||||
just before midnight earns nothing that night), on at most `max_interest_on` (10,000) coins of an account; a player
|
||||
saves at most `max_deposit` (25,000). One night's interest for everyone is at most `max_treasury_percent` (5) of the
|
||||
Treasury, shared out pro rata when that's short: the bank never makes money, it hands back part of the taxes to
|
||||
those who keep coins out of circulation. Interest stays saved (logged as `bank_interest`); deposits and withdrawals
|
||||
are `bank_deposit` and `bank_withdraw`. No loans: their collateral (items) can't be held safely here, and a loan
|
||||
without it is free money for an alt that never pays back. Savings are kept in `economy.json` (`ext.bank`).
|
||||
|
||||
**Contracts.** Each day at 00:00 UTC the state posts `jobs.contracts_per_day` (4) contracts drawn from `jobs.items`
|
||||
(farm, mine and mob produce the market buys): "deliver 64 wheat for 128 coins", announced to everyone. `/jobs` lists
|
||||
them; `/jobs deliver <n>` takes `batch` (64) plain items from the inventory (they leave the game) and pays at once from
|
||||
the Treasury, logged as `contract <count> <item>`. A delivery pays the market's sell price plus `premium_percent`
|
||||
(30), and never more than `ask_percent` (90) of what the market asks for the item, checked again at delivery as
|
||||
prices move: buying from the market to deliver never pays. Each contract takes `deliveries` (8) for the whole
|
||||
server, a player makes at most `max_per_player` (2) a day, survival or adventure only, and one day's contracts cost
|
||||
at most `budget_percent` (10) of the Treasury when posted (an empty Treasury posts none). Never AFK income: only a
|
||||
command with the items pays. The board is kept in `economy.json` (`ext.jobs`): a restart neither posts twice nor
|
||||
loses a delivery.
|
||||
|
||||
**Futures.** `/futures long|short <item> <margin> [leverage]` opens a perpetual position on an item's market price:
|
||||
its size is margin × leverage at the mark, in items. The mark is the market's 10-minute average of the mid
|
||||
(`Market::mark_price`/`twap`), never the last trade, so one player can't move it in one go; an item needs 5 minutes of
|
||||
prices first. Leverage: 2x for any traded item, +1x per `volume_per_leverage` (500) items the market traded in 24 h,
|
||||
up to `max_leverage` (10x). The liquidation price is shown when it opens and in the menu. Each minute (the market's
|
||||
price timer, never per tick) positions are marked: one whose equity falls to `maintenance_percent` (5%) of its size
|
||||
is liquidated, online or not, and its whole margin goes to the insurance fund (the player is told when back; a
|
||||
margin of `announce_margin` (1,000) or more is told to everyone). A player never loses more than the margin: a move
|
||||
past it is the fund's (counted as `gaps`). The house is every trade's other side through the insurance fund (part of
|
||||
the Treasury): profits come out of it, losses go in, and a position that would raise the house's net exposure past
|
||||
what the fund could pay in a `stress_percent` (30%) move is refused. Fees `fee_percent` (0.2%) of the size, to open
|
||||
and to close, go to the Treasury. Funding, each hour: the side with more open interest pays the fund up to
|
||||
`funding_percent_hour` (0.05%) of its size, in proportion to the imbalance, from its margins. Caps: `max_player_item`
|
||||
(20,000 coins of size on one item) and `max_player_total` (50,000), open interest on an item at most
|
||||
`max_item_volume_days` (3) days of its market volume. Positions and their margins (the `futures` pool) are in
|
||||
`economy.json` (`ext.futures`), written with the money: a restart keeps them and never liquidates twice.
|
||||
|
||||
**The report.** `/eco stats` (anyone) shows the money supply (wallets, savings and money held, the Treasury, the
|
||||
insurance fund, each pool), what the server made today (market sales, the daily reward) and destroyed (market
|
||||
purchases, operators' `/eco take`), the day's taxes and fees, and how evenly money is spread (Gini over players
|
||||
with money, the richest ten's share). At 00:00 UTC everyone reads the day before in one line (`report.daily_report`).
|
||||
A snapshot of each day is kept 60 days (`report.history_days`) in `economy.json` (`ext.report`). Once a minute
|
||||
`world/horizon-smp/web/economy.json` (`report.web_json`) is written off the tick thread for the site's /hub:
|
||||
`{"schema": 1, "generated": <ms>, "currency", "today", "pools", "minted_today", "burned_today", "treasury": {balance,
|
||||
insurance, income, spent, income_today, spent_today, log}, "taxes": {rates, last_collection}, "days": [...],
|
||||
"daily_report": "<yesterday's line>"}`. The server's Discord relay posts only chat, joins, leaves and deaths: the
|
||||
daily line reaches Discord through whoever reads that file (Kira).
|
||||
|
||||
Other parts reach the pools through `Economy::to_pool`, `from_pool`, `pool_move` and `settle_pool` (a bet against a
|
||||
pool: the stake goes in, the payout comes out, never more than the pool holds), each one audit line.
|
||||
|
||||
The currency is earned in game only: it can't be bought with real money or cashed out (Mojang's usage guidelines).
|
||||
|
||||
## Data
|
||||
|
||||
Everything is in the world's folder, `world/horizon-smp/`, so a backup of the world carries it. A world without that
|
||||
folder is untouched until the mod first runs on it; it changes no block and no player.
|
||||
|
||||
| File | Holds |
|
||||
|---|---|
|
||||
| `config.json` | `currency` (default `coins`), `starting_balance` (default 0), `market`: `enabled`, `items` (each item's `buy`, what the market asks, and `sell`, what it pays, 0 closing that side), `daily_sell_coins` (2000) and `daily_sell_items` (640), 0 for no limit; `shop`: `enabled`, `title`, `categories` (`name`, `icon`, `items`); `web`: `url` (Kira's `/smp/ingest`) and `token` (empty: nothing is sent), where the pages of `web/` go; written with the defaults the first time, and again when a newer version adds keys (your values kept) |
|
||||
| `economy.json` | balances by player UUID, with the name last seen; `held`: coinflip stakes and lottery tickets being decided; `pools`: the Treasury, its insurance fund and other system pools; `treasury`: its income and spending by kind and its last movements; `ext`: other parts' state written in the same step as the money (`tax`: the week collected, land tax owed; `auction`: the listings, bids, mail and notes) |
|
||||
| `places.json` | the spawn, the warps, each player's homes, and the seconds each player has played (written once a minute) |
|
||||
| `nicks.json` | each player's nickname and when they last changed it |
|
||||
| `staff.log` | one line per `/invsee` or `/endersee` menu in which something moved: who, whose, what was taken and put |
|
||||
| `market.json` | what each player sold today (coins and items), for the daily limits |
|
||||
| `market_prices.json` | each item's price factor and history (minutes for 24 h, hours for 30 days: `[time, mid, traded, sold]`), what each player bought in the last day (no selling it back), the day's summary |
|
||||
| `web/market.json` | for the website (`/hub/market`, through Kira), written by a thread each minute prices move: `schema` 1, `generated`, `currency`, `tax_percent`, `taxes_collected`, `daily_summary` (`day`, `lines`), `items` (`id`, `name`, `category`, `price` (the one price; `buy` and `sell` repeat it on the sides the market trades, for older readers), `mid`, `base`, `change_1h`, `change_24h`, `volume_24h`, `day`: 5-minute points, `month`: hours, each `{step, t, price, volume}`). When `web.token` is set, the same thread POSTs each page of `web/` that changed (gzipped, `Authorization: Bearer <token>`) to `<web.url>/<name>`: Kira keeps the last one and serves it to the site; the server needs no inbound access and Kira no key to it |
|
||||
| `presence.json` | the players who have joined (no welcome again), and the day each last got the daily reward |
|
||||
| `board.json` | the players who hid the sidebar (`/sidebar off`) |
|
||||
| `casino.json` | the day's ledger: each player's bets, wins and rounds today (the daily loss cap), the day's biggest wins, each game's totals, the pot's last sweep |
|
||||
| `claims.json` | each claimed chunk (`<dimension> <chunk x> <chunk z>`) with its owner, and whom each owner trusts |
|
||||
| `audit.log` | one JSON line per change, written before the change: `time` (ms), `kind` (`open`, `pay`, `grant`, `land_tax`...), `amount`, `from`/`to` with their balance before, `by` for an operator, `to_pool`/`from_pool` with `pool_before` and `reason` for a pool's movement; a trade's line (`trade`: both players, their items and money) comes before its swap, `trade_failed` after one that didn't go through |
|
||||
|
||||
`economy.json` is written whole to a temporary file, flushed and renamed over the old one, at most once a server tick
|
||||
and when the world closes: a crash leaves the old file or the new one. If it can't be read, the economy stays off (the
|
||||
commands say so) rather than start from nothing.
|
||||
|
||||
## Made on the hook points
|
||||
|
||||
It hooks only Horizon's native hook points: `native_register_commands` and `native_perform_command` (API 8), the
|
||||
acting player's items (API 9), the server menus and `native_exchange_items` (API 10), the players' health and
|
||||
`native_run_command` (API 21), `native_destroy_block` (API 14), `native_right_click_block`, the acting player and the
|
||||
action bar (API 21), `native_block_spread`, `native_piston_move`, `native_explosion_detonate`, `native_fill_bucket` and
|
||||
`native_attack_entity` (API 22), `native_sidebar`, `native_tab_list` and `native_tick_stats` (API 49),
|
||||
`native_set_nickname` and `native_text_allowed` (API 62), the server tick and the world lifecycle.
|
||||
`compatibility.json` names `"hooks": 58`.
|
||||
|
||||
| File | What it is |
|
||||
|---|---|
|
||||
| `mixins/smp/horizon-mixin.toml` | The bundle: twenty-eight modules and the HEAD hooks |
|
||||
| `mixins/smp/smp_store.rs`, `smp_economy.rs`, `smp_market.rs`, `smp_recipes.rs`, `smp_shop.rs`, `smp_nick.rs`, `smp_trade.rs`, `smp_games.rs`, `smp_lottery.rs`, `smp_places.rs`, `smp_claims.rs`, `smp_board.rs`, `smp_presence.rs`, `smp_tax.rs`, `smp_auction.rs`, `smp_bank.rs`, `smp_report.rs`, `smp_jobs.rs`, `smp_market_prices.rs`, `smp_market_menu.rs`, `smp_market_chart.rs`, `smp_invsee.rs`, `smp_futures.rs` | The rules, no game types (a trade's stacks are a type parameter): added to the game as `game::smp_store`, `game::smp_economy`, `game::smp_market`, `game::smp_recipes`, `game::smp_shop`, `game::smp_nick`, `game::smp_trade`, `game::smp_games`, `game::smp_lottery`, `game::smp_places`, `game::smp_claims`, `game::smp_board`, `game::smp_presence`, `game::smp_tax`, `game::smp_auction`, `game::smp_bank`, `game::smp_report`, `game::smp_jobs`, `game::smp_market_prices`, `game::smp_market_menu`, `game::smp_market_chart`, `game::smp_invsee`, `game::smp_futures`; also this crate's modules (`src/lib.rs`), for their tests |
|
||||
| `mixins/smp/glue.rs` | The state for the open world and the edges to the game's types (`game::smp_glue`) |
|
||||
| `mixins/smp/{register,command,tick,lifecycle,menu_clicked,menu_closed,destroy_block,right_click_block,block_spread,piston_move,explosion_detonate,fill_bucket,attack_entity}.rs` | One small helper per hook |
|
||||
| `mixins/smp/smp_casino.rs`, `smp_casino_roulette.rs`, `smp_casino_slots.rs`, `smp_casino_crash.rs`, `smp_casino_blackjack.rs` | The casino's rules, menus and effects (`game::smp_casino*`) |
|
||||
| `mixins/smp/casino_glue.rs` | The casino's effects for a stock client: menu items, sounds, titles, fireworks, boss bars (`game::smp_casino_glue`) |
|
||||
| `proof.py` | A dedicated server built with the mod and two real clients, on fresh temporary data |
|
||||
| `proof_casino.py` | The casino's proof (`SMP_PROOF=casino`): both clients play every game through the menus |
|
||||
|
||||
## Build and prove
|
||||
|
||||
```sh
|
||||
(cd native/smp && cargo test) # the rules
|
||||
python3 native/tools/native.py check smp # apply on the tested Horizon and cargo check the game
|
||||
python3 native/tools/native.py proof smp --resources /path/to/.local/horizon-client/26.3
|
||||
```
|
||||
|
||||
## The official server's engine
|
||||
|
||||
The server runs `horizon-server` as usual, with `[engine] path` pointing at a game built with this mod:
|
||||
|
||||
```sh
|
||||
NATIVE_NO_DEFAULT_FEATURES=1 python3 native/tools/native.py build smp --horizon <the release's commit>
|
||||
```
|
||||
|
||||
prints the built `horizon-client` (`--no-default-features`: the server build, without audio and controllers). When
|
||||
to deploy it on the official server is the owners' decision.
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"game": "26.3",
|
||||
"hooks": 62,
|
||||
"horizon_repository": "https://github.com/horizon-rust/horizon",
|
||||
"horizon_revision": "975c07d9151847e6af13afc4b5ab37b6bbe78ef5",
|
||||
"horizon_mixins_repository": "https://github.com/horizon-rust/horizon-mixins",
|
||||
"horizon_mixins_revision": "0d6b103c70633d8fd9443d8d0acd3aadaacedb06"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// A player hits an entity: a claim's frames, armor stands and animals are
|
||||
// kept from players its owner doesn't trust.
|
||||
fn smp_attack_entity(
|
||||
game: &mut crate::game::Game<'_>,
|
||||
kind: &str,
|
||||
pos: [f64; 3],
|
||||
canceled: &mut bool,
|
||||
) {
|
||||
crate::game::smp_glue::attack(game, kind, pos, canceled);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// A fluid flows or fire spreads into a block: kept out of the land others
|
||||
// claimed.
|
||||
fn smp_block_spread(
|
||||
dimension: crate::game::LevelDimension,
|
||||
from: horizon_core::position::BlockPos,
|
||||
to: horizon_core::position::BlockPos,
|
||||
canceled: &mut bool,
|
||||
) {
|
||||
let dimension = crate::game::smp_glue::dimension_id(dimension);
|
||||
let (from, to) = ([from.x, from.y, from.z], [to.x, to.y, to.z]);
|
||||
if !crate::game::smp_glue::world_allows(dimension, from, &[to]) {
|
||||
*canceled = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
// The casino in the server's game: its menus, and what its effects become
|
||||
// for a stock client (smp_casino's `Fx`): menu items, sounds and titles
|
||||
// through the console's `playsound` and `title`, the action bar, fireworks
|
||||
// and particles over a winner, a line for everyone. glue.rs calls it from the
|
||||
// command, menu and tick hooks with the SMP's state already locked; the
|
||||
// console commands it builds are run by glue.rs once that lock is let go.
|
||||
// Added to the game as `game::smp_casino_glue`.
|
||||
|
||||
use crate::game::{
|
||||
Game,
|
||||
native_server::NativeServerPlayer,
|
||||
smp_casino::{self, Casino, Color, Fx, Icon},
|
||||
smp_economy::{Economy, Out, Player},
|
||||
};
|
||||
use horizon_client::{
|
||||
items::ItemStack,
|
||||
lan::data::component_nbt,
|
||||
text::{self, Text},
|
||||
};
|
||||
|
||||
/// The crash's boss bars: one a player (a bar's players can't be a list of
|
||||
/// names, and tags don't reach a server's players), `smp:casino_crash_<i>`
|
||||
/// for the name in `bars[i]`, and the colour they all have.
|
||||
static BARS: std::sync::Mutex<(Vec<Option<String>>, &str)> =
|
||||
std::sync::Mutex::new((Vec::new(), "yellow"));
|
||||
/// The most bars at once; each taken off at the first hide of a run,
|
||||
/// whatever it held (a run before may have left one).
|
||||
const MAX_BARS: usize = 32;
|
||||
static CLEARED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
fn bar_id(i: usize) -> String {
|
||||
format!("smp:casino_crash_{i}")
|
||||
}
|
||||
|
||||
fn color(c: Color) -> u32 {
|
||||
match c {
|
||||
Color::White => text::WHITE,
|
||||
Color::Gray => text::GRAY,
|
||||
Color::DarkGray => text::DARK_GRAY,
|
||||
Color::Gold => text::GOLD,
|
||||
Color::Yellow => text::YELLOW,
|
||||
Color::Green => text::GREEN,
|
||||
Color::Red => text::RED,
|
||||
Color::Aqua => text::AQUA,
|
||||
}
|
||||
}
|
||||
|
||||
fn stack(icon: Icon) -> ItemStack {
|
||||
let mut stack = ItemStack {
|
||||
item: icon.item.into(),
|
||||
count: u32::from(icon.count.clamp(1, 99)),
|
||||
damage: 0,
|
||||
extra: None,
|
||||
};
|
||||
let title =
|
||||
serde_json::json!({ "text": icon.name, "italic": false, "color": icon.color.name() });
|
||||
stack.data_mut().custom_name = Some(component_nbt(&title));
|
||||
stack
|
||||
}
|
||||
|
||||
fn items(casino: &Casino, economy: &Economy, uuid: u128, now: i64) -> Vec<Option<ItemStack>> {
|
||||
casino
|
||||
.layout(economy, uuid, now)
|
||||
.into_iter()
|
||||
.map(|c| c.map(stack))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Opens (again) the player's casino menu on its view: a new window, titled
|
||||
/// for the game. False when it couldn't open.
|
||||
fn open(game: &mut Game<'_>, casino: &mut Casino, economy: &Economy, uuid: u128, now: i64) -> bool {
|
||||
let Some(view) = casino.seats.get(&uuid).map(|s| s.view) else {
|
||||
return false;
|
||||
};
|
||||
let items = items(casino, economy, uuid, now);
|
||||
let title = Text::literal(view.title()).with_color(text::DARK_GRAY);
|
||||
match game.native_open_menu(uuid, smp_casino::ROWS, title, items) {
|
||||
Some(w) => {
|
||||
if let Some(s) = casino.seats.get_mut(&uuid) {
|
||||
s.window = Some(w);
|
||||
}
|
||||
true
|
||||
}
|
||||
None => {
|
||||
casino.seats.remove(&uuid);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `/casino ...` (inside the player's command).
|
||||
pub(in crate::game) fn command(
|
||||
game: &mut Game<'_>,
|
||||
casino: &mut Casino,
|
||||
economy: &mut Economy,
|
||||
me: &Player,
|
||||
now: i64,
|
||||
line: &str,
|
||||
) -> Vec<Out> {
|
||||
let Some((mut out, view)) = casino.command(economy, me, now, line) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if let Some(view) = view {
|
||||
casino.sit(me.uuid, &me.name, view);
|
||||
if !open(game, casino, economy, me.uuid, now) {
|
||||
out.push(Out::Error("The casino couldn't open.".into()));
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// A click in a player's casino menu: the console commands its effects need,
|
||||
/// for after the SMP's lock.
|
||||
pub(in crate::game) fn clicked(
|
||||
game: &mut Game<'_>,
|
||||
casino: &mut Casino,
|
||||
economy: &mut Economy,
|
||||
uuid: u128,
|
||||
slot: i32,
|
||||
shift: bool,
|
||||
) -> Vec<String> {
|
||||
let Ok(slot) = usize::try_from(slot) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if slot >= smp_casino::SIZE {
|
||||
return Vec::new();
|
||||
}
|
||||
let now = chrono::Utc::now().timestamp_millis();
|
||||
economy.now = now;
|
||||
let fx = casino.click(economy, uuid, slot, shift, now);
|
||||
apply(game, casino, economy, fx, now)
|
||||
}
|
||||
|
||||
/// The casino's share of the server's tick: frames, rounds that end, the
|
||||
/// pot's hourly sweep. The console commands, for after the lock.
|
||||
pub(in crate::game) fn tick(
|
||||
game: &mut Game<'_>,
|
||||
casino: &mut Casino,
|
||||
economy: &mut Economy,
|
||||
now: i64,
|
||||
online: Option<&[u128]>,
|
||||
) -> Vec<String> {
|
||||
let mut fx = casino.tick(economy, now);
|
||||
// Once a second: crash bets of players who left.
|
||||
if let Some(online) = online {
|
||||
fx.extend(casino.gone(economy, online, now));
|
||||
}
|
||||
if fx.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
apply(game, casino, economy, fx, now)
|
||||
}
|
||||
|
||||
/// Carries out `fx`: menus and lines now, console commands returned.
|
||||
fn apply(
|
||||
game: &mut Game<'_>,
|
||||
casino: &mut Casino,
|
||||
economy: &Economy,
|
||||
fx: Vec<Fx>,
|
||||
now: i64,
|
||||
) -> Vec<String> {
|
||||
let mut commands = Vec::new();
|
||||
let mut players: Option<Vec<NativeServerPlayer>> = None;
|
||||
let mut shown = Vec::new();
|
||||
for f in fx {
|
||||
// Where a player is, asked once for the whole batch.
|
||||
let mut find = |uuid: u128, game: &Game<'_>| -> Option<NativeServerPlayer> {
|
||||
players
|
||||
.get_or_insert_with(|| game.native_server_players())
|
||||
.iter()
|
||||
.find(|p| p.uuid == uuid)
|
||||
.cloned()
|
||||
};
|
||||
match f {
|
||||
Fx::Out(Out::Tell(uuid, s)) => {
|
||||
game.native_tell(uuid, Text::literal(s).with_color(text::GOLD));
|
||||
}
|
||||
Fx::Out(Out::All(s)) => game.native_broadcast(Text::literal(s).with_color(text::GOLD)),
|
||||
Fx::Out(Out::Reply(s) | Out::Error(s)) => log::info!("[smp] casino: {s}"),
|
||||
Fx::Sound {
|
||||
to,
|
||||
sound,
|
||||
volume,
|
||||
pitch,
|
||||
} => {
|
||||
if let Some(p) = find(to, game) {
|
||||
let [x, y, z] = p.position;
|
||||
commands.push(format!(
|
||||
"execute in {} run playsound {sound} master {} {x:.2} {y:.2} {z:.2} {volume} {pitch}",
|
||||
p.dimension, p.name
|
||||
));
|
||||
}
|
||||
}
|
||||
Fx::Title {
|
||||
to,
|
||||
title,
|
||||
subtitle,
|
||||
color: c,
|
||||
} => {
|
||||
if let Some(p) = find(to, game) {
|
||||
let line = |s: &str, bold: bool| {
|
||||
serde_json::json!({ "text": s, "color": c.name(), "bold": bold })
|
||||
.to_string()
|
||||
};
|
||||
commands.push(format!("title {} times 5 40 15", p.name));
|
||||
commands.push(format!(
|
||||
"title {} subtitle {}",
|
||||
p.name,
|
||||
line(&subtitle, false)
|
||||
));
|
||||
commands.push(format!("title {} title {}", p.name, line(&title, true)));
|
||||
}
|
||||
}
|
||||
Fx::Bar {
|
||||
to,
|
||||
text: s,
|
||||
color: c,
|
||||
} => {
|
||||
game.native_action_bar(to, Text::literal(s).with_color(color(c)));
|
||||
}
|
||||
Fx::Fireworks(to) => {
|
||||
if let Some(p) = find(to, game) {
|
||||
let [x, y, z] = p.position;
|
||||
// High enough over the player that their blast (5 blocks) never hurts.
|
||||
for (dx, dz, colours) in [
|
||||
(-3.0, 0.0, "16766720,16733525"),
|
||||
(3.0, 1.5, "5635925,16777045"),
|
||||
(0.0, -3.0, "5636095,16733695"),
|
||||
] {
|
||||
commands.push(format!(
|
||||
"execute in {} run summon minecraft:firework_rocket {:.2} {:.2} {:.2} {{LifeTime:18,FireworksItem:{{id:\"minecraft:firework_rocket\",count:1,components:{{\"minecraft:fireworks\":{{flight_duration:1b,explosions:[{{shape:\"large_ball\",colors:[I;{colours}],has_trail:true,has_twinkle:true}}]}}}}}}}}",
|
||||
p.dimension,
|
||||
x + dx,
|
||||
y + 9.0,
|
||||
z + dz
|
||||
));
|
||||
}
|
||||
commands.push(format!(
|
||||
"execute in {} run particle minecraft:totem_of_undying {x:.2} {:.2} {z:.2} 0.6 1 0.6 0.4 60 normal",
|
||||
p.dimension,
|
||||
y + 1.0
|
||||
));
|
||||
}
|
||||
}
|
||||
Fx::Announce(s) => {
|
||||
log::info!("[smp] casino: {s}");
|
||||
game.native_broadcast(
|
||||
Text::literal(format!("[Casino] {s}")).with_color(text::GOLD),
|
||||
);
|
||||
}
|
||||
Fx::Show(uuid) => {
|
||||
// One picture per menu per batch.
|
||||
if !shown.contains(&uuid)
|
||||
&& casino.seats.get(&uuid).is_some_and(|s| s.window.is_some())
|
||||
{
|
||||
shown.push(uuid);
|
||||
let items = items(casino, economy, uuid, now);
|
||||
game.native_set_menu_items(uuid, items);
|
||||
}
|
||||
}
|
||||
Fx::Open(uuid) => {
|
||||
shown.push(uuid);
|
||||
open(game, casino, economy, uuid, now);
|
||||
}
|
||||
Fx::Boss {
|
||||
text: line,
|
||||
color: c,
|
||||
value,
|
||||
} => {
|
||||
let mut bars = BARS.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if let Some(c) = c {
|
||||
bars.1 = match c {
|
||||
Color::Green => "green",
|
||||
Color::Red => "red",
|
||||
_ => "yellow",
|
||||
};
|
||||
}
|
||||
let name = serde_json::json!({ "text": line, "color": "white" });
|
||||
for (i, _) in bars.0.iter().enumerate().filter(|(_, b)| b.is_some()) {
|
||||
let id = bar_id(i);
|
||||
commands.push(format!("bossbar set {id} name {name}"));
|
||||
commands.push(format!("bossbar set {id} value {value}"));
|
||||
if c.is_some() {
|
||||
commands.push(format!("bossbar set {id} color {}", bars.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Fx::BossPlayers(names) => {
|
||||
let mut bars = BARS.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let colour = bars.1;
|
||||
for (i, bar) in bars.0.iter_mut().enumerate() {
|
||||
if bar.as_ref().is_some_and(|n| !names.contains(n)) {
|
||||
*bar = None;
|
||||
commands.push(format!("bossbar remove {}", bar_id(i)));
|
||||
}
|
||||
}
|
||||
for name in names {
|
||||
if bars.0.iter().any(|b| b.as_ref() == Some(&name)) {
|
||||
continue;
|
||||
}
|
||||
let i = match bars.0.iter().position(Option::is_none) {
|
||||
Some(i) => i,
|
||||
None if bars.0.len() < MAX_BARS => {
|
||||
bars.0.push(None);
|
||||
bars.0.len() - 1
|
||||
}
|
||||
None => continue,
|
||||
};
|
||||
let id = bar_id(i);
|
||||
commands.push(format!("bossbar add {id} \"\""));
|
||||
commands.push(format!("bossbar set {id} max 100"));
|
||||
commands.push(format!("bossbar set {id} color {colour}"));
|
||||
commands.push(format!("bossbar set {id} players {name}"));
|
||||
bars.0[i] = Some(name);
|
||||
}
|
||||
}
|
||||
Fx::BossHide => {
|
||||
// Every bar taken off.
|
||||
let mut bars = BARS.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let all = !CLEARED.swap(true, std::sync::atomic::Ordering::Relaxed);
|
||||
let n = if all { MAX_BARS } else { bars.0.len() };
|
||||
for i in 0..n {
|
||||
if all || bars.0[i].is_some() {
|
||||
commands.push(format!("bossbar remove {}", bar_id(i)));
|
||||
}
|
||||
}
|
||||
bars.0.clear();
|
||||
bars.1 = "yellow";
|
||||
}
|
||||
}
|
||||
}
|
||||
commands
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// A player's command on the server: the SMP's own, when it is one.
|
||||
fn smp_perform_command(
|
||||
game: &mut crate::game::Game<'_>,
|
||||
player: &crate::game::native_server::NativeServerPlayer,
|
||||
command: &str,
|
||||
ran: &mut bool,
|
||||
) {
|
||||
if !*ran {
|
||||
crate::game::smp_invsee_glue::perform(game, player, command, ran);
|
||||
}
|
||||
if !*ran {
|
||||
crate::game::smp_glue::perform(game, player, command, ran);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// A player breaks a block: kept out of the land others claimed.
|
||||
fn smp_destroy_block(game: &mut crate::game::Game<'_>, pos: [i32; 3], canceled: &mut bool) {
|
||||
crate::game::smp_glue::guard(game, pos, canceled);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// An explosion's blocks: claimed land is spared.
|
||||
fn smp_explosion_detonate(
|
||||
game: &crate::game::Game<'_>,
|
||||
dimension: &str,
|
||||
blocks: &mut Vec<[i32; 3]>,
|
||||
) {
|
||||
crate::game::smp_glue::explosion(game, dimension, blocks);
|
||||
}
|
||||