Skip to content

Releases ​

Every server package ships at the same version, so one set of notes covers the server and its packages. These notes come from the server's changelog. The newest 6 of 37 releases are below; the full changelog has the rest.

v0.20.0

minor

5 new · 11 fixes and changes · 4 breaking

New 5

  • Run every command from one registry. /tps, /version (/about), /debug, /ban and /pardon now register into the same @jsprismarine/commands registry as the vanilla set, so /help lists them and the remote console completes every command name rather than these five alone. /ban and /pardon still complete a name from the players online and accept one who is offline.

    Breaking: what to update

    Removed with the second dispatcher: the Command class, CommandArguments, the Commands namespace, CommandManager.registerCommand, getCommand, getCommands, getCommandsList and getDispatcher, the commandRegister event and CommandRegisterEvent, and vanillaPermissionOf, which is now commandPermissionOf. asyncCommand is gone; deferCommandWork and collectAsyncCommands move to command/deferred.

    0df23d5
  • The query protocol is part of the server's networking now, with a new query-port setting beside enable-query, which stays on by default.

    Details

    A query-port equal to port, which a fresh config writes, answers on the RakNet socket as before; any other port gets a UDP socket of its own. Query replies now require the challenge token from the handshake, so a forged source address gets no status reply, and full stat requests get the full key list and player names. Basic stat replies follow the protocol, with the host port as a little-endian short.

    Breaking: what to update

    QueryManager, Server.getQueryManager() and the queryToken kernel token are removed, NetworkDispatcherOptions no longer takes a query option, and a RakNetTransportSource needs sendBuffer.

    dc2dfdd
  • Remove the legacy recipe manager. Crafting runs on the content build's recipe book only: CraftingDataPacket is built from it and an ItemStackRequest is resolved against it, so the two always agree on net ids. A content build that produced no crafting payload now sends no recipes, where it used to fall back to a second, differently numbered list.

    Breaking: what to update

    Removed: Server.getRecipeManager, Server.getStationRegistry, recipesToken, stationsToken, the recipeRegister event and RecipeRegisterEvent, and the crafting/ RecipeManager, Recipe, RecipeIngredient, VanillaRecipes and CraftingStation modules. Add recipes through a pack's recipe definitions instead.

    4bb200f
  • The server now names every connection itself, so transports other than RakNet can plug in without their clients' identities colliding.

    Details

    A ConnectionId is allocated per accepted connection from one sequence every transport shares (1, 2, 3 in accept order, never reused), and the session registry, per-connection frame queues, and inbound and outbound packet traces all key on it. A client reconnecting from the same address and port is a new connection with a new ID.

    The transport seam changes with it. TransportConnection.token is replaced by id and gains address, the client's IP address and port. Transport.onDisconnect listeners receive (id, address, reason) and Transport.onFrame listeners (payload, id), and onRaw is optional because only RakNet carries datagrams from hosts that are not connected. SessionManager.add, has, get and remove take a ConnectionId. BaseTransport, KeyedTransport and MultiTransport hold the subscriptions, per-connection ordering, wire-key mapping and transport merging that every transport shares; MultiTransport owns the allocator and hands it to the transports it builds, and Server.getMetadata() no longer needs RakNet to be enabled; RakNetTransport takes the allocator as a third argument. ClientConnection.getConnectionId() and ClientConnection.getAddress() work whichever transport carried the client; ClientConnection.getRakNetSession() is deprecated and throws for a client that did not connect over RakNet. The raknetDisconnect event fires for every transport's clients.

    16e3296
  • @jsprismarine/auth covers both ends of a Bedrock login.

    Details

    XboxAuthProvider signs in to Xbox Live through prismarine-auth, an optional peer dependency loaded only when a provider signs in, and presents the chain and multiplayer token Minecraft services issue for its key. createAuthProvider builds a provider by name, and KeyedAuthProvider is the base both providers share. A provider's getMultiplayerToken() returns its token, and @jsprismarine/client signs its NetherNet offer with it, as a signed-in game client does. The server's login verification moved into the package as verifyLogin, exported from @jsprismarine/auth/server, beside the values both ends agree on in @jsprismarine/auth/protocol.

    Every JWT and JWS is now signed, verified and decoded by jose rather than by hand or through fast-jwt, which no package depends on any more. verifyLogin fetches the issuer's keys through jose's remote key set, and allows a minute of clock drift on a token's expiry as well as its start.

    Breaking: what to update

    @jsprismarine/prismarine/network/LoginVerifier is removed; import verifyLogin, LoginRefused, MojangKeys and useLoginKeys from @jsprismarine/auth/server, and TOKEN_ISSUER from @jsprismarine/auth/protocol. MojangKeys takes a fetch implementation instead of a key set loader and a clock. SessionEncryption.begin returns a promise.

    2f505cd

