Separate client, integrated-server and dedicated-server roles from connection state. Use roles for startup, presentation work and server dimension loading while preserving in-frame client simulation.
Co-Authored-By: OpenAI Codex (GPT-6.1) <noreply@openai.com>
#1428 made the in-frame world the default while a server's players lagged
behind it (signs, books, totems, keep_inventory and the other [server-thread]
issues). With the fixes of this stack a scripted single player session (walk,
mine, place, inventory, combat, eating, boats, minecarts, chests, furnaces,
beds, chat, signs, books, totems, keep_inventory, fishing, maps, saving and
reopening) gives the same results on the server thread as in the frame.
`--in-frame`, `--no-server-thread` or HORIZON_SERVER_THREAD=0 runs the world
in the frame; `--server-thread` still works. LAN guests, dedicated servers and
the command harness are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Players on the Alpha channel report single player as broken since v0.2.1
(#1265 made the integrated server thread the default again). On v0.2.11's
server thread, placed signs open no editor (#1380), held books don't open
(#1366), a totem doesn't save its holder (#1292) and death keeps the
inventory with keep_inventory off (#1284); the in-frame world and Stable
v0.2.0 do all four right. About 45 more [server-thread] issues are open.
`--server-thread` or HORIZON_SERVER_THREAD=1 turns it on, as before #1114;
`--no-server-thread` and HORIZON_SERVER_THREAD=0 still work. LAN guests and
dedicated servers are untouched. Temporary until the server thread reaches
parity (FEATURES 4zg).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A server's player (a LAN guest, and since the server thread the single
player too) always respawned in the Overworld. Its respawn anchor was
dropped when its action ended, and its save kept only an Overworld point.
- The guest keeps a respawn point outside the Overworld (respawn_elsewhere,
saved as the player's `respawn`) and has it in place while it acts, so an
anchor it uses is its own.
- guest_respawn respawns it in that point's level, waits there for the
chunks, then resolves the point through its block
(findRespawnAndUseSpawnBlock): beside the anchor, using a charge, or the
world spawn and block.minecraft.spawn.not_valid when the block is gone.
- `spawnpoint` in another level than the Overworld sets a forced point there
(SetSpawnCommand) instead of Overworld coordinates, and a forced point that
is no anchor holds where a player fits (isPossibleToRespawnInThis), in the
window's own game too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
handle_server_portal ignored End gateways, so on a server (dedicated, or
single player's server thread) no player could use one: the in-frame game's
gateway code moved only its own player.
A gateway that is not cooling down now takes a server player at once
(EndGatewayBlock.entityInside, triggerCooldown, setAsInsidePortal), within
the End, keeping its motion and look (Relative.DELTA and ROTATION). An exact
exit is reached straight away; otherwise the player waits at the destination
while it loads, and the exit is found or built there (the in-frame
resolve_gateway, shared through gateway_job).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a server (dedicated, or single player's server thread) each dimension is
its own level, but a command ran in whichever level was in place. So a guest
in the Nether running `execute in minecraft:overworld run setblock ...` got
"That position is not loaded", and `execute at <a player in another level>`
used the wrong level's blocks.
with_source now puts the source's level in place for the command
(CommandSourceStack.getLevel), as as_target already does for a player in
another level, and puts the old one back after. `execute at` takes the
entity's level (withLevel(entity.level())), and a player's level is the
guest's own (target_level) even while another level is in place.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new `levels` check (--server-thread) runs the host and a guest in different
dimensions: execute in ... tp, mobs ticking in two levels at once with unique
ids, rejoin and save/reload with the guest in the Nether, death there, the
host through a Nether portal alone, the guest through an End portal and the
exit portal alone. All of it already works on the server thread.
docs/server-levels.md says how the server's levels map onto vanilla's, what
the dedicated server and the server thread share, the cost of an extra level
and what's left. docs/server.md no longer says players can't change dimension.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>