Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new option to the spineAtlasCacheBuster pipe #92

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 76 additions & 29 deletions packages/assetpack/src/spine/spineAtlasCacheBuster.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<SpineAtlasCacheBusterOptions> {
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];
}