Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for hashed block network ID's #97

Merged
merged 25 commits into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface Effect {
duration: number;
}

type States = { [key: string]: string | number }

export type Shape = [number, number, number, number, number, number];

Expand Down Expand Up @@ -42,6 +43,9 @@ export declare class Block {
// Contains a full NBT, unserialized object
entity: NBT | null;

// (Bedrock Edition) A hash to uniquely represent block name and properties
hash?: number

/**
* A biome instance.
* @see https://github.com/prismarinejs/prismarine-biome#api.
Expand Down Expand Up @@ -170,14 +174,21 @@ export declare class Block {
* @param properties - A dictionary of block states to build from.
* @param biomeId - The biome this block is in.
*/
static fromProperties(typeId: number | string, properties: { [key: string]: string | number }, biomeId: number): Block;
static fromProperties(typeId: number | string, properties: States, biomeId: number): Block;

/**
* Create a block from a given string.
* @param stateString - the string representation of a block
* @param biomeId - the biome numerical id
*/
static fromString(stateString: string, biomeId: number): Block;

/**
* (Bedrock Edition) Returns an integer hash to reperesent the block state
* @param name name of the block, with a minecraft: prefix
* @param states a record of block state properties
*/
static getHash(prefixedName: string, states: States): number | undefined
}

/** @deprecated */
Expand Down
29 changes: 29 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ function provider (registry, { Biome, version }) {
if (this.name.includes('sign')) {
mergeObject(this, blockMethods.sign)
}

if (blockEnum && registry.supportFeature('blockHashes')) {
this.hash = Block.getHash(this.name, this._properties)
}
}

static fromStateId (stateId, biomeId) {
Expand Down Expand Up @@ -269,6 +273,21 @@ function provider (registry, { Biome, version }) {
return Object.assign(this._properties, this.computedStates)
}

static getHash (name, states) {
if (registry.supportFeature('blockHashes')) {
const sortedStates = {}
for (const key of Object.keys(states).sort()) {
sortedStates[key] = states[key]
}
const tag = nbt.comp({
name: { type: 'string', value: name.includes(':') ? name : `minecraft:${name}` },
states: nbt.comp(sortedStates)
})
const buf = nbt.writeUncompressed(tag, 'little')
return computeFnv1a32Hash(buf)
}
}

canHarvest (heldItemType) {
if (!this.harvestTools) { return true }; // for blocks harvestable by hand
return heldItemType && this.harvestTools && this.harvestTools[heldItemType]
Expand Down Expand Up @@ -391,3 +410,13 @@ function provider (registry, { Biome, version }) {
function mergeObject (to, from) {
Object.defineProperties(to, Object.getOwnPropertyDescriptors(from))
}

function computeFnv1a32Hash (buf) {
const FNV1_OFFSET_32 = 0x811c9dc5
let h = FNV1_OFFSET_32
for (let i = 0; i < buf.length; i++) {
h ^= buf[i] & 0xff
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)
}
return h & 0xffffffff
}
26 changes: 23 additions & 3 deletions test/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,29 @@ describe('fromString', () => {
'1.20': 'minecraft:candle[lit=true]'
}
for (const [version, str] of Object.entries(versions)) {
it(version, () => {
const Block = require('prismarine-block')(version)
const block = Block.fromString(str, 0)
// console.log(block)
expect(block.getProperties().lit).toBeTruthy()
})
}
})

describe('Block hash computation', () => {
for (const version of ['bedrock_1.20.0']) {
const Block = require('prismarine-block')(version)
const block = Block.fromString(str, 0)
console.log(block)
expect(block.getProperties().lit).toBeTruthy()
it('minecraft:soul_soil', function () {
const block = Block.fromString('minecraft:soul_soil', 0)
expect(block.hash).toBe(601701031)
})
it('minecraft:planks', function () {
const block = Block.fromString('minecraft:planks', 0)
expect(block.hash).toBe(1835335165)
})
it('minecraft:stone', function () {
const block = Block.fromString('minecraft:stone', 0)
expect(block.hash).toBe(-1177000405)
})
}
})
Loading