Skip to content

Add block network hash conversion helpers - #2

Merged
HashimTheArab merged 8 commits into
masterfrom
fix/oomph-block-network-hashes
Jul 14, 2026
Merged

Add block network hash conversion helpers#2
HashimTheArab merged 8 commits into
masterfrom
fix/oomph-block-network-hashes

Conversation

@HashimTheArab

@HashimTheArab HashimTheArab commented Jul 13, 2026

Copy link
Copy Markdown

Summary

  • add helpers to normalize decoded chunk and subchunk palettes from block network hashes to registry runtime IDs
  • add chunk and targeted subchunk encoders that emit network hashes without mutating cached chunks
  • preserve unknown/custom palette values unchanged

These are helper APIs for Oomph proxy translation. This PR intentionally does not change Dragonfly session serialization or enable hash mode for native Dragonfly servers.

Validation

  • go test ./server/world/... -count=1
  • go vet ./server/world/...
  • git diff --check

Note

Medium Risk
New conversion paths touch core chunk encoding and palette identity; incorrect hash mapping could corrupt block data on the wire, though cloning limits mutation of cached state.

Overview
Adds chunk palette translation between Bedrock network block hashes and registry runtime IDs for proxy-style workflows, without changing how native Dragonfly serializes chunks.

In-place normalization via ConvertBlockNetworkHashesToRuntimeIDs rewrites decoded palettes through BlockRegistry.HashToRuntimeID, leaving unknown values unchanged. Network encoding uses EncodeWithBlockNetworkHashes and EncodeSubChunkWithBlockNetworkHashes, which clone the chunk (or a single sub-chunk) before RuntimeIDToHash conversion so cached chunks stay in runtime-ID form.

Introduces CompactForRuntimeCache on chunks, sub-chunks, and paletted storages: collapses single-value and uniform storages (detected from packed index words), shrinks oversized bit widths, and drops air-only layers—without the full palette scan used before disk save. Includes a trivial comment whitespace fix in network decode.

Reviewed by Cursor Bugbot for commit 536885c. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added support for converting block data between network hashes and runtime IDs during chunk encoding and decoding.
    • Added chunk and sub-chunk encoding helpers for network-compatible block data.
    • Added lightweight chunk compaction for runtime caching, reducing unnecessary storage while preserving block data.
  • Tests

    • Added coverage for storage, sub-chunk, and chunk compaction behavior, including palette shrinking and uniform block handling.

@cursor

cursor Bot commented Jul 13, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f9c9df6d-22b7-4e6c-b84e-70ad3e5fa575)

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Chunk storage and encoding

Layer / File(s) Summary
Palette hash and runtime conversion
server/world/chunk/block_network_hash.go
Chunk and sub-chunk palettes convert between network hashes and runtime IDs through the block registry, preserving unmapped values.
Network encoding helpers
server/world/chunk/block_network_hash.go, server/world/chunk/decode.go
Whole chunks and selected sub-chunks are cloned, converted to network hashes, and encoded without mutating source data; decode workaround formatting is adjusted.
Runtime-cache compaction
server/world/chunk/paletted_storage.go, server/world/chunk/sub_chunk.go, server/world/chunk/chunk.go, server/world/chunk/compact_runtime_test.go
Storage, sub-chunk, and chunk compaction collapse uniform representations, reduce packed widths, remove air-only layers, and validate resulting values and backing storage behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Chunk
  participant BlockRegistry
  participant NetworkEncoding

  Caller->>Chunk: EncodeWithBlockNetworkHashes
  Chunk->>BlockRegistry: RuntimeIDToHash for palette entries
  BlockRegistry-->>Chunk: Network hashes or unmapped values
  Chunk->>NetworkEncoding: Encode cloned chunk
  NetworkEncoding-->>Caller: SerialisedData
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the new block network hash conversion helper APIs, though it omits the runtime cache compaction additions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/oomph-block-network-hashes

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Jul 13, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_9c0e31b1-a941-4a1f-b31e-2951c67e6c7e)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
server/world/chunk/block_network_hash_test.go (1)

