improvements
This commit is contained in:
+80
-29
@@ -1304,9 +1304,7 @@
|
||||
return width > 0 && height > 0 && width <= 8192 && height <= 8192 ? { width, height } : null;
|
||||
}
|
||||
|
||||
function tryLoadImportedActorTexture(json, geo, modelPath, actorIndex) {
|
||||
let io;
|
||||
try { io = desktopFiles(); } catch (_) { return; }
|
||||
function actorTextureCandidates(json, geo, modelPath) {
|
||||
const candidateIds = [];
|
||||
const addId = (id) => { if (importResourceId(id) && !candidateIds.includes(id)) candidateIds.push(id); };
|
||||
if (typeof json.afw_texture === 'string') addId(json.afw_texture);
|
||||
@@ -1323,6 +1321,25 @@
|
||||
addId(`minecraft:textures/entity/${entity}.png`);
|
||||
}
|
||||
}
|
||||
return candidateIds;
|
||||
}
|
||||
|
||||
function importTextureDimensions(bytes, metadata = null) {
|
||||
let dimensions = pngDimensions(bytes);
|
||||
if (!dimensions) return null;
|
||||
const animation = metadata?.animation;
|
||||
if (animation) {
|
||||
const width = validUvDimension(animation.width, dimensions.width);
|
||||
const height = validUvDimension(animation.height, width);
|
||||
if (width <= dimensions.width && height <= dimensions.height) dimensions = { width, height };
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
function tryLoadImportedActorTexture(json, geo, modelPath, actorIndex) {
|
||||
let io;
|
||||
try { io = desktopFiles(); } catch (_) { return; }
|
||||
const candidateIds = actorTextureCandidates(json, geo, modelPath);
|
||||
if (!candidateIds.length) return;
|
||||
const sourcePaths = [];
|
||||
try { sourcePaths.push(findImportPack(modelPath, io).root); } catch (_) { /* Standalone model. */ }
|
||||
@@ -1342,12 +1359,7 @@
|
||||
let dimensions = pngDimensions(bytes);
|
||||
if (!dimensions) continue;
|
||||
try {
|
||||
const animation = propJson(source, `${relative}.mcmeta`)?.animation;
|
||||
if (animation) {
|
||||
const width = validUvDimension(animation.width, dimensions.width);
|
||||
const height = validUvDimension(animation.height, width);
|
||||
if (width <= dimensions.width && height <= dimensions.height) dimensions = { width, height };
|
||||
}
|
||||
dimensions = importTextureDimensions(bytes, propJson(source, `${relative}.mcmeta`));
|
||||
} catch (_) { /* Keep the PNG dimensions when metadata is invalid. */ }
|
||||
const edit = { elements: Cube.all.filter((cube) => cubeBelongsToActor(cube, actorIndex)),
|
||||
textures: Texture.all.slice(), uv_mode: true, actor_uv_edit: true, actor_texture_edit: true };
|
||||
@@ -5020,22 +5032,53 @@
|
||||
}
|
||||
|
||||
function loadImportTextures(row, packs, io) {
|
||||
const ids = new Set(Object.values(row.json.afw_bone_textures || {}).filter((value) => typeof value === 'string'));
|
||||
if (typeof row.json.afw_texture === 'string') ids.add(row.json.afw_texture);
|
||||
else {
|
||||
const entity = importResourceId(row.entity);
|
||||
for (const resource of [`${entity.namespace}:textures/entity/${entity.resource}/${entity.resource}.png`,
|
||||
`${entity.namespace}:textures/entity/${entity.resource}.png`]) {
|
||||
if (findImportResource(packs, resource, '', '', io)) { row.defaultTexture = resource; ids.add(resource); break; }
|
||||
}
|
||||
}
|
||||
if (typeof row.json.afw_texture === 'string') row.defaultTexture = row.json.afw_texture;
|
||||
const candidates = actorTextureCandidates(row.json, row.geo, row.resolved.file);
|
||||
const ids = new Set([...candidates, ...Object.values(row.json.afw_bone_textures || {})
|
||||
.filter((value) => typeof value === 'string')]);
|
||||
row.textures = new Map();
|
||||
let cachedSources;
|
||||
let modelPack;
|
||||
try { modelPack = findImportPack(row.resolved.file, io); } catch (_) { /* Standalone model. */ }
|
||||
const searchPacks = modelPack && !packs.some((pack) => pack.root === modelPack.root)
|
||||
? [modelPack, ...packs] : packs;
|
||||
for (const resource of ids) {
|
||||
const id = resource.includes(':') ? resource : `minecraft:${resource}`;
|
||||
const texture = findImportResource(packs, id, '', '', io);
|
||||
if (texture) row.textures.set(resource, texture);
|
||||
const texture = findImportResource(searchPacks, id, '', '', io);
|
||||
if (texture) {
|
||||
let dimensions = null;
|
||||
try {
|
||||
if (io.fs.statSync(texture.file).size <= 4 * 1024 * 1024) {
|
||||
const bytes = io.fs.readFileSync(texture.file);
|
||||
let metadata = null;
|
||||
try { metadata = readImportJson(`${texture.file}.mcmeta`, io); } catch (_) { /* Static texture. */ }
|
||||
dimensions = importTextureDimensions(bytes, metadata);
|
||||
}
|
||||
} catch (_) { /* Let Blockbench report unreadable texture files. */ }
|
||||
row.textures.set(resource, { ...texture, dimensions });
|
||||
continue;
|
||||
}
|
||||
if (!cachedSources) {
|
||||
cachedSources = [];
|
||||
for (const entry of discoverPropSources(io)) {
|
||||
try { cachedSources.push(openPropSource(entry.file, io)); } catch (_) { /* Try another asset source. */ }
|
||||
}
|
||||
}
|
||||
const parsed = importResourceId(id);
|
||||
if (!parsed) continue;
|
||||
const relative = `assets/${parsed.namespace}/${parsed.resource}`;
|
||||
for (const source of cachedSources) {
|
||||
let bytes;
|
||||
try { bytes = source.read(relative); } catch (_) { continue; }
|
||||
if (!bytes || bytes.length > 4 * 1024 * 1024) continue;
|
||||
let dimensions = pngDimensions(bytes);
|
||||
if (!dimensions) continue;
|
||||
try { dimensions = importTextureDimensions(bytes, propJson(source, `${relative}.mcmeta`)); }
|
||||
catch (_) { /* Keep the PNG dimensions when metadata is invalid. */ }
|
||||
row.textures.set(resource, { bytes, relative, dimensions });
|
||||
break;
|
||||
}
|
||||
}
|
||||
row.defaultTexture = candidates.find((id) => row.textures.has(id));
|
||||
}
|
||||
|
||||
function commitAutomaticImport(plan) {
|
||||
@@ -5059,22 +5102,30 @@
|
||||
metadata[index] = plan.definition.actors[offset];
|
||||
importGeometryIntoCurrentProject(row.geo, index, false, false);
|
||||
for (const [name, resource] of row.textures) {
|
||||
if (!loadedTextures.has(resource.file)) {
|
||||
const texture = new Texture({ name, uv_width: row.geo.description?.texture_width || 64,
|
||||
uv_height: row.geo.description?.texture_height || 64 });
|
||||
const key = resource.file || `${resource.relative}:${name}`;
|
||||
if (!loadedTextures.has(key)) {
|
||||
const texture = new Texture({ name, uv_width: resource.dimensions?.width || row.geo.description?.texture_width || 64,
|
||||
uv_height: resource.dimensions?.height || row.geo.description?.texture_height || 64 });
|
||||
texture.keep_size = true;
|
||||
texture.load_callback = () => { if (Project?.uuid === projectId) scheduleActorTexturePreviewApply(); };
|
||||
texture.fromPath(resource.file);
|
||||
if (resource.file) texture.fromPath(resource.file);
|
||||
else texture.fromDataURL(`data:image/png;base64,${resource.bytes.toString('base64')}`);
|
||||
texture.name = name;
|
||||
if (resource.relative) texture.relative_path = resource.relative;
|
||||
texture.add(false);
|
||||
loadedTextures.set(resource.file, name);
|
||||
loadedTextures.set(key, name);
|
||||
}
|
||||
}
|
||||
if (row.textures.has(row.defaultTexture)) textures[index] = loadedTextures.get(row.textures.get(row.defaultTexture).file);
|
||||
const base = row.textures.get(row.defaultTexture);
|
||||
if (base) {
|
||||
textures[index] = loadedTextures.get(base.file || `${base.relative}:${row.defaultTexture}`);
|
||||
if (base.dimensions) normalizeActorUvs(index, base.dimensions.width, base.dimensions.height);
|
||||
}
|
||||
for (const [bone, textureName] of Object.entries(row.json.afw_bone_textures || {})) {
|
||||
const group = Group.all.find((candidate) => candidate.name === `actor${index}_${bone}`);
|
||||
if (group && row.textures.has(textureName)) overrides[group.uuid] = { uuid: group.uuid, name: group.name,
|
||||
texture: loadedTextures.get(row.textures.get(textureName).file) };
|
||||
const boneTexture = row.textures.get(textureName);
|
||||
if (group && boneTexture) overrides[group.uuid] = { uuid: group.uuid, name: group.name,
|
||||
texture: loadedTextures.get(boneTexture.file || `${boneTexture.relative}:${textureName}`) };
|
||||
}
|
||||
}
|
||||
setProjectActorNames(names);
|
||||
|
||||
Reference in New Issue
Block a user