更新 extensions/max-studio/assets/max-studio/core/res/CCRemoteSprite.ts
This commit is contained in:
@@ -0,0 +1,193 @@
|
|||||||
|
import { nsStringUtils } from "@taqu/Util/StringUtils";
|
||||||
|
import { isValid } from "cc";
|
||||||
|
import { assetManager, ImageAsset, Texture2D } from "cc";
|
||||||
|
import { SpriteFrame } from "cc";
|
||||||
|
import { UITransform } from "cc";
|
||||||
|
import { Sprite } from "cc";
|
||||||
|
import { _decorator } from "cc";
|
||||||
|
import { EDITOR } from "cc/env";
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
@ccclass("CCRemoteSprite")
|
||||||
|
export class CCRemoteSprite extends Sprite {
|
||||||
|
private static _remoteSpriteCache: Map<string, SpriteFrame> = new Map();
|
||||||
|
private static _loadingSpriteCache: Map<string, Promise<SpriteFrame>> = new Map();
|
||||||
|
private static _checkTimer: NodeJS.Timeout;
|
||||||
|
/**
|
||||||
|
* 远程图片URL
|
||||||
|
*/
|
||||||
|
@property({
|
||||||
|
displayName: "远程图片URL",
|
||||||
|
tooltip: "远程图片的URL地址",
|
||||||
|
visible: true
|
||||||
|
})
|
||||||
|
private _remoteUrl: string = "";
|
||||||
|
|
||||||
|
public get remoteUrl(): string {
|
||||||
|
return this._remoteUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set remoteUrl(value: string) {
|
||||||
|
const newValue = value || "";
|
||||||
|
if (this._remoteUrl !== newValue) {
|
||||||
|
this._remoteUrl = newValue;
|
||||||
|
if (nsStringUtils.isEmpty(this._remoteUrl)) {
|
||||||
|
this.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.spriteFrame == null || this._remoteUrl !== this.spriteFrame.remoteUrl) {
|
||||||
|
this.loadRemoteSprite(this._remoteUrl).catch(err => {
|
||||||
|
app.log.error("RemoteSprite", `加载远程图片失败: ${this._remoteUrl}`, err);
|
||||||
|
// 可以添加默认图片或错误状态处理
|
||||||
|
if (this.isValid) {
|
||||||
|
this.spriteFrame = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onLoad(): void {
|
||||||
|
super.onLoad();
|
||||||
|
if (EDITOR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!CCRemoteSprite._checkTimer) {
|
||||||
|
CCRemoteSprite._checkTimer = setInterval(() => {
|
||||||
|
CCRemoteSprite.checkCache();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nsStringUtils.isEmpty(this.spriteFrame?.remoteUrl)) {
|
||||||
|
this.spriteFrame.addRef();
|
||||||
|
}
|
||||||
|
if (!nsStringUtils.isEmpty(this._remoteUrl) && this.spriteFrame?.remoteUrl !== this._remoteUrl) {
|
||||||
|
this.loadRemoteSprite(this._remoteUrl).catch(err => {
|
||||||
|
app.log.error("RemoteSprite", `onLoad加载远程图片失败: ${this._remoteUrl}`, err);
|
||||||
|
});
|
||||||
|
} else if (nsStringUtils.isEmpty(this._remoteUrl) && !nsStringUtils.isEmpty(this.spriteFrame?.remoteUrl)) {
|
||||||
|
this.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadRemoteSprite(url: string): Promise<void> {
|
||||||
|
if (nsStringUtils.isEmpty(url)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL 相同,且已经加载完成,直接返回
|
||||||
|
if (this.spriteFrame && this.spriteFrame.remoteUrl == url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.release();
|
||||||
|
|
||||||
|
if (CCRemoteSprite._remoteSpriteCache.has(url)) {
|
||||||
|
const sp = CCRemoteSprite._remoteSpriteCache.get(url);
|
||||||
|
sp.addRef();
|
||||||
|
this.spriteFrame = sp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let loadingPromise: Promise<SpriteFrame> = null;
|
||||||
|
if (CCRemoteSprite._loadingSpriteCache.has(url)) {
|
||||||
|
loadingPromise = CCRemoteSprite._loadingSpriteCache.get(url);
|
||||||
|
} else {
|
||||||
|
loadingPromise = new Promise<SpriteFrame>((resolve, reject) => {
|
||||||
|
assetManager.loadRemote(url, (err, asset: ImageAsset) => {
|
||||||
|
if (err) {
|
||||||
|
app.log.error(`loadRemote error: ${url}`, err);
|
||||||
|
CCRemoteSprite._loadingSpriteCache.delete(url);
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
asset.addRef();
|
||||||
|
const texture = new Texture2D();
|
||||||
|
texture.image = asset;
|
||||||
|
const spriteFrame = new SpriteFrame();
|
||||||
|
spriteFrame.texture = texture;
|
||||||
|
spriteFrame.remoteUrl = url;
|
||||||
|
CCRemoteSprite._remoteSpriteCache.set(url, spriteFrame);
|
||||||
|
CCRemoteSprite._loadingSpriteCache.delete(url);
|
||||||
|
resolve(spriteFrame);
|
||||||
|
} catch (createErr) {
|
||||||
|
CCRemoteSprite._loadingSpriteCache.delete(url);
|
||||||
|
reject(createErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
CCRemoteSprite._loadingSpriteCache.set(url, loadingPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sp = await loadingPromise;
|
||||||
|
sp.addRef();
|
||||||
|
// // 检查是否在加载过程中URL发生了变化
|
||||||
|
if (sp && (!isValid(this.node, true) || this._remoteUrl !== url || this.spriteFrame?.remoteUrl === url)) {
|
||||||
|
sp.decRef();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("loadSpriteFrame:", url);
|
||||||
|
this.spriteFrame = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSize(widthOrHeight: number, height?: number): void {
|
||||||
|
height ??= widthOrHeight;
|
||||||
|
this.sizeMode = Sprite.SizeMode.CUSTOM;
|
||||||
|
this.getComponent(UITransform).setContentSize(widthOrHeight, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public release(): void {
|
||||||
|
if (!nsStringUtils.isEmpty(this.spriteFrame?.remoteUrl)) {
|
||||||
|
this.spriteFrame.decRef();
|
||||||
|
}
|
||||||
|
this.spriteFrame = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onDestroy(): void {
|
||||||
|
this.release();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static checkCache() {
|
||||||
|
// 检查缓存中是否有已加载的SpriteFrame
|
||||||
|
let clearUrls = [];
|
||||||
|
|
||||||
|
for (const [url, spriteFrame] of CCRemoteSprite._remoteSpriteCache) {
|
||||||
|
if (spriteFrame.refCount <= 0) {
|
||||||
|
let texture = spriteFrame.texture as Texture2D;
|
||||||
|
let imageAsset: ImageAsset = null;
|
||||||
|
|
||||||
|
// 如果已加入动态合图,必须取原始的Texture2D
|
||||||
|
if (spriteFrame.packable && spriteFrame.original) {
|
||||||
|
texture = spriteFrame.original._texture as Texture2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取ImageAsset引用
|
||||||
|
if (texture?.image) {
|
||||||
|
imageAsset = texture.image;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先销毁spriteFrame(这会自动处理对texture的引用)
|
||||||
|
if (spriteFrame.isValid) {
|
||||||
|
spriteFrame.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再销毁texture
|
||||||
|
if (texture?.isValid) {
|
||||||
|
texture.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后减少ImageAsset的引用计数
|
||||||
|
if (imageAsset?.isValid) {
|
||||||
|
imageAsset.decRef();
|
||||||
|
}
|
||||||
|
clearUrls.push(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.log.log("清理缓存:", clearUrls.length);
|
||||||
|
clearUrls.forEach(url => {
|
||||||
|
CCRemoteSprite._remoteSpriteCache.delete(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user