10-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover unmapped-value preservation.

These tests only exercise successful mappings. Add unknown hash and runtime-ID cases to verify the fallback paths preserve custom palette values unchanged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/world/chunk/block_network_hash_test.go` around lines 10 - 60, Extend
the tests around ConvertBlockNetworkHashesToRuntimeIDs,
EncodeWithBlockNetworkHashes, and EncodeSubChunkWithBlockNetworkHashes to cover
unmapped hashes and runtime IDs. Verify unknown network hashes remain unchanged
during conversion, and unknown runtime IDs remain unchanged in encoded output
while the source chunk is not mutated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/world/chunk/block_network_hash_test.go`:
- Around line 10-60: Extend the tests around
ConvertBlockNetworkHashesToRuntimeIDs, EncodeWithBlockNetworkHashes, and
EncodeSubChunkWithBlockNetworkHashes to cover unmapped hashes and runtime IDs.
Verify unknown network hashes remain unchanged during conversion, and unknown
runtime IDs remain unchanged in encoded output while the source chunk is not
mutated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c2c93858-c585-4951-806e-4225b43cda96

📥 Commits

Reviewing files that changed from the base of the PR and between 865056f and d3a42ef.

📒 Files selected for processing (3)
  • server/world/chunk/block_network_hash.go
  • server/world/chunk/block_network_hash_test.go
  • server/world/chunk/decode.go

@cursor

cursor Bot commented Jul 13, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f238b780-1d53-4b30-9c46-8069608972c9)

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_17d9ccce-dd7c-451e-b907-833873c59ee1)

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_23232594-d94d-4fe4-bfa5-a406e06c3b62)

@HashimTheArab
HashimTheArab merged commit dcd49f2 into master Jul 14, 2026
7 of 8 checks passed
@HashimTheArab
HashimTheArab deleted the fix/oomph-block-network-hashes branch July 14, 2026 05:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
server/world/chunk/compact_runtime_test.go (1)

124-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for growth after a runtime-cache shrink.

This test confirms the shrink itself, but doesn't verify that adding a third distinct palette value afterward still stores/retrieves correctly. Given the potential storage.palette.size/bitsPerIndex desync flagged in paletted_storage.go (Lines 169-188), a follow-up assertion here (e.g. storage.Set a new distinct runtime ID beyond the current 2-value palette and confirm At() returns it correctly) would catch that class of regression directly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/world/chunk/compact_runtime_test.go` around lines 124 - 142, The test
TestPalettedStorageCompactForRuntimeCacheShrinksOversizedMultiValueStorage
should also exercise growth after compactForRuntimeCache: set a coordinate to a
third distinct runtime ID after the shrink, then assert At returns that ID and
the storage expands consistently with the new palette value.
server/world/chunk/paletted_storage.go (1)

190-212: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate bit-packing math instead of reusing filledBitsPerIndex.

indicesPerWord := uint32BitSize / int(storage.bitsPerIndex) recomputes the same relationship already cached in storage.filledBitsPerIndex (used by paletteIndex() for offset math). Deriving it independently here risks silent divergence if the packing formula changes in one place but not the other.

♻️ Suggested refactor
-	indicesPerWord := uint32BitSize / int(storage.bitsPerIndex)
+	indicesPerWord := int(storage.filledBitsPerIndex / storage.bitsPerIndex)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/world/chunk/paletted_storage.go` around lines 190 - 212, Update
PalettedStorage.uniformPaletteIndex to derive indicesPerWord from the existing
storage.filledBitsPerIndex value instead of recomputing it from uint32BitSize
and bitsPerIndex. Keep the fullWords and remainder calculations and validation
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/world/chunk/paletted_storage.go`:
- Around line 169-188: Update compactForRuntimeCache and the resize path so
shrinking packed storage also synchronizes Palette.size with the new width.
Ensure subsequent Palette.Add operations detect when growth is needed and never
write indices that exceed indexMask.

