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) + }) } })