From 44b6105ddbdd4bbbec8b477feee75cf5c116dc23 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 1 Mar 2023 20:04:53 +0100 Subject: [PATCH 01/50] start bedrock implementation --- lib/bedrock-item.js | 177 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + tools/relay.js | 33 +++++++++ 3 files changed, 211 insertions(+) create mode 100644 lib/bedrock-item.js create mode 100644 tools/relay.js diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js new file mode 100644 index 0000000..e6855b3 --- /dev/null +++ b/lib/bedrock-item.js @@ -0,0 +1,177 @@ +function loader(registryOrVersion) { + const registry = + typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; + + class BedrockItem { + constructor(type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { + if (type === null) return; + + this.type = type; + this.count = count; + this.metadata = metadata == null ? 0 : metadata; + this.nbt = nbt || null; + + // TODO + // Only generate if on server side and not provided one + this.stackId = stackId ?? BedrockItem.nextStackId(); + + this.canPlaceOn = canPlaceOn ?? []; + this.canDestroy = canDestroy ?? []; + + const itemEnum = registry.items[type]; + if (itemEnum) { + this.name = itemEnum.name; + this.displayName = itemEnum.displayName; + if ("variations" in itemEnum) { + for (const variation of itemEnum.variations) { + if (variation.metadata === metadata) this.displayName = variation.displayName; + } + } + this.stackSize = itemEnum.stackSize; + } else { + this.name = "unknown"; + this.displayName = "unknown"; + this.stackSize = 1; + } + } + + /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ + static equal(item1, item2, matchStackSize = true, sameStack = false, placeable = false, destroyer = false) { + if (item1 == null && item2 == null) { + return true; + } else if (item1 == null) { + return false; + } else if (item2 == null) { + return false; + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && + (sameStack ? item1.stackId === item2.stackId : true) && + (placeable ? item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() : true) && + (destroyer ? item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() : true) + ); + } + } + + // Stack ID + static currentStackId = 0; + static nextStackId() { + return BedrockItem.currentStackId++; + } + + toNetwork(serverAuthoritative = true) { + if (Object.keys(this).length === 0) return { network_id: 0 }; + + return { + network_id: this.type, + count: this.count, + metadata: this.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? this.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: this.nbt !== null, + nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, + can_place_on: this.canPlaceOn, + can_destroy: this.canDestroy, + }, + }; + } + + /** @returns {BedrockItem} */ + static fromNetwork(item, serverAuthoritative = true) { + return new BedrockItem( + item.network_id, + item.count, + item.metadata, + item.extra.nbt?.nbt ?? null, + item.extra.can_place_on, + item.extra.can_destroy, + item.stack_id + ); + } + + get customName() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.display?.value?.Name?.value ?? null; + } + set customName(newName) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Name = { type: "string", value: newName }; + } + + get customLore() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.display?.value?.Lore?.value.value ?? null; + } + set customLore(newLore) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; + } + + get repairCost() { + if (Object.keys(this).length === 0) return 0; + return this.nbt?.value.RepairCost?.value ?? 0; + } + set repairCost(value) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.RepairCost = { type: "int", value }; + } + + get enchants() { + if (Object.keys(this).length === 0) return 0; + if (!this.nbt?.value?.ench) return []; + return this.nbt.value.ench.value.value.map((ench) => ({ + lvl: ench.lvl.value, + name: registry.enchantments[ench.id.value]?.name || null, // TODO: bedrock enchantments + })); + } + set enchants(normalizedEnchArray) { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: "short", value: registry.enchantmentsByName[name].id }, + lvl: { type: "short", value: lvl }, + })); + + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; + } + } + + get durabilityUsed() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.Damage?.value ?? 0; + } + set durabilityUsed(value) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.Damage = { type: "int", value }; + } + + get spawnEggMobName() { + return this.name.replace("_spawn_egg", ""); + } + + canBePlacedOnBlock(block) { + if (typeof block === "string") { + return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`); + } else { + return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`); + } + } + + canDestroyBlock(block) { + if (typeof block === "string") { + return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`); + } else { + return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`); + } + } + } +} + +module.exports = loader; diff --git a/package.json b/package.json index 578183a..664c84b 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ }, "devDependencies": { "@types/node": "^18.6.4", + "bedrock-protocol": "^3.25.0", "expect": "^29.1.2", "mocha": "^10.0.0", "prismarine-item": "file:.", diff --git a/tools/relay.js b/tools/relay.js new file mode 100644 index 0000000..ee774c1 --- /dev/null +++ b/tools/relay.js @@ -0,0 +1,33 @@ +process.env.DEBUG = process.argv.includes("--debug") && "minecraft-protocol"; + +const { Relay } = require("bedrock-protocol"); + +const relay = new Relay({ + host: "0.0.0.0", + port: 19130, + offline: false, + destination: { + host: "127.0.0.1", + port: 19132, + offline: true, + }, +}); + +relay.listen(); + +relay.on("join", (player) => { + console.log("Player %s joined.", player.getUserData().displayName); + + player.on("clientbound", ({ name, params }) => { + if (name === "start_game") { + console.dir(params.itemstates[0], { depth: null }); + console.dir(params.itemstates.find((x) => x.name === "minecraft:iron_shovel")); + console.dir(params.itemstates.find((x) => x.name.includes("spawn_egg"))); + } + if (name === "inventory_content") { + console.dir({ ...params, input: params.input.filter((x) => x.network_id !== 0) }, { depth: null }); + } + }); + + player.on("serverbound", ({ name, params }) => {}); +}); From cc7829d8aa7e74f764b61039b820c20ee8a5e51f Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 1 Mar 2023 20:16:50 +0100 Subject: [PATCH 02/50] comments --- lib/bedrock-item.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index e6855b3..2aad532 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -2,7 +2,21 @@ function loader(registryOrVersion) { const registry = typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; + // TODO: add support for older versions + // need to see how items are handled in older bedrock versions, + // and probably update features.json in minecraft-data + class BedrockItem { + /** + * @param {number} type + * @param {number} count + * @param {number} metadata + * @param {object} nbt + * @param {string[]} canPlaceOn + * @param {string[]} canDestroy + * @param {number} stackId + * @returns {BedrockItem} + */ constructor(type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { if (type === null) return; @@ -156,6 +170,7 @@ function loader(registryOrVersion) { return this.name.replace("_spawn_egg", ""); } + /** @returns {boolean} */ canBePlacedOnBlock(block) { if (typeof block === "string") { return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`); @@ -164,6 +179,7 @@ function loader(registryOrVersion) { } } + /** @returns {boolean} */ canDestroyBlock(block) { if (typeof block === "string") { return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`); From 9a7634f74b8e7ced1a303ac0bac8b920718f0564 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:00:16 +0100 Subject: [PATCH 03/50] Todo comments --- lib/bedrock-item.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 2aad532..19715b3 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -2,9 +2,15 @@ function loader(registryOrVersion) { const registry = typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; - // TODO: add support for older versions - // need to see how items are handled in older bedrock versions, - // and probably update features.json in minecraft-data + // TODO: + // - tests + // - docs + // - add support for older versions: + // need to see how items are handled in older bedrock protocol versions, + // and probably update features.json in minecraft-data with useful data + // - Stack ID generation + // - Block runtime ID field + // - Setting canPlaceOn and canDestroy with block/item objects? class BedrockItem { /** From befe98284968f6c74f6f21fceb69bafcc8f0dbe5 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:00:50 +0100 Subject: [PATCH 04/50] comment --- lib/bedrock-item.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 19715b3..2362ea9 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -11,6 +11,7 @@ function loader(registryOrVersion) { // - Stack ID generation // - Block runtime ID field // - Setting canPlaceOn and canDestroy with block/item objects? + // - Merge with Item class in ../index.js? class BedrockItem { /** From c0a5b3eca08149f902da7186ec113958b60d9288 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:07:26 +0100 Subject: [PATCH 05/50] return BedrockItem and run standard --- lib/bedrock-item.js | 347 ++++++++++++++++++++++---------------------- tools/relay.js | 52 +++---- 2 files changed, 203 insertions(+), 196 deletions(-) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 2362ea9..0429fbd 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -1,20 +1,20 @@ -function loader(registryOrVersion) { - const registry = - typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; - - // TODO: - // - tests - // - docs - // - add support for older versions: - // need to see how items are handled in older bedrock protocol versions, - // and probably update features.json in minecraft-data with useful data - // - Stack ID generation - // - Block runtime ID field - // - Setting canPlaceOn and canDestroy with block/item objects? - // - Merge with Item class in ../index.js? - - class BedrockItem { - /** +function loader (registryOrVersion) { + const registry = + typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + + // TODO: + // - tests + // - docs + // - add support for older versions: + // need to see how items are handled in older bedrock protocol versions, + // and probably update features.json in minecraft-data with useful data + // - Stack ID generation + // - Block runtime ID field + // - Setting canPlaceOn and canDestroy with block/item objects? + // - Merge with Item class in ../index.js? + + class BedrockItem { + /** * @param {number} type * @param {number} count * @param {number} metadata @@ -24,177 +24,184 @@ function loader(registryOrVersion) { * @param {number} stackId * @returns {BedrockItem} */ - constructor(type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { - if (type === null) return; - - this.type = type; - this.count = count; - this.metadata = metadata == null ? 0 : metadata; - this.nbt = nbt || null; - - // TODO - // Only generate if on server side and not provided one - this.stackId = stackId ?? BedrockItem.nextStackId(); - - this.canPlaceOn = canPlaceOn ?? []; - this.canDestroy = canDestroy ?? []; - - const itemEnum = registry.items[type]; - if (itemEnum) { - this.name = itemEnum.name; - this.displayName = itemEnum.displayName; - if ("variations" in itemEnum) { - for (const variation of itemEnum.variations) { - if (variation.metadata === metadata) this.displayName = variation.displayName; - } - } - this.stackSize = itemEnum.stackSize; - } else { - this.name = "unknown"; - this.displayName = "unknown"; - this.stackSize = 1; - } - } + constructor (type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { + if (type === null) return + + this.type = type + this.count = count + this.metadata = metadata == null ? 0 : metadata + this.nbt = nbt || null + + // TODO + // Only generate if on server side and not provided one + this.stackId = stackId ?? BedrockItem.nextStackId() + + this.canPlaceOn = canPlaceOn ?? [] + this.canDestroy = canDestroy ?? [] + + const itemEnum = registry.items[type] + if (itemEnum) { + this.name = itemEnum.name + this.displayName = itemEnum.displayName + if ('variations' in itemEnum) { + for (const variation of itemEnum.variations) { + if (variation.metadata === metadata) this.displayName = variation.displayName + } + } + this.stackSize = itemEnum.stackSize + } else { + this.name = 'unknown' + this.displayName = 'unknown' + this.stackSize = 1 + } + } - /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ - static equal(item1, item2, matchStackSize = true, sameStack = false, placeable = false, destroyer = false) { - if (item1 == null && item2 == null) { - return true; - } else if (item1 == null) { - return false; - } else if (item2 == null) { - return false; - } else { - return ( - item1.type === item2.type && + /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ + static equal (item1, item2, matchStackSize = true, sameStack = false, placeable = false, destroyer = false) { + if (item1 == null && item2 == null) { + return true + } else if (item1 == null) { + return false + } else if (item2 == null) { + return false + } else { + return ( + item1.type === item2.type && (matchStackSize ? item1.count === item2.count : true) && item1.metadata === item2.metadata && JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && (sameStack ? item1.stackId === item2.stackId : true) && (placeable ? item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() : true) && (destroyer ? item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() : true) - ); - } - } + ) + } + } - // Stack ID - static currentStackId = 0; - static nextStackId() { - return BedrockItem.currentStackId++; - } + // Stack ID + static currentStackId = 0 + static nextStackId () { + return BedrockItem.currentStackId++ + } - toNetwork(serverAuthoritative = true) { - if (Object.keys(this).length === 0) return { network_id: 0 }; - - return { - network_id: this.type, - count: this.count, - metadata: this.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? this.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: this.nbt !== null, - nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, - can_place_on: this.canPlaceOn, - can_destroy: this.canDestroy, - }, - }; - } + toNetwork (serverAuthoritative = true) { + if (Object.keys(this).length === 0) return { network_id: 0 } + + return { + network_id: this.type, + count: this.count, + metadata: this.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? this.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: this.nbt !== null, + nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, + can_place_on: this.canPlaceOn, + can_destroy: this.canDestroy + } + } + } - /** @returns {BedrockItem} */ - static fromNetwork(item, serverAuthoritative = true) { - return new BedrockItem( - item.network_id, - item.count, - item.metadata, - item.extra.nbt?.nbt ?? null, - item.extra.can_place_on, - item.extra.can_destroy, - item.stack_id - ); - } + /** @returns {BedrockItem} */ + static fromNetwork (item, serverAuthoritative = true) { + return new BedrockItem( + item.network_id, + item.count, + item.metadata, + item.extra.nbt?.nbt ?? null, + item.extra.can_place_on, + item.extra.can_destroy, + item.stack_id + ) + } - get customName() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.display?.value?.Name?.value ?? null; - } - set customName(newName) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Name = { type: "string", value: newName }; - } + get customName () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.display?.value?.Name?.value ?? null + } - get customLore() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.display?.value?.Lore?.value.value ?? null; - } - set customLore(newLore) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; - } + set customName (newName) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Name = { type: 'string', value: newName } + } - get repairCost() { - if (Object.keys(this).length === 0) return 0; - return this.nbt?.value.RepairCost?.value ?? 0; - } - set repairCost(value) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.RepairCost = { type: "int", value }; - } + get customLore () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.display?.value?.Lore?.value.value ?? null + } - get enchants() { - if (Object.keys(this).length === 0) return 0; - if (!this.nbt?.value?.ench) return []; - return this.nbt.value.ench.value.value.map((ench) => ({ - lvl: ench.lvl.value, - name: registry.enchantments[ench.id.value]?.name || null, // TODO: bedrock enchantments - })); - } - set enchants(normalizedEnchArray) { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: "short", value: registry.enchantmentsByName[name].id }, - lvl: { type: "short", value: lvl }, - })); - - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; - } - } + set customLore (newLore) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } + } - get durabilityUsed() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.Damage?.value ?? 0; - } - set durabilityUsed(value) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.Damage = { type: "int", value }; - } + get repairCost () { + if (Object.keys(this).length === 0) return 0 + return this.nbt?.value.RepairCost?.value ?? 0 + } - get spawnEggMobName() { - return this.name.replace("_spawn_egg", ""); - } + set repairCost (value) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.RepairCost = { type: 'int', value } + } - /** @returns {boolean} */ - canBePlacedOnBlock(block) { - if (typeof block === "string") { - return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`); - } else { - return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`); - } - } + get enchants () { + if (Object.keys(this).length === 0) return 0 + if (!this.nbt?.value?.ench) return [] + return this.nbt.value.ench.value.value.map((ench) => ({ + lvl: ench.lvl.value, + name: registry.enchantments[ench.id.value]?.name || null // TODO: bedrock enchantments + })) + } - /** @returns {boolean} */ - canDestroyBlock(block) { - if (typeof block === "string") { - return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`); - } else { - return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`); - } - } + set enchants (normalizedEnchArray) { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: 'short', value: registry.enchantmentsByName[name].id }, + lvl: { type: 'short', value: lvl } + })) + + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } + } } + + get durabilityUsed () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.Damage?.value ?? 0 + } + + set durabilityUsed (value) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.Damage = { type: 'int', value } + } + + get spawnEggMobName () { + return this.name.replace('_spawn_egg', '') + } + + /** @returns {boolean} */ + canBePlacedOnBlock (block) { + if (typeof block === 'string') { + return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`) + } else { + return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`) + } + } + + /** @returns {boolean} */ + canDestroyBlock (block) { + if (typeof block === 'string') { + return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`) + } else { + return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`) + } + } + } + + return BedrockItem } -module.exports = loader; +module.exports = loader diff --git a/tools/relay.js b/tools/relay.js index ee774c1..8d7d35d 100644 --- a/tools/relay.js +++ b/tools/relay.js @@ -1,33 +1,33 @@ -process.env.DEBUG = process.argv.includes("--debug") && "minecraft-protocol"; +process.env.DEBUG = process.argv.includes('--debug') && 'minecraft-protocol' -const { Relay } = require("bedrock-protocol"); +const { Relay } = require('bedrock-protocol') const relay = new Relay({ - host: "0.0.0.0", - port: 19130, - offline: false, - destination: { - host: "127.0.0.1", - port: 19132, - offline: true, - }, -}); + host: '0.0.0.0', + port: 19130, + offline: false, + destination: { + host: '127.0.0.1', + port: 19132, + offline: true + } +}) -relay.listen(); +relay.listen() -relay.on("join", (player) => { - console.log("Player %s joined.", player.getUserData().displayName); +relay.on('join', (player) => { + console.log('Player %s joined.', player.getUserData().displayName) - player.on("clientbound", ({ name, params }) => { - if (name === "start_game") { - console.dir(params.itemstates[0], { depth: null }); - console.dir(params.itemstates.find((x) => x.name === "minecraft:iron_shovel")); - console.dir(params.itemstates.find((x) => x.name.includes("spawn_egg"))); - } - if (name === "inventory_content") { - console.dir({ ...params, input: params.input.filter((x) => x.network_id !== 0) }, { depth: null }); - } - }); + player.on('clientbound', ({ name, params }) => { + if (name === 'start_game') { + console.dir(params.itemstates[0], { depth: null }) + console.dir(params.itemstates.find((x) => x.name === 'minecraft:iron_shovel')) + console.dir(params.itemstates.find((x) => x.name.includes('spawn_egg'))) + } + if (name === 'inventory_content') { + console.dir({ ...params, input: params.input.filter((x) => x.network_id !== 0) }, { depth: null }) + } + }) - player.on("serverbound", ({ name, params }) => {}); -}); + player.on('serverbound', ({ name, params }) => {}) +}) From 2e1238ec321f674a3e9957ac22c668a9242b3884 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:35:02 +0100 Subject: [PATCH 06/50] Small changes --- lib/bedrock-item.js | 2 +- tools/relay.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 0429fbd..51c046a 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -84,7 +84,7 @@ function loader (registryOrVersion) { } toNetwork (serverAuthoritative = true) { - if (Object.keys(this).length === 0) return { network_id: 0 } + if (this.type === 0) return { network_id: 0 } return { network_id: this.type, diff --git a/tools/relay.js b/tools/relay.js index 8d7d35d..bdf2f18 100644 --- a/tools/relay.js +++ b/tools/relay.js @@ -1,5 +1,3 @@ -process.env.DEBUG = process.argv.includes('--debug') && 'minecraft-protocol' - const { Relay } = require('bedrock-protocol') const relay = new Relay({ From f8bc473d61416e8e3ad7078f3ca71df3fc38a011 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:44:25 +0100 Subject: [PATCH 07/50] remove tools --- tools/relay.js | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 tools/relay.js diff --git a/tools/relay.js b/tools/relay.js deleted file mode 100644 index bdf2f18..0000000 --- a/tools/relay.js +++ /dev/null @@ -1,31 +0,0 @@ -const { Relay } = require('bedrock-protocol') - -const relay = new Relay({ - host: '0.0.0.0', - port: 19130, - offline: false, - destination: { - host: '127.0.0.1', - port: 19132, - offline: true - } -}) - -relay.listen() - -relay.on('join', (player) => { - console.log('Player %s joined.', player.getUserData().displayName) - - player.on('clientbound', ({ name, params }) => { - if (name === 'start_game') { - console.dir(params.itemstates[0], { depth: null }) - console.dir(params.itemstates.find((x) => x.name === 'minecraft:iron_shovel')) - console.dir(params.itemstates.find((x) => x.name.includes('spawn_egg'))) - } - if (name === 'inventory_content') { - console.dir({ ...params, input: params.input.filter((x) => x.network_id !== 0) }, { depth: null }) - } - }) - - player.on('serverbound', ({ name, params }) => {}) -}) From 137af5049d39f5d3bea3cfedae6b8228aea717ec Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:47:25 +0100 Subject: [PATCH 08/50] matchNbt in equal() --- lib/bedrock-item.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 51c046a..dcac8c6 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -57,7 +57,7 @@ function loader (registryOrVersion) { } /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ - static equal (item1, item2, matchStackSize = true, sameStack = false, placeable = false, destroyer = false) { + static equal (item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { if (item1 == null && item2 == null) { return true } else if (item1 == null) { @@ -67,12 +67,12 @@ function loader (registryOrVersion) { } else { return ( item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && - (sameStack ? item1.stackId === item2.stackId : true) && - (placeable ? item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() : true) && - (destroyer ? item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() : true) + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (sameStack ? item1.stackId === item2.stackId : true) && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) && + (matchNbt ? item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() : true) && + (matchNbt ? item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() : true) ) } } @@ -183,7 +183,7 @@ function loader (registryOrVersion) { } /** @returns {boolean} */ - canBePlacedOnBlock (block) { + canPlaceOnBlock (block) { if (typeof block === 'string') { return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`) } else { From 821ea9a176ffdb322cc156486e632777ac3e515a Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:49:14 +0100 Subject: [PATCH 09/50] better matchNbt --- lib/bedrock-item.js | 354 ++++++++++++++++++++++---------------------- 1 file changed, 178 insertions(+), 176 deletions(-) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index dcac8c6..68b0a5d 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -1,20 +1,20 @@ -function loader (registryOrVersion) { - const registry = - typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion - - // TODO: - // - tests - // - docs - // - add support for older versions: - // need to see how items are handled in older bedrock protocol versions, - // and probably update features.json in minecraft-data with useful data - // - Stack ID generation - // - Block runtime ID field - // - Setting canPlaceOn and canDestroy with block/item objects? - // - Merge with Item class in ../index.js? - - class BedrockItem { - /** +function loader(registryOrVersion) { + const registry = + typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; + + // TODO: + // - tests + // - docs + // - add support for older versions: + // need to see how items are handled in older bedrock protocol versions, + // and probably update features.json in minecraft-data with useful data + // - Stack ID generation + // - Block runtime ID field + // - Setting canPlaceOn and canDestroy with block/item objects? + // - Merge with Item class in ../index.js? + + class BedrockItem { + /** * @param {number} type * @param {number} count * @param {number} metadata @@ -24,184 +24,186 @@ function loader (registryOrVersion) { * @param {number} stackId * @returns {BedrockItem} */ - constructor (type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { - if (type === null) return - - this.type = type - this.count = count - this.metadata = metadata == null ? 0 : metadata - this.nbt = nbt || null - - // TODO - // Only generate if on server side and not provided one - this.stackId = stackId ?? BedrockItem.nextStackId() - - this.canPlaceOn = canPlaceOn ?? [] - this.canDestroy = canDestroy ?? [] - - const itemEnum = registry.items[type] - if (itemEnum) { - this.name = itemEnum.name - this.displayName = itemEnum.displayName - if ('variations' in itemEnum) { - for (const variation of itemEnum.variations) { - if (variation.metadata === metadata) this.displayName = variation.displayName - } - } - this.stackSize = itemEnum.stackSize - } else { - this.name = 'unknown' - this.displayName = 'unknown' - this.stackSize = 1 - } - } + constructor(type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { + if (type === null) return; + + this.type = type; + this.count = count; + this.metadata = metadata == null ? 0 : metadata; + this.nbt = nbt || null; + + // TODO + // Only generate if on server side and not provided one + this.stackId = stackId ?? BedrockItem.nextStackId(); + + this.canPlaceOn = canPlaceOn ?? []; + this.canDestroy = canDestroy ?? []; + + const itemEnum = registry.items[type]; + if (itemEnum) { + this.name = itemEnum.name; + this.displayName = itemEnum.displayName; + if ("variations" in itemEnum) { + for (const variation of itemEnum.variations) { + if (variation.metadata === metadata) this.displayName = variation.displayName; + } + } + this.stackSize = itemEnum.stackSize; + } else { + this.name = "unknown"; + this.displayName = "unknown"; + this.stackSize = 1; + } + } - /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ - static equal (item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { - if (item1 == null && item2 == null) { - return true - } else if (item1 == null) { - return false - } else if (item2 == null) { - return false - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (sameStack ? item1.stackId === item2.stackId : true) && - (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) && - (matchNbt ? item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() : true) && - (matchNbt ? item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() : true) - ) - } - } + /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ + static equal(item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { + if (item1 == null && item2 == null) { + return true; + } else if (item1 == null) { + return false; + } else if (item2 == null) { + return false; + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (sameStack ? item1.stackId === item2.stackId : true) && + (matchNbt + ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && + item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() && + item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() + : true) + ); + } + } - // Stack ID - static currentStackId = 0 - static nextStackId () { - return BedrockItem.currentStackId++ - } + // Stack ID + static currentStackId = 0; + static nextStackId() { + return BedrockItem.currentStackId++; + } - toNetwork (serverAuthoritative = true) { - if (this.type === 0) return { network_id: 0 } - - return { - network_id: this.type, - count: this.count, - metadata: this.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? this.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: this.nbt !== null, - nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, - can_place_on: this.canPlaceOn, - can_destroy: this.canDestroy - } - } - } + toNetwork(serverAuthoritative = true) { + if (this.type === 0) return { network_id: 0 }; + + return { + network_id: this.type, + count: this.count, + metadata: this.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? this.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: this.nbt !== null, + nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, + can_place_on: this.canPlaceOn, + can_destroy: this.canDestroy, + }, + }; + } - /** @returns {BedrockItem} */ - static fromNetwork (item, serverAuthoritative = true) { - return new BedrockItem( - item.network_id, - item.count, - item.metadata, - item.extra.nbt?.nbt ?? null, - item.extra.can_place_on, - item.extra.can_destroy, - item.stack_id - ) - } + /** @returns {BedrockItem} */ + static fromNetwork(item, serverAuthoritative = true) { + return new BedrockItem( + item.network_id, + item.count, + item.metadata, + item.extra.nbt?.nbt ?? null, + item.extra.can_place_on, + item.extra.can_destroy, + item.stack_id + ); + } - get customName () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.display?.value?.Name?.value ?? null - } + get customName() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.display?.value?.Name?.value ?? null; + } - set customName (newName) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Name = { type: 'string', value: newName } - } + set customName(newName) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Name = { type: "string", value: newName }; + } - get customLore () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.display?.value?.Lore?.value.value ?? null - } + get customLore() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.display?.value?.Lore?.value.value ?? null; + } - set customLore (newLore) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } - } + set customLore(newLore) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; + } - get repairCost () { - if (Object.keys(this).length === 0) return 0 - return this.nbt?.value.RepairCost?.value ?? 0 - } + get repairCost() { + if (Object.keys(this).length === 0) return 0; + return this.nbt?.value.RepairCost?.value ?? 0; + } - set repairCost (value) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.RepairCost = { type: 'int', value } - } + set repairCost(value) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.RepairCost = { type: "int", value }; + } - get enchants () { - if (Object.keys(this).length === 0) return 0 - if (!this.nbt?.value?.ench) return [] - return this.nbt.value.ench.value.value.map((ench) => ({ - lvl: ench.lvl.value, - name: registry.enchantments[ench.id.value]?.name || null // TODO: bedrock enchantments - })) - } + get enchants() { + if (Object.keys(this).length === 0) return 0; + if (!this.nbt?.value?.ench) return []; + return this.nbt.value.ench.value.value.map((ench) => ({ + lvl: ench.lvl.value, + name: registry.enchantments[ench.id.value]?.name || null, // TODO: bedrock enchantments + })); + } - set enchants (normalizedEnchArray) { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: 'short', value: registry.enchantmentsByName[name].id }, - lvl: { type: 'short', value: lvl } - })) + set enchants(normalizedEnchArray) { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: "short", value: registry.enchantmentsByName[name].id }, + lvl: { type: "short", value: lvl }, + })); - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } - } - } + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; + } + } - get durabilityUsed () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.Damage?.value ?? 0 - } + get durabilityUsed() { + if (Object.keys(this).length === 0) return null; + return this.nbt?.value?.Damage?.value ?? 0; + } - set durabilityUsed (value) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.Damage = { type: 'int', value } - } + set durabilityUsed(value) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.Damage = { type: "int", value }; + } - get spawnEggMobName () { - return this.name.replace('_spawn_egg', '') - } + get spawnEggMobName() { + return this.name.replace("_spawn_egg", ""); + } - /** @returns {boolean} */ - canPlaceOnBlock (block) { - if (typeof block === 'string') { - return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`) - } else { - return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`) - } - } + /** @returns {boolean} */ + canPlaceOnBlock(block) { + if (typeof block === "string") { + return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`); + } else { + return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`); + } + } - /** @returns {boolean} */ - canDestroyBlock (block) { - if (typeof block === 'string') { - return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`) - } else { - return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`) - } + /** @returns {boolean} */ + canDestroyBlock(block) { + if (typeof block === "string") { + return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`); + } else { + return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`); + } + } } - } - return BedrockItem + return BedrockItem; } -module.exports = loader +module.exports = loader; From f3fc3a863333c52677b91a7f0284211a499c63de Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:50:51 +0100 Subject: [PATCH 10/50] remove bedrock-protocol from devDependencies --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 664c84b..578183a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ }, "devDependencies": { "@types/node": "^18.6.4", - "bedrock-protocol": "^3.25.0", "expect": "^29.1.2", "mocha": "^10.0.0", "prismarine-item": "file:.", From 58557ea1a2285ded8e3033a2666931a1f9d52f1d Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:54:46 +0100 Subject: [PATCH 11/50] Notch -> Network in pc impl, add matchNbt to pc --- index.js | 55 ++++--- lib/bedrock-item.js | 344 ++++++++++++++++++++++---------------------- 2 files changed, 210 insertions(+), 189 deletions(-) diff --git a/index.js b/index.js index a00e139..c302d47 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const nbt = require('prismarine-nbt') function loader (registryOrVersion) { - const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + const registry = + typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion class Item { constructor (type, count, metadata, nbt) { if (type == null) return @@ -21,7 +22,9 @@ function loader (registryOrVersion) { this.displayName = itemEnum.displayName if ('variations' in itemEnum) { for (const i in itemEnum.variations) { - if (itemEnum.variations[i].metadata === metadata) { this.displayName = itemEnum.variations[i].displayName } + if (itemEnum.variations[i].metadata === metadata) { + this.displayName = itemEnum.variations[i].displayName + } } } this.stackSize = itemEnum.stackSize @@ -32,7 +35,7 @@ function loader (registryOrVersion) { } } - static equal (item1, item2, matchStackSize = true) { + static equal (item1, item2, matchStackSize = true, matchNbt = true) { if (item1 == null && item2 == null) { return true } else if (item1 == null) { @@ -40,14 +43,16 @@ function loader (registryOrVersion) { } else if (item2 == null) { return false } else { - return (item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt)) + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) + ) } } - static toNotch (item) { + static toNetwork (item) { if (registry.supportFeature('itemSerializationAllowsPresent')) { if (item == null) return { present: false } const notchItem = { @@ -55,7 +60,9 @@ function loader (registryOrVersion) { itemId: item.type, itemCount: item.count } - if (item.nbt && item.nbt.length !== 0) { notchItem.nbtData = item.nbt } + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt + } return notchItem } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (item == null) return { blockId: -1 } @@ -64,13 +71,15 @@ function loader (registryOrVersion) { itemCount: item.count, itemDamage: item.metadata } - if (item.nbt && item.nbt.length !== 0) { notchItem.nbtData = item.nbt } + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt + } return notchItem } throw new Error("Don't know how to serialize for this mc version ") } - static fromNotch (item) { + static fromNetwork (item) { if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { if (item.present === false) return null return new Item(item.itemId, item.itemCount, item.nbtData) @@ -130,7 +139,7 @@ function loader (registryOrVersion) { } else { itemEnch = [] } - return itemEnch.map(ench => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { let itemEnch = [] if (this?.nbt?.value?.Enchantments) { @@ -140,7 +149,10 @@ function loader (registryOrVersion) { } else { itemEnch = [] } - return itemEnch.map(ench => ({ lvl: ench.lvl, name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null })) + return itemEnch.map((ench) => ({ + lvl: ench.lvl, + name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null + })) } throw new Error("Don't know how to get the enchants from an item on this mc version") } @@ -153,16 +165,25 @@ function loader (registryOrVersion) { if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = type === 'short' ? registry.enchantmentsByName[name].id : `minecraft:${registry.enchantmentsByName[name].name}` + const value = + type === 'short' + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}` return { id: { type, value }, lvl: { type: 'short', value: lvl } } }) if (enchs.length !== 0) { - this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { type: 'list', value: { type: 'compound', value: enchs } } + this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { + type: 'list', + value: { type: 'compound', value: enchs } + } } // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if (registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && registry.itemsByName[this.name].maxDurability) { + if ( + registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && + registry.itemsByName[this.name].maxDurability + ) { this.nbt.value.Damage = { type: 'int', value: 0 } } } @@ -192,7 +213,7 @@ function loader (registryOrVersion) { get spawnEggMobName () { if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { - return registry.entitiesArray.find(o => o.internalId === this.metadata).name + return registry.entitiesArray.find((o) => o.internalId === this.metadata).name } if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { const data = nbt.simplify(this.nbt) diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 68b0a5d..d19a3ee 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -1,20 +1,20 @@ -function loader(registryOrVersion) { - const registry = - typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; - - // TODO: - // - tests - // - docs - // - add support for older versions: - // need to see how items are handled in older bedrock protocol versions, - // and probably update features.json in minecraft-data with useful data - // - Stack ID generation - // - Block runtime ID field - // - Setting canPlaceOn and canDestroy with block/item objects? - // - Merge with Item class in ../index.js? - - class BedrockItem { - /** +function loader (registryOrVersion) { + const registry = + typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + + // TODO: + // - tests + // - docs + // - add support for older versions: + // need to see how items are handled in older bedrock protocol versions, + // and probably update features.json in minecraft-data with useful data + // - Stack ID generation + // - Block runtime ID field + // - Setting canPlaceOn and canDestroy with block/item objects? + // - Merge with Item class in ../index.js? + + class BedrockItem { + /** * @param {number} type * @param {number} count * @param {number} metadata @@ -24,186 +24,186 @@ function loader(registryOrVersion) { * @param {number} stackId * @returns {BedrockItem} */ - constructor(type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { - if (type === null) return; - - this.type = type; - this.count = count; - this.metadata = metadata == null ? 0 : metadata; - this.nbt = nbt || null; - - // TODO - // Only generate if on server side and not provided one - this.stackId = stackId ?? BedrockItem.nextStackId(); - - this.canPlaceOn = canPlaceOn ?? []; - this.canDestroy = canDestroy ?? []; - - const itemEnum = registry.items[type]; - if (itemEnum) { - this.name = itemEnum.name; - this.displayName = itemEnum.displayName; - if ("variations" in itemEnum) { - for (const variation of itemEnum.variations) { - if (variation.metadata === metadata) this.displayName = variation.displayName; - } - } - this.stackSize = itemEnum.stackSize; - } else { - this.name = "unknown"; - this.displayName = "unknown"; - this.stackSize = 1; - } - } + constructor (type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { + if (type === null) return + + this.type = type + this.count = count + this.metadata = metadata == null ? 0 : metadata + this.nbt = nbt || null + + // TODO + // Only generate if on server side and not provided one + this.stackId = stackId ?? BedrockItem.nextStackId() + + this.canPlaceOn = canPlaceOn ?? [] + this.canDestroy = canDestroy ?? [] + + const itemEnum = registry.items[type] + if (itemEnum) { + this.name = itemEnum.name + this.displayName = itemEnum.displayName + if ('variations' in itemEnum) { + for (const variation of itemEnum.variations) { + if (variation.metadata === metadata) this.displayName = variation.displayName + } + } + this.stackSize = itemEnum.stackSize + } else { + this.name = 'unknown' + this.displayName = 'unknown' + this.stackSize = 1 + } + } - /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ - static equal(item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { - if (item1 == null && item2 == null) { - return true; - } else if (item1 == null) { - return false; - } else if (item2 == null) { - return false; - } else { - return ( - item1.type === item2.type && + /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ + static equal (item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { + if (item1 == null && item2 == null) { + return true + } else if (item1 == null) { + return false + } else if (item2 == null) { + return false + } else { + return ( + item1.type === item2.type && (matchStackSize ? item1.count === item2.count : true) && item1.metadata === item2.metadata && (sameStack ? item1.stackId === item2.stackId : true) && (matchNbt - ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && + ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() && item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() - : true) - ); - } - } + : true) + ) + } + } - // Stack ID - static currentStackId = 0; - static nextStackId() { - return BedrockItem.currentStackId++; - } + // Stack ID + static currentStackId = 0 + static nextStackId () { + return BedrockItem.currentStackId++ + } - toNetwork(serverAuthoritative = true) { - if (this.type === 0) return { network_id: 0 }; - - return { - network_id: this.type, - count: this.count, - metadata: this.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? this.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: this.nbt !== null, - nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, - can_place_on: this.canPlaceOn, - can_destroy: this.canDestroy, - }, - }; - } + toNetwork (serverAuthoritative = true) { + if (this.type === 0) return { network_id: 0 } + + return { + network_id: this.type, + count: this.count, + metadata: this.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? this.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: this.nbt !== null, + nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, + can_place_on: this.canPlaceOn, + can_destroy: this.canDestroy + } + } + } - /** @returns {BedrockItem} */ - static fromNetwork(item, serverAuthoritative = true) { - return new BedrockItem( - item.network_id, - item.count, - item.metadata, - item.extra.nbt?.nbt ?? null, - item.extra.can_place_on, - item.extra.can_destroy, - item.stack_id - ); - } + /** @returns {BedrockItem} */ + static fromNetwork (item, serverAuthoritative = true) { + return new BedrockItem( + item.network_id, + item.count, + item.metadata, + item.extra.nbt?.nbt ?? null, + item.extra.can_place_on, + item.extra.can_destroy, + item.stack_id + ) + } - get customName() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.display?.value?.Name?.value ?? null; - } + get customName () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.display?.value?.Name?.value ?? null + } - set customName(newName) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Name = { type: "string", value: newName }; - } + set customName (newName) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Name = { type: 'string', value: newName } + } - get customLore() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.display?.value?.Lore?.value.value ?? null; - } + get customLore () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.display?.value?.Lore?.value.value ?? null + } - set customLore(newLore) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; - } + set customLore (newLore) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } + } - get repairCost() { - if (Object.keys(this).length === 0) return 0; - return this.nbt?.value.RepairCost?.value ?? 0; - } + get repairCost () { + if (Object.keys(this).length === 0) return 0 + return this.nbt?.value.RepairCost?.value ?? 0 + } - set repairCost(value) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.RepairCost = { type: "int", value }; - } + set repairCost (value) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.RepairCost = { type: 'int', value } + } - get enchants() { - if (Object.keys(this).length === 0) return 0; - if (!this.nbt?.value?.ench) return []; - return this.nbt.value.ench.value.value.map((ench) => ({ - lvl: ench.lvl.value, - name: registry.enchantments[ench.id.value]?.name || null, // TODO: bedrock enchantments - })); - } + get enchants () { + if (Object.keys(this).length === 0) return 0 + if (!this.nbt?.value?.ench) return [] + return this.nbt.value.ench.value.value.map((ench) => ({ + lvl: ench.lvl.value, + name: registry.enchantments[ench.id.value]?.name || null // TODO: bedrock enchantments + })) + } - set enchants(normalizedEnchArray) { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: "short", value: registry.enchantmentsByName[name].id }, - lvl: { type: "short", value: lvl }, - })); + set enchants (normalizedEnchArray) { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: 'short', value: registry.enchantmentsByName[name].id }, + lvl: { type: 'short', value: lvl } + })) - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; - } - } + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } + } + } - get durabilityUsed() { - if (Object.keys(this).length === 0) return null; - return this.nbt?.value?.Damage?.value ?? 0; - } + get durabilityUsed () { + if (Object.keys(this).length === 0) return null + return this.nbt?.value?.Damage?.value ?? 0 + } - set durabilityUsed(value) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.Damage = { type: "int", value }; - } + set durabilityUsed (value) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.Damage = { type: 'int', value } + } - get spawnEggMobName() { - return this.name.replace("_spawn_egg", ""); - } + get spawnEggMobName () { + return this.name.replace('_spawn_egg', '') + } - /** @returns {boolean} */ - canPlaceOnBlock(block) { - if (typeof block === "string") { - return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`); - } else { - return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`); - } - } + /** @returns {boolean} */ + canPlaceOnBlock (block) { + if (typeof block === 'string') { + return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`) + } else { + return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`) + } + } - /** @returns {boolean} */ - canDestroyBlock(block) { - if (typeof block === "string") { - return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`); - } else { - return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`); - } - } + /** @returns {boolean} */ + canDestroyBlock (block) { + if (typeof block === 'string') { + return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`) + } else { + return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`) + } } + } - return BedrockItem; + return BedrockItem } -module.exports = loader; +module.exports = loader From 9e5081263491338dd61e9c6fcfb3272d5e9b1b32 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 19:57:31 +0100 Subject: [PATCH 12/50] canPlaceOn and canDestroy --- index.js | 12 +++++------- lib/bedrock-item.js | 42 +++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/index.js b/index.js index c302d47..5cd0761 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,6 @@ const nbt = require('prismarine-nbt') function loader (registryOrVersion) { - const registry = - typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion class Item { constructor (type, count, metadata, nbt) { if (type == null) return @@ -166,9 +165,9 @@ function loader (registryOrVersion) { const enchs = normalizedEnchArray.map(({ name, lvl }) => { const value = - type === 'short' - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}` + type === 'short' + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}` return { id: { type, value }, lvl: { type: 'short', value: lvl } } }) @@ -181,8 +180,7 @@ function loader (registryOrVersion) { // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability if ( - registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && - registry.itemsByName[this.name].maxDurability + registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && registry.itemsByName[this.name].maxDurability ) { this.nbt.value.Damage = { type: 'int', value: 0 } } diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index d19a3ee..b5fcc2e 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -19,12 +19,12 @@ function loader (registryOrVersion) { * @param {number} count * @param {number} metadata * @param {object} nbt - * @param {string[]} canPlaceOn - * @param {string[]} canDestroy + * @param {string[]} canPlaceOnList + * @param {string[]} canDestroyList * @param {number} stackId * @returns {BedrockItem} */ - constructor (type, count, metadata, nbt, canPlaceOn, canDestroy, stackId) { + constructor (type, count, metadata, nbt, canPlaceOnList, canDestroyList, stackId) { if (type === null) return this.type = type @@ -36,8 +36,8 @@ function loader (registryOrVersion) { // Only generate if on server side and not provided one this.stackId = stackId ?? BedrockItem.nextStackId() - this.canPlaceOn = canPlaceOn ?? [] - this.canDestroy = canDestroy ?? [] + this.canPlaceOnList = canPlaceOnList ?? [] + this.canDestroyList = canDestroyList ?? [] const itemEnum = registry.items[type] if (itemEnum) { @@ -67,14 +67,14 @@ function loader (registryOrVersion) { } else { return ( item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (sameStack ? item1.stackId === item2.stackId : true) && - (matchNbt - ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && - item1.canPlaceOn.sort().toString() === item2.canPlaceOn.sort().toString() && - item1.canDestroy.sort().toString() === item2.canDestroy.sort().toString() - : true) + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (sameStack ? item1.stackId === item2.stackId : true) && + (matchNbt + ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && + item1.canPlaceOnList.sort().toString() === item2.canPlaceOnList.sort().toString() && + item1.canDestroyList.sort().toString() === item2.canDestroyList.sort().toString() + : true) ) } } @@ -98,8 +98,8 @@ function loader (registryOrVersion) { extra: { has_nbt: this.nbt !== null, nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, - can_place_on: this.canPlaceOn, - can_destroy: this.canDestroy + can_place_on: this.canPlaceOnList, + can_destroy: this.canDestroyList } } } @@ -185,20 +185,20 @@ function loader (registryOrVersion) { } /** @returns {boolean} */ - canPlaceOnBlock (block) { + canPlaceOn (block) { if (typeof block === 'string') { - return this.canPlaceOn.includes(block) || this.canPlaceOn.includes(`minecraft:${block}`) + return this.canPlaceOnList.includes(block) || this.canPlaceOnList.includes(`minecraft:${block}`) } else { - return this.canDestroy.includes(block.name) || this.canPlaceOn.includes(`minecraft:${block.name}`) + return this.canDestroyList.includes(block.name) || this.canPlaceOnList.includes(`minecraft:${block.name}`) } } /** @returns {boolean} */ - canDestroyBlock (block) { + canDestroy (block) { if (typeof block === 'string') { - return this.canDestroy.includes(block) || this.canDestroy.includes(`minecraft:${block}`) + return this.canDestroyList.includes(block) || this.canDestroyList.includes(`minecraft:${block}`) } else { - return this.canDestroy.includes(block.name) || this.canDestroy.includes(`minecraft:${block.name}`) + return this.canDestroyList.includes(block.name) || this.canDestroyList.includes(`minecraft:${block.name}`) } } } From 06269b8da07d5932266cc82d5acac986721ba739 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 20:06:23 +0100 Subject: [PATCH 13/50] CanPlaceOn and CanDestroy for java - NEED TO TEST --- index.js | 459 ++++++++++++++++++++++++-------------------- lib/bedrock-item.js | 2 +- 2 files changed, 247 insertions(+), 214 deletions(-) diff --git a/index.js b/index.js index 5cd0761..f92d8f8 100644 --- a/index.js +++ b/index.js @@ -1,232 +1,265 @@ -const nbt = require('prismarine-nbt') -function loader (registryOrVersion) { - const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion - class Item { - constructor (type, count, metadata, nbt) { - if (type == null) return - - if (metadata instanceof Object && metadata !== null) { - nbt = metadata - metadata = 0 - } - - this.type = type - this.count = count - this.metadata = metadata == null ? 0 : metadata - this.nbt = nbt || null - - const itemEnum = registry.items[type] - if (itemEnum) { - this.name = itemEnum.name - this.displayName = itemEnum.displayName - if ('variations' in itemEnum) { - for (const i in itemEnum.variations) { - if (itemEnum.variations[i].metadata === metadata) { - this.displayName = itemEnum.variations[i].displayName +const nbt = require("prismarine-nbt"); +function loader(registryOrVersion) { + const registry = + typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; + class Item { + constructor(type, count, metadata, nbt) { + if (type == null) return; + + if (metadata instanceof Object && metadata !== null) { + nbt = metadata; + metadata = 0; } - } - } - this.stackSize = itemEnum.stackSize - } else { - this.name = 'unknown' - this.displayName = 'unknown' - this.stackSize = 1 - } - } - static equal (item1, item2, matchStackSize = true, matchNbt = true) { - if (item1 == null && item2 == null) { - return true - } else if (item1 == null) { - return false - } else if (item2 == null) { - return false - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) - ) - } - } + this.type = type; + this.count = count; + this.metadata = metadata == null ? 0 : metadata; + this.nbt = nbt || null; - static toNetwork (item) { - if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (item == null) return { present: false } - const notchItem = { - present: true, - itemId: item.type, - itemCount: item.count - } - if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt - } - return notchItem - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (item == null) return { blockId: -1 } - const notchItem = { - blockId: item.type, - itemCount: item.count, - itemDamage: item.metadata - } - if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt - } - return notchItem - } - throw new Error("Don't know how to serialize for this mc version ") - } + const itemEnum = registry.items[type]; + if (itemEnum) { + this.name = itemEnum.name; + this.displayName = itemEnum.displayName; + if ("variations" in itemEnum) { + for (const i in itemEnum.variations) { + if (itemEnum.variations[i].metadata === metadata) { + this.displayName = itemEnum.variations[i].displayName; + } + } + } + this.stackSize = itemEnum.stackSize; + } else { + this.name = "unknown"; + this.displayName = "unknown"; + this.stackSize = 1; + } + } - static fromNetwork (item) { - if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { - if (item.present === false) return null - return new Item(item.itemId, item.itemCount, item.nbtData) - } else if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (item.itemId === -1 || item.present === false) return null - return new Item(item.itemId, item.itemCount, item.nbtData) - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (item.blockId === -1) return null - return new Item(item.blockId, item.itemCount, item.itemDamage, item.nbtData) - } - throw new Error("Don't know how to deserialize for this mc version ") - } + static equal(item1, item2, matchStackSize = true, matchNbt = true) { + if (item1 == null && item2 == null) { + return true; + } else if (item1 == null) { + return false; + } else if (item2 == null) { + return false; + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) + ); + } + } - get customName () { - if (Object.keys(this).length === 0) return null - return this?.nbt?.value?.display?.value?.Name?.value ?? null - } + static toNetwork(item) { + if (registry.supportFeature("itemSerializationAllowsPresent")) { + if (item == null) return { present: false }; + const notchItem = { + present: true, + itemId: item.type, + itemCount: item.count, + }; + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt; + } + return notchItem; + } else if (registry.supportFeature("itemSerializationUsesBlockId")) { + if (item == null) return { blockId: -1 }; + const notchItem = { + blockId: item.type, + itemCount: item.count, + itemDamage: item.metadata, + }; + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt; + } + return notchItem; + } + throw new Error("Don't know how to serialize for this mc version "); + } - set customName (newName) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Name = { type: 'string', value: newName } - } + static fromNetwork(item) { + if (registry.supportFeature("itemSerializationWillOnlyUsePresent")) { + if (item.present === false) return null; + return new Item(item.itemId, item.itemCount, item.nbtData); + } else if (registry.supportFeature("itemSerializationAllowsPresent")) { + if (item.itemId === -1 || item.present === false) return null; + return new Item(item.itemId, item.itemCount, item.nbtData); + } else if (registry.supportFeature("itemSerializationUsesBlockId")) { + if (item.blockId === -1) return null; + return new Item(item.blockId, item.itemCount, item.itemDamage, item.nbtData); + } + throw new Error("Don't know how to deserialize for this mc version "); + } - get customLore () { - if (Object.keys(this).length === 0) return null - return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null - } + get customName() { + if (Object.keys(this).length === 0) return null; + return this?.nbt?.value?.display?.value?.Name?.value ?? null; + } - set customLore (newLore) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Lore = { type: 'string', value: newLore } - } + set customName(newName) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Name = { type: "string", value: newName }; + } - // gets the cost based on previous anvil uses - get repairCost () { - if (Object.keys(this).length === 0) return 0 - return this?.nbt?.value?.RepairCost?.value ?? 0 - } + get customLore() { + if (Object.keys(this).length === 0) return null; + return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null; + } - set repairCost (value) { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.RepairCost = { type: 'int', value } - } + set customLore(newLore) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Lore = { type: "string", value: newLore }; + } - get enchants () { - if (Object.keys(this).length === 0) return [] - const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') - const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') - if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') { - let itemEnch - if (this.name === 'enchanted_book' && this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments - } else if (this?.nbt?.value?.ench) { - itemEnch = nbt.simplify(this.nbt).ench - } else { - itemEnch = [] - } - return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) - } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { - let itemEnch = [] - if (this?.nbt?.value?.Enchantments) { - itemEnch = nbt.simplify(this.nbt).Enchantments - } else if (this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments - } else { - itemEnch = [] - } - return itemEnch.map((ench) => ({ - lvl: ench.lvl, - name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null - })) - } - throw new Error("Don't know how to get the enchants from an item on this mc version") - } + // gets the cost based on previous anvil uses + get repairCost() { + if (Object.keys(this).length === 0) return 0; + return this?.nbt?.value?.RepairCost?.value ?? 0; + } - set enchants (normalizedEnchArray) { - const isBook = this.name === 'enchanted_book' - const enchListName = registry.supportFeature('nbtNameForEnchant') - const type = registry.supportFeature('typeOfValueForEnchantLevel') - if (type === null) throw new Error("Don't know the serialized type for enchant level") - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - - const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = - type === 'short' - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}` - return { id: { type, value }, lvl: { type: 'short', value: lvl } } - }) - - if (enchs.length !== 0) { - this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { - type: 'list', - value: { type: 'compound', value: enchs } - } - } - - // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if ( - registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && registry.itemsByName[this.name].maxDurability - ) { - this.nbt.value.Damage = { type: 'int', value: 0 } - } - } + set repairCost(value) { + if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.RepairCost = { type: "int", value }; + } - get durabilityUsed () { - if (Object.keys(this).length === 0) return null - const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage') { - return this?.nbt?.value?.Damage?.value ?? 0 - } else if (where === 'metadata') { - return this.metadata ?? 0 - } - throw new Error("Don't know how to get item durability for this mc version") - } + get enchants() { + if (Object.keys(this).length === 0) return []; + const enchantNbtKey = registry.supportFeature("nbtNameForEnchant"); + const typeOfEnchantLevelValue = registry.supportFeature("typeOfValueForEnchantLevel"); + if (typeOfEnchantLevelValue === "short" && enchantNbtKey === "ench") { + let itemEnch; + if (this.name === "enchanted_book" && this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments; + } else if (this?.nbt?.value?.ench) { + itemEnch = nbt.simplify(this.nbt).ench; + } else { + itemEnch = []; + } + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })); + } else if (typeOfEnchantLevelValue === "string" && enchantNbtKey === "Enchantments") { + let itemEnch = []; + if (this?.nbt?.value?.Enchantments) { + itemEnch = nbt.simplify(this.nbt).Enchantments; + } else if (this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments; + } else { + itemEnch = []; + } + return itemEnch.map((ench) => ({ + lvl: ench.lvl, + name: typeof ench.id === "string" ? ench.id.replace(/minecraft:/, "") : null, + })); + } + throw new Error("Don't know how to get the enchants from an item on this mc version"); + } - set durabilityUsed (value) { - const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage') { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.Damage = { type: 'int', value } - } else if (where === 'metadata') { - this.metadata = value - } else { - throw new Error("Don't know how to set item durability for this mc version") - } - } + set enchants(normalizedEnchArray) { + const isBook = this.name === "enchanted_book"; + const enchListName = registry.supportFeature("nbtNameForEnchant"); + const type = registry.supportFeature("typeOfValueForEnchantLevel"); + if (type === null) throw new Error("Don't know the serialized type for enchant level"); + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + + const enchs = normalizedEnchArray.map(({ name, lvl }) => { + const value = + type === "short" + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}`; + return { id: { type, value }, lvl: { type: "short", value: lvl } }; + }); + + if (enchs.length !== 0) { + this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = { + type: "list", + value: { type: "compound", value: enchs }, + }; + } + + // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability + if ( + registry.supportFeature("whereDurabilityIsSerialized") === "Damage" && + registry.itemsByName[this.name].maxDurability + ) { + this.nbt.value.Damage = { type: "int", value: 0 }; + } + } + + get durabilityUsed() { + if (Object.keys(this).length === 0) return null; + const where = registry.supportFeature("whereDurabilityIsSerialized"); + if (where === "Damage") { + return this?.nbt?.value?.Damage?.value ?? 0; + } else if (where === "metadata") { + return this.metadata ?? 0; + } + throw new Error("Don't know how to get item durability for this mc version"); + } - get spawnEggMobName () { - if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { - return registry.entitiesArray.find((o) => o.internalId === this.metadata).name - } - if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { - const data = nbt.simplify(this.nbt) - const entityName = data.EntityTag.id - return entityName.replace('minecraft:', '') - } - if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { - return this.name.replace('_spawn_egg', '') - } - throw new Error("Don't know how to get spawn egg mob name for this mc version") + set durabilityUsed(value) { + const where = registry.supportFeature("whereDurabilityIsSerialized"); + if (where === "Damage") { + if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.Damage = { type: "int", value }; + } else if (where === "metadata") { + this.metadata = value; + } else { + throw new Error("Don't know how to set item durability for this mc version"); + } + } + + get spawnEggMobName() { + if (registry.supportFeature("spawnEggsUseInternalIdInNbt")) { + return registry.entitiesArray.find((o) => o.internalId === this.metadata).name; + } + if (registry.supportFeature("spawnEggsUseEntityTagInNbt")) { + const data = nbt.simplify(this.nbt); + const entityName = data.EntityTag.id; + return entityName.replace("minecraft:", ""); + } + if (registry.supportFeature("spawnEggsHaveSpawnedEntityInName")) { + return this.name.replace("_spawn_egg", ""); + } + throw new Error("Don't know how to get spawn egg mob name for this mc version"); + } + + // TODO: test this + canPlaceOn(block) { + if (!this.nbt || !this.nbt.value.CanPlaceOn) return true; + if (typeof block === "string") { + return ( + this.nbt.value.CanPlaceOn.value.includes(block) || + this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block}`) + ); + } else { + return ( + this.nbt.value.CanPlaceOn.value.includes(block.name) || + this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block.name}`) + ); + } + } + + canDestroy(block) { + if (!this.nbt || !this.nbt.value.CanPlaceOn) return true; + if (typeof block === "string") { + return ( + this.nbt.value.CanDestroy.value.includes(block) || + this.nbt.value.CanDestroy.value.includes(`minecraft:${block}`) + ); + } else { + return ( + this.nbt.value.CanDestroy.value.includes(block.name) || + this.nbt.value.CanDestroy.value.includes(`minecraft:${block.name}`) + ); + } + } } - } - Item.anvil = require('./lib/anvil.js')(registry, Item) - return Item + Item.anvil = require("./lib/anvil.js")(registry, Item); + return Item; } -module.exports = loader +module.exports = loader; diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index b5fcc2e..17288bf 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -189,7 +189,7 @@ function loader (registryOrVersion) { if (typeof block === 'string') { return this.canPlaceOnList.includes(block) || this.canPlaceOnList.includes(`minecraft:${block}`) } else { - return this.canDestroyList.includes(block.name) || this.canPlaceOnList.includes(`minecraft:${block.name}`) + return this.canPlaceOnList.includes(block.name) || this.canPlaceOnList.includes(`minecraft:${block.name}`) } } From a444f9037c46527bcf98ddfccd8844c3d0a4270e Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 20:07:54 +0100 Subject: [PATCH 14/50] Fix weird indentation from my formatter --- index.js | 469 +++++++++++++++++++++++++++---------------------------- 1 file changed, 234 insertions(+), 235 deletions(-) diff --git a/index.js b/index.js index f92d8f8..8516300 100644 --- a/index.js +++ b/index.js @@ -1,265 +1,264 @@ -const nbt = require("prismarine-nbt"); -function loader(registryOrVersion) { - const registry = - typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; - class Item { - constructor(type, count, metadata, nbt) { - if (type == null) return; +const nbt = require('prismarine-nbt') +function loader (registryOrVersion) { + const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + class Item { + constructor (type, count, metadata, nbt) { + if (type == null) return - if (metadata instanceof Object && metadata !== null) { - nbt = metadata; - metadata = 0; - } - - this.type = type; - this.count = count; - this.metadata = metadata == null ? 0 : metadata; - this.nbt = nbt || null; + if (metadata instanceof Object && metadata !== null) { + nbt = metadata + metadata = 0 + } - const itemEnum = registry.items[type]; - if (itemEnum) { - this.name = itemEnum.name; - this.displayName = itemEnum.displayName; - if ("variations" in itemEnum) { - for (const i in itemEnum.variations) { - if (itemEnum.variations[i].metadata === metadata) { - this.displayName = itemEnum.variations[i].displayName; - } - } - } - this.stackSize = itemEnum.stackSize; - } else { - this.name = "unknown"; - this.displayName = "unknown"; - this.stackSize = 1; - } - } + this.type = type + this.count = count + this.metadata = metadata == null ? 0 : metadata + this.nbt = nbt || null - static equal(item1, item2, matchStackSize = true, matchNbt = true) { - if (item1 == null && item2 == null) { - return true; - } else if (item1 == null) { - return false; - } else if (item2 == null) { - return false; - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) - ); + const itemEnum = registry.items[type] + if (itemEnum) { + this.name = itemEnum.name + this.displayName = itemEnum.displayName + if ('variations' in itemEnum) { + for (const i in itemEnum.variations) { + if (itemEnum.variations[i].metadata === metadata) { + this.displayName = itemEnum.variations[i].displayName } + } } + this.stackSize = itemEnum.stackSize + } else { + this.name = 'unknown' + this.displayName = 'unknown' + this.stackSize = 1 + } + } - static toNetwork(item) { - if (registry.supportFeature("itemSerializationAllowsPresent")) { - if (item == null) return { present: false }; - const notchItem = { - present: true, - itemId: item.type, - itemCount: item.count, - }; - if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt; - } - return notchItem; - } else if (registry.supportFeature("itemSerializationUsesBlockId")) { - if (item == null) return { blockId: -1 }; - const notchItem = { - blockId: item.type, - itemCount: item.count, - itemDamage: item.metadata, - }; - if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt; - } - return notchItem; - } - throw new Error("Don't know how to serialize for this mc version "); - } + static equal (item1, item2, matchStackSize = true, matchNbt = true) { + if (item1 == null && item2 == null) { + return true + } else if (item1 == null) { + return false + } else if (item2 == null) { + return false + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) + ) + } + } - static fromNetwork(item) { - if (registry.supportFeature("itemSerializationWillOnlyUsePresent")) { - if (item.present === false) return null; - return new Item(item.itemId, item.itemCount, item.nbtData); - } else if (registry.supportFeature("itemSerializationAllowsPresent")) { - if (item.itemId === -1 || item.present === false) return null; - return new Item(item.itemId, item.itemCount, item.nbtData); - } else if (registry.supportFeature("itemSerializationUsesBlockId")) { - if (item.blockId === -1) return null; - return new Item(item.blockId, item.itemCount, item.itemDamage, item.nbtData); - } - throw new Error("Don't know how to deserialize for this mc version "); + static toNetwork (item) { + if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (item == null) return { present: false } + const notchItem = { + present: true, + itemId: item.type, + itemCount: item.count } - - get customName() { - if (Object.keys(this).length === 0) return null; - return this?.nbt?.value?.display?.value?.Name?.value ?? null; + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt } - - set customName(newName) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Name = { type: "string", value: newName }; + return notchItem + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (item == null) return { blockId: -1 } + const notchItem = { + blockId: item.type, + itemCount: item.count, + itemDamage: item.metadata } - - get customLore() { - if (Object.keys(this).length === 0) return null; - return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null; + if (item.nbt && item.nbt.length !== 0) { + notchItem.nbtData = item.nbt } + return notchItem + } + throw new Error("Don't know how to serialize for this mc version ") + } - set customLore(newLore) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Lore = { type: "string", value: newLore }; - } + static fromNetwork (item) { + if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { + if (item.present === false) return null + return new Item(item.itemId, item.itemCount, item.nbtData) + } else if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (item.itemId === -1 || item.present === false) return null + return new Item(item.itemId, item.itemCount, item.nbtData) + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (item.blockId === -1) return null + return new Item(item.blockId, item.itemCount, item.itemDamage, item.nbtData) + } + throw new Error("Don't know how to deserialize for this mc version ") + } - // gets the cost based on previous anvil uses - get repairCost() { - if (Object.keys(this).length === 0) return 0; - return this?.nbt?.value?.RepairCost?.value ?? 0; - } + get customName () { + if (Object.keys(this).length === 0) return null + return this?.nbt?.value?.display?.value?.Name?.value ?? null + } - set repairCost(value) { - if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.RepairCost = { type: "int", value }; - } + set customName (newName) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Name = { type: 'string', value: newName } + } - get enchants() { - if (Object.keys(this).length === 0) return []; - const enchantNbtKey = registry.supportFeature("nbtNameForEnchant"); - const typeOfEnchantLevelValue = registry.supportFeature("typeOfValueForEnchantLevel"); - if (typeOfEnchantLevelValue === "short" && enchantNbtKey === "ench") { - let itemEnch; - if (this.name === "enchanted_book" && this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments; - } else if (this?.nbt?.value?.ench) { - itemEnch = nbt.simplify(this.nbt).ench; - } else { - itemEnch = []; - } - return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })); - } else if (typeOfEnchantLevelValue === "string" && enchantNbtKey === "Enchantments") { - let itemEnch = []; - if (this?.nbt?.value?.Enchantments) { - itemEnch = nbt.simplify(this.nbt).Enchantments; - } else if (this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments; - } else { - itemEnch = []; - } - return itemEnch.map((ench) => ({ - lvl: ench.lvl, - name: typeof ench.id === "string" ? ench.id.replace(/minecraft:/, "") : null, - })); - } - throw new Error("Don't know how to get the enchants from an item on this mc version"); - } + get customLore () { + if (Object.keys(this).length === 0) return null + return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null + } - set enchants(normalizedEnchArray) { - const isBook = this.name === "enchanted_book"; - const enchListName = registry.supportFeature("nbtNameForEnchant"); - const type = registry.supportFeature("typeOfValueForEnchantLevel"); - if (type === null) throw new Error("Don't know the serialized type for enchant level"); - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + set customLore (newLore) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Lore = { type: 'string', value: newLore } + } - const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = - type === "short" - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}`; - return { id: { type, value }, lvl: { type: "short", value: lvl } }; - }); + // gets the cost based on previous anvil uses + get repairCost () { + if (Object.keys(this).length === 0) return 0 + return this?.nbt?.value?.RepairCost?.value ?? 0 + } - if (enchs.length !== 0) { - this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = { - type: "list", - value: { type: "compound", value: enchs }, - }; - } + set repairCost (value) { + if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.RepairCost = { type: 'int', value } + } - // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if ( - registry.supportFeature("whereDurabilityIsSerialized") === "Damage" && - registry.itemsByName[this.name].maxDurability - ) { - this.nbt.value.Damage = { type: "int", value: 0 }; - } + get enchants () { + if (Object.keys(this).length === 0) return [] + const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') + const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') + if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') { + let itemEnch + if (this.name === 'enchanted_book' && this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments + } else if (this?.nbt?.value?.ench) { + itemEnch = nbt.simplify(this.nbt).ench + } else { + itemEnch = [] } - - get durabilityUsed() { - if (Object.keys(this).length === 0) return null; - const where = registry.supportFeature("whereDurabilityIsSerialized"); - if (where === "Damage") { - return this?.nbt?.value?.Damage?.value ?? 0; - } else if (where === "metadata") { - return this.metadata ?? 0; - } - throw new Error("Don't know how to get item durability for this mc version"); + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) + } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { + let itemEnch = [] + if (this?.nbt?.value?.Enchantments) { + itemEnch = nbt.simplify(this.nbt).Enchantments + } else if (this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments + } else { + itemEnch = [] } + return itemEnch.map((ench) => ({ + lvl: ench.lvl, + name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null + })) + } + throw new Error("Don't know how to get the enchants from an item on this mc version") + } - set durabilityUsed(value) { - const where = registry.supportFeature("whereDurabilityIsSerialized"); - if (where === "Damage") { - if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.Damage = { type: "int", value }; - } else if (where === "metadata") { - this.metadata = value; - } else { - throw new Error("Don't know how to set item durability for this mc version"); - } - } + set enchants (normalizedEnchArray) { + const isBook = this.name === 'enchanted_book' + const enchListName = registry.supportFeature('nbtNameForEnchant') + const type = registry.supportFeature('typeOfValueForEnchantLevel') + if (type === null) throw new Error("Don't know the serialized type for enchant level") + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - get spawnEggMobName() { - if (registry.supportFeature("spawnEggsUseInternalIdInNbt")) { - return registry.entitiesArray.find((o) => o.internalId === this.metadata).name; - } - if (registry.supportFeature("spawnEggsUseEntityTagInNbt")) { - const data = nbt.simplify(this.nbt); - const entityName = data.EntityTag.id; - return entityName.replace("minecraft:", ""); - } - if (registry.supportFeature("spawnEggsHaveSpawnedEntityInName")) { - return this.name.replace("_spawn_egg", ""); - } - throw new Error("Don't know how to get spawn egg mob name for this mc version"); - } + const enchs = normalizedEnchArray.map(({ name, lvl }) => { + const value = + type === 'short' + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}` + return { id: { type, value }, lvl: { type: 'short', value: lvl } } + }) - // TODO: test this - canPlaceOn(block) { - if (!this.nbt || !this.nbt.value.CanPlaceOn) return true; - if (typeof block === "string") { - return ( - this.nbt.value.CanPlaceOn.value.includes(block) || - this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block}`) - ); - } else { - return ( - this.nbt.value.CanPlaceOn.value.includes(block.name) || - this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block.name}`) - ); - } + if (enchs.length !== 0) { + this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { + type: 'list', + value: { type: 'compound', value: enchs } } + } - canDestroy(block) { - if (!this.nbt || !this.nbt.value.CanPlaceOn) return true; - if (typeof block === "string") { - return ( - this.nbt.value.CanDestroy.value.includes(block) || - this.nbt.value.CanDestroy.value.includes(`minecraft:${block}`) - ); - } else { - return ( - this.nbt.value.CanDestroy.value.includes(block.name) || - this.nbt.value.CanDestroy.value.includes(`minecraft:${block.name}`) - ); - } - } + // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability + if ( + registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && + registry.itemsByName[this.name].maxDurability + ) { + this.nbt.value.Damage = { type: 'int', value: 0 } + } + } + + get durabilityUsed () { + if (Object.keys(this).length === 0) return null + const where = registry.supportFeature('whereDurabilityIsSerialized') + if (where === 'Damage') { + return this?.nbt?.value?.Damage?.value ?? 0 + } else if (where === 'metadata') { + return this.metadata ?? 0 + } + throw new Error("Don't know how to get item durability for this mc version") + } + + set durabilityUsed (value) { + const where = registry.supportFeature('whereDurabilityIsSerialized') + if (where === 'Damage') { + if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.Damage = { type: 'int', value } + } else if (where === 'metadata') { + this.metadata = value + } else { + throw new Error("Don't know how to set item durability for this mc version") + } + } + + get spawnEggMobName () { + if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { + return registry.entitiesArray.find((o) => o.internalId === this.metadata).name + } + if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { + const data = nbt.simplify(this.nbt) + const entityName = data.EntityTag.id + return entityName.replace('minecraft:', '') + } + if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { + return this.name.replace('_spawn_egg', '') + } + throw new Error("Don't know how to get spawn egg mob name for this mc version") + } + + // TODO: test this + canPlaceOn (block) { + if (!this.nbt || !this.nbt.value.CanPlaceOn) return true + if (typeof block === 'string') { + return ( + this.nbt.value.CanPlaceOn.value.includes(block) || + this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block}`) + ) + } else { + return ( + this.nbt.value.CanPlaceOn.value.includes(block.name) || + this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block.name}`) + ) + } + } + + canDestroy (block) { + if (!this.nbt || !this.nbt.value.CanPlaceOn) return true + if (typeof block === 'string') { + return ( + this.nbt.value.CanDestroy.value.includes(block) || + this.nbt.value.CanDestroy.value.includes(`minecraft:${block}`) + ) + } else { + return ( + this.nbt.value.CanDestroy.value.includes(block.name) || + this.nbt.value.CanDestroy.value.includes(`minecraft:${block.name}`) + ) + } } + } - Item.anvil = require("./lib/anvil.js")(registry, Item); - return Item; + Item.anvil = require('./lib/anvil.js')(registry, Item) + return Item } -module.exports = loader; +module.exports = loader From 5c182d8abf135eba28cf3d4dece61cca73b2c8ad Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 20:10:00 +0100 Subject: [PATCH 15/50] notch -> network --- index.js | 12 ++++++------ lib/bedrock-item.js | 21 ++++++++++----------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/index.js b/index.js index 8516300..be4c587 100644 --- a/index.js +++ b/index.js @@ -54,26 +54,26 @@ function loader (registryOrVersion) { static toNetwork (item) { if (registry.supportFeature('itemSerializationAllowsPresent')) { if (item == null) return { present: false } - const notchItem = { + const networkItem = { present: true, itemId: item.type, itemCount: item.count } if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt + networkItem.nbtData = item.nbt } - return notchItem + return networkItem } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (item == null) return { blockId: -1 } - const notchItem = { + const networkItem = { blockId: item.type, itemCount: item.count, itemDamage: item.metadata } if (item.nbt && item.nbt.length !== 0) { - notchItem.nbtData = item.nbt + networkItem.nbtData = item.nbt } - return notchItem + return networkItem } throw new Error("Don't know how to serialize for this mc version ") } diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js index 17288bf..6b900dd 100644 --- a/lib/bedrock-item.js +++ b/lib/bedrock-item.js @@ -1,6 +1,5 @@ function loader (registryOrVersion) { - const registry = - typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion // TODO: // - tests @@ -15,15 +14,15 @@ function loader (registryOrVersion) { class BedrockItem { /** - * @param {number} type - * @param {number} count - * @param {number} metadata - * @param {object} nbt - * @param {string[]} canPlaceOnList - * @param {string[]} canDestroyList - * @param {number} stackId - * @returns {BedrockItem} - */ + * @param {number} type + * @param {number} count + * @param {number} metadata + * @param {object} nbt + * @param {string[]} canPlaceOnList + * @param {string[]} canDestroyList + * @param {number} stackId + * @returns {BedrockItem} + */ constructor (type, count, metadata, nbt, canPlaceOnList, canDestroyList, stackId) { if (type === null) return From c97d5ef53720c313337b916a3bc14a918b132387 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 20:23:41 +0100 Subject: [PATCH 16/50] revert the breaking change --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index be4c587..205c9c8 100644 --- a/index.js +++ b/index.js @@ -51,7 +51,7 @@ function loader (registryOrVersion) { } } - static toNetwork (item) { + static toNotch (item) { if (registry.supportFeature('itemSerializationAllowsPresent')) { if (item == null) return { present: false } const networkItem = { @@ -78,7 +78,7 @@ function loader (registryOrVersion) { throw new Error("Don't know how to serialize for this mc version ") } - static fromNetwork (item) { + static fromNotch (item) { if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { if (item.present === false) return null return new Item(item.itemId, item.itemCount, item.nbtData) From 50d943fa4f3aae57c5b8f130028b0f47d1ecb6ed Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 2 Mar 2023 20:28:29 +0100 Subject: [PATCH 17/50] clarify in comments that this is not tested --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 205c9c8..4469cd9 100644 --- a/index.js +++ b/index.js @@ -225,7 +225,8 @@ function loader (registryOrVersion) { throw new Error("Don't know how to get spawn egg mob name for this mc version") } - // TODO: test this + // TODO: test this, implement it properly + // Most likely is not supported by every version canPlaceOn (block) { if (!this.nbt || !this.nbt.value.CanPlaceOn) return true if (typeof block === 'string') { @@ -240,7 +241,6 @@ function loader (registryOrVersion) { ) } } - canDestroy (block) { if (!this.nbt || !this.nbt.value.CanPlaceOn) return true if (typeof block === 'string') { From 397cd6bd25de96dc3577ba82287392b4922e5b58 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Fri, 3 Mar 2023 19:13:08 +0100 Subject: [PATCH 18/50] Start bedrock support in original Item class --- index.js | 539 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 303 insertions(+), 236 deletions(-) diff --git a/index.js b/index.js index 4469cd9..0bfbb5f 100644 --- a/index.js +++ b/index.js @@ -1,264 +1,331 @@ -const nbt = require('prismarine-nbt') -function loader (registryOrVersion) { - const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion - class Item { - constructor (type, count, metadata, nbt) { - if (type == null) return - - if (metadata instanceof Object && metadata !== null) { - nbt = metadata - metadata = 0 - } - - this.type = type - this.count = count - this.metadata = metadata == null ? 0 : metadata - this.nbt = nbt || null - - const itemEnum = registry.items[type] - if (itemEnum) { - this.name = itemEnum.name - this.displayName = itemEnum.displayName - if ('variations' in itemEnum) { - for (const i in itemEnum.variations) { - if (itemEnum.variations[i].metadata === metadata) { - this.displayName = itemEnum.variations[i].displayName +const nbt = require("prismarine-nbt"); +function loader(registryOrVersion) { + const registry = + typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; + class Item { + constructor(type, count, metadata, nbt) { + if (type == null) return; + + if (metadata instanceof Object && metadata !== null) { + nbt = metadata; + metadata = 0; + } + + this.type = type; + this.count = count; + this.metadata = metadata == null ? 0 : metadata; + this.nbt = nbt || null; + + const itemEnum = registry.items[type]; + if (itemEnum) { + this.name = itemEnum.name; + this.displayName = itemEnum.displayName; + if ("variations" in itemEnum) { + const variation = itemEnum.variations.find((item) => item.metadata === metadata); + if (variation) this.displayName = variation.displayName; + } + this.stackSize = itemEnum.stackSize; + } else { + this.name = "unknown"; + this.displayName = "unknown"; + this.stackSize = 1; } - } } - this.stackSize = itemEnum.stackSize - } else { - this.name = 'unknown' - this.displayName = 'unknown' - this.stackSize = 1 - } - } - static equal (item1, item2, matchStackSize = true, matchNbt = true) { - if (item1 == null && item2 == null) { - return true - } else if (item1 == null) { - return false - } else if (item2 == null) { - return false - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) - ) - } - } + static equal(item1, item2, matchStackSize = true, matchNbt = true) { + if (item1 == null && item2 == null) { + return true; + } else if (item1 == null) { + return false; + } else if (item2 == null) { + return false; + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) + ); + } + } - static toNotch (item) { - if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (item == null) return { present: false } - const networkItem = { - present: true, - itemId: item.type, - itemCount: item.count + static toNotch(item, serverAuthoritative = true) { + if (registry.supportFeature("itemSerializationAllowsPresent")) { + if (item == null) return { present: false }; + const networkItem = { + present: true, + itemId: item.type, + itemCount: item.count, + }; + if (item.nbt && item.nbt.length !== 0) { + networkItem.nbtData = item.nbt; + } + return networkItem; + } else if (registry.supportFeature("itemSerializationUsesBlockId")) { + if (item == null) return { blockId: -1 }; + const networkItem = { + blockId: item.type, + itemCount: item.count, + itemDamage: item.metadata, + }; + if (item.nbt && item.nbt.length !== 0) { + networkItem.nbtData = item.nbt; + } + return networkItem; + } else if (registry.type === "bedrock") { + // TODO: older versions, stack_id + if (item.type === 0) return { network_id: 0 }; + + const networkItem = { + network_id: item.type, + count: item.count, + metadata: item.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? item.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: item.nbt !== null, + nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, + can_place_on: item.canPlaceOn, + can_destroy: item.canDestroy, + }, + }; + + return networkItem; + } + throw new Error("Don't know how to serialize for this mc version "); } - if (item.nbt && item.nbt.length !== 0) { - networkItem.nbtData = item.nbt + + static fromNotch(networkItem) { + if (registry.supportFeature("itemSerializationWillOnlyUsePresent")) { + if (networkItem.present === false) return null; + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData); + } else if (registry.supportFeature("itemSerializationAllowsPresent")) { + if (networkItem.itemId === -1 || networkItem.present === false) return null; + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData); + } else if (registry.supportFeature("itemSerializationUsesBlockId")) { + if (networkItem.blockId === -1) return null; + return new Item( + networkItem.blockId, + networkItem.itemCount, + networkItem.itemDamage, + networkItem.nbtData + ); + } else if (registry.type === "bedrock") { + // TODO: older versions, stack_id + const item = new Item( + networkItem.network_id, + networkItem.count, + networkItem.metadata, + networkItem.extra.nbt + ); + item.canPlaceOn = networkItem.extra.canPlaceOn; + item.canDestroy = networkItem.extra.canDestroy; + return item; + } + throw new Error("Don't know how to deserialize for this mc version "); } - return networkItem - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (item == null) return { blockId: -1 } - const networkItem = { - blockId: item.type, - itemCount: item.count, - itemDamage: item.metadata + + get customName() { + if (Object.keys(this).length === 0) return null; + return this?.nbt?.value?.display?.value?.Name?.value ?? null; } - if (item.nbt && item.nbt.length !== 0) { - networkItem.nbtData = item.nbt + + set customName(newName) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + this.nbt.value.display.value.Name = { type: "string", value: newName }; } - return networkItem - } - throw new Error("Don't know how to serialize for this mc version ") - } - static fromNotch (item) { - if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { - if (item.present === false) return null - return new Item(item.itemId, item.itemCount, item.nbtData) - } else if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (item.itemId === -1 || item.present === false) return null - return new Item(item.itemId, item.itemCount, item.nbtData) - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (item.blockId === -1) return null - return new Item(item.blockId, item.itemCount, item.itemDamage, item.nbtData) - } - throw new Error("Don't know how to deserialize for this mc version ") - } + get customLore() { + if (Object.keys(this).length === 0) return null; + return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null; + } - get customName () { - if (Object.keys(this).length === 0) return null - return this?.nbt?.value?.display?.value?.Name?.value ?? null - } + set customLore(newLore) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; + if (registry.type === "bedrock") { + this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; + } else { + // Is this correct? Judging by the code in the getter, + // it should be a list in java too + this.nbt.value.display.value.Lore = { type: "string", value: newLore }; + } + } - set customName (newName) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Name = { type: 'string', value: newName } - } + // gets the cost based on previous anvil uses + get repairCost() { + if (Object.keys(this).length === 0) return 0; + return this?.nbt?.value?.RepairCost?.value ?? 0; + } - get customLore () { - if (Object.keys(this).length === 0) return null - return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null - } + set repairCost(value) { + if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.RepairCost = { type: "int", value }; + } - set customLore (newLore) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Lore = { type: 'string', value: newLore } - } + get enchants() { + if (Object.keys(this).length === 0) return []; + const enchantNbtKey = registry.supportFeature("nbtNameForEnchant"); + const typeOfEnchantLevelValue = registry.supportFeature("typeOfValueForEnchantLevel"); - // gets the cost based on previous anvil uses - get repairCost () { - if (Object.keys(this).length === 0) return 0 - return this?.nbt?.value?.RepairCost?.value ?? 0 - } + // TODO: add bedrock features for enchantments to features.json in minecraft-data + if ((typeOfEnchantLevelValue === "short" && enchantNbtKey === "ench") || registry.type === "bedrock") { + let itemEnch = []; + if (this.name === "enchanted_book" && this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments; + } else if (this?.nbt?.value?.ench) { + itemEnch = nbt.simplify(this.nbt).ench; + } else { + itemEnch = []; + } + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })); + } else if (typeOfEnchantLevelValue === "string" && enchantNbtKey === "Enchantments") { + let itemEnch = []; + if (this?.nbt?.value?.Enchantments) { + itemEnch = nbt.simplify(this.nbt).Enchantments; + } else if (this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments; + } else { + itemEnch = []; + } + return itemEnch.map((ench) => ({ + lvl: ench.lvl, + name: typeof ench.id === "string" ? ench.id.replace(/minecraft:/, "") : null, + })); + } + throw new Error("Don't know how to get the enchants from an item on this mc version"); + } - set repairCost (value) { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.RepairCost = { type: 'int', value } - } + set enchants(normalizedEnchArray) { + if (registry.type === "bedrock") { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: "short", value: registry.enchantmentsByName[name].id }, + lvl: { type: "short", value: lvl }, + })); + + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; + } + } else if (registry.type === "pc") { + const isBook = this.name === "enchanted_book"; + const enchListName = registry.supportFeature("nbtNameForEnchant"); + const type = registry.supportFeature("typeOfValueForEnchantLevel"); + if (type === null) throw new Error("Don't know the serialized type for enchant level"); + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + + const enchs = normalizedEnchArray.map(({ name, lvl }) => { + const value = + type === "short" + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}`; + return { id: { type, value }, lvl: { type: "short", value: lvl } }; + }); + + if (enchs.length !== 0) { + this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = { + type: "list", + value: { type: "compound", value: enchs }, + }; + } - get enchants () { - if (Object.keys(this).length === 0) return [] - const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') - const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') - if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') { - let itemEnch - if (this.name === 'enchanted_book' && this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments - } else if (this?.nbt?.value?.ench) { - itemEnch = nbt.simplify(this.nbt).ench - } else { - itemEnch = [] + // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability + if ( + registry.supportFeature("whereDurabilityIsSerialized") === "Damage" && + registry.itemsByName[this.name].maxDurability + ) { + this.nbt.value.Damage = { type: "int", value: 0 }; + } + } } - return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) - } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { - let itemEnch = [] - if (this?.nbt?.value?.Enchantments) { - itemEnch = nbt.simplify(this.nbt).Enchantments - } else if (this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments - } else { - itemEnch = [] + + // TODO: namespaces other than minecraft: + // The item palette on bedrock can contain items + // with other namespaces, probably need to handle + // this in prismarine-registry + // Also this needs to be tested + get canPlaceOn() { + if (Object.keys(this).length === 0) return []; + + if (!this.nbt?.value?.CanPlaceOn) return []; + + return nbt.simplify(this.nbt).CanPlaceOn; } - return itemEnch.map((ench) => ({ - lvl: ench.lvl, - name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null - })) - } - throw new Error("Don't know how to get the enchants from an item on this mc version") - } - set enchants (normalizedEnchArray) { - const isBook = this.name === 'enchanted_book' - const enchListName = registry.supportFeature('nbtNameForEnchant') - const type = registry.supportFeature('typeOfValueForEnchantLevel') - if (type === null) throw new Error("Don't know the serialized type for enchant level") - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - - const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = - type === 'short' - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}` - return { id: { type, value }, lvl: { type: 'short', value: lvl } } - }) - - if (enchs.length !== 0) { - this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { - type: 'list', - value: { type: 'compound', value: enchs } + set canPlaceOn(blockNameArray) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.CanPlaceOn = { + type: "list", + value: { type: "string", value: blockNameArray }, + }; } - } - - // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if ( - registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && - registry.itemsByName[this.name].maxDurability - ) { - this.nbt.value.Damage = { type: 'int', value: 0 } - } - } - get durabilityUsed () { - if (Object.keys(this).length === 0) return null - const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage') { - return this?.nbt?.value?.Damage?.value ?? 0 - } else if (where === 'metadata') { - return this.metadata ?? 0 - } - throw new Error("Don't know how to get item durability for this mc version") - } + get canDestroy() { + if (Object.keys(this).length === 0) return []; - set durabilityUsed (value) { - const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage') { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.Damage = { type: 'int', value } - } else if (where === 'metadata') { - this.metadata = value - } else { - throw new Error("Don't know how to set item durability for this mc version") - } - } + if (!this.nbt?.value?.CanDestroy) return []; - get spawnEggMobName () { - if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { - return registry.entitiesArray.find((o) => o.internalId === this.metadata).name - } - if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { - const data = nbt.simplify(this.nbt) - const entityName = data.EntityTag.id - return entityName.replace('minecraft:', '') - } - if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { - return this.name.replace('_spawn_egg', '') - } - throw new Error("Don't know how to get spawn egg mob name for this mc version") - } + return nbt.simplify(this.nbt).CanDestroy; + } - // TODO: test this, implement it properly - // Most likely is not supported by every version - canPlaceOn (block) { - if (!this.nbt || !this.nbt.value.CanPlaceOn) return true - if (typeof block === 'string') { - return ( - this.nbt.value.CanPlaceOn.value.includes(block) || - this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block}`) - ) - } else { - return ( - this.nbt.value.CanPlaceOn.value.includes(block.name) || - this.nbt.value.CanPlaceOn.value.includes(`minecraft:${block.name}`) - ) - } - } - canDestroy (block) { - if (!this.nbt || !this.nbt.value.CanPlaceOn) return true - if (typeof block === 'string') { - return ( - this.nbt.value.CanDestroy.value.includes(block) || - this.nbt.value.CanDestroy.value.includes(`minecraft:${block}`) - ) - } else { - return ( - this.nbt.value.CanDestroy.value.includes(block.name) || - this.nbt.value.CanDestroy.value.includes(`minecraft:${block.name}`) - ) - } + set canDestroy(blockNameArray) { + if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.CanDestroy = { + type: "list", + value: { type: "string", value: blockNameArray }, + }; + } + + get durabilityUsed() { + if (Object.keys(this).length === 0) return null; + const where = registry.supportFeature("whereDurabilityIsSerialized"); + if (where === "Damage" || registry.type === "bedrock") { + return this?.nbt?.value?.Damage?.value ?? 0; + } else if (where === "metadata") { + return this.metadata ?? 0; + } + throw new Error("Don't know how to get item durability for this mc version"); + } + + set durabilityUsed(value) { + const where = registry.supportFeature("whereDurabilityIsSerialized"); + if (where === "Damage" || registry.type === "bedrock") { + if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; + this.nbt.value.Damage = { type: "int", value }; + } else if (where === "metadata") { + this.metadata = value; + } else { + throw new Error("Don't know how to set item durability for this mc version"); + } + } + + get spawnEggMobName() { + if (registry.supportFeature("spawnEggsUseInternalIdInNbt")) { + return registry.entitiesArray.find((o) => o.internalId === this.metadata).name; + } + if (registry.supportFeature("spawnEggsUseEntityTagInNbt")) { + const data = nbt.simplify(this.nbt); + const entityName = data.EntityTag.id; + return entityName.replace("minecraft:", ""); + } + if (registry.supportFeature("spawnEggsHaveSpawnedEntityInName")) { + return this.name.replace("_spawn_egg", ""); + } + if (registry.type === "bedrock") { + // TODO: add to features.json + // According to the wiki, the different metadata values were split + // into their own IDs in 1.16.100 + // https://minecraft.fandom.com/wiki/Spawn_Egg#History + return this.name.replace("_spawn_egg", ""); + } + throw new Error("Don't know how to get spawn egg mob name for this mc version"); + } } - } - Item.anvil = require('./lib/anvil.js')(registry, Item) - return Item + Item.anvil = require("./lib/anvil.js")(registry, Item); + return Item; } -module.exports = loader +module.exports = loader; From c07449fc37c9811fb2306a2de8d668a2b1c354bc Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Fri, 3 Mar 2023 19:15:18 +0100 Subject: [PATCH 19/50] Linter --- index.js | 599 +++++++++++++++++++++++++++---------------------------- 1 file changed, 299 insertions(+), 300 deletions(-) diff --git a/index.js b/index.js index 0bfbb5f..f7bf9da 100644 --- a/index.js +++ b/index.js @@ -1,331 +1,330 @@ -const nbt = require("prismarine-nbt"); -function loader(registryOrVersion) { - const registry = - typeof registryOrVersion === "string" ? require("prismarine-registry")(registryOrVersion) : registryOrVersion; - class Item { - constructor(type, count, metadata, nbt) { - if (type == null) return; - - if (metadata instanceof Object && metadata !== null) { - nbt = metadata; - metadata = 0; - } - - this.type = type; - this.count = count; - this.metadata = metadata == null ? 0 : metadata; - this.nbt = nbt || null; - - const itemEnum = registry.items[type]; - if (itemEnum) { - this.name = itemEnum.name; - this.displayName = itemEnum.displayName; - if ("variations" in itemEnum) { - const variation = itemEnum.variations.find((item) => item.metadata === metadata); - if (variation) this.displayName = variation.displayName; - } - this.stackSize = itemEnum.stackSize; - } else { - this.name = "unknown"; - this.displayName = "unknown"; - this.stackSize = 1; - } +const nbt = require('prismarine-nbt') +function loader (registryOrVersion) { + const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion + class Item { + constructor (type, count, metadata, nbt) { + if (type == null) return + + if (metadata instanceof Object && metadata !== null) { + nbt = metadata + metadata = 0 + } + + this.type = type + this.count = count + this.metadata = metadata == null ? 0 : metadata + this.nbt = nbt || null + + const itemEnum = registry.items[type] + if (itemEnum) { + this.name = itemEnum.name + this.displayName = itemEnum.displayName + if ('variations' in itemEnum) { + const variation = itemEnum.variations.find((item) => item.metadata === metadata) + if (variation) this.displayName = variation.displayName } + this.stackSize = itemEnum.stackSize + } else { + this.name = 'unknown' + this.displayName = 'unknown' + this.stackSize = 1 + } + } - static equal(item1, item2, matchStackSize = true, matchNbt = true) { - if (item1 == null && item2 == null) { - return true; - } else if (item1 == null) { - return false; - } else if (item2 == null) { - return false; - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) - ); - } - } + static equal (item1, item2, matchStackSize = true, matchNbt = true) { + if (item1 == null && item2 == null) { + return true + } else if (item1 == null) { + return false + } else if (item2 == null) { + return false + } else { + return ( + item1.type === item2.type && + (matchStackSize ? item1.count === item2.count : true) && + item1.metadata === item2.metadata && + (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) + ) + } + } - static toNotch(item, serverAuthoritative = true) { - if (registry.supportFeature("itemSerializationAllowsPresent")) { - if (item == null) return { present: false }; - const networkItem = { - present: true, - itemId: item.type, - itemCount: item.count, - }; - if (item.nbt && item.nbt.length !== 0) { - networkItem.nbtData = item.nbt; - } - return networkItem; - } else if (registry.supportFeature("itemSerializationUsesBlockId")) { - if (item == null) return { blockId: -1 }; - const networkItem = { - blockId: item.type, - itemCount: item.count, - itemDamage: item.metadata, - }; - if (item.nbt && item.nbt.length !== 0) { - networkItem.nbtData = item.nbt; - } - return networkItem; - } else if (registry.type === "bedrock") { - // TODO: older versions, stack_id - if (item.type === 0) return { network_id: 0 }; - - const networkItem = { - network_id: item.type, - count: item.count, - metadata: item.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? item.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: item.nbt !== null, - nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, - can_place_on: item.canPlaceOn, - can_destroy: item.canDestroy, - }, - }; - - return networkItem; - } - throw new Error("Don't know how to serialize for this mc version "); + static toNotch (item, serverAuthoritative = true) { + if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (item == null) return { present: false } + const networkItem = { + present: true, + itemId: item.type, + itemCount: item.count } - - static fromNotch(networkItem) { - if (registry.supportFeature("itemSerializationWillOnlyUsePresent")) { - if (networkItem.present === false) return null; - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData); - } else if (registry.supportFeature("itemSerializationAllowsPresent")) { - if (networkItem.itemId === -1 || networkItem.present === false) return null; - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData); - } else if (registry.supportFeature("itemSerializationUsesBlockId")) { - if (networkItem.blockId === -1) return null; - return new Item( - networkItem.blockId, - networkItem.itemCount, - networkItem.itemDamage, - networkItem.nbtData - ); - } else if (registry.type === "bedrock") { - // TODO: older versions, stack_id - const item = new Item( - networkItem.network_id, - networkItem.count, - networkItem.metadata, - networkItem.extra.nbt - ); - item.canPlaceOn = networkItem.extra.canPlaceOn; - item.canDestroy = networkItem.extra.canDestroy; - return item; - } - throw new Error("Don't know how to deserialize for this mc version "); + if (item.nbt && item.nbt.length !== 0) { + networkItem.nbtData = item.nbt } - - get customName() { - if (Object.keys(this).length === 0) return null; - return this?.nbt?.value?.display?.value?.Name?.value ?? null; + return networkItem + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (item == null) return { blockId: -1 } + const networkItem = { + blockId: item.type, + itemCount: item.count, + itemDamage: item.metadata } - - set customName(newName) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - this.nbt.value.display.value.Name = { type: "string", value: newName }; + if (item.nbt && item.nbt.length !== 0) { + networkItem.nbtData = item.nbt } - - get customLore() { - if (Object.keys(this).length === 0) return null; - return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null; + return networkItem + } else if (registry.type === 'bedrock') { + // TODO: older versions, stack_id + if (item.type === 0) return { network_id: 0 } + + const networkItem = { + network_id: item.type, + count: item.count, + metadata: item.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? item.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: item.nbt !== null, + nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, + can_place_on: item.canPlaceOn, + can_destroy: item.canDestroy + } } - set customLore(newLore) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - if (!this.nbt.value.display) this.nbt.value.display = { type: "compound", value: {} }; - if (registry.type === "bedrock") { - this.nbt.value.display.value.Lore = { type: "list", value: { type: "string", value: newLore } }; - } else { - // Is this correct? Judging by the code in the getter, - // it should be a list in java too - this.nbt.value.display.value.Lore = { type: "string", value: newLore }; - } - } + return networkItem + } + throw new Error("Don't know how to serialize for this mc version ") + } - // gets the cost based on previous anvil uses - get repairCost() { - if (Object.keys(this).length === 0) return 0; - return this?.nbt?.value?.RepairCost?.value ?? 0; - } + static fromNotch (networkItem) { + if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { + if (networkItem.present === false) return null + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + } else if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (networkItem.itemId === -1 || networkItem.present === false) return null + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (networkItem.blockId === -1) return null + return new Item( + networkItem.blockId, + networkItem.itemCount, + networkItem.itemDamage, + networkItem.nbtData + ) + } else if (registry.type === 'bedrock') { + // TODO: older versions, stack_id + const item = new Item( + networkItem.network_id, + networkItem.count, + networkItem.metadata, + networkItem.extra.nbt + ) + item.canPlaceOn = networkItem.extra.canPlaceOn + item.canDestroy = networkItem.extra.canDestroy + return item + } + throw new Error("Don't know how to deserialize for this mc version ") + } + + get customName () { + if (Object.keys(this).length === 0) return null + return this?.nbt?.value?.display?.value?.Name?.value ?? null + } + + set customName (newName) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + this.nbt.value.display.value.Name = { type: 'string', value: newName } + } + + get customLore () { + if (Object.keys(this).length === 0) return null + return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null + } + + set customLore (newLore) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } + if (registry.type === 'bedrock') { + this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } + } else { + // Is this correct? Judging by the code in the getter, + // it should be a list in java too + this.nbt.value.display.value.Lore = { type: 'string', value: newLore } + } + } + + // gets the cost based on previous anvil uses + get repairCost () { + if (Object.keys(this).length === 0) return 0 + return this?.nbt?.value?.RepairCost?.value ?? 0 + } - set repairCost(value) { - if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.RepairCost = { type: "int", value }; + set repairCost (value) { + if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.RepairCost = { type: 'int', value } + } + + get enchants () { + if (Object.keys(this).length === 0) return [] + const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') + const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') + + // TODO: add bedrock features for enchantments to features.json in minecraft-data + if ((typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') || registry.type === 'bedrock') { + let itemEnch = [] + if (this.name === 'enchanted_book' && this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments + } else if (this?.nbt?.value?.ench) { + itemEnch = nbt.simplify(this.nbt).ench + } else { + itemEnch = [] + } + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) + } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { + let itemEnch = [] + if (this?.nbt?.value?.Enchantments) { + itemEnch = nbt.simplify(this.nbt).Enchantments + } else if (this?.nbt?.value?.StoredEnchantments) { + itemEnch = nbt.simplify(this.nbt).StoredEnchantments + } else { + itemEnch = [] } + return itemEnch.map((ench) => ({ + lvl: ench.lvl, + name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null + })) + } + throw new Error("Don't know how to get the enchants from an item on this mc version") + } + + set enchants (normalizedEnchArray) { + if (registry.type === 'bedrock') { + const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + id: { type: 'short', value: registry.enchantmentsByName[name].id }, + lvl: { type: 'short', value: lvl } + })) - get enchants() { - if (Object.keys(this).length === 0) return []; - const enchantNbtKey = registry.supportFeature("nbtNameForEnchant"); - const typeOfEnchantLevelValue = registry.supportFeature("typeOfValueForEnchantLevel"); - - // TODO: add bedrock features for enchantments to features.json in minecraft-data - if ((typeOfEnchantLevelValue === "short" && enchantNbtKey === "ench") || registry.type === "bedrock") { - let itemEnch = []; - if (this.name === "enchanted_book" && this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments; - } else if (this?.nbt?.value?.ench) { - itemEnch = nbt.simplify(this.nbt).ench; - } else { - itemEnch = []; - } - return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })); - } else if (typeOfEnchantLevelValue === "string" && enchantNbtKey === "Enchantments") { - let itemEnch = []; - if (this?.nbt?.value?.Enchantments) { - itemEnch = nbt.simplify(this.nbt).Enchantments; - } else if (this?.nbt?.value?.StoredEnchantments) { - itemEnch = nbt.simplify(this.nbt).StoredEnchantments; - } else { - itemEnch = []; - } - return itemEnch.map((ench) => ({ - lvl: ench.lvl, - name: typeof ench.id === "string" ? ench.id.replace(/minecraft:/, "") : null, - })); - } - throw new Error("Don't know how to get the enchants from an item on this mc version"); + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } + } + } else if (registry.type === 'pc') { + const isBook = this.name === 'enchanted_book' + const enchListName = registry.supportFeature('nbtNameForEnchant') + const type = registry.supportFeature('typeOfValueForEnchantLevel') + if (type === null) throw new Error("Don't know the serialized type for enchant level") + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + + const enchs = normalizedEnchArray.map(({ name, lvl }) => { + const value = + type === 'short' + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}` + return { id: { type, value }, lvl: { type: 'short', value: lvl } } + }) + + if (enchs.length !== 0) { + this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { + type: 'list', + value: { type: 'compound', value: enchs } + } } - set enchants(normalizedEnchArray) { - if (registry.type === "bedrock") { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: "short", value: registry.enchantmentsByName[name].id }, - lvl: { type: "short", value: lvl }, - })); - - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.ench = { type: "list", value: { type: "compound", value: enchs } }; - } - } else if (registry.type === "pc") { - const isBook = this.name === "enchanted_book"; - const enchListName = registry.supportFeature("nbtNameForEnchant"); - const type = registry.supportFeature("typeOfValueForEnchantLevel"); - if (type === null) throw new Error("Don't know the serialized type for enchant level"); - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - - const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = - type === "short" - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}`; - return { id: { type, value }, lvl: { type: "short", value: lvl } }; - }); - - if (enchs.length !== 0) { - this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = { - type: "list", - value: { type: "compound", value: enchs }, - }; - } - - // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if ( - registry.supportFeature("whereDurabilityIsSerialized") === "Damage" && - registry.itemsByName[this.name].maxDurability - ) { - this.nbt.value.Damage = { type: "int", value: 0 }; - } - } + // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability + if ( + registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && + registry.itemsByName[this.name].maxDurability + ) { + this.nbt.value.Damage = { type: 'int', value: 0 } } + } + } - // TODO: namespaces other than minecraft: - // The item palette on bedrock can contain items - // with other namespaces, probably need to handle - // this in prismarine-registry - // Also this needs to be tested - get canPlaceOn() { - if (Object.keys(this).length === 0) return []; + // TODO: namespaces other than minecraft: + // The item palette on bedrock can contain items + // with other namespaces, probably need to handle + // this in prismarine-registry + // Also this needs to be tested + get canPlaceOn () { + if (Object.keys(this).length === 0) return [] - if (!this.nbt?.value?.CanPlaceOn) return []; + if (!this.nbt?.value?.CanPlaceOn) return [] - return nbt.simplify(this.nbt).CanPlaceOn; - } + return nbt.simplify(this.nbt).CanPlaceOn + } - set canPlaceOn(blockNameArray) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.CanPlaceOn = { - type: "list", - value: { type: "string", value: blockNameArray }, - }; - } + set canPlaceOn (blockNameArray) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.CanPlaceOn = { + type: 'list', + value: { type: 'string', value: blockNameArray } + } + } - get canDestroy() { - if (Object.keys(this).length === 0) return []; + get canDestroy () { + if (Object.keys(this).length === 0) return [] - if (!this.nbt?.value?.CanDestroy) return []; + if (!this.nbt?.value?.CanDestroy) return [] - return nbt.simplify(this.nbt).CanDestroy; - } + return nbt.simplify(this.nbt).CanDestroy + } - set canDestroy(blockNameArray) { - if (!this.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.CanDestroy = { - type: "list", - value: { type: "string", value: blockNameArray }, - }; - } + set canDestroy (blockNameArray) { + if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.CanDestroy = { + type: 'list', + value: { type: 'string', value: blockNameArray } + } + } - get durabilityUsed() { - if (Object.keys(this).length === 0) return null; - const where = registry.supportFeature("whereDurabilityIsSerialized"); - if (where === "Damage" || registry.type === "bedrock") { - return this?.nbt?.value?.Damage?.value ?? 0; - } else if (where === "metadata") { - return this.metadata ?? 0; - } - throw new Error("Don't know how to get item durability for this mc version"); - } + get durabilityUsed () { + if (Object.keys(this).length === 0) return null + const where = registry.supportFeature('whereDurabilityIsSerialized') + if (where === 'Damage' || registry.type === 'bedrock') { + return this?.nbt?.value?.Damage?.value ?? 0 + } else if (where === 'metadata') { + return this.metadata ?? 0 + } + throw new Error("Don't know how to get item durability for this mc version") + } - set durabilityUsed(value) { - const where = registry.supportFeature("whereDurabilityIsSerialized"); - if (where === "Damage" || registry.type === "bedrock") { - if (!this?.nbt) this.nbt = { name: "", type: "compound", value: {} }; - this.nbt.value.Damage = { type: "int", value }; - } else if (where === "metadata") { - this.metadata = value; - } else { - throw new Error("Don't know how to set item durability for this mc version"); - } - } + set durabilityUsed (value) { + const where = registry.supportFeature('whereDurabilityIsSerialized') + if (where === 'Damage' || registry.type === 'bedrock') { + if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } + this.nbt.value.Damage = { type: 'int', value } + } else if (where === 'metadata') { + this.metadata = value + } else { + throw new Error("Don't know how to set item durability for this mc version") + } + } - get spawnEggMobName() { - if (registry.supportFeature("spawnEggsUseInternalIdInNbt")) { - return registry.entitiesArray.find((o) => o.internalId === this.metadata).name; - } - if (registry.supportFeature("spawnEggsUseEntityTagInNbt")) { - const data = nbt.simplify(this.nbt); - const entityName = data.EntityTag.id; - return entityName.replace("minecraft:", ""); - } - if (registry.supportFeature("spawnEggsHaveSpawnedEntityInName")) { - return this.name.replace("_spawn_egg", ""); - } - if (registry.type === "bedrock") { - // TODO: add to features.json - // According to the wiki, the different metadata values were split - // into their own IDs in 1.16.100 - // https://minecraft.fandom.com/wiki/Spawn_Egg#History - return this.name.replace("_spawn_egg", ""); - } - throw new Error("Don't know how to get spawn egg mob name for this mc version"); - } + get spawnEggMobName () { + if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { + return registry.entitiesArray.find((o) => o.internalId === this.metadata).name + } + if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { + const data = nbt.simplify(this.nbt) + const entityName = data.EntityTag.id + return entityName.replace('minecraft:', '') + } + if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { + return this.name.replace('_spawn_egg', '') + } + if (registry.type === 'bedrock') { + // TODO: add to features.json + // According to the wiki, the different metadata values were split + // into their own IDs in 1.16.100 + // https://minecraft.fandom.com/wiki/Spawn_Egg#History + return this.name.replace('_spawn_egg', '') + } + throw new Error("Don't know how to get spawn egg mob name for this mc version") } + } - Item.anvil = require("./lib/anvil.js")(registry, Item); - return Item; + Item.anvil = require('./lib/anvil.js')(registry, Item) + return Item } -module.exports = loader; +module.exports = loader From b7842439c9967b353e611b38389b6b71c1f10676 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sat, 4 Mar 2023 16:55:07 +0100 Subject: [PATCH 20/50] blocksCanPlaceOn and blocksCanDestroy --- README.md | 10 +++++++++- index.js | 36 ++++++++++-------------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 105c1ca..2fd7ace 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,14 @@ the item's custom lore (ie. set in give command) A getter/setter for abstracting the underlying nbt (does calculations) +#### item.blocksCanPlaceOn + +A getter/setter for abstracting the underlying nbt, an array of block names that this item can be placed on in adventure mode + +#### item.blocksCanDestroy + +A getter/setter for abstracting the underlying nbt, an array of block names that this item can destroy in adventure mode + #### item.repairCost A getter/setter for abstracting the underlying nbt. @@ -91,7 +99,7 @@ See https://minecraft.gamepedia.com/Anvil_mechanics#Anvil_Uses #### item.spawnEggMobName -A getter for abstracting the underlying nbt, get's the mob name from a spawn egg Item. e.g. a zombie spawn egg on 1.8 will return `Zombie` +A getter for abstracting the underlying nbt, gets the mob name from a spawn egg Item. e.g. a zombie spawn egg on 1.8 will return `Zombie` ## History diff --git a/index.js b/index.js index f7bf9da..505ecbb 100644 --- a/index.js +++ b/index.js @@ -104,22 +104,12 @@ function loader (registryOrVersion) { return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (networkItem.blockId === -1) return null - return new Item( - networkItem.blockId, - networkItem.itemCount, - networkItem.itemDamage, - networkItem.nbtData - ) + return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) } else if (registry.type === 'bedrock') { // TODO: older versions, stack_id - const item = new Item( - networkItem.network_id, - networkItem.count, - networkItem.metadata, - networkItem.extra.nbt - ) - item.canPlaceOn = networkItem.extra.canPlaceOn - item.canDestroy = networkItem.extra.canDestroy + const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt) + item.blocksCanPlaceOn = networkItem.extra.canPlaceOn + item.blocksCanDestroy = networkItem.extra.canDestroy return item } throw new Error("Don't know how to deserialize for this mc version ") @@ -245,7 +235,7 @@ function loader (registryOrVersion) { // with other namespaces, probably need to handle // this in prismarine-registry // Also this needs to be tested - get canPlaceOn () { + get blocksCanPlaceOn () { if (Object.keys(this).length === 0) return [] if (!this.nbt?.value?.CanPlaceOn) return [] @@ -253,15 +243,12 @@ function loader (registryOrVersion) { return nbt.simplify(this.nbt).CanPlaceOn } - set canPlaceOn (blockNameArray) { + set blocksCanPlaceOn (blocks) { if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.CanPlaceOn = { - type: 'list', - value: { type: 'string', value: blockNameArray } - } + this.nbt.value.CanPlaceOn = nbt.list(nbt.string(blocks.map(b => b.startsWith('minecraft:') ? b : `minecraft:${b}`))) } - get canDestroy () { + get blocksCanDestroy () { if (Object.keys(this).length === 0) return [] if (!this.nbt?.value?.CanDestroy) return [] @@ -269,12 +256,9 @@ function loader (registryOrVersion) { return nbt.simplify(this.nbt).CanDestroy } - set canDestroy (blockNameArray) { + set blocksCanDestroy (blocks) { if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.CanDestroy = { - type: 'list', - value: { type: 'string', value: blockNameArray } - } + this.nbt.value.CanDestroy = nbt.list(nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`)))) } get durabilityUsed () { From 738356deb7bed5ccd74bf4a09b915814cb0ffd71 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sat, 4 Mar 2023 17:04:55 +0100 Subject: [PATCH 21/50] start implementing stack ID --- index.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 505ecbb..60065f1 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,11 @@ const nbt = require('prismarine-nbt') function loader (registryOrVersion) { const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion class Item { - constructor (type, count, metadata, nbt) { + constructor (type, count, metadata, nbt, stackId) { if (type == null) return if (metadata instanceof Object && metadata !== null) { + stackId = nbt nbt = metadata metadata = 0 } @@ -14,6 +15,7 @@ function loader (registryOrVersion) { this.count = count this.metadata = metadata == null ? 0 : metadata this.nbt = nbt || null + this.stackId = stackId ?? Item.nextStackId() const itemEnum = registry.items[type] if (itemEnum) { @@ -48,6 +50,12 @@ function loader (registryOrVersion) { } } + // Stack ID + static currentStackId = 0 + static nextStackId () { + return Item.currentStackId++ + } + static toNotch (item, serverAuthoritative = true) { if (registry.supportFeature('itemSerializationAllowsPresent')) { if (item == null) return { present: false } @@ -73,6 +81,9 @@ function loader (registryOrVersion) { return networkItem } else if (registry.type === 'bedrock') { // TODO: older versions, stack_id + // item format changes in 1.16.220, NBT data isn't inside extra field + // stack ID related fields and block runtime ID don't exist + // <.220 there is a field called auxiliary_value if (item.type === 0) return { network_id: 0 } const networkItem = { @@ -245,7 +256,9 @@ function loader (registryOrVersion) { set blocksCanPlaceOn (blocks) { if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.CanPlaceOn = nbt.list(nbt.string(blocks.map(b => b.startsWith('minecraft:') ? b : `minecraft:${b}`))) + this.nbt.value.CanPlaceOn = nbt.list( + nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) + ) } get blocksCanDestroy () { @@ -258,7 +271,9 @@ function loader (registryOrVersion) { set blocksCanDestroy (blocks) { if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.CanDestroy = nbt.list(nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`)))) + this.nbt.value.CanDestroy = nbt.list( + nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) + ) } get durabilityUsed () { From 11b1b3eaa2973abf23dcde9b6d1f97f1aac71792 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sat, 4 Mar 2023 17:06:18 +0100 Subject: [PATCH 22/50] add stack ID to fromNotch() --- index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 60065f1..37a35c9 100644 --- a/index.js +++ b/index.js @@ -118,7 +118,13 @@ function loader (registryOrVersion) { return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) } else if (registry.type === 'bedrock') { // TODO: older versions, stack_id - const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt) + const item = new Item( + networkItem.network_id, + networkItem.count, + networkItem.metadata, + networkItem.extra.nbt, + networkItem.stack_id + ) item.blocksCanPlaceOn = networkItem.extra.canPlaceOn item.blocksCanDestroy = networkItem.extra.canDestroy return item From 20937d4e7ef35a88103077498ac7188b655b0822 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 13:38:36 +0100 Subject: [PATCH 23/50] Initial support for <1.16.220, however item formats are inconsistent and this can be improved --- index.js | 91 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index 37a35c9..b6923cc 100644 --- a/index.js +++ b/index.js @@ -80,28 +80,45 @@ function loader (registryOrVersion) { } return networkItem } else if (registry.type === 'bedrock') { - // TODO: older versions, stack_id - // item format changes in 1.16.220, NBT data isn't inside extra field - // stack ID related fields and block runtime ID don't exist - // <.220 there is a field called auxiliary_value - if (item.type === 0) return { network_id: 0 } + // This can later be changed to use supportFeature + if (registry.version['<']('1.16.220')) { + if (item.type === 0) return { runtime_id: 0, item: { network_id: 0 } } + + const networkItem = { + runtime_id: item.id, + item: { + network_id: item.id, + auxiliary_value: (item.metadata << 8) | (item.count & 0xff), + has_nbt: item.nbt !== null, + nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, + can_place_on: item.blocksCanPlaceOn, + can_destroy: item.blocksCanDestroy + // blocking_tick: 0, // TODO + } + } - const networkItem = { - network_id: item.type, - count: item.count, - metadata: item.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? item.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: item.nbt !== null, - nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, - can_place_on: item.canPlaceOn, - can_destroy: item.canDestroy + return networkItem + } else { + if (item.type === 0) return { network_id: 0 } + + const networkItem = { + network_id: item.type, + count: item.count, + metadata: item.metadata, + has_stack_id: serverAuthoritative, + stack_id: serverAuthoritative ? item.stackId : undefined, + block_runtime_id: 0, // TODO + extra: { + has_nbt: item.nbt !== null, + nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, + can_place_on: item.canPlaceOn, + can_destroy: item.canDestroy + // blocking_tick: 0, // TODO + } } - } - return networkItem + return networkItem + } } throw new Error("Don't know how to serialize for this mc version ") } @@ -117,17 +134,31 @@ function loader (registryOrVersion) { if (networkItem.blockId === -1) return null return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) } else if (registry.type === 'bedrock') { - // TODO: older versions, stack_id - const item = new Item( - networkItem.network_id, - networkItem.count, - networkItem.metadata, - networkItem.extra.nbt, - networkItem.stack_id - ) - item.blocksCanPlaceOn = networkItem.extra.canPlaceOn - item.blocksCanDestroy = networkItem.extra.canDestroy - return item + if (registry.version['<']('1.16.220')) { + // unsure about this, different packets use slightly different formats, but everything + // in the item field stays the same - just sometimes it isn't in the item field + const item = new Item( + networkItem.item?.network_id ?? networkItem.network_id, + (networkItem.item?.auxiliary_value ?? networkItem.auxiliary_value) & 0xff, + (networkItem.item?.auxiliary_value ?? networkItem.auxiliary_value) >> 8, + networkItem.item?.nbt ?? networkItem.nbt, + networkItem.stack_id + ) + item.blocksCanPlaceOn = networkItem.item?.can_place_on ?? networkItem.can_place_on + item.blocksCanDestroy = networkItem.item?.can_destroy ?? networkItem.can_destroy + return item + } else { + const item = new Item( + networkItem.network_id, + networkItem.count, + networkItem.metadata, + networkItem.extra.nbt, + networkItem.stack_id + ) + item.blocksCanPlaceOn = networkItem.extra.canPlaceOn + item.blocksCanDestroy = networkItem.extra.canDestroy + return item + } } throw new Error("Don't know how to deserialize for this mc version ") } From afb0d997cc2b30ab1c87ca21617988752778aef4 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 14:17:07 +0100 Subject: [PATCH 24/50] <1.16.220 support, can be improved later to use supportFeature() --- index.js | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index b6923cc..a36e520 100644 --- a/index.js +++ b/index.js @@ -81,31 +81,25 @@ function loader (registryOrVersion) { return networkItem } else if (registry.type === 'bedrock') { // This can later be changed to use supportFeature + if (item.type === 0) return { network_id: 0 } if (registry.version['<']('1.16.220')) { - if (item.type === 0) return { runtime_id: 0, item: { network_id: 0 } } - const networkItem = { - runtime_id: item.id, - item: { - network_id: item.id, - auxiliary_value: (item.metadata << 8) | (item.count & 0xff), - has_nbt: item.nbt !== null, - nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, - can_place_on: item.blocksCanPlaceOn, - can_destroy: item.blocksCanDestroy - // blocking_tick: 0, // TODO - } + network_id: item.id, + auxiliary_value: (item.metadata << 8) | (item.count & 0xff), + has_nbt: item.nbt !== null, + nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, + can_place_on: item.blocksCanPlaceOn, + can_destroy: item.blocksCanDestroy + // blocking_tick: 0, // TODO } return networkItem } else { - if (item.type === 0) return { network_id: 0 } - const networkItem = { network_id: item.type, count: item.count, metadata: item.metadata, - has_stack_id: serverAuthoritative, + has_stack_id: +serverAuthoritative, stack_id: serverAuthoritative ? item.stackId : undefined, block_runtime_id: 0, // TODO extra: { @@ -123,7 +117,7 @@ function loader (registryOrVersion) { throw new Error("Don't know how to serialize for this mc version ") } - static fromNotch (networkItem) { + static fromNotch (networkItem, stackId) { if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { if (networkItem.present === false) return null return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) @@ -138,11 +132,11 @@ function loader (registryOrVersion) { // unsure about this, different packets use slightly different formats, but everything // in the item field stays the same - just sometimes it isn't in the item field const item = new Item( - networkItem.item?.network_id ?? networkItem.network_id, - (networkItem.item?.auxiliary_value ?? networkItem.auxiliary_value) & 0xff, - (networkItem.item?.auxiliary_value ?? networkItem.auxiliary_value) >> 8, - networkItem.item?.nbt ?? networkItem.nbt, - networkItem.stack_id + networkItem.network_id, + networkItem.auxiliary_value & 0xff, + networkItem.auxiliary_value >> 8, + networkItem.nbt, + stackId ) item.blocksCanPlaceOn = networkItem.item?.can_place_on ?? networkItem.can_place_on item.blocksCanDestroy = networkItem.item?.can_destroy ?? networkItem.can_destroy From e8d03a482e3764972597a0fa0f4088596e17a70c Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 14:24:07 +0100 Subject: [PATCH 25/50] update types and docs --- README.md | 11 ++++--- index.d.ts | 92 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 2fd7ace..20cb54b 100644 --- a/README.md +++ b/README.md @@ -19,21 +19,22 @@ console.log(Item.fromNotch(notchItem)) ## API -### Item(type, count[, metadata], nbt) +### Item(type, count[, metadata, nbt, stackId]) #### Item.toNotch(item) Take an `item` in the format of the minecraft packets and return an `Item` instance. -#### Item.fromNotch(item) +#### Item.fromNotch(item[, stackId]) -Take an `Item` instance and return it in the format of the minecraft packets. +Take an `Item` instance and returns it in the format of the minecraft packets. +- stackId for bedrock items before 1.16.220 ### Item.anvil(itemOne, itemTwo, creative[, newName]) Take two seperate `item` instances, and makes one item using the same combining done by the vanilla anvil -### Item.equal(itemOne, itemTwo[, matchStackSize]) +### Item.equal(itemOne, itemTwo[, matchStackSize, matchNbt]) `itemOne` - first item @@ -41,6 +42,8 @@ Take two seperate `item` instances, and makes one item using the same combining `matchStackSize` - whether to check for count equality +`matchNbt` - wether to check for NBT equality + Checks equality between two items based on itemType, count, metadata, and stringified nbt #### item.type diff --git a/index.d.ts b/index.d.ts index fb7ce9d..6f5b47c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,38 +5,72 @@ import { Tags, TagType } from 'prismarine-nbt' type ItemLike = Item | null declare class Item { - constructor(type: number, count: number, metadata?: number, nbt?: object); - type: number; - slot: number; - count: number; - metadata: number; - nbt: Tags[TagType] | null; - name: string; - displayName: string; - stackSize: number; - durabilityUsed: number; - enchants: NormalizedEnchant[]; - repairCost: number; - customName: string | null; - customLore: string | null; - readonly spawnEggMobName: string; - static equal(item1: Item, item2: Item, matchStackSize: boolean): boolean; - static toNotch(item: ItemLike): NotchItem; - static fromNotch(item: NotchItem): ItemLike; - static anvil (itemOne: ItemLike, itemTwo: ItemLike, creative: boolean, rename: string | undefined): { xpCost: number, item: ItemLike } + constructor(type: number, count: number, metadata?: number, nbt?: object, stackId?: number); + type: number; + slot: number; + count: number; + metadata: number; + nbt: Tags[TagType] | null; + stackId: number; + name: string; + displayName: string; + stackSize: number; + durabilityUsed: number; + enchants: NormalizedEnchant[]; + blocksCanPlaceOn: string[]; + blocksCanDestroy: string[]; + repairCost: number; + customName: string | null; + customLore: string | null; + readonly spawnEggMobName: string; + static equal(item1: Item, item2: Item, matchStackSize: boolean, matchNbt: boolean): boolean; + static toNotch(item: ItemLike): NetworkItem; + static fromNotch(item: NetworkItem): ItemLike; + static anvil( + itemOne: ItemLike, + itemTwo: ItemLike, + creative: boolean, + rename: string | undefined + ): { xpCost: number; item: ItemLike }; + static currentStackId: number; + static nextStackId(): number; } -declare interface NotchItem { - // 1.8 - 1.12 - blockId?: number; - itemDamage?: number; - // 1.13 - 1.15 - present?: boolean; - itemId?: number; +declare type PcNetworkItem = { + // 1.8 - 1.12 + blockId?: number; + itemDamage?: number; + // 1.13 - 1.15 + present?: boolean; + itemId?: number; - itemCount?: number; - nbtData?: Buffer; -} + itemCount?: number; + nbtData?: Buffer; +}; + +declare type BedrockNetworkItem = + | { network_id: 0 } + | ({ + // >= 1.16.220 + network_id: number; + count: number; + metadata: number; + block_runtime_id: number; + extra: { + can_place_on: string[]; + can_destroy: string[]; + blocking_tick?: number; + } & ({ has_nbt: false } | { has_nbt: true; nbt: { version: 1; nbt: Tags[TagType] } }); + } & ({ has_stack_id: 0 } | { has_stack_id: 1; stack_id: number })) + | ({ + // < 1.16.220 + network_id: number; + auxiliary_value: number; + can_place_on: string[]; + can_destroy: string[]; + } & ({ has_nbt: false } | { has_nbt: true; nbt: { version: 1; nbt: Tags[TagType] } })); + +declare type NetworkItem = PcNetworkItem | BedrockNetworkItem; declare interface NormalizedEnchant { name: string; From 6aaa0664d12ecd152c68f14bf364d38b99b22989 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 14:26:07 +0100 Subject: [PATCH 26/50] update docs --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 20cb54b..11a1818 100644 --- a/README.md +++ b/README.md @@ -89,11 +89,11 @@ A getter/setter for abstracting the underlying nbt (does calculations) #### item.blocksCanPlaceOn -A getter/setter for abstracting the underlying nbt, an array of block names that this item can be placed on in adventure mode +In adventure mode, the list of block names (as strings) that this Item can be placed on #### item.blocksCanDestroy -A getter/setter for abstracting the underlying nbt, an array of block names that this item can destroy in adventure mode +In adventure mode, the list of block names (as strings) that this Item can be used to break #### item.repairCost @@ -102,7 +102,7 @@ See https://minecraft.gamepedia.com/Anvil_mechanics#Anvil_Uses #### item.spawnEggMobName -A getter for abstracting the underlying nbt, gets the mob name from a spawn egg Item. e.g. a zombie spawn egg on 1.8 will return `Zombie` +If the current item is a type of Spawn Egg, the protocol name of the entity that will be spawned. For example, a zombie spawn egg on 1.8 will return `Zombie`. ## History From a81f9069f3417e438fd9eb9d34d5833d2b2eb61d Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 14:48:24 +0100 Subject: [PATCH 27/50] use NBT builder functions where possible --- index.js | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index a36e520..43c9894 100644 --- a/index.js +++ b/index.js @@ -163,25 +163,25 @@ function loader (registryOrVersion) { } set customName (newName) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt) this.nbt = nbt.comp({}) if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Name = { type: 'string', value: newName } + this.nbt.value.display.value.Name = nbt.string(newName) } get customLore () { if (Object.keys(this).length === 0) return null + // feature: itemLoreIsAString return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null } set customLore (newLore) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt) this.nbt = nbt.comp({}) if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } if (registry.type === 'bedrock') { - this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } + this.nbt.value.display.value.Lore = nbt.list(nbt.string(newLore)) } else { - // Is this correct? Judging by the code in the getter, - // it should be a list in java too - this.nbt.value.display.value.Lore = { type: 'string', value: newLore } + // feature: itemLoreIsAString + this.nbt.value.display.value.Lore = nbt.string(newLore) } } @@ -191,9 +191,9 @@ function loader (registryOrVersion) { return this?.nbt?.value?.RepairCost?.value ?? 0 } - set repairCost (value) { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.RepairCost = { type: 'int', value } + set repairCost (newRepairCost) { + if (!this?.nbt) this.nbt = nbt.comp({}) + this.nbt.value.RepairCost = nbt.int(newRepairCost) } get enchants () { @@ -232,34 +232,31 @@ function loader (registryOrVersion) { set enchants (normalizedEnchArray) { if (registry.type === 'bedrock') { const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: 'short', value: registry.enchantmentsByName[name].id }, - lvl: { type: 'short', value: lvl } + id: nbt.short(registry.enchantmentsByName[name].id), + lvl: nbt.short(lvl) })) if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } + if (!this.nbt) this.nbt = nbt.comp({}) + this.nbt.value.ench = nbt.list(nbt.comp(enchs)) } } else if (registry.type === 'pc') { const isBook = this.name === 'enchanted_book' const enchListName = registry.supportFeature('nbtNameForEnchant') const type = registry.supportFeature('typeOfValueForEnchantLevel') if (type === null) throw new Error("Don't know the serialized type for enchant level") - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt) this.nbt = nbt.comp({}) const enchs = normalizedEnchArray.map(({ name, lvl }) => { const value = type === 'short' ? registry.enchantmentsByName[name].id : `minecraft:${registry.enchantmentsByName[name].name}` - return { id: { type, value }, lvl: { type: 'short', value: lvl } } + return { id: { type, value }, lvl: nbt.short(lvl) } }) if (enchs.length !== 0) { - this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = { - type: 'list', - value: { type: 'compound', value: enchs } - } + this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = nbt.list(nbt.comp(enchs)) } // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability @@ -272,11 +269,6 @@ function loader (registryOrVersion) { } } - // TODO: namespaces other than minecraft: - // The item palette on bedrock can contain items - // with other namespaces, probably need to handle - // this in prismarine-registry - // Also this needs to be tested get blocksCanPlaceOn () { if (Object.keys(this).length === 0) return [] @@ -286,7 +278,7 @@ function loader (registryOrVersion) { } set blocksCanPlaceOn (blocks) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt) this.nbt = nbt.comp({}) this.nbt.value.CanPlaceOn = nbt.list( nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) ) @@ -301,7 +293,7 @@ function loader (registryOrVersion) { } set blocksCanDestroy (blocks) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } + if (!this.nbt) this.nbt = nbt.comp({}) this.nbt.value.CanDestroy = nbt.list( nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) ) @@ -321,8 +313,8 @@ function loader (registryOrVersion) { set durabilityUsed (value) { const where = registry.supportFeature('whereDurabilityIsSerialized') if (where === 'Damage' || registry.type === 'bedrock') { - if (!this?.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.Damage = { type: 'int', value } + if (!this?.nbt) this.nbt = nbt.comp({}) + this.nbt.value.Damage = nbt.int(value) } else if (where === 'metadata') { this.metadata = value } else { From 75c2a726e7ae9489b3b77e02d4a6e5865151a139 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Sun, 5 Mar 2023 15:56:27 +0100 Subject: [PATCH 28/50] nbt.simplify() to make it more readable --- index.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 43c9894..99bcf2f 100644 --- a/index.js +++ b/index.js @@ -158,8 +158,9 @@ function loader (registryOrVersion) { } get customName () { - if (Object.keys(this).length === 0) return null - return this?.nbt?.value?.display?.value?.Name?.value ?? null + if (Object.keys(this).length === 0 || !this.nbt) return null + + return nbt.simplify(this.nbt).display?.Name ?? null } set customName (newName) { @@ -169,9 +170,9 @@ function loader (registryOrVersion) { } get customLore () { - if (Object.keys(this).length === 0) return null - // feature: itemLoreIsAString - return this?.nbt?.value?.display?.value?.Lore?.value.value ?? null + if (Object.keys(this).length === 0 || !this.nbt) return null + + return nbt.simplify(this.nbt).display?.Lore ?? null } set customLore (newLore) { @@ -187,12 +188,14 @@ function loader (registryOrVersion) { // gets the cost based on previous anvil uses get repairCost () { - if (Object.keys(this).length === 0) return 0 - return this?.nbt?.value?.RepairCost?.value ?? 0 + if (Object.keys(this).length === 0 || !this.nbt) return 0 + + return nbt.simplify(this.nbt).RepairCost ?? 0 } set repairCost (newRepairCost) { if (!this?.nbt) this.nbt = nbt.comp({}) + this.nbt.value.RepairCost = nbt.int(newRepairCost) } From 982d13256ea13f3a19009f04edec6ab438eb4fa1 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Mon, 6 Mar 2023 19:00:39 +0100 Subject: [PATCH 29/50] use optional chaining --- index.js | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 99bcf2f..192fa9c 100644 --- a/index.js +++ b/index.js @@ -158,9 +158,7 @@ function loader (registryOrVersion) { } get customName () { - if (Object.keys(this).length === 0 || !this.nbt) return null - - return nbt.simplify(this.nbt).display?.Name ?? null + return this?.nbt?.value?.display?.value?.Name ?? null } set customName (newName) { @@ -170,9 +168,7 @@ function loader (registryOrVersion) { } get customLore () { - if (Object.keys(this).length === 0 || !this.nbt) return null - - return nbt.simplify(this.nbt).display?.Lore ?? null + return this?.nbt?.value?.display?.value?.Lore ?? null } set customLore (newLore) { @@ -188,9 +184,7 @@ function loader (registryOrVersion) { // gets the cost based on previous anvil uses get repairCost () { - if (Object.keys(this).length === 0 || !this.nbt) return 0 - - return nbt.simplify(this.nbt).RepairCost ?? 0 + return this?.nbt?.value?.RepairCost ?? 0; } set repairCost (newRepairCost) { @@ -273,11 +267,7 @@ function loader (registryOrVersion) { } get blocksCanPlaceOn () { - if (Object.keys(this).length === 0) return [] - - if (!this.nbt?.value?.CanPlaceOn) return [] - - return nbt.simplify(this.nbt).CanPlaceOn + return this?.nbt?.value?.CanPlaceOn ?? [] } set blocksCanPlaceOn (blocks) { @@ -288,11 +278,7 @@ function loader (registryOrVersion) { } get blocksCanDestroy () { - if (Object.keys(this).length === 0) return [] - - if (!this.nbt?.value?.CanDestroy) return [] - - return nbt.simplify(this.nbt).CanDestroy + return this?.nbt?.value?.CanDestroy ?? [] } set blocksCanDestroy (blocks) { From 40462c30396125e3452e1123adf8975ef347092b Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Mon, 6 Mar 2023 19:06:42 +0100 Subject: [PATCH 30/50] update types --- index.d.ts | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6f5b47c..0a864bf 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,7 +16,8 @@ declare class Item { displayName: string; stackSize: number; durabilityUsed: number; - enchants: NormalizedEnchant[]; + get enchants(): { name: string; lvl: number }[]; + set enchants(enchantments: { name: string; lvl: number }[]); blocksCanPlaceOn: string[]; blocksCanDestroy: string[]; repairCost: number; @@ -36,7 +37,7 @@ declare class Item { static nextStackId(): number; } -declare type PcNetworkItem = { +declare interface PcNetworkItem { // 1.8 - 1.12 blockId?: number; itemDamage?: number; @@ -46,35 +47,31 @@ declare type PcNetworkItem = { itemCount?: number; nbtData?: Buffer; -}; +} -declare type BedrockNetworkItem = - | { network_id: 0 } - | ({ - // >= 1.16.220 - network_id: number; - count: number; - metadata: number; - block_runtime_id: number; - extra: { - can_place_on: string[]; - can_destroy: string[]; - blocking_tick?: number; - } & ({ has_nbt: false } | { has_nbt: true; nbt: { version: 1; nbt: Tags[TagType] } }); - } & ({ has_stack_id: 0 } | { has_stack_id: 1; stack_id: number })) - | ({ - // < 1.16.220 - network_id: number; - auxiliary_value: number; - can_place_on: string[]; - can_destroy: string[]; - } & ({ has_nbt: false } | { has_nbt: true; nbt: { version: 1; nbt: Tags[TagType] } })); +declare interface BedrockNetworkItem { + network_id: number; -declare type NetworkItem = PcNetworkItem | BedrockNetworkItem; + // >= 1.16.220 + count?: number; + metadata?: number; + has_stack_id?: 0 | 1; + stack_id?: number; + block_runtime_id?: number; + extra?: { + has_nbt: boolean; + nbt?: { version: 1; nbt: Tags[TagType] }; + can_place_on: string[]; + can_destroy: string[]; + blocking_tick?: number; + }; -declare interface NormalizedEnchant { - name: string; - lvl: number + // < 1.16.220 + auxiliary_value?: number; + can_place_on?: string[]; + can_destroy?: string[]; } +declare type NetworkItem = PcNetworkItem | BedrockNetworkItem; + export default function loader(mcVersion: string): typeof Item; From e6a48f1f0846ac192dd40b58b0bb762807000554 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Mon, 6 Mar 2023 19:08:55 +0100 Subject: [PATCH 31/50] update docs --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11a1818..af6301a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,13 @@ the item's custom lore (ie. set in give command) #### item.enchants -A getter/setter for abstracting the underlying nbt (does calculations) +#### get item.enchants(): { name: string, lvl: number }[] + +Returns an array of enchants on the Item with their name and level + +#### set item.enchants({ name: string, lvl: number }[]) + +Updates the Item's NBT enchantments based on assigned array #### item.blocksCanPlaceOn From be38e1ba8b07afc001e00ca4a9a84c05fc5baa11 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 15 Mar 2023 16:49:43 +0100 Subject: [PATCH 32/50] Use supportFeature and bedrock features added in mcdata PR; fixes --- index.d.ts | 2 + index.js | 191 +++++++++++++++++++++++++++++------------------------ 2 files changed, 108 insertions(+), 85 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0a864bf..335b856 100644 --- a/index.d.ts +++ b/index.d.ts @@ -68,6 +68,8 @@ declare interface BedrockNetworkItem { // < 1.16.220 auxiliary_value?: number; + has_nbt?: boolean; + nbt?: { version: 1; nbt: Tags[TagType] } can_place_on?: string[]; can_destroy?: string[]; } diff --git a/index.js b/index.js index 192fa9c..3abfabc 100644 --- a/index.js +++ b/index.js @@ -51,6 +51,7 @@ function loader (registryOrVersion) { } // Stack ID + // Probably needs to be moved to prismarine-registry later on as calling the loader again will reset it static currentStackId = 0 static nextStackId () { return Item.currentStackId++ @@ -80,17 +81,18 @@ function loader (registryOrVersion) { } return networkItem } else if (registry.type === 'bedrock') { - // This can later be changed to use supportFeature if (item.type === 0) return { network_id: 0 } - if (registry.version['<']('1.16.220')) { + + // if (registry.version['<']('1.16.220')) { + if (registry.supportFeature('itemSerializeUsesAuxValue')) { const networkItem = { network_id: item.id, auxiliary_value: (item.metadata << 8) | (item.count & 0xff), has_nbt: item.nbt !== null, nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, can_place_on: item.blocksCanPlaceOn, - can_destroy: item.blocksCanDestroy - // blocking_tick: 0, // TODO + can_destroy: item.blocksCanDestroy, + blocking_tick: 0 } return networkItem @@ -101,13 +103,13 @@ function loader (registryOrVersion) { metadata: item.metadata, has_stack_id: +serverAuthoritative, stack_id: serverAuthoritative ? item.stackId : undefined, - block_runtime_id: 0, // TODO + block_runtime_id: 0, extra: { has_nbt: item.nbt !== null, nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, - can_place_on: item.canPlaceOn, - can_destroy: item.canDestroy - // blocking_tick: 0, // TODO + can_place_on: item.blocksCanPlaceOn, + can_destroy: item.blocksCanDestroy, + blocking_tick: 0 } } @@ -128,29 +130,15 @@ function loader (registryOrVersion) { if (networkItem.blockId === -1) return null return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) } else if (registry.type === 'bedrock') { - if (registry.version['<']('1.16.220')) { - // unsure about this, different packets use slightly different formats, but everything - // in the item field stays the same - just sometimes it isn't in the item field - const item = new Item( - networkItem.network_id, - networkItem.auxiliary_value & 0xff, - networkItem.auxiliary_value >> 8, - networkItem.nbt, - stackId - ) - item.blocksCanPlaceOn = networkItem.item?.can_place_on ?? networkItem.can_place_on - item.blocksCanDestroy = networkItem.item?.can_destroy ?? networkItem.can_destroy + if (registry.supportFeature('itemSerializeUsesAuxValue')) { + const item = new Item(networkItem.network_id, networkItem.auxiliary_value & 0xff, networkItem.auxiliary_value >> 8, networkItem.nbt?.nbt, stackId) + item.blocksCanPlaceOn = networkItem.can_place_on + item.blocksCanDestroy = networkItem.can_destroy return item } else { - const item = new Item( - networkItem.network_id, - networkItem.count, - networkItem.metadata, - networkItem.extra.nbt, - networkItem.stack_id - ) - item.blocksCanPlaceOn = networkItem.extra.canPlaceOn - item.blocksCanDestroy = networkItem.extra.canDestroy + const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt?.nbt, networkItem.stack_id) + item.blocksCanPlaceOn = networkItem.extra.can_place_on + item.blocksCanDestroy = networkItem.extra.can_destroy return item } } @@ -158,7 +146,7 @@ function loader (registryOrVersion) { } get customName () { - return this?.nbt?.value?.display?.value?.Name ?? null + return this?.nbt?.value?.display?.value?.Name?.value ?? null } set customName (newName) { @@ -168,28 +156,27 @@ function loader (registryOrVersion) { } get customLore () { - return this?.nbt?.value?.display?.value?.Lore ?? null + if (!this.nbt?.value?.display) return null + return nbt.simplify(this.nbt).display.Lore ?? null } set customLore (newLore) { if (!this.nbt) this.nbt = nbt.comp({}) if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - if (registry.type === 'bedrock') { - this.nbt.value.display.value.Lore = nbt.list(nbt.string(newLore)) - } else { - // feature: itemLoreIsAString - this.nbt.value.display.value.Lore = nbt.string(newLore) - } + + this.nbt.value.display.value.Lore = registry.supportFeature('itemLoreIsAString') + ? nbt.string(newLore) + : nbt.list(nbt.string(newLore)) } // gets the cost based on previous anvil uses get repairCost () { - return this?.nbt?.value?.RepairCost ?? 0; + return this?.nbt?.value?.RepairCost?.value ?? 0 } set repairCost (newRepairCost) { if (!this?.nbt) this.nbt = nbt.comp({}) - + this.nbt.value.RepairCost = nbt.int(newRepairCost) } @@ -198,10 +185,13 @@ function loader (registryOrVersion) { const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') - // TODO: add bedrock features for enchantments to features.json in minecraft-data - if ((typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') || registry.type === 'bedrock') { + if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') { let itemEnch = [] - if (this.name === 'enchanted_book' && this?.nbt?.value?.StoredEnchantments) { + if ( + this.name === 'enchanted_book' && + this?.nbt?.value?.StoredEnchantments && + registry.supportFeature('booksUseStoredEnchantments') + ) { itemEnch = nbt.simplify(this.nbt).StoredEnchantments } else if (this?.nbt?.value?.ench) { itemEnch = nbt.simplify(this.nbt).ench @@ -220,41 +210,61 @@ function loader (registryOrVersion) { } return itemEnch.map((ench) => ({ lvl: ench.lvl, - name: typeof ench.id === 'string' ? ench.id.replace(/minecraft:/, '') : null + name: typeof ench.id === 'string' ? ench.id.replace('minecraft:', '') : null })) } throw new Error("Don't know how to get the enchants from an item on this mc version") } set enchants (normalizedEnchArray) { - if (registry.type === 'bedrock') { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: nbt.short(registry.enchantmentsByName[name].id), - lvl: nbt.short(lvl) - })) + const enchListName = registry.supportFeature('nbtNameForEnchant') + const type = registry.supportFeature('typeOfValueForEnchantLevel') + if (type === null) throw new Error("Don't know the serialized type for enchant level") - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = nbt.comp({}) - this.nbt.value.ench = nbt.list(nbt.comp(enchs)) + const enchs = normalizedEnchArray.map(({ name, lvl }) => { + const value = + type === 'short' + ? registry.enchantmentsByName[name].id + : `minecraft:${registry.enchantmentsByName[name].name}` + return { id: { type, value }, lvl: nbt.short(lvl) } + }) + + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = nbt.comp({}) + if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { + this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) + } else { + this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) } + } + + if (registry.type === 'bedrock') { + // const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ + // id: { type, value: registry.enchantmentsByName[name].id }, + // lvl: nbt.short(lvl), + // })); + // if (enchs.length !== 0) { + // if (!this.nbt) this.nbt = nbt.comp({}); + // this.nbt.value.ench = nbt.list(nbt.comp(enchs)); + // } } else if (registry.type === 'pc') { - const isBook = this.name === 'enchanted_book' - const enchListName = registry.supportFeature('nbtNameForEnchant') - const type = registry.supportFeature('typeOfValueForEnchantLevel') - if (type === null) throw new Error("Don't know the serialized type for enchant level") - if (!this.nbt) this.nbt = nbt.comp({}) + // const isBook = this.name === "enchanted_book"; + // const enchListName = registry.supportFeature("nbtNameForEnchant"); + // const type = registry.supportFeature("typeOfValueForEnchantLevel"); + // if (type === null) throw new Error("Don't know the serialized type for enchant level"); + // if (!this.nbt) this.nbt = nbt.comp({}); - const enchs = normalizedEnchArray.map(({ name, lvl }) => { - const value = - type === 'short' - ? registry.enchantmentsByName[name].id - : `minecraft:${registry.enchantmentsByName[name].name}` - return { id: { type, value }, lvl: nbt.short(lvl) } - }) + // const enchs = normalizedEnchArray.map(({ name, lvl }) => { + // const value = + // type === "short" + // ? registry.enchantmentsByName[name].id + // : `minecraft:${registry.enchantmentsByName[name].name}`; + // return { id: { type, value }, lvl: nbt.short(lvl) }; + // }); - if (enchs.length !== 0) { - this.nbt.value[isBook ? 'StoredEnchantments' : enchListName] = nbt.list(nbt.comp(enchs)) - } + // if (enchs.length !== 0) { + // this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = nbt.list(nbt.comp(enchs)); + // } // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability if ( @@ -267,31 +277,49 @@ function loader (registryOrVersion) { } get blocksCanPlaceOn () { - return this?.nbt?.value?.CanPlaceOn ?? [] + return this?.nbt?.value?.CanPlaceOn?.value?.value ?? [] } - set blocksCanPlaceOn (blocks) { + set blocksCanPlaceOn (newBlocks) { if (!this.nbt) this.nbt = nbt.comp({}) - this.nbt.value.CanPlaceOn = nbt.list( - nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) - ) + + const blocks = [] + for (const block of newBlocks) { + let [ns, name] = block.split(':') + if (!name) { + name = ns + ns = 'minecraft' + } + blocks.push(`${ns}:${name}`) + } + + this.nbt.value.CanPlaceOn = nbt.list(nbt.string(blocks)) } get blocksCanDestroy () { - return this?.nbt?.value?.CanDestroy ?? [] + return this?.nbt?.value?.CanDestroy?.value?.value ?? [] } - set blocksCanDestroy (blocks) { + set blocksCanDestroy (newBlocks) { if (!this.nbt) this.nbt = nbt.comp({}) - this.nbt.value.CanDestroy = nbt.list( - nbt.string(blocks.map((b) => (b.startsWith('minecraft:') ? b : `minecraft:${b}`))) - ) + + const blocks = [] + for (const block of newBlocks) { + let [ns, name] = block.split(':') + if (!name) { + name = ns + ns = 'minecraft' + } + blocks.push(`${ns}:${name}`) + } + + this.nbt.value.CanDestroy = nbt.list(nbt.string(blocks)) } get durabilityUsed () { if (Object.keys(this).length === 0) return null const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage' || registry.type === 'bedrock') { + if (where === 'Damage') { return this?.nbt?.value?.Damage?.value ?? 0 } else if (where === 'metadata') { return this.metadata ?? 0 @@ -301,7 +329,7 @@ function loader (registryOrVersion) { set durabilityUsed (value) { const where = registry.supportFeature('whereDurabilityIsSerialized') - if (where === 'Damage' || registry.type === 'bedrock') { + if (where === 'Damage') { if (!this?.nbt) this.nbt = nbt.comp({}) this.nbt.value.Damage = nbt.int(value) } else if (where === 'metadata') { @@ -323,13 +351,6 @@ function loader (registryOrVersion) { if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { return this.name.replace('_spawn_egg', '') } - if (registry.type === 'bedrock') { - // TODO: add to features.json - // According to the wiki, the different metadata values were split - // into their own IDs in 1.16.100 - // https://minecraft.fandom.com/wiki/Spawn_Egg#History - return this.name.replace('_spawn_egg', '') - } throw new Error("Don't know how to get spawn egg mob name for this mc version") } } From e1d8ea64e22af6c1f6a186cbeac4d012d71db2ba Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 16 Mar 2023 17:21:33 +0100 Subject: [PATCH 33/50] Add stack ID to tests (temp) and damage default to 0 --- index.js | 39 ++------------------------------------ test/anvil.test.js | 47 +++++++++++++++++++++++++++++++++++----------- test/basic.test.js | 20 +++++++++++++++----- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/index.js b/index.js index 3abfabc..fddf247 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,8 @@ function loader (registryOrVersion) { if (variation) this.displayName = variation.displayName } this.stackSize = itemEnum.stackSize + // The 'itemEnum.maxDurability' checks to see if this item can lose durability + if (itemEnum.maxDurability) this.durabilityUsed ||= 0 } else { this.name = 'unknown' this.displayName = 'unknown' @@ -237,43 +239,6 @@ function loader (registryOrVersion) { this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) } } - - if (registry.type === 'bedrock') { - // const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - // id: { type, value: registry.enchantmentsByName[name].id }, - // lvl: nbt.short(lvl), - // })); - // if (enchs.length !== 0) { - // if (!this.nbt) this.nbt = nbt.comp({}); - // this.nbt.value.ench = nbt.list(nbt.comp(enchs)); - // } - } else if (registry.type === 'pc') { - // const isBook = this.name === "enchanted_book"; - // const enchListName = registry.supportFeature("nbtNameForEnchant"); - // const type = registry.supportFeature("typeOfValueForEnchantLevel"); - // if (type === null) throw new Error("Don't know the serialized type for enchant level"); - // if (!this.nbt) this.nbt = nbt.comp({}); - - // const enchs = normalizedEnchArray.map(({ name, lvl }) => { - // const value = - // type === "short" - // ? registry.enchantmentsByName[name].id - // : `minecraft:${registry.enchantmentsByName[name].name}`; - // return { id: { type, value }, lvl: nbt.short(lvl) }; - // }); - - // if (enchs.length !== 0) { - // this.nbt.value[isBook ? "StoredEnchantments" : enchListName] = nbt.list(nbt.comp(enchs)); - // } - - // The 'registry.itemsByName[this.name].maxDurability' checks to see if this item can lose durability - if ( - registry.supportFeature('whereDurabilityIsSerialized') === 'Damage' && - registry.itemsByName[this.name].maxDurability - ) { - this.nbt.value.Damage = { type: 'int', value: 0 } - } - } } get blocksCanPlaceOn () { diff --git a/test/anvil.test.js b/test/anvil.test.js index 74aac4c..6c1bd10 100644 --- a/test/anvil.test.js +++ b/test/anvil.test.js @@ -11,6 +11,8 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(sword2, sword1, false, undefined) const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) const inverseFinalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + finalItem.stackId = res.item.stackId + inverseFinalItem.stackId = inverse.item.stackId expect(res.xpCost).toStrictEqual(3) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -23,6 +25,8 @@ describe('1.8.9 anvil', () => { const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }) const res = Item.anvil(book1, book2, false, undefined) const inverse = Item.anvil(book2, book1, false, undefined) + finalItem.stackId = res.item.stackId + inverseFinalItem.stackId = inverse.item.stackId expect(res.xpCost).toStrictEqual(2) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -36,6 +40,7 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(book, sword, false, undefined) const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) const inverseFinalItem = null + finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(6) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -49,6 +54,7 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(book, sword, true, undefined) const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) const inverseFinalItem = null + finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(11) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -61,6 +67,7 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(null, item, false, 'ababa') const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) const inverseFinalItem = null + finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -80,6 +87,7 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(null, item, false, 'ababa') const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) const inverseFinalItem = null + finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -92,6 +100,7 @@ describe('1.8.9 anvil', () => { const inverse = Item.anvil(null, item, false, 'ababa') const finalItem = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) const inverseFinalItem = null + finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -105,6 +114,7 @@ describe('1.8.9 anvil', () => { const inverseFinalItem = null const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) + finalItem.stackId = res.item.stackId expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) }) @@ -116,6 +126,8 @@ describe('1.8.9 anvil', () => { const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }] } } } } }) const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) + finalItem.stackId = res.item.stackId + inverseFinalItem.stackId = inverse.item.stackId expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) }) @@ -125,6 +137,7 @@ describe('1.8.9 anvil', () => { it('try renaming', () => { const res = Item.anvil(chestplate, null, false, 'Hello!') const expectedItem = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 127 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Hello!' } } } } } }) + expectedItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(39) expect(res.item).toStrictEqual(expectedItem) }) @@ -159,6 +172,8 @@ describe('1.16.5 anvil', () => { const expectedItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }) const inverse = Item.anvil(seconditem, firstItem, false, undefined) const expectedInverseItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }) + expectedItem.stackId = anvil.item.stackId + expectedInverseItem.stackId = inverse.item.stackId expect(anvil.item).toStrictEqual(expectedItem) expect(inverse.item).toStrictEqual(expectedInverseItem) }) @@ -168,6 +183,7 @@ describe('1.16.5 anvil', () => { const secondItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) const resItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) + resItem.stackId = anvil.item.stackId expect(anvil.item).toStrictEqual(resItem) expect(anvil.xpCost).toStrictEqual(7) }) @@ -177,6 +193,7 @@ describe('1.16.5 anvil', () => { const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2 }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) + expectedItem.stackId = anvil.item.stackId expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -186,6 +203,7 @@ describe('1.16.5 anvil', () => { const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2, nbtData: { name: '', type: 'compound', value: { Enchantments: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'string', value: 'minecraft:unbreaking' }, lvl: { type: 'short', value: 2 } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) + expectedItem.stackId = anvil.item.stackId expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -210,15 +228,15 @@ describe('1.16.5 anvil', () => { const itemTwo = new Item(598, 1) itemTwo.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }] // expected way - const expectedItem = new Item(598, 1) + const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) + const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) expectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 - const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(16) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1) + const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -230,15 +248,15 @@ describe('1.16.5 anvil', () => { const itemTwo = new Item(598, 1) itemTwo.enchants = [{ name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 3 }] // expected way - const expectedItem = new Item(598, 1) + const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) + const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) expectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 - const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(15) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1) + const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -250,15 +268,15 @@ describe('1.16.5 anvil', () => { const itemTwo = new Item(598, 1) itemTwo.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 2 }] // expected way - const expectedItem = new Item(598, 1) + const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) + const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) expectedItem.enchants = [{ name: 'sharpness', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 - const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(13) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1) + const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) inverseExpectedItem.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 3 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -270,10 +288,10 @@ describe('1.16.5 anvil', () => { const itemTwo = new Item(848, 1) itemTwo.enchants = [{ name: 'protection', lvl: 3 }, { name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 2 }] // expected way - const expectedItem = new Item(598, 1) + const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) + const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) expectedItem.enchants = [{ name: 'looting', lvl: 3 }, { name: 'sharpness', lvl: 1 }] expectedItem.repairCost = 1 - const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(7) }) @@ -295,24 +313,28 @@ describe('1.16.5 anvil', () => { eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }] eqItem.repairCost = 1 const res = Item.anvil(a1, a2, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 12, eqItem) b1 = res.item }) it('thorns3+ff4', () => { const eqItem = makeBook([{ name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }], 1) const res = Item.anvil(a3, a4, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 4, eqItem) b2 = res.item }) it('depth3+p4', () => { const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }], 1) const res = Item.anvil(a5, a6, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 4, eqItem) b3 = res.item }) it('ub3+mending', () => { const eqItem = makeBook([{ name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 1) const res = Item.anvil(a7, a8, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 2, eqItem) b4 = res.item }) @@ -323,12 +345,14 @@ describe('1.16.5 anvil', () => { eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }] eqItem.repairCost = 3 const res = Item.anvil(b1, b2, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 16 + 2, eqItem) // 1 working per item c1 = res.item }) it('d3p4 + u3m1', () => { const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 3) const res = Item.anvil(b3, b4, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 5 + 2, eqItem) // 1 working on each book c2 = res.item }) @@ -339,6 +363,7 @@ describe('1.16.5 anvil', () => { eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }, { name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }] eqItem.repairCost = 7 const res = Item.anvil(c1, c2, false, undefined) + eqItem.stackId = res.item.stackId expectAnvilEq(res, 15 + 6, eqItem) // 3 lvl repairCost on each item }) }) diff --git a/test/basic.test.js b/test/basic.test.js index 2a66cdb..94ed80c 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -8,7 +8,7 @@ describe('test based on examples', () => { const ironShovelItem = new Item(256, 1) it('constructor makes item correctly', () => { - const val = { type: 256, count: 1, metadata: 0, nbt: null, name: 'iron_shovel', displayName: 'Iron Shovel', stackSize: 1 } + const val = { type: 256, count: 1, metadata: 0, nbt: null, name: 'iron_shovel', displayName: 'Iron Shovel', stackSize: 1, stackId: 0 } expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(val) }) @@ -19,7 +19,7 @@ describe('test based on examples', () => { it('use .fromNotch', () => { const toNotch = Item.toNotch(ironShovelItem) const fromNotch = Item.fromNotch(toNotch) - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 256 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 256, stackId: 1 } expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) }) }) @@ -28,19 +28,19 @@ describe('test based on examples', () => { const ironShovelItem = new Item(472, 1) it('constructor makes item correctly', () => { - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 472 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}}, stackSize: 1, type: 472, stackId: 0 } expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(expectedObj) }) it('use .toNotch', () => { - const expectedObj = { itemCount: 1, itemId: 472, present: true } + const expectedObj = { itemCount: 1, itemId: 472, present: true, nbtData: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}} } expect(Item.toNotch(ironShovelItem)).toStrictEqual(expectedObj) }) it('use .fromNotch', () => { const toNotch = Item.toNotch(ironShovelItem) const fromNotch = Item.fromNotch(toNotch) - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 472 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}}, stackSize: 1, type: 472, stackId: 1 } expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) }) }) @@ -115,6 +115,7 @@ describe('test anvil functions', () => { }) describe('1.16.5 test', () => { const Item = require('prismarine-item')('1.16.5') + it('diamond sword (unenchanted)', () => { const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }) const enchs = item.enchants @@ -189,6 +190,7 @@ describe('test anvil functions', () => { const newItem = new Item(279, 1) newItem.enchants = enchs newItem.repairCost = 1 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) @@ -198,6 +200,7 @@ describe('test anvil functions', () => { const newItem = new Item(314, 1) newItem.enchants = enchs newItem.repairCost = 3 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) @@ -207,6 +210,7 @@ describe('test anvil functions', () => { const newItem = new Item(398, 1) newItem.enchants = enchs newItem.repairCost = 1 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) @@ -216,6 +220,7 @@ describe('test anvil functions', () => { const newItem = new Item(274, 1) newItem.enchants = enchs newItem.repairCost = 1 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) @@ -225,6 +230,7 @@ describe('test anvil functions', () => { const newItem = new Item(346, 1) newItem.enchants = enchs newItem.repairCost = 3 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) }) @@ -235,6 +241,7 @@ describe('test anvil functions', () => { const enchs = item.enchants const newItem = new Item(603, 1) newItem.enchants = enchs + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('iron shovel w/ eff2 for2 ub2', () => { @@ -243,6 +250,7 @@ describe('test anvil functions', () => { const newItem = new Item(600, 1) newItem.enchants = enchs newItem.repairCost = 3 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('ench book w/ resp1 blastprot 1', () => { @@ -251,6 +259,7 @@ describe('test anvil functions', () => { const newItem = new Item(848, 1) newItem.enchants = enchs newItem.repairCost = 1 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('fishing rod w/ mending', () => { @@ -259,6 +268,7 @@ describe('test anvil functions', () => { const newItem = new Item(684, 1) newItem.enchants = enchs newItem.repairCost = 1 + newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) }) From 398f5c14de4ca3bf7d85a2db7232952bc5b88009 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 16 Mar 2023 18:12:45 +0100 Subject: [PATCH 34/50] remove separate BedrockItem class, don't check ench len --- index.js | 15 ++-- lib/bedrock-item.js | 208 -------------------------------------------- 2 files changed, 6 insertions(+), 217 deletions(-) delete mode 100644 lib/bedrock-item.js diff --git a/index.js b/index.js index fddf247..9dca703 100644 --- a/index.js +++ b/index.js @@ -85,7 +85,6 @@ function loader (registryOrVersion) { } else if (registry.type === 'bedrock') { if (item.type === 0) return { network_id: 0 } - // if (registry.version['<']('1.16.220')) { if (registry.supportFeature('itemSerializeUsesAuxValue')) { const networkItem = { network_id: item.id, @@ -221,7 +220,7 @@ function loader (registryOrVersion) { set enchants (normalizedEnchArray) { const enchListName = registry.supportFeature('nbtNameForEnchant') const type = registry.supportFeature('typeOfValueForEnchantLevel') - if (type === null) throw new Error("Don't know the serialized type for enchant level") + if (!type) throw new Error("Don't know the serialized type for enchant level") const enchs = normalizedEnchArray.map(({ name, lvl }) => { const value = @@ -231,13 +230,11 @@ function loader (registryOrVersion) { return { id: { type, value }, lvl: nbt.short(lvl) } }) - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = nbt.comp({}) - if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { - this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) - } else { - this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) - } + if (!this.nbt) this.nbt = nbt.comp({}) + if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { + this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) + } else { + this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) } } diff --git a/lib/bedrock-item.js b/lib/bedrock-item.js deleted file mode 100644 index 6b900dd..0000000 --- a/lib/bedrock-item.js +++ /dev/null @@ -1,208 +0,0 @@ -function loader (registryOrVersion) { - const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion - - // TODO: - // - tests - // - docs - // - add support for older versions: - // need to see how items are handled in older bedrock protocol versions, - // and probably update features.json in minecraft-data with useful data - // - Stack ID generation - // - Block runtime ID field - // - Setting canPlaceOn and canDestroy with block/item objects? - // - Merge with Item class in ../index.js? - - class BedrockItem { - /** - * @param {number} type - * @param {number} count - * @param {number} metadata - * @param {object} nbt - * @param {string[]} canPlaceOnList - * @param {string[]} canDestroyList - * @param {number} stackId - * @returns {BedrockItem} - */ - constructor (type, count, metadata, nbt, canPlaceOnList, canDestroyList, stackId) { - if (type === null) return - - this.type = type - this.count = count - this.metadata = metadata == null ? 0 : metadata - this.nbt = nbt || null - - // TODO - // Only generate if on server side and not provided one - this.stackId = stackId ?? BedrockItem.nextStackId() - - this.canPlaceOnList = canPlaceOnList ?? [] - this.canDestroyList = canDestroyList ?? [] - - const itemEnum = registry.items[type] - if (itemEnum) { - this.name = itemEnum.name - this.displayName = itemEnum.displayName - if ('variations' in itemEnum) { - for (const variation of itemEnum.variations) { - if (variation.metadata === metadata) this.displayName = variation.displayName - } - } - this.stackSize = itemEnum.stackSize - } else { - this.name = 'unknown' - this.displayName = 'unknown' - this.stackSize = 1 - } - } - - /** @param {BedrockItem} item1 @param {BedrockItem} item2 */ - static equal (item1, item2, matchStackSize = true, matchNbt = true, sameStack = false) { - if (item1 == null && item2 == null) { - return true - } else if (item1 == null) { - return false - } else if (item2 == null) { - return false - } else { - return ( - item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && - item1.metadata === item2.metadata && - (sameStack ? item1.stackId === item2.stackId : true) && - (matchNbt - ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) && - item1.canPlaceOnList.sort().toString() === item2.canPlaceOnList.sort().toString() && - item1.canDestroyList.sort().toString() === item2.canDestroyList.sort().toString() - : true) - ) - } - } - - // Stack ID - static currentStackId = 0 - static nextStackId () { - return BedrockItem.currentStackId++ - } - - toNetwork (serverAuthoritative = true) { - if (this.type === 0) return { network_id: 0 } - - return { - network_id: this.type, - count: this.count, - metadata: this.metadata, - has_stack_id: serverAuthoritative, - stack_id: serverAuthoritative ? this.stackId : undefined, - block_runtime_id: 0, // TODO - extra: { - has_nbt: this.nbt !== null, - nbt: this.nbt !== null ? { version: 1, nbt: this.nbt } : undefined, - can_place_on: this.canPlaceOnList, - can_destroy: this.canDestroyList - } - } - } - - /** @returns {BedrockItem} */ - static fromNetwork (item, serverAuthoritative = true) { - return new BedrockItem( - item.network_id, - item.count, - item.metadata, - item.extra.nbt?.nbt ?? null, - item.extra.can_place_on, - item.extra.can_destroy, - item.stack_id - ) - } - - get customName () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.display?.value?.Name?.value ?? null - } - - set customName (newName) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Name = { type: 'string', value: newName } - } - - get customLore () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.display?.value?.Lore?.value.value ?? null - } - - set customLore (newLore) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - if (!this.nbt.value.display) this.nbt.value.display = { type: 'compound', value: {} } - this.nbt.value.display.value.Lore = { type: 'list', value: { type: 'string', value: newLore } } - } - - get repairCost () { - if (Object.keys(this).length === 0) return 0 - return this.nbt?.value.RepairCost?.value ?? 0 - } - - set repairCost (value) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.RepairCost = { type: 'int', value } - } - - get enchants () { - if (Object.keys(this).length === 0) return 0 - if (!this.nbt?.value?.ench) return [] - return this.nbt.value.ench.value.value.map((ench) => ({ - lvl: ench.lvl.value, - name: registry.enchantments[ench.id.value]?.name || null // TODO: bedrock enchantments - })) - } - - set enchants (normalizedEnchArray) { - const enchs = normalizedEnchArray.map(({ name, lvl }) => ({ - id: { type: 'short', value: registry.enchantmentsByName[name].id }, - lvl: { type: 'short', value: lvl } - })) - - if (enchs.length !== 0) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.ench = { type: 'list', value: { type: 'compound', value: enchs } } - } - } - - get durabilityUsed () { - if (Object.keys(this).length === 0) return null - return this.nbt?.value?.Damage?.value ?? 0 - } - - set durabilityUsed (value) { - if (!this.nbt) this.nbt = { name: '', type: 'compound', value: {} } - this.nbt.value.Damage = { type: 'int', value } - } - - get spawnEggMobName () { - return this.name.replace('_spawn_egg', '') - } - - /** @returns {boolean} */ - canPlaceOn (block) { - if (typeof block === 'string') { - return this.canPlaceOnList.includes(block) || this.canPlaceOnList.includes(`minecraft:${block}`) - } else { - return this.canPlaceOnList.includes(block.name) || this.canPlaceOnList.includes(`minecraft:${block.name}`) - } - } - - /** @returns {boolean} */ - canDestroy (block) { - if (typeof block === 'string') { - return this.canDestroyList.includes(block) || this.canDestroyList.includes(`minecraft:${block}`) - } else { - return this.canDestroyList.includes(block.name) || this.canDestroyList.includes(`minecraft:${block.name}`) - } - } - } - - return BedrockItem -} - -module.exports = loader From bdecc1ad53ba42a76e1f55940d86544a7c4f0604 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 16 Mar 2023 18:14:07 +0100 Subject: [PATCH 35/50] linter --- test/basic.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/basic.test.js b/test/basic.test.js index 94ed80c..8f37651 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -28,19 +28,19 @@ describe('test based on examples', () => { const ironShovelItem = new Item(472, 1) it('constructor makes item correctly', () => { - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}}, stackSize: 1, type: 472, stackId: 0 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: 0 } expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(expectedObj) }) it('use .toNotch', () => { - const expectedObj = { itemCount: 1, itemId: 472, present: true, nbtData: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}} } + const expectedObj = { itemCount: 1, itemId: 472, present: true, nbtData: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } } } expect(Item.toNotch(ironShovelItem)).toStrictEqual(expectedObj) }) it('use .fromNotch', () => { const toNotch = Item.toNotch(ironShovelItem) const fromNotch = Item.fromNotch(toNotch) - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: "", type: "compound", value: { Damage: { type: "int", value: 0 }}}, stackSize: 1, type: 472, stackId: 1 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: 1 } expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) }) }) From d32d4b01d4e5dab4cb5bcaca76f3e9ee733ce672 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 16 Mar 2023 18:17:22 +0100 Subject: [PATCH 36/50] don't use Or assignment to support older node --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 9dca703..d5919cf 100644 --- a/index.js +++ b/index.js @@ -27,7 +27,7 @@ function loader (registryOrVersion) { } this.stackSize = itemEnum.stackSize // The 'itemEnum.maxDurability' checks to see if this item can lose durability - if (itemEnum.maxDurability) this.durabilityUsed ||= 0 + if (itemEnum.maxDurability && !this.durabilityUsed) this.durabilityUsed = 0 } else { this.name = 'unknown' this.displayName = 'unknown' From 9a5e9cdd49521fda0a2fed6578b06005402908ac Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Thu, 16 Mar 2023 18:19:04 +0100 Subject: [PATCH 37/50] revert checking enchs length --- index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index d5919cf..866e038 100644 --- a/index.js +++ b/index.js @@ -230,11 +230,13 @@ function loader (registryOrVersion) { return { id: { type, value }, lvl: nbt.short(lvl) } }) - if (!this.nbt) this.nbt = nbt.comp({}) - if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { - this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) - } else { - this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) + if (enchs.length !== 0) { + if (!this.nbt) this.nbt = nbt.comp({}) + if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { + this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) + } else { + this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) + } } } From edc9aa4bc6caef178360d7df8de72525428bbcad Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Fri, 17 Mar 2023 06:39:43 +0100 Subject: [PATCH 38/50] use stackID parameter in tests --- index.js | 9 ++--- test/anvil.test.js | 87 +++++++++++++++++----------------------------- test/basic.test.js | 45 ++++++++++-------------- 3 files changed, 54 insertions(+), 87 deletions(-) diff --git a/index.js b/index.js index 866e038..a9609f7 100644 --- a/index.js +++ b/index.js @@ -123,21 +123,22 @@ function loader (registryOrVersion) { static fromNotch (networkItem, stackId) { if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { if (networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData, stackId) } else if (registry.supportFeature('itemSerializationAllowsPresent')) { if (networkItem.itemId === -1 || networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData, stackId) } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (networkItem.blockId === -1) return null - return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) + return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData, stackId) } else if (registry.type === 'bedrock') { + if (networkItem.network_id === 0) return new Item(0) if (registry.supportFeature('itemSerializeUsesAuxValue')) { const item = new Item(networkItem.network_id, networkItem.auxiliary_value & 0xff, networkItem.auxiliary_value >> 8, networkItem.nbt?.nbt, stackId) item.blocksCanPlaceOn = networkItem.can_place_on item.blocksCanDestroy = networkItem.can_destroy return item } else { - const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt?.nbt, networkItem.stack_id) + const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt?.nbt, networkItem.stack_id ?? stackId) item.blocksCanPlaceOn = networkItem.extra.can_place_on item.blocksCanDestroy = networkItem.extra.can_destroy return item diff --git a/test/anvil.test.js b/test/anvil.test.js index 6c1bd10..67de139 100644 --- a/test/anvil.test.js +++ b/test/anvil.test.js @@ -9,10 +9,8 @@ describe('1.8.9 anvil', () => { const sword2 = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3 }) const res = Item.anvil(sword1, sword2, false, undefined) const inverse = Item.anvil(sword2, sword1, false, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - const inverseFinalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - finalItem.stackId = res.item.stackId - inverseFinalItem.stackId = inverse.item.stackId + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) + const inverseFinalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, inverse.item.stackId) expect(res.xpCost).toStrictEqual(3) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -21,12 +19,10 @@ describe('1.8.9 anvil', () => { it('combine two books', () => { const book1 = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }) const book2 = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }) - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }) - const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }) const res = Item.anvil(book1, book2, false, undefined) const inverse = Item.anvil(book2, book1, false, undefined) - finalItem.stackId = res.item.stackId - inverseFinalItem.stackId = inverse.item.stackId + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }, res.item.stackId) + const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }, inverse.item.stackId) expect(res.xpCost).toStrictEqual(2) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -38,9 +34,8 @@ describe('1.8.9 anvil', () => { const book = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) const res = Item.anvil(sword, book, false, undefined) const inverse = Item.anvil(book, sword, false, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) const inverseFinalItem = null - finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(6) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -52,9 +47,8 @@ describe('1.8.9 anvil', () => { const book = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) const res = Item.anvil(sword, book, true, undefined) const inverse = Item.anvil(book, sword, true, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) const inverseFinalItem = null - finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(11) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -65,9 +59,8 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0 }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }, res.item.stackId) const inverseFinalItem = null - finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -85,9 +78,8 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }, res.item.stackId) const inverseFinalItem = null - finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -98,9 +90,8 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0 }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) + const finalItem = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }, res.item.stackId) const inverseFinalItem = null - finalItem.stackId = res.item.stackId expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) expect(res.item).toStrictEqual(finalItem) @@ -110,11 +101,10 @@ describe('1.8.9 anvil', () => { it('combine w/ pre-rename', () => { const itemOne = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Diamond Sword1212' } } } } } }) const itemTwo = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Diamond Sword1212' } } } } } }) - const inverseFinalItem = null const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) - finalItem.stackId = res.item.stackId + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Diamond Sword1212' } } } } } }, res.item.stackId) + const inverseFinalItem = null expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) }) @@ -122,12 +112,10 @@ describe('1.8.9 anvil', () => { it('incompatible books', () => { const itemOne = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }] } } } } }) const itemTwo = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }) - const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }) - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }] } } } } }) const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) - finalItem.stackId = res.item.stackId - inverseFinalItem.stackId = inverse.item.stackId + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }] } } } } }, res.item.stackId) + const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }, inverse.item.stackId) expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) }) @@ -136,8 +124,7 @@ describe('1.8.9 anvil', () => { const chestplate = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 63 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Chain Chaestaaplateaaa' } } } } } }) it('try renaming', () => { const res = Item.anvil(chestplate, null, false, 'Hello!') - const expectedItem = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 127 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Hello!' } } } } } }) - expectedItem.stackId = res.item.stackId + const expectedItem = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 127 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Hello!' } } } } } }, res.item.stackId) expect(res.xpCost).toStrictEqual(39) expect(res.item).toStrictEqual(expectedItem) }) @@ -153,8 +140,8 @@ describe('1.16.5 anvil', () => { const Item = require('prismarine-item')('1.16.5') const registry = require('prismarine-registry')('1.16.5') - function makeBook (ench, repairCost) { - const i = new Item(registry.itemsByName.enchanted_book.id, 1) + function makeBook (ench, repairCost, stackId) { + const i = new Item(registry.itemsByName.enchanted_book.id, 1, 0, null, stackId) i.enchants = ench if (repairCost > 0) i.repairCost = repairCost return i @@ -169,11 +156,9 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }) const seconditem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }) const anvil = Item.anvil(firstItem, seconditem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }) const inverse = Item.anvil(seconditem, firstItem, false, undefined) - const expectedInverseItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }) - expectedItem.stackId = anvil.item.stackId - expectedInverseItem.stackId = inverse.item.stackId + const expectedItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }, anvil.item.stackId) + const expectedInverseItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }, inverse.item.stackId) expect(anvil.item).toStrictEqual(expectedItem) expect(inverse.item).toStrictEqual(expectedInverseItem) }) @@ -182,8 +167,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const resItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) - resItem.stackId = anvil.item.stackId + const resItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }, anvil.item.stackId) expect(anvil.item).toStrictEqual(resItem) expect(anvil.xpCost).toStrictEqual(7) }) @@ -192,8 +176,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 300 } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2 }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) - expectedItem.stackId = anvil.item.stackId + const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }, anvil.item.stackId) expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -202,8 +185,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 300 } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2, nbtData: { name: '', type: 'compound', value: { Enchantments: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'string', value: 'minecraft:unbreaking' }, lvl: { type: 'short', value: 2 } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) - expectedItem.stackId = anvil.item.stackId + const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }, anvil.item.stackId) expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -309,61 +291,54 @@ describe('1.16.5 anvil', () => { const a8 = makeBook([{ name: 'mending', lvl: 1 }], 0) describe('first combine', () => { it('enchant boot+ss3', () => { - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) + const res = Item.anvil(a1, a2, false, undefined) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }] eqItem.repairCost = 1 - const res = Item.anvil(a1, a2, false, undefined) - eqItem.stackId = res.item.stackId expectAnvilEq(res, 12, eqItem) b1 = res.item }) it('thorns3+ff4', () => { - const eqItem = makeBook([{ name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }], 1) const res = Item.anvil(a3, a4, false, undefined) - eqItem.stackId = res.item.stackId + const eqItem = makeBook([{ name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }], 1, res.item.stackId) expectAnvilEq(res, 4, eqItem) b2 = res.item }) it('depth3+p4', () => { - const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }], 1) const res = Item.anvil(a5, a6, false, undefined) - eqItem.stackId = res.item.stackId + const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }], 1, res.item.stackId) expectAnvilEq(res, 4, eqItem) b3 = res.item }) it('ub3+mending', () => { - const eqItem = makeBook([{ name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 1) const res = Item.anvil(a7, a8, false, undefined) - eqItem.stackId = res.item.stackId + const eqItem = makeBook([{ name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 1, res.item.stackId) expectAnvilEq(res, 2, eqItem) b4 = res.item }) }) describe('second combine', () => { it('ss3 boots + t3 ff4', () => { - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) + const res = Item.anvil(b1, b2, false, undefined) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }] eqItem.repairCost = 3 - const res = Item.anvil(b1, b2, false, undefined) - eqItem.stackId = res.item.stackId expectAnvilEq(res, 16 + 2, eqItem) // 1 working per item c1 = res.item }) it('d3p4 + u3m1', () => { - const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 3) const res = Item.anvil(b3, b4, false, undefined) - eqItem.stackId = res.item.stackId + const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 3, res.item.stackId) expectAnvilEq(res, 5 + 2, eqItem) // 1 working on each book c2 = res.item }) }) describe('third combine', () => { it('d3p4 + u3m1', () => { - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) + const res = Item.anvil(c1, c2, false, undefined) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }, { name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }] eqItem.repairCost = 7 - const res = Item.anvil(c1, c2, false, undefined) - eqItem.stackId = res.item.stackId expectAnvilEq(res, 15 + 6, eqItem) // 3 lvl repairCost on each item }) }) diff --git a/test/basic.test.js b/test/basic.test.js index 8f37651..1a0ff33 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -185,90 +185,81 @@ describe('test anvil functions', () => { const Item = require('prismarine-item')('1.8.8') it('diamond axe with fortune 2', () => { - const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants const newItem = new Item(279, 1) + const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 1 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('gold helmet with fire prot 3, aqua afin 1, unbr 2', () => { - const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - const enchs = item.enchants const newItem = new Item(314, 1) + const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 3 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('carrot on stick with unbr 1', () => { - const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants const newItem = new Item(398, 1) + const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 1 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('stone pick with eff 4', () => { - const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants const newItem = new Item(274, 1) + const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 1 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('fishing rod with luck 3 lure 3', () => { - const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - const enchs = item.enchants const newItem = new Item(346, 1) + const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 3 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) }) describe('1.16.5 test', () => { const Item = require('prismarine-item')('1.16.5') it('diamond sword (unenchanted)', () => { - const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }) - const enchs = item.enchants const newItem = new Item(603, 1) + const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('iron shovel w/ eff2 for2 ub2', () => { - const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }) - const enchs = item.enchants const newItem = new Item(600, 1) + const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 3 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('ench book w/ resp1 blastprot 1', () => { - const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants const newItem = new Item(848, 1) + const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 1 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) it('fishing rod w/ mending', () => { - const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }) - const enchs = item.enchants const newItem = new Item(684, 1) + const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }, newItem.stackId) + const enchs = item.enchants newItem.enchants = enchs newItem.repairCost = 1 - newItem.stackId = item.stackId expect(newItem).toStrictEqual(item) }) }) From b32b23aaa0b4750fcd7bdf11f3e6fc1b010cea37 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Fri, 17 Mar 2023 06:41:08 +0100 Subject: [PATCH 39/50] remove network types and add stackID to fromNotch --- index.d.ts | 43 ++----------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/index.d.ts b/index.d.ts index 335b856..c9d0d3f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -25,8 +25,8 @@ declare class Item { customLore: string | null; readonly spawnEggMobName: string; static equal(item1: Item, item2: Item, matchStackSize: boolean, matchNbt: boolean): boolean; - static toNotch(item: ItemLike): NetworkItem; - static fromNotch(item: NetworkItem): ItemLike; + static toNotch(item: ItemLike): object; + static fromNotch(item: object, stackId?: number): ItemLike; static anvil( itemOne: ItemLike, itemTwo: ItemLike, @@ -37,43 +37,4 @@ declare class Item { static nextStackId(): number; } -declare interface PcNetworkItem { - // 1.8 - 1.12 - blockId?: number; - itemDamage?: number; - // 1.13 - 1.15 - present?: boolean; - itemId?: number; - - itemCount?: number; - nbtData?: Buffer; -} - -declare interface BedrockNetworkItem { - network_id: number; - - // >= 1.16.220 - count?: number; - metadata?: number; - has_stack_id?: 0 | 1; - stack_id?: number; - block_runtime_id?: number; - extra?: { - has_nbt: boolean; - nbt?: { version: 1; nbt: Tags[TagType] }; - can_place_on: string[]; - can_destroy: string[]; - blocking_tick?: number; - }; - - // < 1.16.220 - auxiliary_value?: number; - has_nbt?: boolean; - nbt?: { version: 1; nbt: Tags[TagType] } - can_place_on?: string[]; - can_destroy?: string[]; -} - -declare type NetworkItem = PcNetworkItem | BedrockNetworkItem; - export default function loader(mcVersion: string): typeof Item; From 057f0b297a0e525950069e2bf22952256bbad87c Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 11 Apr 2023 15:17:52 +0200 Subject: [PATCH 40/50] update docs and types --- README.md | 11 ++++++++--- index.d.ts | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index af6301a..355ad7c 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,14 @@ console.log(Item.fromNotch(notchItem)) ### Item(type, count[, metadata, nbt, stackId]) -#### Item.toNotch(item) +#### Item.toNotch(item[, serverAuthoritative]) -Take an `item` in the format of the minecraft packets and return an `Item` instance. +Take an `Item` instance and returns it in the format of the minecraft packets. +- serverAuthoritative: Whether the server is using server authoritative inventory (whether or not to write a Stack ID) #### Item.fromNotch(item[, stackId]) -Take an `Item` instance and returns it in the format of the minecraft packets. +Take an `item` in the format of the minecraft packets and return an `Item` instance. - stackId for bedrock items before 1.16.220 ### Item.anvil(itemOne, itemTwo, creative[, newName]) @@ -61,6 +62,10 @@ See http://www.minecraftwiki.net/wiki/Data_values#Data Buffer. +#### item.stackId + +The stack ID of the item. + #### item.name #### item.displayName diff --git a/index.d.ts b/index.d.ts index c9d0d3f..a5214f4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -11,7 +11,7 @@ declare class Item { count: number; metadata: number; nbt: Tags[TagType] | null; - stackId: number; + stackId: number | null; name: string; displayName: string; stackSize: number; @@ -24,8 +24,8 @@ declare class Item { customName: string | null; customLore: string | null; readonly spawnEggMobName: string; - static equal(item1: Item, item2: Item, matchStackSize: boolean, matchNbt: boolean): boolean; - static toNotch(item: ItemLike): object; + static equal(item1: Item, item2: Item, matchStackSize?: boolean, matchNbt?: boolean): boolean; + static toNotch(item: ItemLike, serverAuthoritative?: boolean): object; static fromNotch(item: object, stackId?: number): ItemLike; static anvil( itemOne: ItemLike, From bf66f4263d604db83dda418a7f6f44d3d3e671ff Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 11 Apr 2023 15:18:29 +0200 Subject: [PATCH 41/50] stack ID is null in java (mcdata feature?) --- README.md | 2 +- index.js | 76 +++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 355ad7c..62277d5 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Buffer. #### item.stackId -The stack ID of the item. +The stack ID of the item, if the version supports Stack IDs. #### item.name diff --git a/index.js b/index.js index a9609f7..39bba94 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,13 @@ function loader (registryOrVersion) { this.count = count this.metadata = metadata == null ? 0 : metadata this.nbt = nbt || null - this.stackId = stackId ?? Item.nextStackId() + + // Probably add a new feature to mcdata, e.g itemsCanHaveStackId + if (registry.type === 'bedrock') { + this.stackId = stackId ?? Item.nextStackId() + } else { + this.stackId = null + } const itemEnum = registry.items[type] if (itemEnum) { @@ -67,7 +73,7 @@ function loader (registryOrVersion) { itemId: item.type, itemCount: item.count } - if (item.nbt && item.nbt.length !== 0) { + if (item.nbt && Object.keys(item.nbt.value).length !== 0) { networkItem.nbtData = item.nbt } return networkItem @@ -78,42 +84,48 @@ function loader (registryOrVersion) { itemCount: item.count, itemDamage: item.metadata } - if (item.nbt && item.nbt.length !== 0) { + if (item.nbt && Object.keys(item.nbt.value).length !== 0) { networkItem.nbtData = item.nbt } return networkItem } else if (registry.type === 'bedrock') { - if (item.type === 0) return { network_id: 0 } + if (item == null || item.type === 0) return { network_id: 0 } if (registry.supportFeature('itemSerializeUsesAuxValue')) { const networkItem = { network_id: item.id, auxiliary_value: (item.metadata << 8) | (item.count & 0xff), - has_nbt: item.nbt !== null, - nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, can_place_on: item.blocksCanPlaceOn, can_destroy: item.blocksCanDestroy, blocking_tick: 0 } - + if (item.nbt && Object.keys(item.nbt.value).length !== 0) { + networkItem.has_nbt = true + networkItem.nbt = { version: 1, nbt: item.nbt } + } else { + networkItem.has_nbt = false + } return networkItem } else { const networkItem = { network_id: item.type, count: item.count, metadata: item.metadata, - has_stack_id: +serverAuthoritative, + has_stack_id: serverAuthoritative, stack_id: serverAuthoritative ? item.stackId : undefined, block_runtime_id: 0, extra: { - has_nbt: item.nbt !== null, - nbt: item.nbt !== null ? { version: 1, nbt: item.nbt } : undefined, can_place_on: item.blocksCanPlaceOn, can_destroy: item.blocksCanDestroy, blocking_tick: 0 } } - + if (item.nbt && Object.keys(item.nbt.value).length !== 0) { + networkItem.extra.has_nbt = true + networkItem.extra.nbt = { version: 1, nbt: item.nbt } + } else { + networkItem.has_nbt = false + } return networkItem } } @@ -123,24 +135,24 @@ function loader (registryOrVersion) { static fromNotch (networkItem, stackId) { if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { if (networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData, stackId) + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) } else if (registry.supportFeature('itemSerializationAllowsPresent')) { if (networkItem.itemId === -1 || networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData, stackId) + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (networkItem.blockId === -1) return null - return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData, stackId) + return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) } else if (registry.type === 'bedrock') { - if (networkItem.network_id === 0) return new Item(0) + if (networkItem.network_id === 0) return null if (registry.supportFeature('itemSerializeUsesAuxValue')) { const item = new Item(networkItem.network_id, networkItem.auxiliary_value & 0xff, networkItem.auxiliary_value >> 8, networkItem.nbt?.nbt, stackId) - item.blocksCanPlaceOn = networkItem.can_place_on - item.blocksCanDestroy = networkItem.can_destroy + if (networkItem.can_place_on.length > 0) item.blocksCanPlaceOn = networkItem.can_place_on + if (networkItem.can_destroy.length > 0) item.blocksCanDestroy = networkItem.can_destroy return item } else { - const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt?.nbt, networkItem.stack_id ?? stackId) - item.blocksCanPlaceOn = networkItem.extra.can_place_on - item.blocksCanDestroy = networkItem.extra.can_destroy + const item = new Item(networkItem.network_id, networkItem.count, networkItem.metadata, networkItem.extra.nbt?.nbt, networkItem.stack_id) + if (networkItem.extra.can_place_on.length > 0) item.blocksCanPlaceOn = networkItem.extra.can_place_on + if (networkItem.extra.can_destroy.length > 0) item.blocksCanDestroy = networkItem.extra.can_destroy return item } } @@ -223,6 +235,8 @@ function loader (registryOrVersion) { const type = registry.supportFeature('typeOfValueForEnchantLevel') if (!type) throw new Error("Don't know the serialized type for enchant level") + const useStoredEnchants = this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments') + const enchs = normalizedEnchArray.map(({ name, lvl }) => { const value = type === 'short' @@ -233,11 +247,9 @@ function loader (registryOrVersion) { if (enchs.length !== 0) { if (!this.nbt) this.nbt = nbt.comp({}) - if (this.name === 'enchanted_book' && registry.supportFeature('booksUseStoredEnchantments')) { - this.nbt.value.StoredEnchantments = nbt.list(nbt.comp(enchs)) - } else { - this.nbt.value[enchListName] = nbt.list(nbt.comp(enchs)) - } + this.nbt.value[useStoredEnchants ? 'StoredEnchantments' : enchListName] = nbt.list(nbt.comp(enchs)) + } else if (this.enchants.length !== 0) { + delete this.nbt?.[useStoredEnchants ? 'StoredEnchantments' : enchListName] } } @@ -246,6 +258,10 @@ function loader (registryOrVersion) { } set blocksCanPlaceOn (newBlocks) { + if (newBlocks.length === 0) { + if (this.blocksCanPlaceOn.length !== 0) delete this.nbt.value.CanPlaceOn + return + } if (!this.nbt) this.nbt = nbt.comp({}) const blocks = [] @@ -266,6 +282,10 @@ function loader (registryOrVersion) { } set blocksCanDestroy (newBlocks) { + if (newBlocks.length === 0) { + if (this.blocksCanDestroy.length !== 0) delete this.nbt.value.CanDestroy + return + } if (!this.nbt) this.nbt = nbt.comp({}) const blocks = [] @@ -305,6 +325,9 @@ function loader (registryOrVersion) { } get spawnEggMobName () { + if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { + return this.name.replace('_spawn_egg', '') + } if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { return registry.entitiesArray.find((o) => o.internalId === this.metadata).name } @@ -313,9 +336,6 @@ function loader (registryOrVersion) { const entityName = data.EntityTag.id return entityName.replace('minecraft:', '') } - if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { - return this.name.replace('_spawn_egg', '') - } throw new Error("Don't know how to get spawn egg mob name for this mc version") } } From 5dc0be5224567f226734af5bf6432ecd8f90f0b9 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 11 Apr 2023 15:18:50 +0200 Subject: [PATCH 42/50] Fix tests for stack ID, start adding bedrock tests --- test/anvil.test.js | 68 +++--- test/basic.test.js | 580 ++++++++++++++++++++++++++++----------------- 2 files changed, 400 insertions(+), 248 deletions(-) diff --git a/test/anvil.test.js b/test/anvil.test.js index 67de139..f4d7b35 100644 --- a/test/anvil.test.js +++ b/test/anvil.test.js @@ -9,8 +9,8 @@ describe('1.8.9 anvil', () => { const sword2 = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3 }) const res = Item.anvil(sword1, sword2, false, undefined) const inverse = Item.anvil(sword2, sword1, false, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) - const inverseFinalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, inverse.item.stackId) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const inverseFinalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) expect(res.xpCost).toStrictEqual(3) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -21,8 +21,8 @@ describe('1.8.9 anvil', () => { const book2 = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }) const res = Item.anvil(book1, book2, false, undefined) const inverse = Item.anvil(book2, book1, false, undefined) - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }, res.item.stackId) - const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }, inverse.item.stackId) + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } } } } }) + const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }] } } } } }) expect(res.xpCost).toStrictEqual(2) expect(inverse.xpCost).toStrictEqual(5) expect(res.item).toStrictEqual(finalItem) @@ -34,7 +34,7 @@ describe('1.8.9 anvil', () => { const book = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) const res = Item.anvil(sword, book, false, undefined) const inverse = Item.anvil(book, sword, false, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) const inverseFinalItem = null expect(res.xpCost).toStrictEqual(6) expect(inverse.xpCost).toStrictEqual(0) @@ -47,7 +47,7 @@ describe('1.8.9 anvil', () => { const book = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) const res = Item.anvil(sword, book, true, undefined) const inverse = Item.anvil(book, sword, true, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 3, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) const inverseFinalItem = null expect(res.xpCost).toStrictEqual(11) expect(inverse.xpCost).toStrictEqual(0) @@ -59,7 +59,7 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0 }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) const inverseFinalItem = null expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) @@ -78,7 +78,7 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) const inverseFinalItem = null expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) @@ -90,7 +90,7 @@ describe('1.8.9 anvil', () => { const item = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0 }) const res = Item.anvil(item, null, false, 'ababa') const inverse = Item.anvil(null, item, false, 'ababa') - const finalItem = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'ababa' } } } } } }) const inverseFinalItem = null expect(res.xpCost).toStrictEqual(1) expect(inverse.xpCost).toStrictEqual(0) @@ -103,7 +103,7 @@ describe('1.8.9 anvil', () => { const itemTwo = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 48 } }, { lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } } } } }) const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) - const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Diamond Sword1212' } } } } } }, res.item.stackId) + const finalItem = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 3 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Diamond Sword1212' } } } } } }) const inverseFinalItem = null expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) @@ -114,8 +114,8 @@ describe('1.8.9 anvil', () => { const itemTwo = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }) const res = Item.anvil(itemOne, itemTwo, false, undefined) const inverse = Item.anvil(itemTwo, itemOne, false, undefined) - const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }] } } } } }, res.item.stackId) - const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }, inverse.item.stackId) + const finalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 33 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }] } } } } }) + const inverseFinalItem = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 35 } }] } } } } }) expect(res.item).toStrictEqual(finalItem) expect(inverse.item).toStrictEqual(inverseFinalItem) }) @@ -124,7 +124,7 @@ describe('1.8.9 anvil', () => { const chestplate = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 63 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Chain Chaestaaplateaaa' } } } } } }) it('try renaming', () => { const res = Item.anvil(chestplate, null, false, 'Hello!') - const expectedItem = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 127 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Hello!' } } } } } }, res.item.stackId) + const expectedItem = Item.fromNotch({ blockId: 303, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 127 }, display: { type: 'compound', value: { Name: { type: 'string', value: 'Hello!' } } } } } }) expect(res.xpCost).toStrictEqual(39) expect(res.item).toStrictEqual(expectedItem) }) @@ -140,8 +140,8 @@ describe('1.16.5 anvil', () => { const Item = require('prismarine-item')('1.16.5') const registry = require('prismarine-registry')('1.16.5') - function makeBook (ench, repairCost, stackId) { - const i = new Item(registry.itemsByName.enchanted_book.id, 1, 0, null, stackId) + function makeBook (ench, repairCost) { + const i = new Item(registry.itemsByName.enchanted_book.id, 1, 0, null) i.enchants = ench if (repairCost > 0) i.repairCost = repairCost return i @@ -157,8 +157,8 @@ describe('1.16.5 anvil', () => { const seconditem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }) const anvil = Item.anvil(firstItem, seconditem, false, undefined) const inverse = Item.anvil(seconditem, firstItem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }, anvil.item.stackId) - const expectedInverseItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }, inverse.item.stackId) + const expectedItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:fire_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }] } } } } }) + const expectedInverseItem = Item.fromNotch({ present: true, itemId: 638, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 7 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:unbreaking' } }, { lvl: { type: 'short', value: 4 }, id: { type: 'string', value: 'minecraft:projectile_protection' } }, { lvl: { type: 'short', value: 3 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:aqua_affinity' } }] } } } } }) expect(anvil.item).toStrictEqual(expectedItem) expect(inverse.item).toStrictEqual(expectedInverseItem) }) @@ -167,7 +167,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const resItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }, anvil.item.stackId) + const resItem = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'string', value: 'minecraft:sharpness' } }] } } } } }) expect(anvil.item).toStrictEqual(resItem) expect(anvil.xpCost).toStrictEqual(7) }) @@ -176,7 +176,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 300 } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2 }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }, anvil.item.stackId) + const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -185,7 +185,7 @@ describe('1.16.5 anvil', () => { const firstItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 300 } } } }) const secondItem = Item.fromNotch({ present: true, itemId: 579, itemCount: 2, nbtData: { name: '', type: 'compound', value: { Enchantments: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'string', value: 'minecraft:unbreaking' }, lvl: { type: 'short', value: 2 } }] } } } } }) const anvil = Item.anvil(firstItem, secondItem, false, undefined) - const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }, anvil.item.stackId) + const expectedItem = Item.fromNotch({ present: true, itemId: 598, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 176 }, RepairCost: { type: 'int', value: 1 } } } }) expect(anvil.item).toStrictEqual(expectedItem) expect(anvil.xpCost).toStrictEqual(2) expect(anvil.usedMats).toStrictEqual(2) @@ -211,14 +211,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) + const expectedItem = new Item(598, 1, 0, null) expectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(16) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) + const inverseExpectedItem = new Item(598, 1, 0, null) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -231,14 +231,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 3 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) + const expectedItem = new Item(598, 1, 0, null) expectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(15) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) + const inverseExpectedItem = new Item(598, 1, 0, null) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -251,14 +251,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 2 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) + const expectedItem = new Item(598, 1, 0, null) expectedItem.enchants = [{ name: 'sharpness', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(13) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null, inverseAnvilResults.item.stackId) + const inverseExpectedItem = new Item(598, 1, 0, null) inverseExpectedItem.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 3 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -271,7 +271,7 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'protection', lvl: 3 }, { name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 2 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null, anvilResults.item.stackId) + const expectedItem = new Item(598, 1, 0, null) expectedItem.enchants = [{ name: 'looting', lvl: 3 }, { name: 'sharpness', lvl: 1 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) @@ -292,7 +292,7 @@ describe('1.16.5 anvil', () => { describe('first combine', () => { it('enchant boot+ss3', () => { const res = Item.anvil(a1, a2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }] eqItem.repairCost = 1 expectAnvilEq(res, 12, eqItem) @@ -300,19 +300,19 @@ describe('1.16.5 anvil', () => { }) it('thorns3+ff4', () => { const res = Item.anvil(a3, a4, false, undefined) - const eqItem = makeBook([{ name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }], 1, res.item.stackId) + const eqItem = makeBook([{ name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }], 1) expectAnvilEq(res, 4, eqItem) b2 = res.item }) it('depth3+p4', () => { const res = Item.anvil(a5, a6, false, undefined) - const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }], 1, res.item.stackId) + const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }], 1) expectAnvilEq(res, 4, eqItem) b3 = res.item }) it('ub3+mending', () => { const res = Item.anvil(a7, a8, false, undefined) - const eqItem = makeBook([{ name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 1, res.item.stackId) + const eqItem = makeBook([{ name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 1) expectAnvilEq(res, 2, eqItem) b4 = res.item }) @@ -320,7 +320,7 @@ describe('1.16.5 anvil', () => { describe('second combine', () => { it('ss3 boots + t3 ff4', () => { const res = Item.anvil(b1, b2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }] eqItem.repairCost = 3 expectAnvilEq(res, 16 + 2, eqItem) // 1 working per item @@ -328,7 +328,7 @@ describe('1.16.5 anvil', () => { }) it('d3p4 + u3m1', () => { const res = Item.anvil(b3, b4, false, undefined) - const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 3, res.item.stackId) + const eqItem = makeBook([{ name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }], 3) expectAnvilEq(res, 5 + 2, eqItem) // 1 working on each book c2 = res.item }) @@ -336,7 +336,7 @@ describe('1.16.5 anvil', () => { describe('third combine', () => { it('d3p4 + u3m1', () => { const res = Item.anvil(c1, c2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null, res.item.stackId) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }, { name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }] eqItem.repairCost = 7 expectAnvilEq(res, 15 + 6, eqItem) // 3 lvl repairCost on each item diff --git a/test/basic.test.js b/test/basic.test.js index 1a0ff33..930ad92 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -8,7 +8,7 @@ describe('test based on examples', () => { const ironShovelItem = new Item(256, 1) it('constructor makes item correctly', () => { - const val = { type: 256, count: 1, metadata: 0, nbt: null, name: 'iron_shovel', displayName: 'Iron Shovel', stackSize: 1, stackId: 0 } + const val = { type: 256, count: 1, metadata: 0, nbt: null, name: 'iron_shovel', displayName: 'Iron Shovel', stackSize: 1, stackId: null } expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(val) }) @@ -19,7 +19,7 @@ describe('test based on examples', () => { it('use .fromNotch', () => { const toNotch = Item.toNotch(ironShovelItem) const fromNotch = Item.fromNotch(toNotch) - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 256, stackId: 1 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: null, stackSize: 1, type: 256, stackId: null } expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) }) }) @@ -28,7 +28,7 @@ describe('test based on examples', () => { const ironShovelItem = new Item(472, 1) it('constructor makes item correctly', () => { - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: 0 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: null } expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(expectedObj) }) @@ -40,228 +40,380 @@ describe('test based on examples', () => { it('use .fromNotch', () => { const toNotch = Item.toNotch(ironShovelItem) const fromNotch = Item.fromNotch(toNotch) - const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: 1 } + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: 472, stackId: null } + expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) + }) + }) + describe('bedrock_1.19.1 iron shovel', () => { + const registry = require('prismarine-registry')('bedrock_1.19.1') + const Item = require('prismarine-item')(registry) + const ironShovelItem = new Item(registry.itemsByName.iron_shovel.id, 1) + + it('constructor makes item correctly', () => { + const val = { type: registry.itemsByName.iron_shovel.id, count: 1, metadata: 0, nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, name: 'iron_shovel', displayName: 'Iron Shovel', stackSize: 1, stackId: 0 } + expect(JSON.parse(JSON.stringify(ironShovelItem))).toStrictEqual(val) + }) + + it('use .toNotch', () => { + expect(Item.toNotch(ironShovelItem)).toStrictEqual({ network_id: registry.itemsByName.iron_shovel.id, count: 1, metadata: 0, has_stack_id: true, stack_id: 0, block_runtime_id: 0, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } } }, can_place_on: [], can_destroy: [], blocking_tick: 0 } }) + }) + + it('use .fromNotch', () => { + const toNotch = Item.toNotch(ironShovelItem) + const fromNotch = Item.fromNotch(toNotch) + const expectedObj = { count: 1, displayName: 'Iron Shovel', metadata: 0, name: 'iron_shovel', nbt: { name: '', type: 'compound', value: { Damage: { type: 'int', value: 0 } } }, stackSize: 1, type: registry.itemsByName.iron_shovel.id, stackId: 0 } expect(JSON.parse(JSON.stringify(fromNotch))).toStrictEqual(expectedObj) }) }) }) -describe('test anvil functions', () => { - describe('Item.getEnchants', () => { - describe('1.8.8 test', () => { - const Item = require('prismarine-item')('1.8.8') - - it('diamond axe with fortune 2', () => { - const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 2, name: 'fortune' }]) - }) - - it('gold helmet with fire prot 3, aqua afin 1, unbr 2', () => { - const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 3, name: 'fire_protection' }, { lvl: 2, name: 'unbreaking' }, { lvl: 1, name: 'aqua_affinity' }]) - }) - - it('carrot on stick with unbr 1', () => { - const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 1, name: 'unbreaking' }]) - }) - - it('stone pick with eff 4', () => { - const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 4, name: 'efficiency' }]) - }) - - it('fishing rod with luck 3 lure 3', () => { - const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 3, name: 'luck_of_the_sea' }, { lvl: 3, name: 'lure' }]) - }) - - it('diamond sword (unenchanted)', () => { - const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0 }) - const enchs = item.enchants - expect(enchs).toStrictEqual([]) - }) - - it('enchanted book rename', () => { - const item = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 1, name: 'blast_protection' }]) - }) - - it('(64x) blocks rename', () => { - const item = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0 }) - const enchs = item.enchants - expect(enchs).toStrictEqual([]) - }) - }) - describe('1.12.2 test', () => { - const Item = require('prismarine-item')('1.12.2') - - it('sharp 5 dia sword', () => { - const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 5, name: 'sharpness' }]) - }) - it('mending 1 elytra', () => { - const item = Item.fromNotch({ blockId: 443, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'int', value: 1 }, id: { type: 'int', value: 70 } }] } } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 1, name: 'mending' }]) - }) - }) - describe('1.16.5 test', () => { - const Item = require('prismarine-item')('1.16.5') +describe('get Item.enchants', () => { + describe('1.8.8 test', () => { + const Item = require('prismarine-item')('1.8.8') + + it('diamond axe with fortune 2', () => { + const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 2, name: 'fortune' }]) + }) + + it('gold helmet with fire prot 3, aqua afin 1, unbr 2', () => { + const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 3, name: 'fire_protection' }, { lvl: 2, name: 'unbreaking' }, { lvl: 1, name: 'aqua_affinity' }]) + }) + + it('carrot on stick with unbr 1', () => { + const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'unbreaking' }]) + }) + + it('stone pick with eff 4', () => { + const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 4, name: 'efficiency' }]) + }) + + it('fishing rod with luck 3 lure 3', () => { + const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 3, name: 'luck_of_the_sea' }, { lvl: 3, name: 'lure' }]) + }) + + it('diamond sword (unenchanted)', () => { + const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0 }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + + it('enchanted book rename', () => { + const item = Item.fromNotch({ blockId: 403, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 3 } }] } } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'blast_protection' }]) + }) + + it('(64x) blocks rename', () => { + const item = Item.fromNotch({ blockId: 1, itemCount: 64, itemDamage: 0 }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + }) + describe('1.12.2 test', () => { + const Item = require('prismarine-item')('1.12.2') + + it('sharp 5 dia sword', () => { + const item = Item.fromNotch({ blockId: 276, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 5 }, id: { type: 'short', value: 16 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 5, name: 'sharpness' }]) + }) + it('mending 1 elytra', () => { + const item = Item.fromNotch({ blockId: 443, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'int', value: 1 }, id: { type: 'int', value: 70 } }] } } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'mending' }]) + }) + }) + describe('1.16.5 test', () => { + const Item = require('prismarine-item')('1.16.5') + + it('diamond sword (unenchanted)', () => { + const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + it('iron shovel w/ eff2 for2 ub2', () => { + const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 2, name: 'efficiency' }, { lvl: 2, name: 'fortune' }, { lvl: 2, name: 'unbreaking' }]) + }) + it('ench book w/ resp1 blastprot 1', () => { + const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'respiration' }, { lvl: 1, name: 'blast_protection' }]) + }) + it('music disc', () => { + const item = Item.fromNotch({ present: true, itemId: 911, itemCount: 1 }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + it('fishing rod w/ mending', () => { + const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'mending' }]) + }) + }) + describe('bedrock_1.17.10 test', () => { + const Item = require('prismarine-item')('bedrock_1.17.10') + + it('stone sword (unenchanted)', () => { + const item = Item.fromNotch({ network_id: 704, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + it('unbreaking 1 iron pickaxe', () => { + const item = Item.fromNotch({ network_id: 716, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 17 }, lvl: { type: 'short', value: 1 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'unbreaking' }]) + }) + it('efficiency 5 diamond shovel', () => { + const item = Item.fromNotch({ network_id: 720, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 15 }, lvl: { type: 'short', value: 5 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 5, name: 'efficiency' }]) + }) + it('protection 4, mending diamond leggings', () => { + const item = Item.fromNotch({ network_id: 752, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 0 }, lvl: { type: 'short', value: 4 } }, { id: { type: 'short', value: 26 }, lvl: { type: 'short', value: 1 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 4, name: 'protection' }, { lvl: 1, name: 'mending' }]) + }) + }) + describe('bedrock_1.19.1 test', () => { + const Item = require('prismarine-item')('bedrock_1.19.1') - it('diamond sword (unenchanted)', () => { - const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([]) - }) - it('iron shovel w/ eff2 for2 ub2', () => { - const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 2, name: 'efficiency' }, { lvl: 2, name: 'fortune' }, { lvl: 2, name: 'unbreaking' }]) - }) - it('ench book w/ resp1 blastprot 1', () => { - const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 1, name: 'respiration' }, { lvl: 1, name: 'blast_protection' }]) - }) - it('music disc', () => { - const item = Item.fromNotch({ present: true, itemId: 911, itemCount: 1 }) - const enchs = item.enchants - expect(enchs).toStrictEqual([]) - }) - it('fishing rod w/ mending', () => { - const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }) - const enchs = item.enchants - expect(enchs).toStrictEqual([{ lvl: 1, name: 'mending' }]) - }) + it('iron hoe (unenchanted)', () => { + const item = Item.fromNotch({ network_id: 754, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([]) + }) + it('silk touch stone axe', () => { + const item = Item.fromNotch({ network_id: 743, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 16 }, lvl: { type: 'short', value: 1 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 1, name: 'silk_touch' }]) + }) + it('lure 3 fishing rod', () => { + const item = Item.fromNotch({ network_id: 836, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 24 }, lvl: { type: 'short', value: 3 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 3, name: 'lure' }]) + }) + it('fire prot 3, unbreaking 2, respiration 3 diamond helmet', () => { + const item = Item.fromNotch({ network_id: 786, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 1 }, lvl: { type: 'short', value: 3 } }, { id: { type: 'short', value: 17 }, lvl: { type: 'short', value: 2 } }, { id: { type: 'short', value: 6 }, lvl: { type: 'short', value: 3 } }] } } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + expect(enchs).toStrictEqual([{ lvl: 3, name: 'fire_protection' }, { lvl: 2, name: 'unbreaking' }, { lvl: 3, name: 'respiration' }]) }) }) - describe('item.spawnEggMobName', () => { - describe('1.8.9 test', () => { - it('zombie egg', () => { - const Item = require('prismarine-item')('1.8.9') - const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 54 }) - expect(item.spawnEggMobName).toStrictEqual('Zombie') - }) - }) - describe('1.11.2 test', () => { - it('zombie egg', () => { - const Item = require('prismarine-item')('1.11.2') - const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) - expect(item.spawnEggMobName).toStrictEqual('zombie') - }) - }) - describe('1.11.2 test', () => { - it('zombie egg', () => { - const Item = require('prismarine-item')('1.11.2') - const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) - expect(item.spawnEggMobName).toStrictEqual('zombie') - }) - }) - describe('1.11.2 test', () => { - it('zombie egg', () => { - const Item = require('prismarine-item')('1.11.2') - const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) - expect(item.spawnEggMobName).toStrictEqual('zombie') - }) - }) - describe('1.16.5 test', () => { - it('zombie egg', () => { - const Item = require('prismarine-item')('1.16.5') - const item = Item.fromNotch({ present: true, itemId: 819, itemCount: 1 }) - expect(item.spawnEggMobName).toStrictEqual('zombie') - }) +}) +describe('item.spawnEggMobName', () => { + describe('1.8.9 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('1.8.9') + const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 54 }) + expect(item.spawnEggMobName).toStrictEqual('Zombie') + }) + }) + describe('1.11.2 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('1.11.2') + const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) + expect(item.spawnEggMobName).toStrictEqual('zombie') }) }) - describe('item.setEnchants', () => { - describe('1.8.8 test', () => { - const Item = require('prismarine-item')('1.8.8') - - it('diamond axe with fortune 2', () => { - const newItem = new Item(279, 1) - const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 1 - expect(newItem).toStrictEqual(item) - }) - - it('gold helmet with fire prot 3, aqua afin 1, unbr 2', () => { - const newItem = new Item(314, 1) - const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 3 - expect(newItem).toStrictEqual(item) - }) - - it('carrot on stick with unbr 1', () => { - const newItem = new Item(398, 1) - const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 1 - expect(newItem).toStrictEqual(item) - }) - - it('stone pick with eff 4', () => { - const newItem = new Item(274, 1) - const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 1 - expect(newItem).toStrictEqual(item) - }) - - it('fishing rod with luck 3 lure 3', () => { - const newItem = new Item(346, 1) - const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 3 - expect(newItem).toStrictEqual(item) - }) - }) - describe('1.16.5 test', () => { + describe('1.11.2 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('1.11.2') + const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) + expect(item.spawnEggMobName).toStrictEqual('zombie') + }) + }) + describe('1.11.2 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('1.11.2') + const item = Item.fromNotch({ blockId: 383, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { EntityTag: { type: 'compound', value: { id: { type: 'string', value: 'minecraft:zombie' } } } } } }) + expect(item.spawnEggMobName).toStrictEqual('zombie') + }) + }) + describe('1.16.5 test', () => { + it('zombie egg', () => { const Item = require('prismarine-item')('1.16.5') - it('diamond sword (unenchanted)', () => { - const newItem = new Item(603, 1) - const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - expect(newItem).toStrictEqual(item) - }) - it('iron shovel w/ eff2 for2 ub2', () => { - const newItem = new Item(600, 1) - const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 3 - expect(newItem).toStrictEqual(item) - }) - it('ench book w/ resp1 blastprot 1', () => { - const newItem = new Item(848, 1) - const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 1 - expect(newItem).toStrictEqual(item) - }) - it('fishing rod w/ mending', () => { - const newItem = new Item(684, 1) - const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }, newItem.stackId) - const enchs = item.enchants - newItem.enchants = enchs - newItem.repairCost = 1 - expect(newItem).toStrictEqual(item) - }) + const item = Item.fromNotch({ present: true, itemId: 819, itemCount: 1 }) + expect(item.spawnEggMobName).toStrictEqual('zombie') + }) + }) + describe('bedrock_1.17.10 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('bedrock_1.17.10') + const item = Item.fromNotch({ network_id: 936, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + expect(item.spawnEggMobName).toStrictEqual('zombie') + }) + }) + describe('bedrock_1.19.1 test', () => { + it('zombie egg', () => { + const Item = require('prismarine-item')('bedrock_1.19.1') + const item = Item.fromNotch({ network_id: 979, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + expect(item.spawnEggMobName).toStrictEqual('zombie') + }) + }) +}) +describe('set item.enchants', () => { + describe('1.8.8 test', () => { + const Item = require('prismarine-item')('1.8.8') + + it('diamond axe with fortune 2', () => { + const newItem = new Item(279, 1) + const item = Item.fromNotch({ blockId: 279, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 35 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + + it('gold helmet with fire prot 3, aqua afin 1, unbr 2', () => { + const newItem = new Item(314, 1) + const item = Item.fromNotch({ blockId: 314, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 1 } }, { lvl: { type: 'short', value: 2 }, id: { type: 'short', value: 34 } }, { lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 6 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) + }) + + it('carrot on stick with unbr 1', () => { + const newItem = new Item(398, 1) + const item = Item.fromNotch({ blockId: 398, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'short', value: 34 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + + it('stone pick with eff 4', () => { + const newItem = new Item(274, 1) + const item = Item.fromNotch({ blockId: 274, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 4 }, id: { type: 'short', value: 32 } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + + it('fishing rod with luck 3 lure 3', () => { + const newItem = new Item(346, 1) + const item = Item.fromNotch({ blockId: 346, itemCount: 1, itemDamage: 0, nbtData: { type: 'compound', name: '', value: { ench: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 61 } }, { lvl: { type: 'short', value: 3 }, id: { type: 'short', value: 62 } }] } }, RepairCost: { type: 'int', value: 3 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) + }) + }) + describe('1.16.5 test', () => { + const Item = require('prismarine-item')('1.16.5') + it('diamond sword (unenchanted)', () => { + const newItem = new Item(603, 1) + const item = Item.fromNotch({ present: true, itemId: 603, itemCount: 1, nbtData: { type: 'compound', name: '', value: { Damage: { type: 'int', value: 0 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + expect(newItem).toStrictEqual(item) + }) + it('iron shovel w/ eff2 for2 ub2', () => { + const newItem = new Item(600, 1) + const item = Item.fromNotch({ present: true, itemId: 600, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 3 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:efficiency' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:fortune' } }, { lvl: { type: 'short', value: 2 }, id: { type: 'string', value: 'minecraft:unbreaking' } }] } } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) + }) + it('ench book w/ resp1 blastprot 1', () => { + const newItem = new Item(848, 1) + const item = Item.fromNotch({ present: true, itemId: 848, itemCount: 1, nbtData: { type: 'compound', name: '', value: { StoredEnchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:respiration' } }, { lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:blast_protection' } }] } }, RepairCost: { type: 'int', value: 1 } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + it('fishing rod w/ mending', () => { + const newItem = new Item(684, 1) + const item = Item.fromNotch({ present: true, itemId: 684, itemCount: 1, nbtData: { type: 'compound', name: '', value: { RepairCost: { type: 'int', value: 1 }, Damage: { type: 'int', value: 0 }, Enchantments: { type: 'list', value: { type: 'compound', value: [{ lvl: { type: 'short', value: 1 }, id: { type: 'string', value: 'minecraft:mending' } }] } } } } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + }) + describe('bedrock_1.17.10 test', () => { + const registry = require('prismarine-registry')('bedrock_1.17.10') + const Item = require('prismarine-item')(registry) + + it('unenchanted stone sword', () => { + const newItem = new Item(704, 1) + const item = Item.fromNotch({ network_id: 704, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + expect(newItem).toStrictEqual(item) + }) + it('unbreaking 1 iron pickaxe', () => { + const newItem = new Item(716, 1) + const item = Item.fromNotch({ network_id: 716, count: 1, metadata: 0, stack_id: 1, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 17 }, lvl: { type: 'short', value: 1 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) + }) + it('efficiency 5 diamond shovel', () => { + const newItem = new Item(720, 1) + const item = Item.fromNotch({ network_id: 720, count: 1, metadata: 0, stack_id: 2, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 15 }, lvl: { type: 'short', value: 5 } }] } }, RepairCost: { type: 'int', value: 2 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 2 + expect(newItem).toStrictEqual(item) + }) + it('protection 4, mending diamond leggings', () => { + const newItem = new Item(752, 1) + const item = Item.fromNotch({ network_id: 752, count: 1, metadata: 0, stack_id: 3, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 0 }, lvl: { type: 'short', value: 4 } }, { id: { type: 'short', value: 26 }, lvl: { type: 'short', value: 1 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) + }) + }) + describe('bedrock_1.19.1 test', () => { + const Item = require('prismarine-item')('bedrock_1.19.1') + + it('unenchanted iron hoe', () => { + const newItem = new Item(754, 1) + const item = Item.fromNotch({ network_id: 754, count: 1, metadata: 0, stack_id: 0, has_stack_id: true, extra: { has_nbt: false, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + expect(newItem).toStrictEqual(item) + }) + it('silk touch stone axe', () => { + const newItem = new Item(743, 1) + const item = Item.fromNotch({ network_id: 743, count: 1, metadata: 0, stack_id: 1, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 16 }, lvl: { type: 'short', value: 1 } }] } }, RepairCost: { type: 'int', value: 1 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 1 + expect(newItem).toStrictEqual(item) + }) + it('lure 3 fishing rod', () => { + const newItem = new Item(836, 1) + const item = Item.fromNotch({ network_id: 836, count: 1, metadata: 0, stack_id: 2, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 24 }, lvl: { type: 'short', value: 3 } }] } }, RepairCost: { type: 'int', value: 2 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 2 + expect(newItem).toStrictEqual(item) + }) + it('fire prot 3, unbreaking 2, respiration 3 diamond helmet', () => { + const newItem = new Item(786, 1) + const item = Item.fromNotch({ network_id: 786, count: 1, metadata: 0, stack_id: 3, has_stack_id: true, extra: { has_nbt: true, nbt: { version: 1, nbt: { name: '', type: 'compound', value: { ench: { type: 'list', value: { type: 'compound', value: [{ id: { type: 'short', value: 1 }, lvl: { type: 'short', value: 3 } }, { id: { type: 'short', value: 17 }, lvl: { type: 'short', value: 2 } }, { id: { type: 'short', value: 6 }, lvl: { type: 'short', value: 3 } }] } }, RepairCost: { type: 'int', value: 3 } } } }, can_place_on: [], can_destroy: [] } }) + const enchs = item.enchants + newItem.enchants = enchs + newItem.repairCost = 3 + expect(newItem).toStrictEqual(item) }) }) }) From c59897590646537ad11063cc2d44863c8bce4c99 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 11 Apr 2023 15:35:21 +0200 Subject: [PATCH 43/50] clean up some unnecessary values --- test/anvil.test.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/anvil.test.js b/test/anvil.test.js index f4d7b35..9a2cbdf 100644 --- a/test/anvil.test.js +++ b/test/anvil.test.js @@ -141,7 +141,7 @@ describe('1.16.5 anvil', () => { const registry = require('prismarine-registry')('1.16.5') function makeBook (ench, repairCost) { - const i = new Item(registry.itemsByName.enchanted_book.id, 1, 0, null) + const i = new Item(registry.itemsByName.enchanted_book.id, 1) i.enchants = ench if (repairCost > 0) i.repairCost = repairCost return i @@ -211,14 +211,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null) + const expectedItem = new Item(598, 1) expectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(16) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null) + const inverseExpectedItem = new Item(598, 1) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 4 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -231,14 +231,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 3 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null) + const expectedItem = new Item(598, 1) expectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'knockback', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(15) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null) + const inverseExpectedItem = new Item(598, 1) inverseExpectedItem.enchants = [{ name: 'sharpness', lvl: 3 }, { name: 'looting', lvl: 3 }, { name: 'knockback', lvl: 2 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -251,14 +251,14 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 2 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null) + const expectedItem = new Item(598, 1) expectedItem.enchants = [{ name: 'sharpness', lvl: 2 }, { name: 'looting', lvl: 3 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) expect(anvilResults.xpCost).toStrictEqual(13) // inverse const inverseAnvilResults = Item.anvil(itemTwo, itemOne, false, undefined) - const inverseExpectedItem = new Item(598, 1, 0, null) + const inverseExpectedItem = new Item(598, 1) inverseExpectedItem.enchants = [{ name: 'smite', lvl: 5 }, { name: 'looting', lvl: 3 }] inverseExpectedItem.repairCost = 1 expect(inverseAnvilResults.item).toStrictEqual(inverseExpectedItem) @@ -271,7 +271,7 @@ describe('1.16.5 anvil', () => { itemTwo.enchants = [{ name: 'protection', lvl: 3 }, { name: 'sharpness', lvl: 1 }, { name: 'looting', lvl: 2 }] // expected way const anvilResults = Item.anvil(itemOne, itemTwo, false, undefined) - const expectedItem = new Item(598, 1, 0, null) + const expectedItem = new Item(598, 1) expectedItem.enchants = [{ name: 'looting', lvl: 3 }, { name: 'sharpness', lvl: 1 }] expectedItem.repairCost = 1 expect(anvilResults.item).toStrictEqual(expectedItem) @@ -292,7 +292,7 @@ describe('1.16.5 anvil', () => { describe('first combine', () => { it('enchant boot+ss3', () => { const res = Item.anvil(a1, a2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }] eqItem.repairCost = 1 expectAnvilEq(res, 12, eqItem) @@ -320,7 +320,7 @@ describe('1.16.5 anvil', () => { describe('second combine', () => { it('ss3 boots + t3 ff4', () => { const res = Item.anvil(b1, b2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }] eqItem.repairCost = 3 expectAnvilEq(res, 16 + 2, eqItem) // 1 working per item @@ -336,7 +336,7 @@ describe('1.16.5 anvil', () => { describe('third combine', () => { it('d3p4 + u3m1', () => { const res = Item.anvil(c1, c2, false, undefined) - const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1, 0, null) + const eqItem = new Item(registry.itemsByName.diamond_boots.id, 1) eqItem.enchants = [{ name: 'soul_speed', lvl: 3 }, { name: 'thorns', lvl: 3 }, { name: 'feather_falling', lvl: 4 }, { name: 'depth_strider', lvl: 3 }, { name: 'protection', lvl: 4 }, { name: 'unbreaking', lvl: 3 }, { name: 'mending', lvl: 1 }] eqItem.repairCost = 7 expectAnvilEq(res, 15 + 6, eqItem) // 3 lvl repairCost on each item From 60bbb4a46c3bc6f2fa5efa6dfad21267458c4cc1 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 11 Apr 2023 16:54:21 +0200 Subject: [PATCH 44/50] no need to test for null --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 39bba94..a6114b5 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ function loader (registryOrVersion) { constructor (type, count, metadata, nbt, stackId) { if (type == null) return - if (metadata instanceof Object && metadata !== null) { + if (metadata instanceof Object) { stackId = nbt nbt = metadata metadata = 0 From 96d061d04ccaab7b01d6f7d62c8f5e1849d19327 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Tue, 18 Jul 2023 19:52:25 +0200 Subject: [PATCH 45/50] More readable notch methods --- index.js | 89 +++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/index.js b/index.js index a6114b5..f43aa78 100644 --- a/index.js +++ b/index.js @@ -66,48 +66,42 @@ function loader (registryOrVersion) { } static toNotch (item, serverAuthoritative = true) { - if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (item == null) return { present: false } - const networkItem = { - present: true, - itemId: item.type, - itemCount: item.count - } - if (item.nbt && Object.keys(item.nbt.value).length !== 0) { - networkItem.nbtData = item.nbt - } - return networkItem - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (item == null) return { blockId: -1 } - const networkItem = { - blockId: item.type, - itemCount: item.count, - itemDamage: item.metadata - } - if (item.nbt && Object.keys(item.nbt.value).length !== 0) { - networkItem.nbtData = item.nbt + const hasNBT = item.nbt && Object.keys(item.nbt.value).length > 0 + + if (registry.type === 'pc') { + if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (item == null) return { present: false } + const networkItem = { + present: true, + itemId: item.type, + itemCount: item.count + } + if (hasNBT) networkItem.nbtData = item.nbt + return networkItem + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (item == null) return { blockId: -1 } + const networkItem = { + blockId: item.type, + itemCount: item.count, + itemDamage: item.metadata + } + if (hasNBT) networkItem.nbtData = item.nbt + return networkItem } - return networkItem } else if (registry.type === 'bedrock') { if (item == null || item.type === 0) return { network_id: 0 } - if (registry.supportFeature('itemSerializeUsesAuxValue')) { - const networkItem = { + return { network_id: item.id, auxiliary_value: (item.metadata << 8) | (item.count & 0xff), can_place_on: item.blocksCanPlaceOn, can_destroy: item.blocksCanDestroy, - blocking_tick: 0 + blocking_tick: 0, + has_nbt: hasNBT, + nbt: hasNBT ? { version: 1, nbt: item.nbt } : undefined } - if (item.nbt && Object.keys(item.nbt.value).length !== 0) { - networkItem.has_nbt = true - networkItem.nbt = { version: 1, nbt: item.nbt } - } else { - networkItem.has_nbt = false - } - return networkItem } else { - const networkItem = { + return { network_id: item.type, count: item.count, metadata: item.metadata, @@ -117,31 +111,28 @@ function loader (registryOrVersion) { extra: { can_place_on: item.blocksCanPlaceOn, can_destroy: item.blocksCanDestroy, - blocking_tick: 0 + blocking_tick: 0, + has_nbt: hasNBT, + nbt: hasNBT ? { version: 1, nbt: item.nbt } : undefined } } - if (item.nbt && Object.keys(item.nbt.value).length !== 0) { - networkItem.extra.has_nbt = true - networkItem.extra.nbt = { version: 1, nbt: item.nbt } - } else { - networkItem.has_nbt = false - } - return networkItem } } throw new Error("Don't know how to serialize for this mc version ") } static fromNotch (networkItem, stackId) { - if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { - if (networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) - } else if (registry.supportFeature('itemSerializationAllowsPresent')) { - if (networkItem.itemId === -1 || networkItem.present === false) return null - return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) - } else if (registry.supportFeature('itemSerializationUsesBlockId')) { - if (networkItem.blockId === -1) return null - return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) + if (registry.type === 'pc') { + if (registry.supportFeature('itemSerializationWillOnlyUsePresent')) { + if (networkItem.present === false) return null + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + } else if (registry.supportFeature('itemSerializationAllowsPresent')) { + if (networkItem.itemId === -1 || networkItem.present === false) return null + return new Item(networkItem.itemId, networkItem.itemCount, networkItem.nbtData) + } else if (registry.supportFeature('itemSerializationUsesBlockId')) { + if (networkItem.blockId === -1) return null + return new Item(networkItem.blockId, networkItem.itemCount, networkItem.itemDamage, networkItem.nbtData) + } } else if (registry.type === 'bedrock') { if (networkItem.network_id === 0) return null if (registry.supportFeature('itemSerializeUsesAuxValue')) { From 497ae97e36a4b1e9d2debaee065c616385819cdc Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 19 Jul 2023 14:13:29 +0200 Subject: [PATCH 46/50] Change blocksCanPlaceOn/Destroy to return [name, properties] --- README.md | 7 ++--- index.d.ts | 7 +++-- index.js | 64 ++++++++++++++++++++++++++-------------------- test/basic.test.js | 2 +- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index d49c1a6..959b72a 100644 --- a/README.md +++ b/README.md @@ -98,11 +98,12 @@ Returns an array of enchants on the Item with their name and level Updates the Item's NBT enchantments based on assigned array -#### item.blocksCanPlaceOn - +#### get item.blocksCanPlaceOn(): [name, Block][] +#### set item.blocksCanPlaceOn(blockNames: string[]) In adventure mode, the list of block names (as strings) that this Item can be placed on -#### item.blocksCanDestroy +#### get item.blocksCanDestroy(): [name, Block][] +#### set item.blocksCanDestroy(blockNames: string[]) In adventure mode, the list of block names (as strings) that this Item can be used to break diff --git a/index.d.ts b/index.d.ts index 2448771..0268c57 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,7 @@ /// import { Tags, TagType } from 'prismarine-nbt' +import { Block } from "minecraft-data" export type ItemLike = Item | null @@ -18,8 +19,10 @@ declare class Item { durabilityUsed: number; get enchants(): { name: string; lvl: number }[]; set enchants(enchantments: { name: string; lvl: number }[]); - blocksCanPlaceOn: string[]; - blocksCanDestroy: string[]; + get blocksCanPlaceOn(): [string, Block][]; + set blocksCanPlaceOn(blockNames: string[]); + get blocksCanDestroy(): [string, Block][]; + set blocksCanDestroy(blockNames: string[]); repairCost: number; customName: string | null; customLore: string | string[] | null; diff --git a/index.js b/index.js index f43aa78..bcd8391 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const nbt = require('prismarine-nbt') + function loader (registryOrVersion) { const registry = typeof registryOrVersion === 'string' ? require('prismarine-registry')(registryOrVersion) : registryOrVersion class Item { @@ -27,11 +28,13 @@ function loader (registryOrVersion) { if (itemEnum) { this.name = itemEnum.name this.displayName = itemEnum.displayName + this.stackSize = itemEnum.stackSize + if ('variations' in itemEnum) { const variation = itemEnum.variations.find((item) => item.metadata === metadata) if (variation) this.displayName = variation.displayName } - this.stackSize = itemEnum.stackSize + // The 'itemEnum.maxDurability' checks to see if this item can lose durability if (itemEnum.maxDurability && !this.durabilityUsed) this.durabilityUsed = 0 } else { @@ -51,15 +54,14 @@ function loader (registryOrVersion) { } else { return ( item1.type === item2.type && - (matchStackSize ? item1.count === item2.count : true) && item1.metadata === item2.metadata && + (matchStackSize ? item1.count === item2.count : true) && (matchNbt ? JSON.stringify(item1.nbt) === JSON.stringify(item2.nbt) : true) ) } } - // Stack ID - // Probably needs to be moved to prismarine-registry later on as calling the loader again will reset it + // TODO: Move stack ID handling to prismarine-registry, as calling the loader again resets it here static currentStackId = 0 static nextStackId () { return Item.currentStackId++ @@ -71,25 +73,24 @@ function loader (registryOrVersion) { if (registry.type === 'pc') { if (registry.supportFeature('itemSerializationAllowsPresent')) { if (item == null) return { present: false } - const networkItem = { + return { present: true, itemId: item.type, - itemCount: item.count + itemCount: item.count, + nbtData: hasNBT ? item.nbt : undefined } - if (hasNBT) networkItem.nbtData = item.nbt - return networkItem } else if (registry.supportFeature('itemSerializationUsesBlockId')) { if (item == null) return { blockId: -1 } - const networkItem = { + return { blockId: item.type, itemCount: item.count, - itemDamage: item.metadata + itemDamage: item.metadata, + nbtData: hasNBT ? item.nbt : undefined } - if (hasNBT) networkItem.nbtData = item.nbt - return networkItem } } else if (registry.type === 'bedrock') { if (item == null || item.type === 0) return { network_id: 0 } + if (registry.supportFeature('itemSerializeUsesAuxValue')) { return { network_id: item.id, @@ -135,6 +136,7 @@ function loader (registryOrVersion) { } } else if (registry.type === 'bedrock') { if (networkItem.network_id === 0) return null + if (registry.supportFeature('itemSerializeUsesAuxValue')) { const item = new Item(networkItem.network_id, networkItem.auxiliary_value & 0xff, networkItem.auxiliary_value >> 8, networkItem.nbt?.nbt, stackId) if (networkItem.can_place_on.length > 0) item.blocksCanPlaceOn = networkItem.can_place_on @@ -189,30 +191,31 @@ function loader (registryOrVersion) { if (Object.keys(this).length === 0) return [] const enchantNbtKey = registry.supportFeature('nbtNameForEnchant') const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel') + const useStoredEnchantments = registry.supportFeature('booksUseStoredEnchantments') && this.name === 'enchanted_book' if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') { let itemEnch = [] - if ( - this.name === 'enchanted_book' && - this?.nbt?.value?.StoredEnchantments && - registry.supportFeature('booksUseStoredEnchantments') - ) { + + if (useStoredEnchantments && this?.nbt?.value?.StoredEnchantments) { itemEnch = nbt.simplify(this.nbt).StoredEnchantments } else if (this?.nbt?.value?.ench) { itemEnch = nbt.simplify(this.nbt).ench } else { itemEnch = [] } + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: registry.enchantments[ench.id]?.name || null })) } else if (typeOfEnchantLevelValue === 'string' && enchantNbtKey === 'Enchantments') { let itemEnch = [] - if (this?.nbt?.value?.Enchantments) { - itemEnch = nbt.simplify(this.nbt).Enchantments - } else if (this?.nbt?.value?.StoredEnchantments) { + + if (useStoredEnchantments && this?.nbt?.value?.StoredEnchantments) { itemEnch = nbt.simplify(this.nbt).StoredEnchantments + } else if (this?.nbt?.value?.Enchantments) { + itemEnch = nbt.simplify(this.nbt).Enchantments } else { itemEnch = [] } + return itemEnch.map((ench) => ({ lvl: ench.lvl, name: typeof ench.id === 'string' ? ench.id.replace('minecraft:', '') : null @@ -245,7 +248,8 @@ function loader (registryOrVersion) { } get blocksCanPlaceOn () { - return this?.nbt?.value?.CanPlaceOn?.value?.value ?? [] + const blockNames = this?.nbt?.value?.CanPlaceOn?.value?.value ?? [] + return blockNames.map(name => [name, registry.blocksByName[name.replace('minecraft:', '')]]) } set blocksCanPlaceOn (newBlocks) { @@ -255,21 +259,22 @@ function loader (registryOrVersion) { } if (!this.nbt) this.nbt = nbt.comp({}) - const blocks = [] + const blockNames = [] for (const block of newBlocks) { let [ns, name] = block.split(':') if (!name) { name = ns ns = 'minecraft' } - blocks.push(`${ns}:${name}`) + blockNames.push(`${ns}:${name}`) } - this.nbt.value.CanPlaceOn = nbt.list(nbt.string(blocks)) + this.nbt.value.CanPlaceOn = nbt.list(nbt.string(blockNames)) } get blocksCanDestroy () { - return this?.nbt?.value?.CanDestroy?.value?.value ?? [] + const blockNames = this?.nbt?.value?.CanDestroy?.value?.value ?? [] + return blockNames.map(name => [name, registry.blocksByName[name.replace('minecraft:', '')]]) } set blocksCanDestroy (newBlocks) { @@ -279,17 +284,17 @@ function loader (registryOrVersion) { } if (!this.nbt) this.nbt = nbt.comp({}) - const blocks = [] + const blockNames = [] for (const block of newBlocks) { let [ns, name] = block.split(':') if (!name) { name = ns ns = 'minecraft' } - blocks.push(`${ns}:${name}`) + blockNames.push(`${ns}:${name}`) } - this.nbt.value.CanDestroy = nbt.list(nbt.string(blocks)) + this.nbt.value.CanDestroy = nbt.list(nbt.string(blockNames)) } get durabilityUsed () { @@ -319,14 +324,17 @@ function loader (registryOrVersion) { if (registry.supportFeature('spawnEggsHaveSpawnedEntityInName')) { return this.name.replace('_spawn_egg', '') } + if (registry.supportFeature('spawnEggsUseInternalIdInNbt')) { return registry.entitiesArray.find((o) => o.internalId === this.metadata).name } + if (registry.supportFeature('spawnEggsUseEntityTagInNbt')) { const data = nbt.simplify(this.nbt) const entityName = data.EntityTag.id return entityName.replace('minecraft:', '') } + throw new Error("Don't know how to get spawn egg mob name for this mc version") } } diff --git a/test/basic.test.js b/test/basic.test.js index 930ad92..7e6e125 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -13,7 +13,7 @@ describe('test based on examples', () => { }) it('use .toNotch', () => { - expect(Item.toNotch(ironShovelItem)).toStrictEqual({ blockId: 256, itemCount: 1, itemDamage: 0 }) + expect(Item.toNotch(ironShovelItem)).toStrictEqual({ blockId: 256, itemCount: 1, itemDamage: 0, nbtData: undefined }) }) it('use .fromNotch', () => { From e3c384d87bf42ec1f3834f577a75dd19dfcff98a Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 19 Jul 2023 14:13:54 +0200 Subject: [PATCH 47/50] Anvil is undefined if registry type is bedrock --- lib/anvil.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/anvil.js b/lib/anvil.js index c4f0cc9..e23cee3 100644 --- a/lib/anvil.js +++ b/lib/anvil.js @@ -1,4 +1,7 @@ function loader (registry, Item) { + // TODO: anvil support for bedrock + if (registry.type === 'bedrock') return undefined + function combine (itemOne, itemTwo, creative, renamedName) { const rename = typeof renamedName === 'string' const data = { From 4eae3bf715ad0eaae6f7b05272af11634a368808 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 19 Jul 2023 15:03:57 +0200 Subject: [PATCH 48/50] change blocksCanPlaceOn/Destroy --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bcd8391..ac58076 100644 --- a/index.js +++ b/index.js @@ -249,7 +249,7 @@ function loader (registryOrVersion) { get blocksCanPlaceOn () { const blockNames = this?.nbt?.value?.CanPlaceOn?.value?.value ?? [] - return blockNames.map(name => [name, registry.blocksByName[name.replace('minecraft:', '')]]) + return blockNames.map(name => [name]) } set blocksCanPlaceOn (newBlocks) { @@ -274,7 +274,7 @@ function loader (registryOrVersion) { get blocksCanDestroy () { const blockNames = this?.nbt?.value?.CanDestroy?.value?.value ?? [] - return blockNames.map(name => [name, registry.blocksByName[name.replace('minecraft:', '')]]) + return blockNames.map(name => [name]) } set blocksCanDestroy (newBlocks) { From 60ec7229a2ef0c74c9b3576605f187e3b7082be2 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 19 Jul 2023 15:05:10 +0200 Subject: [PATCH 49/50] update types and docs --- README.md | 4 ++-- index.d.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 959b72a..da33f8b 100644 --- a/README.md +++ b/README.md @@ -98,11 +98,11 @@ Returns an array of enchants on the Item with their name and level Updates the Item's NBT enchantments based on assigned array -#### get item.blocksCanPlaceOn(): [name, Block][] +#### get item.blocksCanPlaceOn(): [name][] #### set item.blocksCanPlaceOn(blockNames: string[]) In adventure mode, the list of block names (as strings) that this Item can be placed on -#### get item.blocksCanDestroy(): [name, Block][] +#### get item.blocksCanDestroy(): [name][] #### set item.blocksCanDestroy(blockNames: string[]) In adventure mode, the list of block names (as strings) that this Item can be used to break diff --git a/index.d.ts b/index.d.ts index 0268c57..6aa1f1d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -19,9 +19,9 @@ declare class Item { durabilityUsed: number; get enchants(): { name: string; lvl: number }[]; set enchants(enchantments: { name: string; lvl: number }[]); - get blocksCanPlaceOn(): [string, Block][]; + get blocksCanPlaceOn(): [string][]; set blocksCanPlaceOn(blockNames: string[]); - get blocksCanDestroy(): [string, Block][]; + get blocksCanDestroy(): [string][]; set blocksCanDestroy(blockNames: string[]); repairCost: number; customName: string | null; From 916a7fa89bf6b1efac122fade22f7db4aa81c363 Mon Sep 17 00:00:00 2001 From: CreeperG16 Date: Wed, 19 Jul 2023 18:03:49 +0200 Subject: [PATCH 50/50] Update index.d.ts --- index.d.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6aa1f1d..b57fe6a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,11 +1,10 @@ /// import { Tags, TagType } from 'prismarine-nbt' -import { Block } from "minecraft-data" export type ItemLike = Item | null -declare class Item { +export class Item { constructor(type: number, count: number, metadata?: number, nbt?: object, stackId?: number); type: number; slot: number;