Fixes and changes 11

  • Build the shipped block-state schemas from @jsprismarine/blocks' vanilla palette instead of reading the generated catalog a second time, so one package owns which states a block has and what each accepts. BlockStateValue is now @jsprismarine/blocks' type, re-exported unchanged, and schemaFromModel turns a BlockStateModel into the NBT-typed schema the runtime id hash uses. Runtime ids do not change.

    8c2054b
  • Give each data-driven mob one runtime id. Its client-facing body used to draw a second id after the runtime drew the first, so the wire, the world's entity map and the runtime named the same mob by two numbers bridged by a lookup table. The body now carries the runtime's id, and Entity and GenericEntity take an optional runtimeId for a body whose id was drawn elsewhere.

    bfa224c
  • New package @jsprismarine/nethernet holds the NetherNet pieces a server and a client share: HTTP signaling, the signed a=identity on SDP answers, the LAN advertisement codec and the ES384 JSON Web Signatures Bedrock uses. @jsprismarine/prismarine uses it for its NetherNet transport and its encryption handshake.

    e498e81
  • The server accepts Bedrock clients over NetherNet, the WebRTC transport Bedrock Dedicated Server defaults to, alongside RakNet.

    Details

    A client joining by address signals over HTTP on the TCP side of the game port (GET /v1/join and POST /v1/join/{networkId}), and every answer carries the server's signed identity, whose P-384 key the server keeps in nethernet-identity.pem in its data directory so returning players are not asked to trust a new one. With enable-lan-visibility on, it answers NetherNet discovery on UDP port 7551, so players on the local network see it among their LAN games and join it over NetherNet. The advertisement carries the same MOTD, version and player counts as the RakNet server list entry, and the player count now covers every transport's clients. NetherNetTransport carries the peers of a nethernet server, adding and removing the 0xFE batch id the NetherNet wire leaves out.

    40bef5d
  • ServerName.ownPlayerCount() hands the advertised player count to whoever owns the server name: the RakNet sockets then report their sessions through ServerName.setSessionCount, which no longer changes the count. JSPrismarine takes the count over, so a RakNet socket no longer briefly overwrites a count that includes NetherNet players with its own session count.

    5409d2e
  • Remove ProtoChunk, ProtoChunkDetachedError, HEIGHTMAPS and the ProtoChunk* payload types from @jsprismarine/chunkgen.

    Details

    Nothing ran on them: the server's generator climbs the ladder with its own GenerationChunk. ChunkHolder, ChunkHolderMap, GenerationScheduler, StepRegion, StepTask, StepTasks, NeighborReader and ChunkStepBody now take the chunk type as a required parameter. ChunkStatusRegressionError moves beside StagedChunk, and the prismarine generator raises it in place of its own GenerationChunkRegressionError.

    67d6870

v0.19.1

patch

3 fixes and changes

Fixes and changes 3

  • A broken bed or banner now drops the item of its own color instead of the black one.

    Details

    Bedrock keeps their color in the block entity, so the loot lookup reads it from there: blockEntityRecord exposes a bed's color and a banner's Base as dyeIndex, blockLootTableOf and rollBlockDrops use it to pick the Java table, and /loot mine passes it too. @jsprismarine/mapping adds bedrockBlockEntityDyeIndexOf and javaBlockOfBedrockDyeIndex to convert between a Java colored block and that index.

    5129bc5
  • ChunkScheduler.tick no longer spins when every player's next chunk has to wait for generation depth. A deferred chunk reset the count of players with nothing to send, so two or more players behind a full depth kept the pass going until the 5 ms budget ran out, every tick. With an injected clock that never advanced, it never ended at all. This happened on two-core hosts, where the default depth is two. A full round of deferrals now ends the pass, and a chunk held for a sender without enqueue returns to the front of its queue.

    52d1d18
  • SharedTerrainTileStore no longer blocks a worker thread while it waits for another owner to finish building a terrain tile. It waited with Atomics.wait everywhere but the main thread, which held the whole thread, so an owner running on that thread could not finish until the 100 ms timeout passed. Both waits now use Atomics.waitAsync, and releasing a slot also wakes a waiter on its initialization word.

    e3adf62

