From bc8a7af40438d6d6c715fc8d1e1da8a087c588ad Mon Sep 17 00:00:00 2001 From: FreezeEngine Date: Sat, 4 Jan 2025 09:49:47 +0300 Subject: [PATCH 1/3] Add support for Bedrock edition block hashes (#97) * Added getHashValue * Added getHash to Block * simplify and add test * Fixed hashing * Added other collided blocks * prismarine-block to global * Update index.js * Update index.d.ts * added 4 byte mask * Added sorting * Added getHashValue * Added getHash to Block * simplify and add test * Fixed hashing * Added other collided blocks * prismarine-block to global * Update index.js * Update index.d.ts * added 4 byte mask * Added sorting * Add back EOL for lint * Description corrections * Updated docs * Updated docs #2 --------- Co-authored-by: extremeheat --- doc/API.md | 35 +++++++++++++++++++++++++++++------ index.d.ts | 13 ++++++++++++- index.js | 29 +++++++++++++++++++++++++++++ test/basic.test.js | 26 ++++++++++++++++++++++++-- 4 files changed, 94 insertions(+), 9 deletions(-) diff --git a/doc/API.md b/doc/API.md index 30f3607..cf12be8 100644 --- a/doc/API.md +++ b/doc/API.md @@ -7,12 +7,19 @@ * `stateString` is the string representation of a block * `biomeId` is the biome numerical id -#### Block(type,biomeId,metadata) +#### Block.fromProperties(typeId, properties, biomeId) + +* `typeId` - The block type ID (numerical or string) +* `properties` - A dictionary of block state properties to build from +* `biomeId` - The biome numerical id + +#### Block(type, biomeId, metadata, stateId = null) Constructor of a block * `type` is the block numerical id * `biomeId` is the biome numerical id * `metadata` is the metadata numerical value +* `stateId` (optional) represents the state of the block (same as metadata in newer versions) #### block.canHarvest(heldItemType) @@ -24,6 +31,13 @@ Tells you if `heldItemType` is one of the right tool to harvest the block. Parse the block state and return its properties. +#### getHash(prefixedName, states) + +**(Bedrock Edition)** Returns an integer hash to represent the block state. + +* `prefixedName` - The name of the block, including the `minecraft:` prefix (string). +* `states` - A record of block state properties. + #### block.digTime(heldItemType, creative, inWater, notOnGround, enchantments = [], effects = {}) Tells you how long it will take to dig the block, in milliseconds. @@ -45,15 +59,19 @@ Numerical id. #### block.name +Minecraft ID (string) of the block. + #### block.displayName +Display name of the block. + #### block.shapes Array of bounding boxes representing the block shape. Each bounding box is an array of the form `[xmin, ymin, zmin, xmax, ymax, zmax]`. Depends on the type and state of the block. #### block.entity -If this block is a block entity, this contains the NBT data for the entity +If this block is a block entity, this contains the NBT data for the entity. #### block.blockEntity @@ -64,6 +82,10 @@ Simplified block entity data using prismarine-nbt's simplify() function. Only fo Number which represents different things depending on the block. See http://www.minecraftwiki.net/wiki/Data_values#Data +#### block.hash + +**(Bedrock Edition)** A hash uniquely representing the block name and its properties (number). + #### block.light #### block.skyLight @@ -93,7 +115,7 @@ Boolean, whether the block is considered diggable. #### block.boundingBox -The shape of the block according to the physics engine's collision decection. Currently one of: +The shape of the block according to the physics engine's collision detection. Currently one of: * `block` - currently, partially solid blocks, such as half-slabs and ladders, are considered entirely solid. * `empty` - such as flowers and lava. @@ -131,11 +153,12 @@ Sets the text for the sign, can be plaintext, or array of JSON or prismarine-cha #### getSignText (): [string, string?] -Gets the plain text content of the sign, the first item of the array returned and the second is the back and will be undefined for versions that don't support writing on the back of signs. +Gets the plain text content of the sign. The first item of the array returned and the second is the back, which will be undefined for versions that don't support writing on the back of signs. #### get .signText -Deprecated, returns a plaintext string containing the sign's text +Deprecated, returns a plaintext string containing the sign's text. #### set .signText -Deprecated, sets the text for a sign's text, can be plaintext, or array of JSON or prismarine-chat instances + +Deprecated, sets the text for a sign's text. Can be plaintext, or array of JSON or prismarine-chat instances. diff --git a/index.d.ts b/index.d.ts index 8ed7013..c6f804d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -11,6 +11,7 @@ interface Effect { duration: number; } +type States = { [key: string]: string | number } export type Shape = [number, number, number, number, number, number]; @@ -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 its properties + hash?: number + /** * A biome instance. * @see https://github.com/prismarinejs/prismarine-biome#api. @@ -170,7 +174,7 @@ 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. @@ -178,6 +182,13 @@ export declare class Block { * @param biomeId - the biome numerical id */ static fromString(stateString: string, biomeId: number): Block; + + /** + * (Bedrock Edition) Returns an integer hash to represent the block state + * @param prefixedName 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 */ diff --git a/index.js b/index.js index 31a2b29..870cb07 100644 --- a/index.js +++ b/index.js @@ -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) { @@ -271,6 +275,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] @@ -393,3 +412,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 +} diff --git a/test/basic.test.js b/test/basic.test.js index d4e1cd6..4544db1 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -130,6 +130,7 @@ describe('Dig time', () => { it('using iron_shovel', () => { const tool = registry.itemsByName[toolName] const block = Block.fromStateId(registry.blocksByName[blockName].defaultState) + console.log('Block', block) const time = block.digTime(tool.id, false, false, false, [], {}) expect(time).toBe(750) }) @@ -171,8 +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) - 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) + }) } }) From 21e8ea2128df9bb90b59aa58fa491d6dd6031a3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:22:16 +0100 Subject: [PATCH 2/3] Bump mocha from 10.8.2 to 11.0.1 (#104) Bumps [mocha](https://github.com/mochajs/mocha) from 10.8.2 to 11.0.1. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v10.8.2...v11.0.1) --- updated-dependencies: - dependency-name: mocha dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e603616..930650b 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "expect": "^29.1.0", "minecraft-protocol": "^1.30.0", "minecraft-wrap": "^1.4.0", - "mocha": "^10.0.0", + "mocha": "^11.0.1", "prismarine-block": "file:", "standard": "^17.1.0" }, From 785b74bf44f3b1cf8aee787a2d7b62c9ba0aa8a4 Mon Sep 17 00:00:00 2001 From: rom1504bot Date: Sat, 4 Jan 2025 19:25:41 +0100 Subject: [PATCH 3/3] Release 1.20.0 (#106) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- README.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b22e1c2..702acb3 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,10 @@ See [doc/API.md](doc/API.md) ## History +### 1.20.0 +* [Bump mocha from 10.8.2 to 11.0.1 (#104)](https://github.com/PrismarineJS/prismarine-block/commit/21e8ea2128df9bb90b59aa58fa491d6dd6031a3f) (thanks @dependabot[bot]) +* [Add support for Bedrock edition block hashes (#97)](https://github.com/PrismarineJS/prismarine-block/commit/bc8a7af40438d6d6c715fc8d1e1da8a087c588ad) (thanks @FreezeEngine) + ### 1.19.0 * [Update npm-publish.yml](https://github.com/PrismarineJS/prismarine-block/commit/faed7f0390d3f4fd0b15e24193463ed111dbc69a) (thanks @rom1504) diff --git a/package.json b/package.json index 930650b..90e75ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prismarine-block", - "version": "1.19.0", + "version": "1.20.0", "description": "Represent a minecraft block with its associated data", "main": "index.js", "scripts": {