Skip to content

Commit bc8a7af

Browse files
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 <[email protected]>
1 parent 251e0b0 commit bc8a7af

File tree

4 files changed

+94
-9
lines changed

4 files changed

+94
-9
lines changed

doc/API.md

+29-6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@
77
* `stateString` is the string representation of a block
88
* `biomeId` is the biome numerical id
99

10-
#### Block(type,biomeId,metadata)
10+
#### Block.fromProperties(typeId, properties, biomeId)
11+
12+
* `typeId` - The block type ID (numerical or string)
13+
* `properties` - A dictionary of block state properties to build from
14+
* `biomeId` - The biome numerical id
15+
16+
#### Block(type, biomeId, metadata, stateId = null)
1117

1218
Constructor of a block
1319
* `type` is the block numerical id
1420
* `biomeId` is the biome numerical id
1521
* `metadata` is the metadata numerical value
22+
* `stateId` (optional) represents the state of the block (same as metadata in newer versions)
1623

1724
#### block.canHarvest(heldItemType)
1825

@@ -24,6 +31,13 @@ Tells you if `heldItemType` is one of the right tool to harvest the block.
2431

2532
Parse the block state and return its properties.
2633

34+
#### getHash(prefixedName, states)
35+
36+
**(Bedrock Edition)** Returns an integer hash to represent the block state.
37+
38+
* `prefixedName` - The name of the block, including the `minecraft:` prefix (string).
39+
* `states` - A record of block state properties.
40+
2741
#### block.digTime(heldItemType, creative, inWater, notOnGround, enchantments = [], effects = {})
2842

2943
Tells you how long it will take to dig the block, in milliseconds.
@@ -45,15 +59,19 @@ Numerical id.
4559

4660
#### block.name
4761

62+
Minecraft ID (string) of the block.
63+
4864
#### block.displayName
4965

66+
Display name of the block.
67+
5068
#### block.shapes
5169

5270
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.
5371

5472
#### block.entity
5573

56-
If this block is a block entity, this contains the NBT data for the entity
74+
If this block is a block entity, this contains the NBT data for the entity.
5775

5876
#### block.blockEntity
5977

@@ -64,6 +82,10 @@ Simplified block entity data using prismarine-nbt's simplify() function. Only fo
6482
Number which represents different things depending on the block.
6583
See http://www.minecraftwiki.net/wiki/Data_values#Data
6684

85+
#### block.hash
86+
87+
**(Bedrock Edition)** A hash uniquely representing the block name and its properties (number).
88+
6789
#### block.light
6890

6991
#### block.skyLight
@@ -93,7 +115,7 @@ Boolean, whether the block is considered diggable.
93115

94116
#### block.boundingBox
95117

96-
The shape of the block according to the physics engine's collision decection. Currently one of:
118+
The shape of the block according to the physics engine's collision detection. Currently one of:
97119

