import { ResV1RoleGameAvgDetailRoleGame } from '../netController/CXResponse';
const { ccclass } = cc._decorator;
export type SkeletonDataType = { imageUrl: string; skeJsonUrl: string; atlasUrl: string };
export type SkeletonMapType = {
name: string;
skeData: sp.SkeletonData;
image: cc.Texture2D;
skeJson: string | null;
atlas: string | null;
};
export type TSpineResData = NonNullable<
NonNullable<ResV1RoleGameAvgDetailRoleGame>['data']
>['spineFiles']['0'];
@ccclass
export default class SpineController {
private map: { [key: string]: { res: SkeletonMapType; tag: Array<number> } } = {};
// eslint-disable-next-line no-use-before-define
private static P: SpineController;
static get instance() {
if (!SpineController.P) {
SpineController.P = new SpineController();
}
return SpineController.P;
}
public async loadStorySpineAssets(storyId: number, dataList: TSpineResData[]) {
if (!dataList || dataList.length === 0) return Promise.resolve();
const promiseArray: Array<Promise<SkeletonMapType>> = [];
for (let i = 0, len = dataList.length; i < len; i++) {
const tmpValue = dataList[i];
const param: SkeletonDataType = {
imageUrl: '',
skeJsonUrl: '',
atlasUrl: '',
};
tmpValue.files?.forEach((value) => {
switch (value.name.split('.').pop()) {
case 'png':
param.imageUrl = value.key || '';
break;
case 'json':
param.skeJsonUrl = value.key || '';
break;
case 'atlas':
param.atlasUrl = value.key || '';
break;
}
});
if (param.imageUrl && param.skeJsonUrl && param.atlasUrl) {
promiseArray.push(this.load(param, tmpValue.spineName || ''));
} else {
console.error(storyId, ' spine资源缺失 :', tmpValue.spineName);
}
}
const resources = await Promise.all(promiseArray);
resources.forEach((res, index) => {
if (this.map[res.name]) {
this.map[res.name].tag.includes(storyId)
? null
: this.map[dataList[index].spineName].tag.push(storyId);
} else {
this.map[res.name] = {
res: res,
tag: [storyId],
};
}
});
}
public releaseStorySpineAssets(storyId: number) {
// release all spine by storyId
Object.keys(this.map).forEach((key) => {
const value = this.map[key];
const storyIndex = value.tag.indexOf(storyId);
if (storyIndex !== -1) {
value.tag.splice(storyIndex, 1);
if (value.tag.length === 0) {
this.releaseSkeletonData(key);
}
}
});
}
private load(data: SkeletonDataType, name: string): Promise<SkeletonMapType> {
const { imageUrl, skeJsonUrl, atlasUrl } = data;
return new Promise((resolve, reject) => {
if (this.map[name]) {
resolve(this.map[name].res);
return;
}
cc.assetManager.loadAny(
[
{ url: atlasUrl, ext: '.txt' },
{ url: skeJsonUrl, ext: '.txt' },
],
(error, assets: Array<string>) => {
if (error) {
reject(error);
} else {
cc.assetManager.loadRemote(imageUrl, (error, img: cc.Texture2D) => {
if (error) {
reject(error);
} else {
const skeData = new sp.SkeletonData();
skeData.skeletonJson = assets[1];
skeData.atlasText = assets[0].toString();
skeData.textures = [img];
img.genMipmaps = true;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
const s = imageUrl.split('/').pop().split('?').shift();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
skeData.textureNames = [s];
const uuid = new Date().getTime().toString();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
skeData._uuid = uuid;
resolve({
name: name,
skeData: skeData,
skeJson: assets[1],
atlas: assets[0],
image: img,
});
}
});
}
}
);
});
}
private releaseSkeletonData(name: string) {
const deleteItem = this.map[name];
deleteItem.res.skeData.destroy();
cc.assetManager.releaseAsset(deleteItem.res.image);
deleteItem.res.atlas = null;
deleteItem.res.skeJson = null;
delete this.map[name];
}
getSpineData(name: string) {
return this.map[name].res.skeData;
}
}