v0.19.0

minor

2 new · 14 fixes and changes

New 2

  • DataEntity.equipmentInventorySlots is now a Map<MobEquipmentSlot, number> instead of a partial record. Read a slot with get, set one with set and clear one with delete. Saved entities keep the same on-disk shape. The new withoutEquipmentSlot helper in entity/equipment copies an equipment set with one slot emptied.

    6b28547
  • Player.setPosition now takes the same options as Entity.setPosition, the new exported EntityPositionOptions. The movement mode and the broadcast flag moved to Player.setPlayerPosition(options, broadcast), so replace player.setPosition({ position, type }, false) with player.setPlayerPosition({ position, type }, false).

    fb2dffc

Fixes and changes 14

  • BaseProvider now declares the optional members of Provider, such as supportsChunkUnload, readPlayerData and the replay snapshot methods. Level, World and the test level helpers type their provider as BaseProvider instead of BaseProvider & Provider.

    84bb6e0
  • The block pass of a generated chunk's Bedrock translation now runs in a generation worker. The server thread translates each palette entry, a few dozen per chunk, and the worker walks the chunk's blocks into section indices and palettes, which was the largest part of a completed chunk's server-thread work. Chunks are byte-identical to the ones built on the server thread.

    8e09026
  • A dimension change now holds its first chunks back until the client reports that the change's loading screen opened, or for two seconds at most. A client that decoded those chunks before switching dimension filed them under the dimension it was leaving and then waited on its loading screen forever.

    11e6795
  • A dimension change for a dead player, such as a /teleport into another dimension under the death screen, now waits until the player respawns and then carries the player there. It used to go out to a client that never opened its loading screen, and every later change of world waited behind it for a minute.

    5d9abed
  • A command run in a dimension nobody has entered yet, such as execute in minecraft:the_nether run fill, no longer acts on the Overworld instead. The dimension's world is started and the command sees it with no chunks loaded, so a block write there places nothing, as Java's "That position is not loaded" does.

    e79d383
  • Point the Discord link in each package README at the project's current invite.

    e785c39

v0.18.0

minor

1 new · 22 fixes and changes

New 1

  • Village raids run.

    Details

    A player with Bad Omen who stands in a village starts one: the omen is spent, a countdown runs, and Java's waves of pillagers, vindicators, evokers, witches and ravagers spawn around the village, three, five or seven by difficulty and one more for a stronger omen, each only once the last is dead. Clearing every wave wins the raid and gives the players nearby Hero of the Village; a village that stops being one, a raid that outlasts 48000 ticks or one nobody is near ends it. Villagers read the raid state, so they take cover between waves and celebrate a win, and an active raid is saved with the level and carries on after a restart.

    ccf5f0b