98120
* `block` - currently, partially solid blocks, such as half-slabs and ladders, are considered entirely solid.
99121
* `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
131153

132154
#### getSignText (): [string, string?]
133155

134-
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.
156+
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.
135157

136158
#### get .signText
137159

138-
Deprecated, returns a plaintext string containing the sign's text
160+
Deprecated, returns a plaintext string containing the sign's text.
139161

140162
#### set .signText
141-
Deprecated, sets the text for a sign's text, can be plaintext, or array of JSON or prismarine-chat instances
163+
164+
Deprecated, sets the text for a sign's text. Can be plaintext, or array of JSON or prismarine-chat instances.

index.d.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface Effect {
1111
duration: number;
1212
}
1313

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

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

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

46+
// (Bedrock Edition) A hash to uniquely represent block name and its properties
47+
hash?: number
48+
4549
/**
4650
* A biome instance.
4751
* @see https://github.com/prismarinejs/prismarine-biome#api.
@@ -170,14 +174,21 @@ export declare class Block {
170174
* @param properties - A dictionary of block states to build from.
171175
* @param biomeId - The biome this block is in.
172176
*/
173-
static fromProperties(typeId: number | string, properties: { [key: string]: string | number }, biomeId: number): Block;
177+
static fromProperties(typeId: number | string, properties: States, biomeId: number): Block;
174178

175179
/**
176180
* Create a block from a given string.
177181
* @param stateString - the string representation of a block
178182
* @param biomeId - the biome numerical id
179183
*/
180184
static fromString(stateString: string, biomeId: number): Block;
185+
186+
/**
187+
* (Bedrock Edition) Returns an integer hash to represent the block state
188+
* @param prefixedName name of the block, with a minecraft: prefix
189+
* @param states a record of block state properties
190+
*/
191+
static getHash(prefixedName: string, states: States): number | undefined
181192
}
182193

183194
/** @deprecated */

index.js

+29
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ function provider (registry, { Biome, version }) {
195195
if (this.name.includes('sign')) {
196196
mergeObject(this, blockMethods.sign)
197197
}
198+
199+
if (blockEnum && registry.supportFeature('blockHashes')) {
200+
this.hash = Block.getHash(this.name, this._properties)
201+
}
198202
}
199203

200204
static fromStateId (stateId, biomeId) {
@@ -271,6 +275,21 @@ function provider (registry, { Biome, version }) {
271275
return Object.assign(this._properties, this.computedStates)
272276
}
273277

278+
static getHash (name, states) {
279+
if (registry.supportFeature('blockHashes')) {
280+
const sortedStates = {}
281+
for (const key of Object.keys(states).sort()) {
282+
sortedStates[key] = states[key]
283+
}
284+
const tag = nbt.comp({
285+
name: { type: 'string', value: name.includes(':') ? name : `minecraft:${name}` },
286+
states: nbt.comp(sortedStates)
287+
})
288+
const buf = nbt.writeUncompressed(tag, 'little')
289+
return computeFnv1a32Hash(buf)
290+
}
291+
}
292+
274293
canHarvest (heldItemType) {
275294
if (!this.harvestTools) { return true }; // for blocks harvestable by hand
276295
return heldItemType && this.harvestTools && this.harvestTools[heldItemType]
@@ -393,3 +412,13 @@ function provider (registry, { Biome, version }) {
393412
function mergeObject (to, from) {
394413
Object.defineProperties(to, Object.getOwnPropertyDescriptors(from))
395414
}
415+
416+
function computeFnv1a32Hash (buf) {
417+
const FNV1_OFFSET_32 = 0x811c9dc5
418+
let h = FNV1_OFFSET_32
419+
for (let i = 0; i < buf.length; i++) {
420+
h ^= buf[i] & 0xff
421+
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)
422+
}
423+
return h & 0xffffffff
424+
}

test/basic.test.js

+24-2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ describe('Dig time', () => {
130130
it('using iron_shovel', () => {
131131
const tool = registry.itemsByName[toolName]
132132
const block = Block.fromStateId(registry.blocksByName[blockName].defaultState)
133+
console.log('Block', block)
133134
const time = block.digTime(tool.id, false, false, false, [], {})
134135
expect(time).toBe(750)
135136
})
@@ -171,8 +172,29 @@ describe('fromString', () => {
171172
'1.20': 'minecraft:candle[lit=true]'
172173
}
173174
for (const [version, str] of Object.entries(versions)) {
175+
it(version, () => {
176+
const Block = require('prismarine-block')(version)
177+
const block = Block.fromString(str, 0)
178+
// console.log(block)
179+
expect(block.getProperties().lit).toBeTruthy()
180+
})
181+
}
182+
})
183+
184+
describe('Block hash computation', () => {
185+
for (const version of ['bedrock_1.20.0']) {
174186
const Block = require('prismarine-block')(version)
175-
const block = Block.fromString(str, 0)
176-
expect(block.getProperties().lit).toBeTruthy()
187+
it('minecraft:soul_soil', function () {
188+
const block = Block.fromString('minecraft:soul_soil', 0)
189+
expect(block.hash).toBe(601701031)
190+
})
191+
it('minecraft:planks', function () {
192+
const block = Block.fromString('minecraft:planks', 0)
193+
expect(block.hash).toBe(1835335165)
194+
})
195+
it('minecraft:stone', function () {
196+
const block = Block.fromString('minecraft:stone', 0)
197+
expect(block.hash).toBe(-1177000405)
198+
})
177199
}
178200
})

0 commit comments

Comments
 (0)