Repository navigation
Fix connections of fences, glass panes, iron bars and walls, and door states of LevelDB worlds - #2290
Draft
zisunny104 wants to merge 9 commits into
Draft
zisunny104 wants to merge 9 commits into
zisunny104 wants to merge 9 commits into
Conversation
Since the 26.50 palette the client takes the four connection states of fences, glass panes and iron bars from the block state instead of working them out itself. Nukkit always sent the unconnected state, so a neighbour placed next to it overwrote the connection the client had just predicted and the blocks were drawn as separate posts. The connections are now stored in the block data above the type bits and are sent as the matching state: the 16 states follow the unconnected state in the palette, ordered north, east, south, west from the lowest bit. They are recalculated when the block is placed and when a neighbour changes. The LevelDB palette has no connection states, so every state maps to the unconnected one there and the wood type or colour is kept on save. Panes also connect to every kind of pane, bars and glass, and wooden fences no longer connect to nether brick fences. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The LevelDB palette used to save chunks has no connection states, so the state kept for a fence, glass pane or iron bars in memory lost its connections. They were right when the block was placed, but missing when the chunk was sent to the client again, and an update after removing a neighbour was skipped because the stored and the new connections looked equal. Keep the connections in the in-memory state and keep writing the unconnected state to the disk. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The connections are not saved with the chunk, so fences, glass panes and iron bars loaded from the disk had none. Work them out when the chunk is loaded, and fix the blocks next to the border of the chunks that were already loaded and send them to the players. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…their width Fences and glass panes connect to the solid back of a stair, not to its steps or sides; before they connected to every side because stairs count as solid. A fence only connects to a fence gate in the direction the gate is as wide as, not in front of it or behind it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- A world converted from the anvil format has walls without connection states, they stayed separate posts until a neighbouring block was updated. ConnectionUpdater now works them out again with the other connection blocks, also across chunk borders. - BlockWall.autoConfigureState can take the neighbouring blocks from a function, so the same logic is used for a block that is not part of a loaded level yet. - Glass panes and iron bars connect to walls, like in the game. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The shipped palette has no legacy block for part of the states, for example the top half of a door that faces south or a sideways wood block, so they were loaded as the default block of the palette and showed up as a missing or a wrong block. - The two halves of a door are given the data the game gives them itself: the facing and the open bit for the bottom half, the hinge for the top half. - Any other state without a legacy block is given the block of a state of the same name. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A state without a legacy block was given the id of a state of the same name and the data 0. For the sideways wood blocks that meant the oak wood block, for the stems that meant growth 0. It is now given the legacy block of the state of the same name that has the most properties in common and a legacy block of its own, so that the wood type and the growth of a stem are kept. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
zisunny104
marked this pull request as draft
October 18, 2026 07:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fences, glass panes, iron bars and walls loaded from a world are drawn as separate posts since the 26.50 palette, and some door states of a LevelDB world are loaded as a missing block. This makes the server send and work out the right states.
Problem
Since 26.50 the four
minecraft:connection_*states of fences, glass panes and iron bars are part of the block state (Fence on the wiki: connection changes now update neighbours "for parity with Java Edition"). Nukkit only knows the unconnected state, so when a block is placed next to a fence the client first predicts the connection and the server then overwrites it with the unconnected state. In game every fence ends up with an arm towards the block placed after it and none towards the one before it, and glass panes stay as separate posts.The connections are not saved in a LevelDB chunk, and a world converted from the anvil format has none for walls either, so every fence, pane, bars and wall of a loaded world stays a separate post until a neighbouring block changes.
The shipped LevelDB palette also has no legacy block for a part of the door states (for example the top half of a door with some of the facings, or an open bottom half with the hinge set). They were loaded as the default block of the palette, so doors of a LevelDB world showed up as a cherry wood block or as nothing.
Changes
ConnectionBlockinterface. The four connections are stored in the block data above the type bits (wood type, colour). The bit order is the order of the 16 states in the vanilla palette: north is the lowest bit, then east, south and west, so the runtime id of a state is the runtime id of the unconnected state plus the connection bits (checked against the canonical block palette of the Cloudburst data repository for glass panes, stained and hard glass panes, iron bars and several fence types).BlockFence,BlockThin(glass panes, stained glass panes, iron bars) implement it. The connections are worked out when the block is placed and when a neighbour changes. Glass panes and iron bars get a data field (BlockThinhad none); the items only keep the type bits.GlobalBlockPaletteregisters the 16 states of every fence, pane and iron bars type. The old LevelDB palette has no connection states, so there all of them map to the unconnected state and the wood type or colour is kept when saving.BlockStateMapping), otherwise they were lost as soon as the chunk was sent to the client again. The state written to the disk is still the unconnected one.ConnectionUpdaterworks the connections out again when a chunk is loaded, and fixes the blocks next to the border of chunks that were already loaded. It now also does this for walls, usingBlockWall.autoConfigureState, which can take the neighbouring blocks from a function so that it works for a chunk that is not part of a loaded level yet.NukkitLegacyMappergives a state without a legacy block the data the game gives it itself: for the two halves of a door the facing and the open bit for the bottom half and the hinge for the top half, for any other state the legacy block of the state of the same name that has the most properties in common, so that the wood type of a sideways wood block and the growth of a stem are kept. The state itself is not changed, so what is sent to the client and saved stays the same.Not changed
Testing
Initial chunk delivery ordering (2026-10-18)
On first entry into a world, an asynchronous chunk snapshot can be captured before an adjacent chunk loads. Loading that neighbour corrects and sends the pane/fence connection states, but the older snapshot can finish later and overwrite those updates. Previously, the callback rejected that snapshot only for caching, while still sending it to players. Entering the same area again can therefore look correct even though the first entry did not.
Pending sends now retain the source chunk identity and its network version. A callback for an outdated or replaced chunk is discarded, leaving the players queued for a fresh snapshot on the next tick. The network version is separate from the disk dirty counter, so saving a chunk or clearing its connection-only dirty flag cannot make an old snapshot look current. This applies with chunk caching both enabled and disabled.
Validation: five regression tests exercise the actual request/callback methods with controlled provider completion: a connection update during encoding and subsequent retry, dirty-counter reset during encoding, stale completion with caching enabled, chunk replacement, and unchanged delivery. The previous core delivers stale results in the non-cached failure cases; the fixed implementation passes all five. The cached stale-result test also checks that rejection happens before compression. In-game validation of the reported first-entry/re-entry sequence is still pending; this PR remains a draft.
首次進入世界的區塊傳送順序(2026-10-18)
首次進入時,非同步區塊快照可能早於鄰區塊載入;鄰區塊載入後雖然已修正並送出玻璃片/柵欄連接,稍後完成的舊快照仍可能覆蓋它。原本只禁止快取這份過期結果,仍會把它送給玩家,因此第二次進入反而可能正常。
現在會核對原區塊實例與獨立的網路版本,捨棄過期結果,保留等待玩家並於下一個 tick 重新編碼。存檔或清除 dirty flag 不會重設網路版本;快取開啟與關閉都適用。5 個回歸測試已通過;首次進入/再次傳送的遊戲內驗證尚待進行,PR 維持草稿。
Screenshots
The test area was built without any neighbour update, so the saved blocks have no connections. "Before" is the area right after it was built; "After" is the same area after the server was stopped and started again, when the chunks are loaded and the connections are worked out. The test area pictures are taken from a similar angle; the two fence pictures are not the same spot.
Wooden fences and nether brick fences do not connect to each other, like in vanilla; fences only connect to fences of the same kind, to full solid blocks and to fence gates. In the "After" fence picture the nether brick fence next to the wooden ones is therefore left unconnected, which is the expected result.
Doors
Before this PR, some door states of a LevelDB world had no legacy block in the shipped palette and were loaded as the default block of the palette, a cherry wood block. In game a door is then missing a half: the doorway is filled with a wrong block, or with a block that shows nothing but still has an outline. 9 of the 32 states of every door type are affected (for example an open bottom half with the hinge set, or the top half of a door with some of the facings). With this PR they are loaded as doors.
The two pictures show the two ways the problem looks in game, both before this PR:
In the right picture the block has an outline and the name at the bottom of the screen says it is a cherry wood block, but it is drawn as nothing. I did not take a picture of the same doors after the fix; the doors of the test area above (the row at the back) are drawn as doors.
玻璃片、柵欄、鐵柵欄與石牆從世界載入後會變成單獨的柱子,LevelDB 世界裡部分門的狀態會被載入成缺少的方塊。此 PR 讓伺服器送出並算出正確的狀態。
🤖 Generated with Claude Code