diff --git a/packages/assetpack/src/spine/spineAtlasCacheBuster.ts b/packages/assetpack/src/spine/spineAtlasCacheBuster.ts index 2e17ab32..3ae8720f 100644 --- a/packages/assetpack/src/spine/spineAtlasCacheBuster.ts +++ b/packages/assetpack/src/spine/spineAtlasCacheBuster.ts @@ -1,8 +1,22 @@ import fs from 'fs-extra'; +import type { Asset, AssetPipe } from '../core/index.js'; import { checkExt, findAssets } from '../core/index.js'; import { AtlasView } from './AtlasView.js'; -import type { Asset, AssetPipe } from '../core/index.js'; +type SpinsAsset = { + name: string; + directory: string; + atlas?: Asset; + json?: Asset; +}; + +export interface SpineAtlasCacheBusterOptions { + /** + * Set this value to true if .atlas file and .json file must have the same file names (including the HASH in the name). + * This is important for the Pixi spineTextureAtlasLoader function + */ + jsonAndAltasHasTheSameNames?: boolean; +} /** * This should be used after the cache buster plugin in the pipes. @@ -18,67 +32,100 @@ import type { Asset, AssetPipe } from '../core/index.js'; * @param _options * @returns */ -export function spineAtlasCacheBuster(): AssetPipe -{ - const defaultOptions = {}; +export function spineAtlasCacheBuster( + _options: SpineAtlasCacheBusterOptions = {}, +): AssetPipe { + const defaultOptions = { + jsonAndAltasHasTheSameNames: false, + ..._options, + }; - const atlasFileToFix: Asset[] = []; + const potentialSpineAssetsToFix: SpinsAsset[] = []; + const atlasExt = '.atlas'; + const jsonExt = '.json'; return { folder: false, name: 'spine-cache-buster', defaultOptions, - test(asset: Asset, _options) - { - return checkExt(asset.path, '.atlas'); + test(asset: Asset, _options) { + return checkExt(asset.path, atlasExt) || checkExt(asset.path, jsonExt); }, - async transform(asset: Asset, _options) - { - atlasFileToFix.push(asset); + async transform(asset: Asset, _options) { + const name = getAssetFileNameWithoutHashAndExtension(asset); + let spineAsset: SpinsAsset | undefined = potentialSpineAssetsToFix.find( + (item) => item.name === name && item.directory === asset.directory, + ); + if (spineAsset === undefined) { + spineAsset = { + name: name, + directory: asset.directory, + }; + potentialSpineAssetsToFix.push(spineAsset); + } + + if (asset.extension === atlasExt) { + spineAsset.atlas = asset; + } + + if (asset.extension === jsonExt) { + spineAsset.json = asset; + } return [asset]; }, - async finish(asset: Asset) - { - // first we retrieve the final transformed children - so the atlas files that have been copied - // to the output folder. - const atlasAssets = atlasFileToFix.map((asset) => asset.getFinalTransformedChildren()[0]); + async finish(asset: Asset, options) { + const spineAssetsToFix = potentialSpineAssetsToFix.filter( + (item) => item.atlas !== undefined && item.json !== undefined, + ); - atlasAssets.forEach((atlasAsset) => - { + spineAssetsToFix.forEach((spineAsset) => { // we are going to replace the textures in the atlas file with the new cache busted textures // as we do this, the hash of the atlas file will change, so we need to update the path // and also remove the original file. + // first we retrieve the final transformed children - so the atlas files that have been copied + // to the output folder. + const atlasAsset = spineAsset.atlas?.getFinalTransformedChildren()[0]; + const jsonAsset = spineAsset.json?.getFinalTransformedChildren()[0]; + if (atlasAsset === undefined) { + return; + } + if (jsonAsset === undefined) { + return; + } const originalHash = atlasAsset.hash; const originalPath = atlasAsset.path; - const atlasView = new AtlasView(atlasAsset.buffer); - atlasView.getTextures().forEach((texture) => - { - const textureAssets = findAssets((asset) => - asset.filename === texture, asset, true); - + atlasView.getTextures().forEach((texture) => { + const textureAssets = findAssets((asset) => asset.filename === texture, asset, true); // last transformed child is the renamed texture const cacheBustedTexture = textureAssets[0].getFinalTransformedChildren()[0]; - atlasView.replaceTexture(texture, cacheBustedTexture.filename); }); atlasAsset.buffer = atlasView.buffer; - atlasAsset.path = atlasAsset.path.replace(originalHash, atlasAsset.hash); + if (options.jsonAndAltasHasTheSameNames) { + atlasAsset.path = atlasAsset.path.replace(originalHash, jsonAsset.hash); + } else { + atlasAsset.path = atlasAsset.path.replace(originalHash, atlasAsset.hash); + } - fs.removeSync(originalPath); + (fs as any).removeSync(originalPath); // rewrite.. fs.writeFileSync(atlasAsset.path, atlasAsset.buffer); }); - atlasFileToFix.length = 0; - } + potentialSpineAssetsToFix.length = 0; + }, }; } + +function getAssetFileNameWithoutHashAndExtension(asset: Asset): string { + return asset.filename.split('-')[0]; +}