---

Nitpick comments:
In `@server/world/chunk/compact_runtime_test.go`:
- Around line 124-142: The test
TestPalettedStorageCompactForRuntimeCacheShrinksOversizedMultiValueStorage
should also exercise growth after compactForRuntimeCache: set a coordinate to a
third distinct runtime ID after the shrink, then assert At returns that ID and
the storage expands consistently with the new palette value.

In `@server/world/chunk/paletted_storage.go`:
- Around line 190-212: Update PalettedStorage.uniformPaletteIndex to derive
indicesPerWord from the existing storage.filledBitsPerIndex value instead of
recomputing it from uint32BitSize and bitsPerIndex. Keep the fullWords and
remainder calculations and validation behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 63bfd3e4-387e-41fc-9bfb-e28e572926aa

📥 Commits

Reviewing files that changed from the base of the PR and between a683785 and 083ef3b.

📒 Files selected for processing (4)
  • server/world/chunk/chunk.go
  • server/world/chunk/compact_runtime_test.go
  • server/world/chunk/paletted_storage.go
  • server/world/chunk/sub_chunk.go

Comment on lines +169 to +188
// compactForRuntimeCache performs the cheap subset of compact that is useful for chunks kept in memory.
// It collapses single-value storages and shrinks oversized storage widths, but avoids scanning multi-value
// storages for unused palette entries.
func (storage *PalettedStorage) compactForRuntimeCache() {
if storage.palette.Len() == 0 {
return
}
if storage.palette.Len() == 1 {
storage.collapseToPaletteIndex(0)
return
}
if index, ok := storage.uniformPaletteIndex(); ok {
storage.collapseToPaletteIndex(index)
return
}

if size := paletteSizeFor(storage.palette.Len()); size < storage.palette.size {
storage.resize(size)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd palette.go --exact-path server/world/chunk
rg -n 'size' server/world/chunk/palette.go -B2 -A2
rg -n 'func.*Add' server/world/chunk/palette.go -A 20
rg -n '\.resize\(' server/world/chunk -B3 -A3
rg -n 'func newPalettedStorage' server/world/chunk/paletted_storage.go -A 15

Repository: oomph-ac/dragonfly

Length of output: 5286


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== paletted_storage.go relevant ranges =="
sed -n '1,220p' server/world/chunk/paletted_storage.go | cat -n | sed -n '1,220p'

echo
echo "== palette.go relevant ranges =="
sed -n '1,180p' server/world/chunk/palette.go | cat -n | sed -n '1,180p'

Repository: oomph-ac/dragonfly

Length of output: 16135


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== resize/addNew/compactForRuntimeCache references =="
rg -n 'compactForRuntimeCache|func \(storage \*PalettedStorage\) resize|func \(storage \*PalettedStorage\) addNew|storage\.palette\.size|needsResize\(\)' server/world/chunk -A 4 -B 4

Repository: oomph-ac/dragonfly

Length of output: 7739


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'compactForRuntimeCache\(' server/world/chunk -A 3 -B 3
rg -n '\.resize\(size\)|\.resize\(storage\.palette\.size\)|increaseSize\(\)' server/world/chunk -A 2 -B 2
rg -n 'type PalettedStorage|func \(storage \*PalettedStorage\) resize' server/world/chunk/paletted_storage.go -A 80 -B 10

Repository: oomph-ac/dragonfly

Length of output: 11297


Sync Palette.size when shrinking storage. compactForRuntimeCache() calls resize(size) without updating storage.palette.size, so the palette can keep a wider capacity than the packed indices. A later Palette.Add may then skip the grow resize and write an index that no longer fits indexMask, corrupting live chunk data. Update the palette size here or inside resize().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/world/chunk/paletted_storage.go` around lines 169 - 188, Update
compactForRuntimeCache and the resize path so shrinking packed storage also
synchronizes Palette.size with the new width. Ensure subsequent Palette.Add
operations detect when growth is needed and never write indices that exceed
indexMask.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant