更新 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