refactor: cleanup texture atlas generators: make typed to gain confidence!
This commit is contained in:
parent
bff4f8d396
commit
d30b00c507
9 changed files with 328 additions and 204 deletions
|
|
@ -8,7 +8,7 @@
|
|||
"pretest": "npm run lint",
|
||||
"lint": "standard",
|
||||
"fix": "standard --fix",
|
||||
"postinstall": "node viewer/generateTextures.js && node buildWorker.mjs"
|
||||
"postinstall": "tsx viewer/prepare/generateTextures.ts && node buildWorker.mjs"
|
||||
},
|
||||
"author": "PrismarineJS",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
const path = require('path')
|
||||
const { makeTextureAtlas } = require('./lib/atlas')
|
||||
const { prepareBlocksStates } = require('./lib/modelsBuilder')
|
||||
const mcAssets = require('minecraft-assets')
|
||||
const fs = require('fs-extra')
|
||||
|
||||
const texturesPath = path.resolve(__dirname, '../public/textures')
|
||||
if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) {
|
||||
console.log('textures folder already exists, skipping...')
|
||||
process.exit(0)
|
||||
}
|
||||
fs.mkdirSync(texturesPath, { recursive: true })
|
||||
|
||||
const blockStatesPath = path.resolve(__dirname, '../public/blocksStates')
|
||||
fs.mkdirSync(blockStatesPath, { recursive: true })
|
||||
|
||||
for (const version of mcAssets.versions) {
|
||||
const assets = mcAssets(version)
|
||||
const atlas = makeTextureAtlas(assets)
|
||||
const out = fs.createWriteStream(path.resolve(texturesPath, version + '.png'))
|
||||
const stream = atlas.canvas.pngStream()
|
||||
stream.on('data', (chunk) => out.write(chunk))
|
||||
stream.on('end', () => console.log('Generated textures/' + version + '.png'))
|
||||
|
||||
const blocksStates = JSON.stringify(prepareBlocksStates(assets, atlas))
|
||||
fs.writeFileSync(path.resolve(blockStatesPath, version + '.json'), blocksStates)
|
||||
|
||||
fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true })
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.resolve(__dirname, '../public/supportedVersions.json'), '[' + mcAssets.versions.map(v => `"${v}"`).toString() + ']')
|
||||
|
|
@ -5,26 +5,26 @@ const Entity = require('./entity/Entity')
|
|||
const { dispose3 } = require('./dispose')
|
||||
|
||||
function getUsernameTexture(username, { fontFamily = 'sans-serif' }) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
const fontSize = 50;
|
||||
const padding = 5
|
||||
ctx.font = `${fontSize}px ${fontFamily}`;
|
||||
const fontSize = 50
|
||||
const padding = 5
|
||||
ctx.font = `${fontSize}px ${fontFamily}`
|
||||
|
||||
const textWidth = ctx.measureText(username).width + padding * 2;
|
||||
const textWidth = ctx.measureText(username).width + padding * 2
|
||||
|
||||
canvas.width = textWidth;
|
||||
canvas.height = fontSize + padding * 2;
|
||||
canvas.width = textWidth
|
||||
canvas.height = fontSize + padding * 2
|
||||
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)'
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
ctx.font = `${fontSize}px ${fontFamily}`;
|
||||
ctx.fillStyle = 'white'
|
||||
ctx.fillText(username, padding, fontSize);
|
||||
ctx.font = `${fontSize}px ${fontFamily}`
|
||||
ctx.fillStyle = 'white'
|
||||
ctx.fillText(username, padding, fontSize)
|
||||
|
||||
return canvas;
|
||||
return canvas
|
||||
}
|
||||
|
||||
function getEntityMesh (entity, scene, options) {
|
||||
|
|
@ -33,7 +33,7 @@ function getEntityMesh (entity, scene, options) {
|
|||
const e = new Entity('1.16.4', entity.name, scene)
|
||||
|
||||
if (entity.username !== undefined) {
|
||||
const canvas = getUsernameTexture(entity.username, options);
|
||||
const canvas = getUsernameTexture(entity.username, options)
|
||||
const tex = new THREE.Texture(canvas)
|
||||
tex.needsUpdate = true
|
||||
const spriteMat = new THREE.SpriteMaterial({ map: tex })
|
||||
|
|
@ -51,7 +51,7 @@ function getEntityMesh (entity, scene, options) {
|
|||
|
||||
const geometry = new THREE.BoxGeometry(entity.width, entity.height, entity.width)
|
||||
geometry.translate(0, entity.height / 2, 0)
|
||||
const material = new THREE.MeshBasicMaterial({ color: 0xff00ff })
|
||||
const material = new THREE.MeshBasicMaterial({ color: 0xff_00_ff })
|
||||
const cube = new THREE.Mesh(geometry, material)
|
||||
return cube
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ function matchProperties (block, properties) {
|
|||
|
||||
function getModelVariants (block) {
|
||||
// air, cave_air, void_air and so on...
|
||||
if (block.name.endsWith('air')) return []
|
||||
if (block.name === 'air' || block.name.endsWith('_air')) return []
|
||||
const state = blockStates[block.name] ?? blockStates.missing_texture
|
||||
if (!state) return []
|
||||
if (state.variants) {
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
function cleanupBlockName (name) {
|
||||
if (name.startsWith('block') || name.startsWith('minecraft:block')) return name.split('/')[1]
|
||||
return name
|
||||
}
|
||||
|
||||
function getModel (name, blocksModels) {
|
||||
name = cleanupBlockName(name)
|
||||
const data = blocksModels[name]
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
|
||||
let model = { textures: {}, elements: [], ao: true }
|
||||
|
||||
for (const axis in ['x', 'y', 'z']) {
|
||||
if (axis in data) {
|
||||
model[axis] = data[axis]
|
||||
}
|
||||
}
|
||||
|
||||
if (data.parent) {
|
||||
model = getModel(data.parent, blocksModels)
|
||||
}
|
||||
if (data.textures) {
|
||||
Object.assign(model.textures, JSON.parse(JSON.stringify(data.textures)))
|
||||
}
|
||||
if (data.elements) {
|
||||
model.elements = JSON.parse(JSON.stringify(data.elements))
|
||||
}
|
||||
if (data.ambientocclusion !== undefined) {
|
||||
model.ao = data.ambientocclusion
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
function prepareModel (model, texturesJson) {
|
||||
// resolve texture names eg west: #all -> blocks/stone
|
||||
for (const tex in model.textures) {
|
||||
let root = model.textures[tex]
|
||||
while (root.charAt(0) === '#') {
|
||||
root = model.textures[root.substr(1)]
|
||||
}
|
||||
model.textures[tex] = root
|
||||
}
|
||||
for (const tex in model.textures) {
|
||||
let name = model.textures[tex]
|
||||
name = cleanupBlockName(name)
|
||||
model.textures[tex] = texturesJson[name]
|
||||
}
|
||||
for (const elem of model.elements) {
|
||||
for (const sideName of Object.keys(elem.faces)) {
|
||||
const face = elem.faces[sideName]
|
||||
|
||||
if (face.texture.charAt(0) === '#') {
|
||||
face.texture = JSON.parse(JSON.stringify(model.textures[face.texture.substr(1)]))
|
||||
} else {
|
||||
let name = face.texture
|
||||
name = cleanupBlockName(name)
|
||||
face.texture = JSON.parse(JSON.stringify(texturesJson[name]))
|
||||
}
|
||||
|
||||
let uv = face.uv
|
||||
if (!uv) {
|
||||
const _from = elem.from
|
||||
const _to = elem.to
|
||||
|
||||
// taken from https://github.com/DragonDev1906/Minecraft-Overviewer/
|
||||
uv = {
|
||||
north: [_to[0], 16 - _to[1], _from[0], 16 - _from[1]],
|
||||
east: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]],
|
||||
south: [_from[0], 16 - _to[1], _to[0], 16 - _from[1]],
|
||||
west: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]],
|
||||
up: [_from[0], _from[2], _to[0], _to[2]],
|
||||
down: [_to[0], _from[2], _from[0], _to[2]]
|
||||
}[sideName]
|
||||
}
|
||||
|
||||
const su = (uv[2] - uv[0]) * face.texture.su / 16
|
||||
const sv = (uv[3] - uv[1]) * face.texture.sv / 16
|
||||
face.texture.bu = face.texture.u + 0.5 * face.texture.su
|
||||
face.texture.bv = face.texture.v + 0.5 * face.texture.sv
|
||||
face.texture.u += uv[0] * face.texture.su / 16
|
||||
face.texture.v += uv[1] * face.texture.sv / 16
|
||||
face.texture.su = su
|
||||
face.texture.sv = sv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveModel (name, blocksModels, texturesJson) {
|
||||
const model = getModel(name, blocksModels)
|
||||
prepareModel(model, texturesJson.textures)
|
||||
return model
|
||||
}
|
||||
|
||||
function prepareBlocksStates (mcAssets, atlas) {
|
||||
const blocksStates = mcAssets.blocksStates
|
||||
mcAssets.blocksStates["missing_texture"] = {
|
||||
"variants": {
|
||||
"normal": {
|
||||
"model": "missing_texture"
|
||||
}
|
||||
}
|
||||
},
|
||||
mcAssets.blocksModels["missing_texture"] = {
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": "blocks/missing_texture"
|
||||
}
|
||||
}
|
||||
for (const block of Object.values(blocksStates)) {
|
||||
if (!block) continue
|
||||
if (block.variants) {
|
||||
for (const variant of Object.values(block.variants)) {
|
||||
if (variant instanceof Array) {
|
||||
for (const v of variant) {
|
||||
v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json)
|
||||
}
|
||||
} else {
|
||||
variant.model = resolveModel(variant.model, mcAssets.blocksModels, atlas.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block.multipart) {
|
||||
for (const variant of block.multipart) {
|
||||
if (variant.apply instanceof Array) {
|
||||
for (const v of variant.apply) {
|
||||
v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json)
|
||||
}
|
||||
} else {
|
||||
variant.apply.model = resolveModel(variant.apply.model, mcAssets.blocksModels, atlas.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocksStates
|
||||
}
|
||||
|
||||
module.exports = { prepareBlocksStates }
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
const fs = require('fs')
|
||||
const { Canvas, Image } = require('canvas')
|
||||
const path = require('path')
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { Canvas, Image } from 'canvas'
|
||||
|
||||
function nextPowerOfTwo (n) {
|
||||
if (n === 0) return 1
|
||||
|
|
@ -13,44 +13,50 @@ function nextPowerOfTwo (n) {
|
|||
return n + 1
|
||||
}
|
||||
|
||||
const localTextures = ['missing_texture.png']
|
||||
|
||||
function readTexture (basePath, name) {
|
||||
if (name === 'missing_texture.png') {
|
||||
if (localTextures.includes(name)) {
|
||||
// grab ./missing_texture.png
|
||||
basePath = __dirname
|
||||
}
|
||||
return fs.readFileSync(path.join(basePath, name), 'base64')
|
||||
}
|
||||
|
||||
function makeTextureAtlas (mcAssets) {
|
||||
export function makeTextureAtlas (mcAssets) {
|
||||
const blocksTexturePath = path.join(mcAssets.directory, '/blocks')
|
||||
const textureFiles = fs.readdirSync(blocksTexturePath).filter(file => file.endsWith('.png'))
|
||||
textureFiles.unshift('missing_texture.png')
|
||||
textureFiles.unshift(...localTextures)
|
||||
|
||||
const texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(textureFiles.length)))
|
||||
const tileSize = 16
|
||||
|
||||
const imgSize = texSize * tileSize
|
||||
const canvas = new Canvas(imgSize, imgSize, 'png')
|
||||
const canvas = new Canvas(imgSize, imgSize, 'png' as any)
|
||||
const g = canvas.getContext('2d')
|
||||
|
||||
const texturesIndex = {}
|
||||
|
||||
let offset = 0
|
||||
for (const i in textureFiles) {
|
||||
const x = (i % texSize) * tileSize
|
||||
const y = Math.floor(i / texSize) * tileSize
|
||||
const pos = +i + offset
|
||||
const x = (pos % texSize) * tileSize
|
||||
const y = Math.floor(pos / texSize) * tileSize
|
||||
|
||||
const name = textureFiles[i].split('.')[0]
|
||||
|
||||
texturesIndex[name] = { u: x / imgSize, v: y / imgSize, su: tileSize / imgSize, sv: tileSize / imgSize }
|
||||
|
||||
const img = new Image()
|
||||
img.src = 'data:image/png;base64,' + readTexture(blocksTexturePath, textureFiles[i])
|
||||
g.drawImage(img, 0, 0, 16, 16, x, y, 16, 16)
|
||||
const needsMoreWidth = img.width > tileSize
|
||||
if (needsMoreWidth) {
|
||||
console.log('needs more', name, img.width, img.height)
|
||||
offset++
|
||||
}
|
||||
const renderWidth = needsMoreWidth ? tileSize * 2 : tileSize
|
||||
g.drawImage(img, 0, 0, img.width, img.height, x, y, renderWidth, tileSize)
|
||||
|
||||
texturesIndex[name] = { u: x / imgSize, v: y / imgSize, su: renderWidth / imgSize, sv: tileSize / imgSize }
|
||||
}
|
||||
|
||||
return { image: canvas.toBuffer(), canvas, json: { size: tileSize / imgSize, textures: texturesIndex } }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
makeTextureAtlas
|
||||
}
|
||||
37
prismarine-viewer/viewer/prepare/generateTextures.ts
Normal file
37
prismarine-viewer/viewer/prepare/generateTextures.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import path from 'path'
|
||||
import { makeTextureAtlas } from './atlas'
|
||||
import { McAssets, prepareBlocksStates } from './modelsBuilder'
|
||||
import mcAssets from 'minecraft-assets'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
const publicPath = path.resolve(__dirname, '../../public')
|
||||
|
||||
const texturesPath = path.join(publicPath, 'textures')
|
||||
if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) {
|
||||
console.log('textures folder already exists, skipping...')
|
||||
process.exit(0)
|
||||
}
|
||||
fs.mkdirSync(texturesPath, { recursive: true })
|
||||
|
||||
const blockStatesPath = path.join(publicPath, 'blocksStates')
|
||||
fs.mkdirSync(blockStatesPath, { recursive: true })
|
||||
|
||||
Promise.resolve().then(async () => {
|
||||
for (const version of mcAssets.versions) {
|
||||
const assets = mcAssets(version)
|
||||
// #region texture atlas
|
||||
const atlas = makeTextureAtlas(assets)
|
||||
const out = fs.createWriteStream(path.resolve(texturesPath, version + '.png'))
|
||||
const stream = (atlas.canvas as any).pngStream()
|
||||
stream.on('data', (chunk) => out.write(chunk))
|
||||
stream.on('end', () => console.log('Generated textures/' + version + '.png'))
|
||||
// #endregion
|
||||
|
||||
const blocksStates = JSON.stringify(prepareBlocksStates(assets, atlas))
|
||||
fs.writeFileSync(path.resolve(blockStatesPath, version + '.json'), blocksStates)
|
||||
|
||||
fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true })
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + mcAssets.versions.map(v => `"${v}"`).toString() + ']')
|
||||
})
|
||||
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
251
prismarine-viewer/viewer/prepare/modelsBuilder.ts
Normal file
251
prismarine-viewer/viewer/prepare/modelsBuilder.ts
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
type ModelBasic = {
|
||||
model: string
|
||||
x?: number
|
||||
y?: number
|
||||
uvlock?: boolean
|
||||
}
|
||||
|
||||
type BlockApplyModel = ModelBasic | (ModelBasic & { weight })[]
|
||||
|
||||
type BlockStateCondition = {
|
||||
[name: string]: string | number
|
||||
}
|
||||
|
||||
type BlockState = {
|
||||
variants?: {
|
||||
[name: string | ""]: BlockApplyModel
|
||||
}
|
||||
multipart?: {
|
||||
when: {
|
||||
[name: string]: string | number
|
||||
} & {
|
||||
OR?: BlockStateCondition[]
|
||||
}
|
||||
apply: BlockApplyModel
|
||||
}[]
|
||||
}
|
||||
|
||||
type BlockModel = {
|
||||
parent?: string
|
||||
textures?: {
|
||||
[name: string]: string
|
||||
}
|
||||
elements?: {
|
||||
from: number[]
|
||||
to: number[]
|
||||
faces: {
|
||||
[name: string]: {
|
||||
texture: string
|
||||
uv?: number[]
|
||||
cullface?: string
|
||||
}
|
||||
}
|
||||
}[]
|
||||
ambientocclusion?: boolean
|
||||
x?: number
|
||||
y?: number
|
||||
z?: number
|
||||
ao?: boolean
|
||||
}
|
||||
|
||||
export type McAssets = {
|
||||
blocksStates: {
|
||||
[x: string]: BlockState
|
||||
}
|
||||
blocksModels: {
|
||||
[x: string]: BlockModel
|
||||
}
|
||||
directory: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export type BlockStatesOutput = {
|
||||
// states: {
|
||||
[blockName: string]: ResolvedModel
|
||||
// }
|
||||
// defaults: {
|
||||
// su: number
|
||||
// sv: number
|
||||
// }
|
||||
}
|
||||
|
||||
export type ResolvedModel = {
|
||||
textures: {
|
||||
[name: string]: {
|
||||
u: number
|
||||
v: number
|
||||
su: number
|
||||
sv: number
|
||||
bu: number
|
||||
bv: number
|
||||
}
|
||||
}
|
||||
elements: {
|
||||
from: number[]
|
||||
to: number[]
|
||||
faces: {
|
||||
[name: string]: {
|
||||
texture: {
|
||||
u: number
|
||||
v: number
|
||||
su: number
|
||||
sv: number
|
||||
bu: number
|
||||
bv: number
|
||||
}
|
||||
}
|
||||
}
|
||||
}[]
|
||||
ao: boolean
|
||||
x?: number
|
||||
y?: number
|
||||
z?: number
|
||||
}
|
||||
|
||||
export const addBlockAllModel = (mcAssets: McAssets, name: string, texture = name) => {
|
||||
mcAssets.blocksStates[name] = {
|
||||
"variants": {
|
||||
"": {
|
||||
"model": name
|
||||
}
|
||||
}
|
||||
}
|
||||
mcAssets.blocksModels[name] = {
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": `blocks/${texture}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupBlockName (name: string) {
|
||||
if (name.startsWith('block') || name.startsWith('minecraft:block')) return name.split('/')[1]
|
||||
return name
|
||||
}
|
||||
|
||||
const objectAssignStrict = <T extends Record<string, any>>(target: T, source: Partial<T>) => Object.assign(target, source)
|
||||
|
||||
function getFinalModel (name: string, blocksModels: { [x: string]: BlockModel }) {
|
||||
name = cleanupBlockName(name)
|
||||
const input = blocksModels[name]
|
||||
if (!input) {
|
||||
return null
|
||||
}
|
||||
|
||||
let out: BlockModel | null = {
|
||||
textures: {},
|
||||
elements: [],
|
||||
ao: true,
|
||||
x: input.x,
|
||||
y: input.y,
|
||||
z: input.z,
|
||||
}
|
||||
|
||||
if (input.parent) {
|
||||
out = getFinalModel(input.parent, blocksModels)
|
||||
if (!out) return null
|
||||
}
|
||||
if (input.textures) {
|
||||
Object.assign(out.textures!, deepCopy(input.textures))
|
||||
}
|
||||
if (input.elements) out.elements = deepCopy(input.elements)
|
||||
if (input.ao !== undefined) out.ao = input.ao
|
||||
return out
|
||||
}
|
||||
|
||||
const deepCopy = (obj) => JSON.parse(JSON.stringify(obj))
|
||||
|
||||
function prepareModel (model: BlockModel, texturesJson) {
|
||||
const newModel = {}
|
||||
|
||||
const getFinalTexture = (originalBlockName) => {
|
||||
// texture name e.g. blocks/anvil_base
|
||||
const cleanBlockName = cleanupBlockName(originalBlockName);
|
||||
return {...texturesJson[cleanBlockName], __debugName: cleanBlockName}
|
||||
}
|
||||
|
||||
const finalTextures = []
|
||||
|
||||
// resolve texture names eg west: #all -> blocks/stone
|
||||
for (const side in model.textures) {
|
||||
let texture = model.textures[side]
|
||||
|
||||
while (texture.charAt(0) === '#') {
|
||||
texture = model.textures[texture.slice(1)]
|
||||
}
|
||||
|
||||
finalTextures[side] = getFinalTexture(texture)
|
||||
}
|
||||
|
||||
for (const elem of model.elements!) {
|
||||
for (const sideName of Object.keys(elem.faces)) {
|
||||
const face = elem.faces[sideName]
|
||||
|
||||
const finalTexture = deepCopy(
|
||||
face.texture.charAt(0) === '#'
|
||||
? finalTextures![face.texture.slice(1)]
|
||||
: getFinalTexture(face.texture)
|
||||
)
|
||||
|
||||
const _from = elem.from
|
||||
const _to = elem.to
|
||||
// taken from https://github.com/DragonDev1906/Minecraft-Overviewer/
|
||||
const uv = face.uv || {
|
||||
// default UVs
|
||||
// format: [u1, v1, u2, v2] (u = x, v = y)
|
||||
north: [_to[0], 16 - _to[1], _from[0], 16 - _from[1]],
|
||||
east: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]],
|
||||
south: [_from[0], 16 - _to[1], _to[0], 16 - _from[1]],
|
||||
west: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]],
|
||||
up: [_from[0], _from[2], _to[0], _to[2]],
|
||||
down: [_to[0], _from[2], _from[0], _to[2]]
|
||||
}[sideName]!
|
||||
|
||||
const su = (uv[2] - uv[0]) / 16 * finalTexture.su
|
||||
const sv = (uv[3] - uv[1]) / 16 * finalTexture.sv
|
||||
finalTexture.u += uv[0] / 16 * finalTexture.su
|
||||
finalTexture.v += uv[1] / 16 * finalTexture.sv
|
||||
finalTexture.su = su
|
||||
finalTexture.sv = sv
|
||||
face.texture = finalTexture
|
||||
}
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
function resolveModel (name, blocksModels, texturesJson) {
|
||||
const model = getFinalModel(name, blocksModels)
|
||||
return prepareModel(model, texturesJson.textures)
|
||||
}
|
||||
|
||||
export function prepareBlocksStates (mcAssets: McAssets, atlas: { json: any }) {
|
||||
addBlockAllModel(mcAssets, 'missing_texture')
|
||||
|
||||
const blocksStates = mcAssets.blocksStates
|
||||
for (const block of Object.values(blocksStates)) {
|
||||
if (!block) continue
|
||||
if (block.variants) {
|
||||
for (const variant of Object.values(block.variants)) {
|
||||
if (variant instanceof Array) {
|
||||
for (const v of variant) {
|
||||
v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any
|
||||
}
|
||||
} else {
|
||||
variant.model = resolveModel(variant.model, mcAssets.blocksModels, atlas.json) as any
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block.multipart) {
|
||||
for (const variant of block.multipart) {
|
||||
if (variant.apply instanceof Array) {
|
||||
for (const v of variant.apply) {
|
||||
v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any
|
||||
}
|
||||
} else {
|
||||
variant.apply.model = resolveModel(variant.apply.model, mcAssets.blocksModels, atlas.json) as any
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocksStates
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue