diff --git a/doc/api.md b/doc/api.md index e3a92f6..1334b9f 100644 --- a/doc/api.md +++ b/doc/api.md @@ -10,6 +10,14 @@ blocks textures by name array of blocks textures +### blocksModels + +map of block variant => model + +### blockStates + +array of block states + ## Items ### items @@ -30,6 +38,10 @@ texture content by name array of texture content +### blockStateVariantsByStateId + +Returns an array of block model variants mapped by block state ID, lookup with .blocksModels field + ## version ## directory diff --git a/index.js b/index.js index 3564233..11e8d47 100644 --- a/index.js +++ b/index.js @@ -1,152 +1,156 @@ const mcDataToNode = require('./lib/loader') -const cache = {} // prevent reindexing when requiring multiple time the same version - -function getVersion (mcVersion) { - if (cache[mcVersion]) { return cache[mcVersion] } - const mcData = data[mcVersion] - if (mcData == null) { return null } - const nmcData = mcDataToNode(mcData, mcVersion) - cache[mcVersion] = nmcData - return nmcData -} - -function toMajor (version) { - const [a, b] = (version + '').split('.') - return a + '.' + b +const path = require('path') +const data = { + pc: { + '1.8.8': { + directory: path.join(__dirname, './minecraft-assets/data/1.8.8/'), + blocksTextures: require('./minecraft-assets/data/1.8.8/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.8.8/items_textures'), + textureContent: require('./minecraft-assets/data/1.8.8/texture_content'), + blocksStates: require('./minecraft-assets/data/1.8.8/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.8.8/blocks_models') + }, + 1.9: { + directory: path.join(__dirname, './minecraft-assets/data/1.9/'), + blocksTextures: require('./minecraft-assets/data/1.9/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.9/items_textures'), + textureContent: require('./minecraft-assets/data/1.9/texture_content'), + blocksStates: require('./minecraft-assets/data/1.9/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.9/blocks_models') + }, + '1.10': { + directory: path.join(__dirname, './minecraft-assets/data/1.10/'), + blocksTextures: require('./minecraft-assets/data/1.10/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.10/items_textures'), + textureContent: require('./minecraft-assets/data/1.10/texture_content'), + blocksStates: require('./minecraft-assets/data/1.10/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.10/blocks_models') + }, + '1.11.2': { + directory: path.join(__dirname, './minecraft-assets/data/1.11.2/'), + blocksTextures: require('./minecraft-assets/data/1.11.2/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.11.2/items_textures'), + textureContent: require('./minecraft-assets/data/1.11.2/texture_content'), + blocksStates: require('./minecraft-assets/data/1.11.2/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.11.2/blocks_models') + }, + 1.12: { + directory: path.join(__dirname, './minecraft-assets/data/1.12/'), + blocksTextures: require('./minecraft-assets/data/1.12/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.12/items_textures'), + textureContent: require('./minecraft-assets/data/1.12/texture_content'), + blocksStates: require('./minecraft-assets/data/1.12/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.12/blocks_models') + }, + 1.13: { + directory: path.join(__dirname, './minecraft-assets/data/1.13/'), + blocksTextures: require('./minecraft-assets/data/1.13/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.13/items_textures'), + textureContent: require('./minecraft-assets/data/1.13/texture_content'), + blocksStates: require('./minecraft-assets/data/1.13/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.13/blocks_models') + }, + '1.13.2': { + directory: path.join(__dirname, './minecraft-assets/data/1.13.2/'), + blocksTextures: require('./minecraft-assets/data/1.13.2/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.13.2/items_textures'), + textureContent: require('./minecraft-assets/data/1.13.2/texture_content'), + blocksStates: require('./minecraft-assets/data/1.13.2/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.13.2/blocks_models') + }, + '1.14.4': { + directory: path.join(__dirname, './minecraft-assets/data/1.14.4/'), + blocksTextures: require('./minecraft-assets/data/1.14.4/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.14.4/items_textures'), + textureContent: require('./minecraft-assets/data/1.14.4/texture_content'), + blocksStates: require('./minecraft-assets/data/1.14.4/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.14.4/blocks_models') + }, + '1.15.2': { + directory: path.join(__dirname, './minecraft-assets/data/1.15.2/'), + blocksTextures: require('./minecraft-assets/data/1.15.2/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.15.2/items_textures'), + textureContent: require('./minecraft-assets/data/1.15.2/texture_content'), + blocksStates: require('./minecraft-assets/data/1.15.2/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.15.2/blocks_models') + }, + '1.16.1': { + directory: path.join(__dirname, './minecraft-assets/data/1.16.1/'), + blocksTextures: require('./minecraft-assets/data/1.16.1/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.16.1/items_textures'), + textureContent: require('./minecraft-assets/data/1.16.1/texture_content'), + blocksStates: require('./minecraft-assets/data/1.16.1/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.16.1/blocks_models') + }, + '1.16.4': { + directory: path.join(__dirname, './minecraft-assets/data/1.16.4/'), + blocksTextures: require('./minecraft-assets/data/1.16.4/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.16.4/items_textures'), + textureContent: require('./minecraft-assets/data/1.16.4/texture_content'), + blocksStates: require('./minecraft-assets/data/1.16.4/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.16.4/blocks_models') + }, + '1.17.1': { + directory: path.join(__dirname, './minecraft-assets/data/1.17.1/'), + blocksTextures: require('./minecraft-assets/data/1.17.1/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.17.1/items_textures'), + textureContent: require('./minecraft-assets/data/1.17.1/texture_content'), + blocksStates: require('./minecraft-assets/data/1.17.1/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.17.1/blocks_models') + }, + '1.18.1': { + directory: path.join(__dirname, './minecraft-assets/data/1.18.1/'), + blocksTextures: require('./minecraft-assets/data/1.18.1/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.18.1/items_textures'), + textureContent: require('./minecraft-assets/data/1.18.1/texture_content'), + blocksStates: require('./minecraft-assets/data/1.18.1/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.18.1/blocks_models') + }, + '1.19.1': { + directory: path.join(__dirname, './minecraft-assets/data/1.19.1/'), + blocksTextures: require('./minecraft-assets/data/1.19.1/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.19.1/items_textures'), + textureContent: require('./minecraft-assets/data/1.19.1/texture_content'), + blocksStates: require('./minecraft-assets/data/1.19.1/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.19.1/blocks_models') + }, + '1.20.2': { + blocksTextures: require('./minecraft-assets/data/1.20.2/blocks_textures'), + itemsTextures: require('./minecraft-assets/data/1.20.2/items_textures'), + textureContent: require('./minecraft-assets/data/1.20.2/texture_content'), + blocksStates: require('./minecraft-assets/data/1.20.2/blocks_states'), + blocksModels: require('./minecraft-assets/data/1.20.2/blocks_models') + } + } } -function minor (version) { - const [, , c] = (version + '.0').split('.') - return parseInt(c, 10) -} +Object.assign(data, { + bedrock: { + '1.19.1': data.pc['1.19.1'], + '1.20.0': data.pc['1.20.2'] + } +}) -module.exports = function (mcVersion) { - // Check exact version first - let assets = getVersion(mcVersion) - if (assets) { return assets } - // If not found, resort to the last of major - assets = getVersion(lastOfMajor[toMajor(mcVersion)]) - return assets -} +// Get {'1.18': ['1.18', '1.18.1', ...]} from ['1.18', '1.18.1', ...] +const reduce = (what) => what.reduce((acc, cur) => { + const major = cur.split('.').slice(0, 2).join('.') + const arr = acc[major] = acc[major] || [] + arr.push(cur) + return acc +}, {}) -const data = { - '1.8.8': { - blocksTextures: require('./minecraft-assets/data/1.8.8/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.8.8/items_textures'), - textureContent: require('./minecraft-assets/data/1.8.8/texture_content'), - blocksStates: require('./minecraft-assets/data/1.8.8/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.8.8/blocks_models') - }, - 1.9: { - blocksTextures: require('./minecraft-assets/data/1.9/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.9/items_textures'), - textureContent: require('./minecraft-assets/data/1.9/texture_content'), - blocksStates: require('./minecraft-assets/data/1.9/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.9/blocks_models') - }, - '1.10': { - blocksTextures: require('./minecraft-assets/data/1.10/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.10/items_textures'), - textureContent: require('./minecraft-assets/data/1.10/texture_content'), - blocksStates: require('./minecraft-assets/data/1.10/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.10/blocks_models') - }, - '1.11.2': { - blocksTextures: require('./minecraft-assets/data/1.11.2/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.11.2/items_textures'), - textureContent: require('./minecraft-assets/data/1.11.2/texture_content'), - blocksStates: require('./minecraft-assets/data/1.11.2/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.11.2/blocks_models') - }, - 1.12: { - blocksTextures: require('./minecraft-assets/data/1.12/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.12/items_textures'), - textureContent: require('./minecraft-assets/data/1.12/texture_content'), - blocksStates: require('./minecraft-assets/data/1.12/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.12/blocks_models') - }, - 1.13: { - blocksTextures: require('./minecraft-assets/data/1.13/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.13/items_textures'), - textureContent: require('./minecraft-assets/data/1.13/texture_content'), - blocksStates: require('./minecraft-assets/data/1.13/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.13/blocks_models') - }, - '1.13.2': { - blocksTextures: require('./minecraft-assets/data/1.13.2/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.13.2/items_textures'), - textureContent: require('./minecraft-assets/data/1.13.2/texture_content'), - blocksStates: require('./minecraft-assets/data/1.13.2/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.13.2/blocks_models') - }, - '1.14.4': { - blocksTextures: require('./minecraft-assets/data/1.14.4/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.14.4/items_textures'), - textureContent: require('./minecraft-assets/data/1.14.4/texture_content'), - blocksStates: require('./minecraft-assets/data/1.14.4/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.14.4/blocks_models') - }, - '1.15.2': { - blocksTextures: require('./minecraft-assets/data/1.15.2/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.15.2/items_textures'), - textureContent: require('./minecraft-assets/data/1.15.2/texture_content'), - blocksStates: require('./minecraft-assets/data/1.15.2/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.15.2/blocks_models') - }, - '1.16.1': { - blocksTextures: require('./minecraft-assets/data/1.16.1/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.16.1/items_textures'), - textureContent: require('./minecraft-assets/data/1.16.1/texture_content'), - blocksStates: require('./minecraft-assets/data/1.16.1/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.16.1/blocks_models') - }, - '1.16.4': { - blocksTextures: require('./minecraft-assets/data/1.16.4/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.16.4/items_textures'), - textureContent: require('./minecraft-assets/data/1.16.4/texture_content'), - blocksStates: require('./minecraft-assets/data/1.16.4/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.16.4/blocks_models') - }, - '1.17.1': { - blocksTextures: require('./minecraft-assets/data/1.17.1/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.17.1/items_textures'), - textureContent: require('./minecraft-assets/data/1.17.1/texture_content'), - blocksStates: require('./minecraft-assets/data/1.17.1/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.17.1/blocks_models') - }, - '1.18.1': { - blocksTextures: require('./minecraft-assets/data/1.18.1/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.18.1/items_textures'), - textureContent: require('./minecraft-assets/data/1.18.1/texture_content'), - blocksStates: require('./minecraft-assets/data/1.18.1/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.18.1/blocks_models') - }, - '1.19.1': { - blocksTextures: require('./minecraft-assets/data/1.19.1/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.19.1/items_textures'), - textureContent: require('./minecraft-assets/data/1.19.1/texture_content'), - blocksStates: require('./minecraft-assets/data/1.19.1/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.19.1/blocks_models') - }, - '1.20.2': { - blocksTextures: require('./minecraft-assets/data/1.20.2/blocks_textures'), - itemsTextures: require('./minecraft-assets/data/1.20.2/items_textures'), - textureContent: require('./minecraft-assets/data/1.20.2/texture_content'), - blocksStates: require('./minecraft-assets/data/1.20.2/blocks_states'), - blocksModels: require('./minecraft-assets/data/1.20.2/blocks_models') - } -} +const cache = { pc: {}, bedrock: {} } // prevent reindexing when requiring multiple time the same version +const byMajor = { pc: reduce(Object.keys(data.pc)), bedrock: reduce(Object.keys(data.bedrock)) } +const lastOfMajor = (type, major) => byMajor[type][major][byMajor[type][major].length - 1] -module.exports.versions = Object.keys(data) +module.exports = function (registry) { + if (typeof registry === 'string') registry = require('prismarine-registry')(registry) + const v = registry.version + if (cache[v.type][v.minecraftVersion]) return cache[v.type][v.minecraftVersion] -const lastOfMajor = {} -for (const version in data) { - const major = toMajor(version) - if (lastOfMajor[major]) { - if (minor(lastOfMajor[major]) < minor(version)) { - lastOfMajor[major] = version - } - } else { - lastOfMajor[major] = version - } + // Check exact version first, else check the last minor version of the major + const assets = data[v.type][v.minecraftVersion] || data[v.type][lastOfMajor(v.type, v.majorVersion)] + const updated = cache[v.type][v.minecraftVersion] = mcDataToNode(assets, registry) + return updated } +module.exports.versions = { pc: Object.keys(data.pc), bedrock: Object.keys(data.bedrock) } diff --git a/lib/indexer.js b/lib/indexer.js index a2432a1..3a08ee6 100644 --- a/lib/indexer.js +++ b/lib/indexer.js @@ -1,3 +1,5 @@ +const mcData = require('minecraft-data') + module.exports.buildIndexFromArray = function (array, fieldToIndex) { if (array === undefined) { return undefined } return array.reduce(function (index, element) { @@ -5,3 +7,117 @@ module.exports.buildIndexFromArray = function (array, fieldToIndex) { return index }, {}) } + +function parseProperties (properties) { + if (typeof properties === 'object') { return properties } + + const json = {} + for (const prop of properties.split(',')) { + const [key, value] = prop.split('=') + json[key] = value + } + return json +} + +function matchProperties (block, properties) { + if (!properties) { return true } + + properties = parseProperties(properties) + const blockProps = block.getProperties() + for (const prop in blockProps) { + if (properties[prop] !== undefined && (blockProps[prop] + '') !== properties[prop]) { + return false + } + } + return true +} + +function getModelVariants (block, blockStates) { + const state = blockStates[block.name] + if (!state) return [] + if (state.variants) { + for (const [properties, variant] of Object.entries(state.variants)) { + if (!matchProperties(block, properties)) continue + if (variant instanceof Array) return [variant[0]] + return [variant] + } + } + if (state.multipart) { + const parts = state.multipart.filter(multipart => matchProperties(block, multipart.when)) + let variants = [] + for (const part of parts) { + if (part.apply instanceof Array) { + variants = [...variants, ...part.apply] + } else { + variants = [...variants, part.apply] + } + } + + return variants + } + + return [] +} + +// This function uses the minecraft-data blockMappings.json to translate the pc blockStates.json +// to bedrock block states. It also handles the special cases of stairs (but not snow layers/waterlogging). +module.exports.buildBedrockBlockStatesArray = function (registry, pcAssetBlockStates) { + const blockStateVariantsByStateId = {} + const blockStates = registry.blockStates + // First make a mapping of pe -> pc blocks from the block mapping schema + const pe = {} + const keyFromStates = states => Object.entries(states).map(entry => entry[0] + '=' + (entry[1].value ?? entry[1])).join(',') + for (const mapping of registry.blockMappings) { + pe[mapping.pe.name] = pe[mapping.pe.name] || {} + pe[mapping.pe.name][keyFromStates(mapping.pe.states)] ??= mapping.pc + } + // Then iterate over all the bedrock blocks and store the ModelVariants for each state ID + for (let stateId = 0; stateId < blockStates.length; stateId++) { + const blockState = blockStates[stateId] + const mapping = pe[blockState.name][keyFromStates(blockState.states)] + let variants + function getProperties () { + const states = { ...mapping.states } + // Stairs need special handling + if (states.shape) states.shape = 'straight' + return states + } + if (mapping) { + variants = getModelVariants({ name: mapping.name, getProperties }, pcAssetBlockStates) + } else { + const fallback = Object.values(pe[blockState.name])[0] + if (fallback) { + variants = getModelVariants({ name: fallback.name, getProperties }, pcAssetBlockStates) + } + } + blockStateVariantsByStateId[stateId] = variants + } + return blockStateVariantsByStateId +} + +module.exports.buildPCBlockStatesArray = function (registry, blockStates) { + const Block = require('prismarine-block')(registry) + const blockStateVariantsByStateId = {} + if (registry.supportFeature('usesBlockStates')) { + const minStateId = 0 + let maxStateId = 0 + for (const block of registry.blocksArray) { + maxStateId = Math.max(maxStateId, block.maxStateId) + if (isNaN(maxStateId)) throw new Error('maxStateId is NaN') + } + for (let i = minStateId; i <= maxStateId; i++) { + const block = Block.fromStateId(i, 0) + const variants = getModelVariants(block, blockStates) + blockStateVariantsByStateId[i] = variants + } + } else { + const states = Object.keys(mcData.legacy.pc.blocks).map(k => k.split(':')) + for (const [type, meta] of states) { + const stateId = type << 4 | meta + const block = Block.fromStateId(stateId, 0) + const variants = getModelVariants(block, blockStates) + blockStateVariantsByStateId[block.stateId] = variants + } + } + return blockStateVariantsByStateId +} diff --git a/lib/indexes.js b/lib/indexes.js index a36df15..1da4538 100644 --- a/lib/indexes.js +++ b/lib/indexes.js @@ -1,9 +1,12 @@ const indexer = require('./indexer.js') -module.exports = function (mcData) { +module.exports = function (mcAssets, registry) { return { - blocksByName: indexer.buildIndexFromArray(mcData.blocksTextures, 'name'), - itemsByName: indexer.buildIndexFromArray(mcData.itemsTextures, 'name'), - textureContentByName: indexer.buildIndexFromArray(mcData.textureContent, 'name') + blocksByName: indexer.buildIndexFromArray(mcAssets.blocksTextures, 'name'), + itemsByName: indexer.buildIndexFromArray(mcAssets.itemsTextures, 'name'), + textureContentByName: indexer.buildIndexFromArray(mcAssets.textureContent, 'name'), + blockStateVariantsByStateId: registry.type === 'bedrock' + ? indexer.buildBedrockBlockStatesArray(registry, mcAssets.blocksStates) + : indexer.buildPCBlockStatesArray(registry, mcAssets.blocksStates) } } diff --git a/lib/loader.js b/lib/loader.js index ac3f354..66e5928 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -3,8 +3,8 @@ const path = require('path') module.exports = mcDataToNode -function mcDataToNode (mcData, mcVersion) { - const indexes = require('./indexes.js')(mcData) +function mcDataToNode (mcData, registry) { + const indexes = require('./indexes.js')(mcData, registry) function findItemOrBlockByName (name) { const item = indexes.itemsByName[name] if (item !== undefined) return item @@ -25,16 +25,17 @@ function mcDataToNode (mcData, mcVersion) { blocksStates: mcData.blocksStates, blocksModels: mcData.blocksModels, - directory: path.join(__dirname, '/../minecraft-assets/data/', mcVersion, '/'), - version: mcVersion, + blockStateVariantsByStateId: indexes.blockStateVariantsByStateId, + version: registry.version, - findItemOrBlockByName: findItemOrBlockByName, - getTexture: getTexture, + directory: mcData.directory, + findItemOrBlockByName, + getTexture, getImageContent: function (name) { const texture = getTexture(name) if (texture == null) { return null } - return 'data:image/png;base64,' + fs.readFileSync(path.join(__dirname, '/../minecraft-assets/data/', mcVersion, '/', texture, '.png'), 'base64') + return 'data:image/png;base64,' + fs.readFileSync(path.join(mcData.directory, texture, '.png'), 'base64') } } } diff --git a/package.json b/package.json index 2eae835..d8de97d 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,9 @@ "main": "index.js", "tonicExampleFilename": "example.js", "scripts": { - "test": "npm run lint", + "test": "npm run lint && mocha --bail --exit", "lint": "standard", - "fix": "standard --fix", - "prepare": "npm install require-self && require-self" + "fix": "standard --fix" }, "repository": { "type": "git", @@ -25,7 +24,12 @@ }, "homepage": "https://github.com/rom1504/node-minecraft-assets#readme", "devDependencies": { - "require-self": "^0.2.3", + "minecraft-assets": "file:.", + "mocha": "^9.2.1", "standard": "^17.0.0" + }, + "dependencies": { + "prismarine-block": "^1.16.3", + "prismarine-registry": "^1.1.0" } } diff --git a/test/api.js b/test/api.js new file mode 100644 index 0000000..762bbbe --- /dev/null +++ b/test/api.js @@ -0,0 +1,16 @@ +/* eslint-env mocha */ +const assert = require('assert') +const versions = ['bedrock_1.19.1', '1.8', '1.9', '1.10', '1.11', '1.12', '1.13.2', '1.14.4', '1.15.2', '1.16.1', '1.17', '1.18'] + +describe('api works', function () { + for (const version of versions) { + it('on ' + version, function () { + const registry = require('prismarine-registry')(version) + const mcAssets = require('minecraft-assets')(registry) + + assert(Object.values(mcAssets.blockStateVariantsByStateId).length > 0) + + console.log('Read', Object.values(mcAssets.blockStateVariantsByStateId).length, 'blockStateVariants') + }) + } +})