Fixes and changes 22

  • A checkout without the Bedrock vanilla behavior pack no longer runs silently without mobs. pnpm dev now downloads the pack when the cache lacks it, and the server logs a warning that names the consequence when the pack is missing. Before, a fresh clone or git worktree started with one entity type: nothing spawned, /summon answered "Unable to summon entity" for every type, and the End had no ender dragon.

    2f242cd
  • Mob pathfinding reads blocks faster.

    Details

    Each block read checked its chunk's revision by summing every section's write counts, and looked up its world by scanning the level's worlds. A chunk now reuses its revision until a block is written, and a level remembers its ready worlds by dimension type. In a CPU profile of a server with eight players and their mobs, tick-loop busy time fell from about 84% to about 53%.

    b1e7419
  • Generating terrain no longer stalls the tick loop.

    Details

    Each terrain chunk hashed the pipeline's whole dimension and noise settings to build its cache key on the main thread; those inputs are now written once per pipeline, and the key stays identical so existing caches still hit. The cache also stopped listing and statting every record on each write. Per-tick bookkeeping got cheaper too: lighting and portal checks skip work when nothing changed, random-tick section lists skip their revision sum when no block was written, and entities without status effects skip that pass. In a CPU profile of a fresh world with eight walking bots, main-thread busy time over a 45 second window fell from about 41 seconds to about 12 seconds.

    df11bd2
  • The console follows a server's own tick rate.

    Details

    The status message carries an optional tickRate, and the server sends it, so a rate set with /tick rate reaches the console. The console caps TPS at that rate instead of 20, colors TPS and tick time against it, and draws the TPS page's graph up to the highest rate in the chosen span, so a span that includes a rate change shows the higher one. A console that gets no tickRate assumes 20.

    9e700bc
  • Settle the change of world after the End credits with the respawn exchange instead of a loading screen the client never closes. The client stayed on its loading screen for the server's one minute timeout, which left the next dimension change refused and the player waiting for chunks.

    7ebbc42
  • The dragon fight's "no loaded pack declares minecraft:ender_dragon" report now names the usual cause, a missing Bedrock vanilla behavior pack, and the command that downloads it.

    7c3ef46

Plus 3 dependency updates.

v0.17.0

minor

4 new · 131 fixes and changes

New 4

  • Load Java's block_transformer registry and resolve tool transforms from it, which is what makes a hoe till, a shovel path, and an axe strip.

    Details

    The behaviors and the item components were already in place, but the table behind WorldActions.transform was an injection point nothing injected, so every tool declined every block. @jsprismarine/packs routes data/<namespace>/block_transformer/ files, the server parses them into ServerContent.blockTransformers, and the resolver answers the rule-based providers over the real tag stack and block mapping, including copy_properties (a stripped log keeps its axis), the offset predicates (tilling needs air above), and disallowed_faces - which is why transform now takes the clicked face.

    8cc701d
  • Remove CommonJS package outputs

    9061024
  • Spawn mobs on the ground under leaves and plants instead of on top of them.

    Details

    The surface spawn pass tries one position per column, and the world adapter answered with one above the highest block that is not air: the canopy over a forest and the tall grass standing on a plain. Every passive spawn rule names the ground it belongs on, so those columns rejected every rule and most of an overworld spawned nothing. ContentBlockAccess.surfaceY now walks down to the first block that blocks motion and is not leaves, which is Java's MOTION_BLOCKING_NO_LEAVES heightmap and the one its SpawnPlacements reads. WorldContentBiomes is now WorldContentFacts and carries the block types, their flattened columns and the tag stack that the walk reads.

    541e593
  • Route sniffer seed drops, warden sonic boom damage and knockback, and villager raid effects through host capabilities.

    15dc167

Fixes and changes 131

  • Verify the Minecraft services token and the client data signature before trusting a login when online-mode is on. The account now comes only from the signed token, a login that cannot be verified is refused, and an existing session is replaced only after the new login is accepted.

    43ecda5
  • Encrypt RakNet sessions with the Bedrock handshake: the server sends ServerToClientHandshake to a login that names an identity key, and finishes the login once the client answers encrypted.

    bbc5ab9
  • Save a trader's offers, their uses and demand, and its experience with the entity, so a villager keeps them across a restart instead of drawing new ones. A damaged saved state is ignored.

    73efe0d
  • Villagers trade with players: the trade screen opens on a villager, shows its offers with their live prices, and a trade spends the payment, hands over the result and moves the villager's stock, demand, experience and level.

    Details

    A villager that works at its job site restocks, up to twice a day. Villagers also work with the world: farmers bake bread, compost seeds, harvest, sow and bone-meal crops, villagers share food, thank a hero of the village and have children, and a villager takes its profession and job site from its trade table. A villager remembers the player who cured it and charges that player less, and holds up its trades to a player who talks to it.

    0e4b2a8
  • Make /damage follow Java 26.3: no source entity unless by names one, from for an indirect cause, at for a location, a single target, and the damage type read from the loaded datapacks, whose tags decide what the blow bypasses.

    d84076a
  • Store section palette indices in bytes until a section needs a 257th state.

    169eec3