93 Commits
Author SHA1 Message Date
d0d3e68ec4 SMP: the /vanish reminder sits on the action bar, not mid-screen (#298)
rdbt (operator, #mod-chat 11-05): the centred 'Vanished: only operators see
you' line covers the view. It is now an action bar line refreshed once a
second; unvanishing sends an empty action bar instead of clearing titles.
proof.py checks the action bar and that nothing shows mid-screen.

Co-authored-by: Horizon agent <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 18:38:01 +01:00
0da4e7d52e SMP: say 0.35.0 at start; claims proof skips the engine's start-up error (#286)
glue.rs's VERSION still read 0.34.0 after #261 (0.35.0). proof.py's claims mode checks the version line and counts errors from the server's Done on (the engine logs one "No key layers" error while loading the world).

Co-authored-by: Horizon agent <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 15:31:11 +01:00
aad3b35a3a SMP: /ledger minted says partial only when the end read misses hours (#263)
* /ledger minted: say "partial" only when the end read stops short of the six hours

The official audit.log is ~9 MB (~1.8 MB a day), so a 1 MiB end read
covers the six hours; the note now depends on whether the lines read
reached back past the window's start, not on the file's size.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* proof.py: config.json now has a reports section

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Horizon agent <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 14:52:13 +01:00
6e79b7f740 SMP 0.35.0: claims stop griefing from outside, chat pings (#261)
* SMP 0.35.0: claims stop griefing from outside, chat pings

Claims: blocks placed (or fire, buckets, spawn eggs) against a claim's
border from outside, dispensers acting into a claim, lava lighting a
claim's blocks from outside, projectiles of non-members (buttons, targets,
chorus, pots, TNT, crystals, pearls, potions, animals, frames), animals,
frames and stands used by non-members, frames and animals hit by blasts
are all kept. Trust lookups no longer allocate.

Chat pings (jaszka's ask): naming an online player in chat, or /msg to
them, plays the experience orb sound to them alone (3 s apart, never the
sender), /pingsound on|off.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP 0.35.0: rustfmt; the chat queue's module has plain comments

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP 0.35.0: the dispenser hook binds its facing as a parameter

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP 0.35.0: no attribute on the impact helper

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP 0.35.0: README for the claims' new guards and chat pings

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP: log each chat ping on the server

One info line per ping (at most one each 3 s per player), so bots and ops can see pings work.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP: test on eaa7da4, the Horizon the minimap uses

Native mods on the newest hooks (359) must share one Horizon for the together check; r9.1 (52882c1) descends from eaa7da4 with the same hooks.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP: end crystals always guarded in claims; proof SMP_PROOF=claims

A snowball or a punch from someone not trusted no longer sets off a crystal in a claim, even in worlds whose config.json lists protected entities from before. proof.py's claims mode runs two bots on a dedicated server: blocks and fire against the border, dispensers' water and arrows, a crystal, a pearl, TNT by animals and a frame, shears, and the chat pings.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP README: end crystals always guarded

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Horizon agent <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 13:45:57 +01:00
levzzz c2d42eba1b Merge pull request #214 from eltanschauung/minimap-outline-coordinates
Minimap: add optional outline styles and coordinate display
2026-11-05 17:19:17 +05:00
levzzz 070bddc417 Merge pull request #260 from horizon-rust/smp/report-ledger-rtp10k
SMP 0.34.0: /rtp to 10,000 blocks every 5 minutes, /report, /ledger
2026-11-05 17:16:17 +05:00
levzzzandCodex f3d5967ae6 Merge main and preserve control-tool support for both layouts
Co-Authored-By: Codex <[email protected]>
2026-11-05 17:12:28 +05:00
levzzzandCodex 72c0912c7b Fix ledger accounting for pool funding and starting balances
Mark truncated hourly totals and cover real economy writes in a regression test.

Co-Authored-By: Codex <[email protected]>
2026-11-05 17:11:55 +05:00
crystaldevandmakscoder 89020e2062 Fix native.py: pick the newest nightly by date, and build horizon-ctl from its own package (#229)
latest_nightly() chose the newest nightly-source tag by comparing the ref
string, so two tags on the same date were ordered by their short SHA and it
could return an earlier build (2026-11-04-67dad0d over the newer
2026-11-04-3fb4c31, both on 2026-11-04). Pick the newest by the tag's date
and break a same-date tie by the tagged commit's own date.

cargo(action="build") named --bin horizon-ctl under -p horizon-client, but
horizon-ctl is a bin of horizon-client-lib (its path is the client's
src/bin), so the build failed with "no bin target named horizon-ctl in
horizon-client package" (only check worked). Build the ctl under its own
package: -p horizon-client-lib --bin horizon-ctl.

Closes #220
Closes #222

Co-authored-by: makscoder <[email protected]>
2026-11-05 12:58:03 +01:00
Horizon agentandClaude Opus 5.5 ed1a281c9c proof.py: describe the /rtp range and the /report and /ledger step
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 12:53:20 +01:00
Horizon agentandClaude Opus 5.5 e44816b65a SMP 0.34.0: /rtp 500-10,000 blocks every 5 minutes, /report, /ledger
- /rtp: rtp_max_distance 5000 -> 10000, rtp_cooldown_seconds 1800 -> 300
  (defaults; the official config.json has no rtp_* keys, so they apply).
  Same safety: no water, lava or void, chunks loaded with forceload.
- /report <player> <reason> for everyone: a reason is required, one report
  per player every reports.cooldown_seconds (120). Appended to reports.log,
  told at once to the level-3 operators on, logged in the server log; an
  operator who joins later hears how many came in the last 24 hours.
  /reports [page] lists them for operators. (No Kira route exists for
  messages to Discord; Kira only takes the market/economy pages.)
- /ledger for level-3 operators: audit.log already records every coin
  movement before it happens; /ledger [page], /ledger <player> [page] and
  /ledger minted (coins made and destroyed per hour, last 6 h) read the
  end of it (1 MB) when asked, nothing on the tick. Economy::adjust lines
  now carry flow: minted|burned so the hourly count is exact.
- utc_minute and tail() moved to smp_store for both.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 12:39:24 +01:00
e53ad8220b SMP 0.33.0: no daily sale or /pay caps, no resale delay; a 20% price floor instead (#228)
* Remove SMP daily coin cap on sales and payments

Co-Authored-By: Codex gpt-6.1-sol <[email protected]>

* Remove SMP daily per-item sale limit

Co-Authored-By: Codex gpt-6.1-sol <[email protected]>

* Allow immediate resale of SMP market purchases

Co-Authored-By: Codex gpt-6.1-sol <[email protected]>

* SMP 0.33.0: a 20% price floor carries what the daily caps did

With no daily sale caps, the market's moving price is what bounds a farm:
- min_factor 0.6 -> 0.2 (a config still on the old default gets 0.2 at load)
- an item's depth is at most 50 items a 1% (was up to 400), so the cheap
  items farms make reach the floor within 10,000 sold; a family takes its
  step from its cheapest member, so every member does
- tests: 10,000 of any item sold a minute at a time end at the floor and
  bring under half their base value (diamond 21%, wheat 44%), and the price
  comes back within a day; buying and selling straight back (no resale
  delay) never earns, for every item traded both ways, 5 amounts, from a
  fresh price, the floor and the cap (495 round trips)
- proof: 1,000 wheat sold over four minutes, 250 a minute, the price lower
  after each sale

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* SMP proof: the cobblestone stack's comment for the new depth

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Codex gpt-6.1-sol <[email protected]>
Co-authored-by: Ludovic Marie <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 00:14:07 +01:00
Ludovic MarieandClaude Opus 5.5 43fb2513a2 smp: /rtp (/wild): random safe spot 500-5000 blocks out, 30 min cooldown (#241)
* smp: /rtp (/wild) to a random safe spot 500-5000 blocks from the spawn, 30 min cooldown

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: /rtp draws until enough points fall inside a close border

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: /rtp undo as a struct; rustfmt

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: /rtp proof (2 clients, flat world) and SMP_PROOF=rtp tick cost on a normal world; per-/rtp read cost in the log

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: proof checks the /rtp landing with execute ... run say (block tags aside)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-04 21:02:45 +01:00
eltanschauungandCodex 13d6b9fbaa Add optional minimap outline styles and coordinate display
Preserve upstream defaults and existing settings. Include the supplied screenshot, settings regression checks, and the native tool pins and split control-target support needed to validate this renderer integration.

Co-Authored-By: Codex <[email protected]>
2026-11-03 23:16:37 -05:00
ee1620f438 smp: /vanish for operators (#155)
An operator of level 3 leaves the Tab list and world of every player below
level 3 (in any game mode), with no join or leave messages for them;
operators still see them. A subtitle stays on screen the whole time. Vanished
players aren't counted online, don't hold the night up, aren't announced
AFK, and can't be reached by name (/tpa, /trade, /coinflip, /playtime).
Kept in vanish.json. Needs horizon#7003 (native_hide_player).

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Ludovic Marie <[email protected]>
2026-11-04 00:22:13 +01:00
a0dba26666 SMP: emergency switches for operators (/smp off|on|status) (#149)
Operators of level 3 turn parts of the SMP off while the server runs,
by name or all at once (land protection only by name). A part off refuses
its commands and menu clicks and its timed work waits; nothing held is
lost. Kept in switches.json across restarts, logged and audited.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Ludovic Marie <[email protected]>
2026-11-04 00:08:24 +01:00
82e29462a9 SMP: the sidebar no longer lists the richest players (#148)
The sidebar keeps the player's own block (name, balance, playtime, online)
and the address. /baltop still ranks the richest. board.top is ignored.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Ludovic Marie <[email protected]>
2026-11-03 22:35:19 +01:00
AkirabaneandClaude Sonnet 5.5 09f69374d9 smp: /spawn lands on a safe spot within spawn_radius of the spawn point (#190)
/spawn teleported to one fixed point, which on the anarchy server can sit in
a lava cast. After the tp it now runs vanilla's spreadplayers around the
spawn point with places.spawn_radius (default 250, like the live server's
respawn_radius), which picks a random column that is not fluid, fire or
magma and has solid ground, retrying until one is found. Warps, homes, /back
and /tpa are unchanged. Radius 0 keeps the exact point.

Refs #144

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-11-03 19:41:23 +01:00
Ludovic MarieandClaude Opus 5.5 5628be3e6b voicechat-server: proximity voice chat on Horizon's own server (native server mod) (#173)
* voicechat-server: proximity voice chat on Horizon's own server

A native server mod (voicechat_server 1.0.0): the server half for voice chat
clients that speak Simple Voice Chat 2.6.x's protocol, such as azetech's
Complex Voice Chat. The handshake rides Horizon's mod messages on voicechat:
channel names; voices go over UDP through the server, sealed per player with
AES-128-GCM, to the players nearby in the same dimension or in the speaker's
group. A player without a voice client is never sent anything, and the UDP
port opens only when the first voice client asks.

The relay is a bundle crate (horizon-mixins 0.6.0): every native mod now pins
horizon-mixins d9c83d7, since native.py builds them with one, and package
includes a bundle's crates.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* voicechat-server: replay-proof re-authentication; packages carry LICENSE

- A secret belongs to the first address that authenticates with it: an
  Authenticate copied and sent from another address is refused however long
  the client was quiet (the 5 s move rule is gone). Exact replays are dropped
  too: the last 64 control packets' nonces per player, and a 64-wide window
  on voice packets' sequence numbers.
- A client the server stops hearing for 10 keep-alives gets a fresh secret
  over the game connection (Complex Voice Chat 2.1.0 reconnects on any
  voicechat:secret), keeping its group; the old key then opens nothing. So
  a NAT that rebinds recovers without a rejoin (2.1.0 never re-sends
  Authenticate after its ack, so the old move rule never helped it).
- Secret requests: one answer a second a player (more requests meanwhile
  get one answer), the snapshot replaces what still waited. Group and state
  changes 2 a second (burst 10). At most 512 messages wait per player.
- Client pings aren't echoed (the server never pings; SVC's server doesn't
  echo either), and the relay thread never spins on a socket error.
- The glue lists the players on a message only when the sender is new, not
  on every voice chat message.
- native.py package puts native/<mod>/LICENSE into the .hnmod as
  mixins/<id>/LICENSE (Horizon's bundle reader accepts LICENSE* there); the
  CI check requires it. Every native mod's package now carries its licence.

Tests: a_replayed_handshake_after_a_silence_moves_nothing,
a_client_the_server_stops_hearing_gets_a_fresh_secret,
repeated_secret_requests_and_group_changes_stay_bounded.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-03 04:16:31 +01:00
Ludovic MarieandClaude Opus 5.5 58fbad4a85 SMP 0.31.0: the auction house lists whole stacks (#183)
rdbt's ask: /ah refused anything that wasn't a plain item. A listing now
carries the whole stack (enchantments, name, damage, lore, a shulker box's
or a bundle's contents, every component) as the game writes it in player
files (ItemStack.CODEC NBT, hex), through listing, purchase, auction win,
mail and returns, saved in economy.json in the same step as the money.
Given back with native_give_stack; what doesn't fit waits in the mail.

Taken only when it reads back equal; not market charts, nor stacks over
32 KiB of data. Creative players are still refused. Listings and mail from
0.30 (no `stack`) load unchanged and give plain items as before.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-03 04:04:06 +01:00
Ludovic MarieandClaude Opus 5.5 b22a9c42a3 SMP 0.30.1: the claim-free zone covers every dimension (#162)
rdbt: the zone around 0 0 should apply in the Nether and the End too.
Claims there are refused and dropped at start in every dimension.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-02 17:01:15 +01:00
Ludovic MarieandClaude Opus 5.5 6ab145fce5 SMP 0.30.0: a claim-free zone around 0 0 (claims.free_radius) (#159)
Operators asked for the land near spawn to be free for all: no one may
claim a chunk that touches the zone, and claims already there are dropped
at start, each logged. Off by default (0).

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-02 16:09:20 +01:00
c240394cde smp: simplify the economy: no taxes, fees, Treasury, bank, jobs or futures (#153)
* smp: simplify the economy, drop the tax code

No more VAT on auction sales, weekly land and wealth taxes, /taxes and
/eco taxes, tax on market trades or teleport fees. The Treasury stays
(fees and house edges in, operators' grants out) with /treasury, now in
its own small module. Old taxes/tax_percent/fees config keys are ignored
and owed land tax is forgiven.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: remove the Treasury, the bank, jobs and futures, and every fee

Operators make money with /eco give <player> <amount> <reason> (everyone
reads it) and take it with /eco take. The auction listing fee and the
coinflip/lottery fee are gone. The casino's pot gets its float once, made
for it, then keeps the house edge.

A world from before this gets its bank savings and open futures margins
back at the first start; the Treasury, insurance fund, contracts and land
tax owed are dropped.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* smp: keep the casino's float mark in economy.json

The "pot got its float" flag lived in casino.json while the money went to
economy.json, so a lost or unreadable casino.json, or a crash between the
two saves, made up to 20,000 again on the next start. The mark now sits in
the economy's ext, written in the same file as the pot.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Ludovic Marie <[email protected]>
2026-11-02 15:02:43 +01:00
Ludovic MarieandClaude Opus 5.5 d57056b937 SMP 0.29.1: an operator may open their own ender chest with /endersee (#156)
/invsee on yourself stays refused (it would move stacks into the same
inventory); your own ender chest is a second container, so /endersee works.
Asked by bunchy7s (operator) on Discord.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-02 13:36:10 +01:00
Ludovic MarieandClaude Opus 5.5 61e99d5df7 SMP 0.29.0: carry the old price history and futures entries over
A book from before 0.29 quotes its history in the old mid of buy and sell
(diamond 250); the one price is 200. Scaled once at load (the book now
records its bases), so charts, 1 h/24 h moves, the news and the futures'
TWAP see no cliff; open futures positions get the same ratio on their
entry, so none gains or loses by it. Each minute's band opens at the
loaded price rather than at the base.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 00:28:31 +01:00
Ludovic MarieandClaude Opus 5.5 59f2388a0f SMP 0.29.0: one market price per item, to buy and to sell
Ludovic: the market's buy and sell prices didn't make sense (diamond bought
for 400 and sold for 100, two numbers everywhere). Each item now has one
price, the geometric mean of the old pair (diamond 200, iron 15, wheat 2),
shown in /worth, /market, /shop, the chart maps and market.json (`price`;
`buy`/`sell` repeat it on the sides the market trades).

- A trade of N is priced along the curve it moves (each unit moves the log
  price by 1%/depth): buying N and selling them back returns exactly what
  was paid less the tax, for 1, 64 or past the band. Rounding goes against
  the trader (up when buying, down when selling).
- Prices move as trades happen; all trades together move an item at most
  5% a minute: past that a purchase is cut short and a sale keeps the
  rest (flat pricing at the edge would let slow buying plus a flat dump
  earn). At the 0.6/1.6 factor bounds the rest goes at the bound.
- Items linked by recipes share one moving price, a block moving it as its
  9 ingots do; the vanilla-recipe test checks every item at the worst
  drift too, and finds a block sold for its ingots once unlinked.
- The tax is its own receipt line ("Tax 2%: -12 coins. You get 583
  coins."). Daily sell limits unchanged.
- A config with two prices gets one at load, logged ("one price now").

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 00:20:33 +01:00
Ludovic MarieandClaude Opus 5.5 31d77513fe SMP 0.28.0: the casino's daily win cap (10,000 net a day, configurable)
A player whose net casino winnings today reach casino.daily_win_cap
(10,000, same as the loss cap) is refused new bets until 00:00 UTC, with
a message saying why. The round that crosses the cap is paid in full; a
blackjack double inside a hand already dealt is still allowed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 22:43:50 +01:00
Ludovic MarieandClaude Opus 5.5 5ba617927f SMP 0.27.0: futures in the game (/futures menu, minute marking)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 22:43:47 +01:00
Ludovic MarieandClaude Opus 5.5 7257e32237 SMP futures: the rules (perpetuals on market prices, house = insurance fund)
Not wired into the game yet: the glue waits for the market's mark_price/twap/volume API.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 22:43:46 +01:00
Ludovic MarieandClaude Opus 5.5 7ec0a0516d smp proof: the selling limit counts Steve's /pay (#139), Moves may read 0.0% on a minute-old history
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 22:36:10 +01:00
Ludovic MarieandClaude Opus 5.5 c3839da0ef smp 0.26.0: a moving market, /market, price charts on maps, pages pushed to Kira
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 21:02:28 +01:00
Ludovic MarieandClaude Opus 5.5 8295b4c1ef smp 0.25.0: /invsee and /endersee for operators
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 19:42:27 +01:00
Ludovic MarieandClaude Opus 5.5 964325b819 SMP 0.24.0: /pay received counts toward the daily selling limit
Selling up to the cap on alts and paying it all to a main bypassed the daily sell
limit (reported by pointofpressure). A /pay now checks the receiver's remaining
daily_sell_coins and is refused past it; a payment made counts toward it. Trades
and auction sales are unaffected.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 19:30:11 +01:00
Ludovic MarieandClaude Opus 5.5 693205032b SMP 0.23.0: the casino (roulette, slots, crash, blackjack), paid from its own pot
/casino opens a lobby menu; each game is a chest menu a stock client plays,
animated at most 5 pictures a second per open menu and only while a round
moves, with sounds, titles, the action bar, a boss bar for crash, fireworks
and a line for everyone on a jackpot.

- European roulette (2.70% edge), slots with a published paytable (94.2%
  paid back), one shared crash round (96%), blackjack S17 3:2 (~1% edge).
- Draws by the server (ChaCha20 keyed from the system) before the
  animation. Bet limits, a daily loss cap a player, a cooldown.
- Bets are held, then settled once through settle_pool into the casino's
  pot (capped, never minted); hourly the pot above its float goes to the
  Treasury (casino_profit), below it the Treasury tops it up (casino_float).
- Closing the menu or leaving never loses a round.
- casino.json: the day's ledger, wins, totals. proof_casino.py plays every
  game on a real server with two clients.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:59:50 +01:00
Ludovic MarieandClaude Opus 5.5 409cac606e smp 0.22.0: nicknames for operators only
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:24:39 +01:00
Ludovic MarieandClaude Opus 5.5 219c9302d9 SMP 0.21.0: daily contracts (/jobs), paid from the Treasury
Four contracts a day from farm, mine and mob produce; a delivery of 64 plain items
pays the market's sell price +30%, never over 90% of its ask (rechecked at
delivery), from the Treasury. 8 deliveries a contract, 2 a player a day, at most
10% of the Treasury a day, survival/adventure only.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:18:13 +01:00
Ludovic MarieandClaude Opus 5.5 bb97027039 SMP 0.20.0: /eco stats, the daily economy report, web/economy.json
/eco stats: the supply and where it sits, what the server made and destroyed
today (new per-kind flows in economy.json), the day's taxes, Gini and top-10
share. At 00:00 UTC everyone reads the day before; 60 daily snapshots kept in
ext.report. web/economy.json once a minute, written off the tick thread, with
every Treasury movement and the tax code, for /hub.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:13:49 +01:00
Ludovic MarieandClaude Opus 5.5 27bfc9da13 SMP 0.19.0: the bank (/bank), savings paid by the Treasury
Deposits wait in the `bank` pool; interest 0.1% a day on up to 10,000 coins,
paid at 00:00 UTC from the Treasury on the day's lowest amount (no
deposit-before-midnight trick), at most 5% of the Treasury a night, pro rata.
At most 25,000 saved. The wealth tax counts savings. No loans.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:08:26 +01:00
Ludovic MarieandClaude Opus 5.5 fa61a38111 SMP 0.18.0: travel fees to the Treasury, a daily reward for playing
Teleports cost a fee (home 5, warp 10, back 10, tpa 10, spawn free), checked when
the command runs and paid to the Treasury when the teleport happens; one called off
costs nothing and keeps /back and the cooldown. The daily reward waits for 10
minutes of play that day (moving or commands), so alts that only log in get
nothing. Proof: fees and delay off to keep its sums; config_keys gets `auction`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 18:04:22 +01:00
Ludovic MarieandClaude Opus 5.5 7c850a3056 SMP 0.17.0: the auction house (/ah)
Players sell to players: fixed-price listings or timed auctions, browsed
in a chest menu by category (or a search), cheapest a unit first.

- Listing fee 1% (min 1 coin) and 5% VAT on each sale go to the Treasury.
- Listed items leave the inventory at once; unsold ones, auction wins and
  what didn't fit come back by mail (/ah claim, or the menu's mail page).
- A purchase is one step under the SMP's lock: the listing leaves first,
  so of two buyers at once the second finds it gone.
- Bids are held in the `auction` pool; the outbid get theirs back at once;
  a bid in the last 60 s moves the end back to 60 s; offline sellers are
  paid and get a note when they're back.
- Listings, bids, mail and notes are written in economy.json with the
  money (ext.auction): a crash can't split items from coins.
- Plain items only until native_give_stack is stamped.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 17:51:31 +01:00
Ludovic MarieandClaude Opus 5.5 3f115b7e06 SMP: the pools other parts use aren't dead code in the game build
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 17:47:43 +01:00
Ludovic MarieandClaude Opus 5.5 a864f877ec SMP 0.16.0: a state Treasury, nobody makes money, the tax code
Every tax, fee and house edge now goes into a Treasury pool kept in
economy.json with the balances; operators pay only from it, with a reason
everyone sees (/treasury pay, logged as `grant`). /eco give, /eco set and
/eco give * are gone: nobody can make money, operators included. /eco take
moves a cheat's gains into the Treasury.

- smp_economy: system pools (`pools`: treasury, insurance, casino...),
  to_pool / from_pool / pool_move / settle_pool, each one audit line; the
  Treasury's income and spending by kind (today, all time) and its last 50
  movements; `ext` for other parts' state written in the same step as the
  money. award()'s fee goes to the Treasury.
- smp_tax: the tax code (VAT 5% for the auction house, land tax 5 coins a
  week per chunk past 4, wealth tax 1/2/3% above 50k/250k/1M a week),
  collected on Monday 00:00 UTC (an O(1) check each second), unpaid land tax
  owed and blocking new claims; /treasury, /treasury log, /eco taxes,
  /eco taxes pay.
- proof: funds players from a seeded Treasury instead of /eco give, and
  checks /treasury, /treasury log, /eco taxes and the refusals.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 17:39:49 +01:00
Ludovic MarieandClaude Sonnet 5.5 6c2a827c34 docs: point native-mod build instructions at the Mods page
"Settings → Game → Native mods (experimental)" no longer exists. The launcher builds
native mods from the Mods page (Build on the native build row); the game lists and
toggles them under Options → Mods. Prose only: no sha256, file or version changes.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-01 02:52:17 +01:00
Ludovic MarieandClaude Opus 5.5 3395149802 SMP 0.15.0: nicknames that can't pass for someone else
rdbt (Team moderator) reported /nick abuse on the official server. Nicknames now:
- show as ~name in chat, the Tab list and the sidebar;
- are compared case-insensitively, with _ dropped and look-alikes folded (0/o, 1/i/l, 3/e...);
- are refused when equal to, or containing, a known player's name (economy accounts, usercache.json), an
  operator's, a Team member's (nicks.protected) or another player's nickname, or when they read as a reserved
  word (server, console, admin, mod, owner, staff, op, horizon, kira, notch, mojang, herobrine...);
- need nicks.min_playtime_minutes (60) of play first, operators excepted; the chat filter and cooldown stay;
- that break these rules are taken off at start, each logged.

/pay, /tpa, /trade, /playtime, /tpaccept, /tpdeny and /eco take a nickname where they take a player's name;
/nick alone says how to take it off. The proof covers each rule end to end.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 00:58:13 +01:00
Ludovic MarieandClaude Opus 5.5 3749d679bd SMP 0.14.0: the sidebar as an SMP scoreboard, the player's own block first
Title "Horizon SMP": the player's name (their nickname if set), balance,
playtime and the players online; then the three richest; then the
server's address (board.footer, play.playhorizon.dev). The ranking is still
built once for everyone, on a balance change or every refresh_seconds; the
players' own lines are looked at on the same refresh_seconds and sent only
where they changed (and to newcomers). 0.13's untouched defaults (Richest
players, top 10) move to the new ones. Feedback from rdbt (Team moderator).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 23:46:25 +01:00
Ludovic Marie d933c333e6 Merge pull request #114 from horizon-rust/feat/smp-nick
SMP 0.13.0: nicknames (/nick, /realname)
2026-10-31 22:59:15 +01:00
Ludovic MarieandClaude Opus 5.5 c86a73887a SMP 0.13.0: nicknames (/nick, /realname)
/nick <name> and /nick off for players, /nick <player> <name|off> and
/realname <nick> for operators. The nickname shows in chat and the Tab list
(horizon API 62: native_set_nickname), the hover keeps the real name, and
the log, the anticheat and Discord keep the real one. Rules: 3-16 letters,
digits or _; never a known player's name, an operator's or another
player's nickname; through the chat filter (native_text_allowed); a
10-minute cooldown. Saved in world/horizon-smp/nicks.json.

Also: the redundant 'eco give * <amount>' literal is gone (the engine left
it out: '*' isn't a command word; <player:word> takes it).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 22:55:57 +01:00
Ludovic Marie 6d9e3a2064 Merge pull request #59 from horizon-rust/docs/no-wasm-docs
Docs: drop the WebAssembly mod wording
2026-10-31 22:36:23 +01:00
Ludovic MarieandClaude Opus 5.5 f56752d74f SMP 0.12.0: /shop menu, daily selling limits, no profitable recipe loop, /money and /eco give *
- /shop: the market as a 6-row chest menu: categories (config.json `shop`), a click buys one, a shift-click 64,
  a click on a stack of yours sells it, "Sell all"; balance, today's limit and help in the bottom row. Through the
  market's own rules; items move by the console's clear/give, measured before and after.
- Market: buy always dearer than sell (else the sale closes), no recipe chain makes a sold item for less than it
  sells (smp_recipes, Bellman-Ford over the recipes; the tests walk every vanilla recipe when the data is there),
  daily limits per player (2,000 coins, 640 of each item, market.json), checked arithmetic, item ids validated.
- 56 default prices in 7 categories; a config still holding the 18 old defaults gets the new ones.
- /money give|take|set (= /eco), /eco give * <amount> for everyone on; recipients are told; all logged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 21:13:11 +01:00
Ludovic Marie 455a8b800f Merge branch 'feat/smp-presence' into feat/smp-shop 2026-10-31 20:47:27 +01:00