import { access } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { createGameAssetIO, convertDocumentTexturesToKtx2 } from "./lib/ktx2.mjs"; const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const sourceRoot = path.join(repositoryRoot, "game_assets"); const sourceAssets = [ "models/claudecraft/chars/players/druid.glb", "models/claudecraft/chars/players/knight.glb", "models/claudecraft/chars/players/mage.glb", "models/claudecraft/chars/players/ranger.glb", "models/claudecraft/chars/players/rogue.glb", "models/claudecraft/weapons/adv_dagger.glb", "models/claudecraft/weapons/adv_druid_staff.glb", "models/claudecraft/weapons/adv_sword_1handed.glb", "models/claudecraft/weapons/adv_wand.glb", "models/claudecraft/weapons/crossbow_2handed.glb", "models/claudecraft/weapons/shield_badge.glb", "models/claudecraft/weapons/spellbook_open.glb", ]; function optimizedPath(sourcePath) { return sourcePath.replace(/\.glb$/, "-uastc.glb"); } function sortedNames(properties) { return properties.map((property) => property.getName()).sort(); } const io = await createGameAssetIO(); for (const relativePath of sourceAssets) { const inputPath = path.join(sourceRoot, relativePath); const outputRelativePath = optimizedPath(relativePath); const outputPath = path.join(sourceRoot, outputRelativePath); await access(inputPath); const document = await io.read(inputPath); const sourceRootProperties = document.getRoot(); const expected = { animations: sortedNames(sourceRootProperties.listAnimations()), materials: sortedNames(sourceRootProperties.listMaterials()), meshes: sortedNames(sourceRootProperties.listMeshes()), nodes: sortedNames(sourceRootProperties.listNodes()), scenes: sortedNames(sourceRootProperties.listScenes()), textureCount: sourceRootProperties.listTextures().length, }; await convertDocumentTexturesToKtx2(document, "iwt-ktx2-"); await io.write(outputPath, document); const outputDocument = await io.read(outputPath); const outputRoot = outputDocument.getRoot(); const actual = { animations: sortedNames(outputRoot.listAnimations()), materials: sortedNames(outputRoot.listMaterials()), meshes: sortedNames(outputRoot.listMeshes()), nodes: sortedNames(outputRoot.listNodes()), scenes: sortedNames(outputRoot.listScenes()), textureCount: outputRoot.listTextures().length, }; if ( JSON.stringify(actual) !== JSON.stringify(expected) || outputRoot.listTextures().some((texture) => texture.getMimeType() !== "image/ktx2") || outputRoot.listExtensionsUsed().some((extension) => extension.extensionName === "EXT_texture_webp") ) { throw new Error(`Generated asset failed round-trip validation: ${outputRelativePath}`); } console.log(`Built game_assets/${outputRelativePath}`); }