diff --git a/assets/core/Oops.ts b/assets/core/Oops.ts index 1e9dda9..9688e80 100644 --- a/assets/core/Oops.ts +++ b/assets/core/Oops.ts @@ -22,7 +22,7 @@ import { GameManager } from "./game/GameManager"; import { LayerManager } from "./gui/layer/LayerManager"; /** 框架版本号 */ -export var version: string = "2.0.0.20250514"; +export var version: string = "2.1.0.20250921"; /** 框架核心模块访问入口 */ export class oops { diff --git a/assets/core/Root.ts b/assets/core/Root.ts index 98e18cb..d5d3c3c 100644 --- a/assets/core/Root.ts +++ b/assets/core/Root.ts @@ -12,7 +12,7 @@ import { AudioManager } from "./common/audio/AudioManager"; import { EventMessage } from "./common/event/EventMessage"; import { message } from "./common/event/MessageManager"; import { resLoader } from "./common/loader/ResLoader"; -import { StorageManager } from "./common/storage/StorageManager"; +import { IStorageSecurity, StorageManager } from "./common/storage/StorageManager"; import { StorageSecuritySimple } from "./common/storage/StorageSecuritySimple"; import { TimerManager } from "./common/timer/TimerManager"; import { GameManager } from "./game/GameManager"; @@ -52,7 +52,7 @@ export class Root extends Component { // 创建持久根节点 this.persist = new Node("OopsFrameworkPersistNode"); director.addPersistRootNode(this.persist); - // oops.config.btc = new BuildTimeConstants(); + // Web平台查询参数管理 oops.config.query = new GameQueryConfig(); // 资源管理模块 @@ -79,8 +79,10 @@ export class Root extends Component { // 本地存储模块 oops.storage = new StorageManager(); - oops.storage.init(new StorageSecuritySimple); - // oops.storage.init(new StorageSecurityCrypto); + let security: IStorageSecurity = new StorageSecuritySimple(); // new StorageSecurityCrypto(); + security.key = oops.config.game.localDataKey; + security.iv = oops.config.game.localDataIv; + oops.storage.init(security); // 创建音频模块 oops.audio = this.persist.addComponent(AudioManager); diff --git a/assets/core/common/audio/AudioEffectPool.ts b/assets/core/common/audio/AudioEffectPool.ts index c676057..b3a4055 100644 --- a/assets/core/common/audio/AudioEffectPool.ts +++ b/assets/core/common/audio/AudioEffectPool.ts @@ -148,7 +148,7 @@ export class AudioEffectPool { this.res_project.set(bundle, paths); } if (paths.indexOf(path) == -1) paths.push(path); - clip = await resLoader.loadAsync(bundle, path, AudioClip); + clip = await resLoader.load(bundle, path, AudioClip); } } @@ -203,9 +203,13 @@ export class AudioEffectPool { resLoader.release(ae.path, ae.params!.bundle); } } - ae.params && ae.params.onPlayComplete && ae.params.onPlayComplete(ae); - this.put(ae); - // console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`); + + // 循环播放的音效或自动释放音乐资源的音效,自动回收音乐播放器 + if (!ae.params.loop || ae.params.destroy) { + ae.params && ae.params.onPlayComplete && ae.params.onPlayComplete(ae); + this.put(ae); + // console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`); + } } /** diff --git a/assets/core/common/audio/AudioManager.ts b/assets/core/common/audio/AudioManager.ts index d13885a..865e34c 100644 --- a/assets/core/common/audio/AudioManager.ts +++ b/assets/core/common/audio/AudioManager.ts @@ -5,8 +5,7 @@ import { AudioEffectPool } from "./AudioEffectPool"; import { AudioEffectType } from "./AudioEnum"; import { AudioMusic } from "./AudioMusic"; import { IAudioData, IAudioParams } from "./IAudio"; - -const LOCAL_STORE_KEY = "game_audio"; +import { GameStorage } from "db://oops-framework/module/common/GameStorage"; /** * 音频管理 @@ -66,7 +65,7 @@ export class AudioManager extends Component { /** 保存音乐音效的音量、开关配置数据到本地 */ save() { - oops.storage.set(LOCAL_STORE_KEY, this.data); + oops.storage.set(GameStorage.Audio, this.data); } /** 本地加载音乐音效的音量、开关配置数据并设置到游戏中 */ @@ -74,7 +73,7 @@ export class AudioManager extends Component { this.music = new AudioMusic(); this.music.parent = this.node; - this.data = oops.storage.getJson(LOCAL_STORE_KEY); + this.data = oops.storage.getJson(GameStorage.Audio); if (this.data) { this.setState(); } diff --git a/assets/core/common/audio/AudioMusic.ts b/assets/core/common/audio/AudioMusic.ts index d493c57..3c8b140 100644 --- a/assets/core/common/audio/AudioMusic.ts +++ b/assets/core/common/audio/AudioMusic.ts @@ -123,7 +123,7 @@ export class AudioMusic extends Node { clip = await resLoader.loadRemote(path, { ext: `.${extension}` }); } else { - clip = await resLoader.loadAsync(params.bundle!, path, AudioClip); + clip = await resLoader.load(params.bundle!, path, AudioClip); } this._isLoading = false; diff --git a/assets/core/common/loader/ResLoader.ts b/assets/core/common/loader/ResLoader.ts index 5202b6a..67f7c1d 100644 --- a/assets/core/common/loader/ResLoader.ts +++ b/assets/core/common/loader/ResLoader.ts @@ -1,4 +1,4 @@ -import { __private, AnimationClip, Asset, AssetManager, assetManager, AudioClip, Font, ImageAsset, js, JsonAsset, Material, Mesh, Prefab, resources, sp, SpriteFrame, Texture2D, warn } from "cc"; +import { __private, AnimationClip, Asset, AssetManager, assetManager, AudioClip, Font, ImageAsset, js, JsonAsset, Material, Mesh, Prefab, resources, sp, SpriteFrame, Texture2D } from "cc"; export type AssetType = __private.__types_globals__Constructor | null; export type Paths = string | string[]; @@ -37,36 +37,37 @@ export class ResLoader { defaultBundleName: string = "resources"; /** 下载时的最大并发数 - 项目设置 -> 项目数据 -> 资源下载并发数,设置默认值;初始值为15 */ - get maxConcurrency() { + get maxConcurrency(): number { return assetManager.downloader.maxConcurrency; } - set maxConcurrency(value) { + set maxConcurrency(value: number) { assetManager.downloader.maxConcurrency = value; } /** 下载时每帧可以启动的最大请求数 - 默认值为15 */ - get maxRequestsPerFrame() { + get maxRequestsPerFrame(): number { return assetManager.downloader.maxRequestsPerFrame; } - set maxRequestsPerFrame(value) { + set maxRequestsPerFrame(value: number) { assetManager.downloader.maxRequestsPerFrame = value; } /** 失败重试次数 - 默认值为0 */ - get maxRetryCount() { + get maxRetryCount(): number { return assetManager.downloader.maxRetryCount; } - set maxRetryCount(value) { + set maxRetryCount(value: number) { assetManager.downloader.maxRetryCount = value; } /** 重试的间隔时间,单位为毫秒 - 默认值为2000毫秒 */ - get retryInterval() { + get retryInterval(): number { return assetManager.downloader.retryInterval; } - set retryInterval(value) { + set retryInterval(value: number) { assetManager.downloader.retryInterval = value; } + //#endregion //#region 加载远程资源 /** @@ -78,10 +79,10 @@ export class ResLoader { var data = await oops.res.loadRemote(this.url, opt); const texture = new Texture2D(); texture.image = data; - + const spriteFrame = new SpriteFrame(); spriteFrame.texture = texture; - + var sprite = this.sprite.addComponent(Sprite); sprite.spriteFrame = spriteFrame; */ @@ -149,54 +150,40 @@ export class ResLoader { * @param onProgress 加载进度回调 * @param onComplete 加载完成回调 */ - preload(bundleName: string, paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - preload(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - preload(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void; - preload(bundleName: string, paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; - preload(paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - preload(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - preload(paths: Paths, onComplete?: CompleteCallback): void; - preload(paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; + preload(bundleName: string, paths: Paths, type: AssetType, onProgress: ProgressCallback): Promise; + preload(bundleName: string, paths: Paths, onProgress: ProgressCallback): Promise; + preload(bundleName: string, paths: Paths): Promise; + preload(bundleName: string, paths: Paths, type: AssetType): Promise; + preload(paths: Paths, type: AssetType, onProgress: ProgressCallback): Promise; + preload(paths: Paths, onProgress: ProgressCallback): Promise; + preload(paths: Paths): Promise; + preload(paths: Paths, type: AssetType): Promise; preload( bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback, - onProgress?: ProgressCallback | CompleteCallback, - onComplete?: CompleteCallback, + paths?: Paths | AssetType | ProgressCallback, + type?: AssetType | ProgressCallback, + onProgress?: ProgressCallback ) { - let args: ILoadResArgs | null = null; - if (typeof paths === "string" || paths instanceof Array) { - args = this.parseLoadResArgs(paths, type, onProgress, onComplete); - args.bundle = bundleName; - } - else { - args = this.parseLoadResArgs(bundleName, paths, type, onProgress); - args.bundle = this.defaultBundleName; - } - args.preload = true; - this.loadByArgs(args); - } - - /** - * 异步加载一个资源 - * @param bundleName 远程包名 - * @param paths 资源路径 - * @param type 资源类型 - */ - preloadAsync(bundleName: string, paths: Paths, type: AssetType): Promise; - preloadAsync(bundleName: string, paths: Paths): Promise; - preloadAsync(paths: Paths, type: AssetType): Promise; - preloadAsync(paths: Paths): Promise; - preloadAsync(bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback): Promise { return new Promise((resolve, reject) => { - this.preload(bundleName, paths, type, (err: Error | null, data: AssetManager.RequestItem) => { + let onComplete = (err: Error | null, data: AssetManager.RequestItem) => { if (err) { - warn(err.message); + resolve(null!); + return; } resolve(data); - }); + } + + let args: ILoadResArgs | null = null; + if (typeof paths === "string" || paths instanceof Array) { + args = this.parseLoadResArgs(paths, type, onProgress, onComplete); + args.bundle = bundleName; + } + else { + args = this.parseLoadResArgs(bundleName, paths, type, onComplete); + args.bundle = this.defaultBundleName; + } + args.preload = true; + this.loadByArgs(args); }); } @@ -244,61 +231,50 @@ export class ResLoader { * @param bundleName 远程包名 * @param paths 资源路径 * @param type 资源类型 - * @param onProgress 加载进度回调 - * @param onComplete 加载完成回调 * @example -oops.res.load("spine_path", sp.SkeletonData, (err: Error | null, sd: sp.SkeletonData) => { - -}); + const sd = await oops.res.load("spine_path", sp.SkeletonData); */ - load(bundleName: string, paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void; - load(bundleName: string, paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; - load(paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(paths: Paths, onComplete?: CompleteCallback): void; - load(paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; - load( - bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback, - onProgress?: ProgressCallback | CompleteCallback, - onComplete?: CompleteCallback, - ) { - let args: ILoadResArgs | null = null; - if (typeof paths === "string" || paths instanceof Array) { - args = this.parseLoadResArgs(paths, type, onProgress, onComplete); - args.bundle = bundleName; - } - else { - args = this.parseLoadResArgs(bundleName, paths, type, onProgress); - args.bundle = this.defaultBundleName; - } - this.loadByArgs(args); + load(bundleName: string, paths: Paths | AssetType, type?: AssetType) { + return new Promise((resolve, reject) => { + let onComplete = (err: Error | null, data: T) => { + if (err) { + resolve(null!); + return; + } + resolve(data); + } + + let args: ILoadResArgs | null = null; + if (typeof paths === "string" || paths instanceof Array) { + args = this.parseLoadResArgs(paths, type, onComplete); + args.bundle = bundleName; + } + else { + args = this.parseLoadResArgs(bundleName, paths, onComplete); + args.bundle = this.defaultBundleName; + } + this.loadByArgs(args); + }); } /** - * 异步加载一个资源 + * 加载指定资源包中的多个任意类型资源 * @param bundleName 远程包名 * @param paths 资源路径 - * @param type 资源类型 + * @param onProgress 加载进度回调 + * @param onComplete 加载完成回调 */ - loadAsync(bundleName: string, paths: Paths, type: AssetType): Promise; - loadAsync(bundleName: string, paths: Paths): Promise; - loadAsync(paths: Paths, type: AssetType): Promise; - loadAsync(paths: Paths): Promise; - loadAsync(bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback): Promise { - return new Promise((resolve, reject) => { - this.load(bundleName, paths, type, (err: Error | null, asset: T) => { - if (err) { - warn(err.message); - } - resolve(asset); - }); - }); + loadAny(bundleName: string | string[], paths: string[] | ProgressCallback, onProgress?: ProgressCallback | CompleteCallback, onComplete?: CompleteCallback): void { + let args: ILoadResArgs | null = null; + if (typeof bundleName === "string" && paths instanceof Array) { + args = this.parseLoadResArgs(paths, onProgress, onComplete); + args.bundle = bundleName; + } + else { + args = this.parseLoadResArgs(bundleName, paths, onProgress); + args.bundle = this.defaultBundleName; + } + this.loadByArgs(args); } /** @@ -309,16 +285,16 @@ oops.res.load("spine_path", sp.SkeletonData, (err: Error | null, sd: sp.Skeleton * @param onProgress 加载进度回调 * @param onComplete 加载完成回调 * @example -// 加载进度事件 -var onProgressCallback = (finished: number, total: number, item: any) => { - console.log("资源加载进度", finished, total); -} - -// 加载完成事件 -var onCompleteCallback = () => { - console.log("资源加载完成"); -} -oops.res.loadDir("game", onProgressCallback, onCompleteCallback); + // 加载进度事件 + var onProgressCallback = (finished: number, total: number, item: any) => { + console.log("资源加载进度", finished, total); + } + + // 加载完成事件 + var onCompleteCallback = () => { + console.log("资源加载完成"); + } + oops.res.loadDir("game", onProgressCallback, onCompleteCallback); */ loadDir(bundleName: string, dir: string, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; loadDir(bundleName: string, dir: string, onProgress: ProgressCallback, onComplete: CompleteCallback): void; @@ -360,7 +336,7 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); if (bundle) { const asset = bundle.get(path); if (asset) { - this.releasePrefabtDepsRecursively(bundleName, asset); + this.releasePrefabtDepsRecursively(asset); } } } @@ -370,13 +346,15 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); * @param path 资源文件夹路径 * @param bundleName 远程资源包名 */ - releaseDir(path: string, bundleName: string = this.defaultBundleName) { + releaseDir(path: string, bundleName?: string) { + if (bundleName == undefined) bundleName = this.defaultBundleName; + const bundle: AssetManager.Bundle | null = assetManager.getBundle(bundleName); if (bundle) { var infos = bundle.getDirWithPath(path); if (infos) { infos.map((info) => { - this.releasePrefabtDepsRecursively(bundleName, info.uuid); + this.releasePrefabtDepsRecursively(info.uuid); }); } @@ -400,64 +378,25 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); } /** 释放预制依赖资源 */ - private releasePrefabtDepsRecursively(bundleName: string, uuid: string | Asset) { + private releasePrefabtDepsRecursively(uuid: string | Asset) { + let asset: Asset | null | undefined; if (uuid instanceof Asset) { + asset = uuid; uuid.decRef(); - // assetManager.releaseAsset(uuid); - // this.debugLogReleasedAsset(bundleName, uuid); } else { - const asset = assetManager.assets.get(uuid); - if (asset) { - asset.decRef(); - // assetManager.releaseAsset(asset); - // this.debugLogReleasedAsset(bundleName, asset); - } + asset = assetManager.assets.get(uuid); + if (asset) asset.decRef(); } - } - private debugLogReleasedAsset(bundleName: string, asset: Asset) { - if (asset.refCount == 0) { - let path = this.getAssetPath(bundleName, asset.uuid); - let content: string = ""; - if (asset instanceof JsonAsset) { - content = "【释放资源】Json【路径】" + path; - } - else if (asset instanceof Prefab) { - content = "【释放资源】Prefab【路径】" + path; - } - else if (asset instanceof SpriteFrame) { - content = "【释放资源】SpriteFrame【路径】" + path; - } - else if (asset instanceof Texture2D) { - content = "【释放资源】Texture2D【路径】" + path; - } - else if (asset instanceof ImageAsset) { - content = "【释放资源】ImageAsset【路径】" + path; - } - else if (asset instanceof AudioClip) { - content = "【释放资源】AudioClip【路径】" + path; - } - else if (asset instanceof AnimationClip) { - content = "【释放资源】AnimationClip【路径】" + path; - } - else if (asset instanceof Font) { - content = "【释放资源】Font【路径】" + path; - } - else if (asset instanceof Material) { - content = "【释放资源】Material【路径】" + path; - } - else if (asset instanceof Mesh) { - content = "【释放资源】Mesh【路径】" + path; - } - else if (asset instanceof sp.SkeletonData) { - content = "【释放资源】Spine【路径】" + path; - } - else { - content = "【释放资源】未知【路径】" + path; - } - console.log(content); - } + // 释放预制引用资源 + // if (asset instanceof Prefab) { + // const uuids: string[] = assetManager.dependUtil.getDepsRecursively(asset.uuid)!; + // uuids.forEach(uuid => { + // const asset = assetManager.assets.get(uuid); + // if (asset) asset.decRef(); + // }); + // } } /** @@ -472,12 +411,7 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); } //#endregion - private parseLoadResArgs( - paths: Paths, - type?: AssetType | ProgressCallback | CompleteCallback, - onProgress?: AssetType | ProgressCallback | CompleteCallback, - onComplete?: ProgressCallback | CompleteCallback - ) { + private parseLoadResArgs(paths: Paths, type?: AssetType | ProgressCallback | CompleteCallback, onProgress?: AssetType | ProgressCallback | CompleteCallback, onComplete?: ProgressCallback | CompleteCallback) { let pathsOut: any = paths; let typeOut: any = type; let onProgressOut: any = onProgress; @@ -525,15 +459,12 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); private async loadByArgs(args: ILoadResArgs) { if (args.bundle) { let bundle = assetManager.bundles.get(args.bundle); - // 获取缓存中的资源包 - if (bundle) { - this.loadByBundleAndArgs(bundle, args); - } + // 自动加载资源包 - else { - bundle = await this.loadBundle(args.bundle); - if (bundle) this.loadByBundleAndArgs(bundle, args); - } + if (bundle == null) bundle = await this.loadBundle(args.bundle); + + // 加载指定资源包中的资源 + this.loadByBundleAndArgs(bundle, args); } // 默认资源包 else { @@ -548,6 +479,50 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback); }) console.log(`当前资源总数:${assetManager.assets.count}`); } + + private debugLogReleasedAsset(bundleName: string, asset: Asset) { + if (asset.refCount == 0) { + let path = this.getAssetPath(bundleName, asset.uuid); + let content: string = ""; + if (asset instanceof JsonAsset) { + content = "【释放资源】Json【路径】" + path; + } + else if (asset instanceof Prefab) { + content = "【释放资源】Prefab【路径】" + path; + } + else if (asset instanceof SpriteFrame) { + content = "【释放资源】SpriteFrame【路径】" + path; + } + else if (asset instanceof Texture2D) { + content = "【释放资源】Texture2D【路径】" + path; + } + else if (asset instanceof ImageAsset) { + content = "【释放资源】ImageAsset【路径】" + path; + } + else if (asset instanceof AudioClip) { + content = "【释放资源】AudioClip【路径】" + path; + } + else if (asset instanceof AnimationClip) { + content = "【释放资源】AnimationClip【路径】" + path; + } + else if (asset instanceof Font) { + content = "【释放资源】Font【路径】" + path; + } + else if (asset instanceof Material) { + content = "【释放资源】Material【路径】" + path; + } + else if (asset instanceof Mesh) { + content = "【释放资源】Mesh【路径】" + path; + } + else if (asset instanceof sp.SkeletonData) { + content = "【释放资源】Spine【路径】" + path; + } + else { + content = "【释放资源】未知【路径】" + path; + } + console.log(content); + } + } } export const resLoader = new ResLoader(); \ No newline at end of file diff --git a/assets/core/common/loader/ZipLoader.ts b/assets/core/common/loader/ZipLoader.ts index b13f3a6..6a7a11c 100644 --- a/assets/core/common/loader/ZipLoader.ts +++ b/assets/core/common/loader/ZipLoader.ts @@ -17,14 +17,11 @@ export class ZipLoader { * @returns */ static load(url: string): Promise { - return new Promise((resolve, reject) => { - resLoader.load(url, BufferAsset, async (error: Error | null, asset: BufferAsset) => { - if (error) return reject(error); - - var zip = await JSZip.loadAsync(asset.buffer()); - this.zips.set(url, zip); - resolve(zip); - }) + return new Promise(async (resolve, reject) => { + let asset = await resLoader.load(url, BufferAsset); + var zip = await JSZip.loadAsync(asset.buffer()); + this.zips.set(url, zip); + resolve(zip); }); } diff --git a/assets/core/common/storage/StorageManager.ts b/assets/core/common/storage/StorageManager.ts index fd14b5e..dec4ea2 100644 --- a/assets/core/common/storage/StorageManager.ts +++ b/assets/core/common/storage/StorageManager.ts @@ -2,6 +2,9 @@ import { sys } from "cc"; import { PREVIEW } from "cc/env"; export interface IStorageSecurity { + key: string; + iv: string; + init(): void; decrypt(str: string): string; encrypt(str: string): string; encryptKey(str: string): string; @@ -23,6 +26,7 @@ export class StorageManager { /** 本地存储数据加密方式初始化 */ init(iis: IStorageSecurity) { this.iss = iis; + this.iss.init(); } /** diff --git a/assets/core/common/storage/StorageSecurityCrypto.ts b/assets/core/common/storage/StorageSecurityCrypto.ts index c5e26a2..1a10202 100644 --- a/assets/core/common/storage/StorageSecurityCrypto.ts +++ b/assets/core/common/storage/StorageSecurityCrypto.ts @@ -1,4 +1,3 @@ -// import { oops } from "../../Oops"; // import { EncryptUtil } from "../../utils/EncryptUtil"; // import { IStorageSecurity } from "./StorageManager"; @@ -12,25 +11,21 @@ // * 2、需要下载 CryptoES 加密库 // */ // export class StorageSecurityCrypto implements IStorageSecurity { -// private _key: string = null!; -// private _iv: string = null!; +// key: string = null!; +// iv: string = null!; -// constructor() { -// const key = oops.config.game.localDataKey; -// const iv = oops.config.game.localDataIv; - -// EncryptUtil.initCrypto(key, iv); - -// this._key = EncryptUtil.md5(key); -// this._iv = EncryptUtil.md5(iv); +// init() { +// this.key = EncryptUtil.md5(this.key); +// this.iv = EncryptUtil.md5(this.iv); +// EncryptUtil.initCrypto(this.key, this.iv); // } // decrypt(str: string): string { -// return EncryptUtil.aesDecrypt(str, this._key, this._iv); +// return EncryptUtil.aesDecrypt(str); // } // encrypt(str: string): string { -// return EncryptUtil.aesEncrypt(str, this._key, this._iv); +// return EncryptUtil.aesEncrypt(str); // } // encryptKey(str: string): string { diff --git a/assets/core/common/storage/StorageSecuritySimple.ts b/assets/core/common/storage/StorageSecuritySimple.ts index 6747f1f..2cfd2cc 100644 --- a/assets/core/common/storage/StorageSecuritySimple.ts +++ b/assets/core/common/storage/StorageSecuritySimple.ts @@ -1,4 +1,3 @@ -import { oops } from '../../Oops'; import { IStorageSecurity } from './StorageManager'; /** @@ -14,42 +13,34 @@ import { IStorageSecurity } from './StorageManager'; * 1、加密强度小 */ export class StorageSecuritySimple implements IStorageSecurity { + key: string = null!; + iv: string = null!; private secretkey: string = null!; - constructor() { - const key = oops.config.game.localDataKey; - const iv = oops.config.game.localDataIv; - this.secretkey = key + iv; + init() { + this.secretkey = this.key + this.iv; } /** * 加密字符串 */ encrypt(data: string): string { - if (!data) return ''; - return this.xorEncrypt(data); + let encryptedText = ''; + for (let i = 0; i < data.length; i++) { + let charCode = data.charCodeAt(i); + encryptedText += String.fromCharCode(charCode + this.secretkey.length); + } + return encryptedText; } /** 解密字符串 */ decrypt(encryptedData: string): string { - if (!encryptedData) return ''; - return this.xorDecrypt(encryptedData); - } - - /** 异或加密 */ - private xorEncrypt(data: string): string { - let result = ''; - for (let i = 0; i < data.length; i++) { - const keyChar = this.secretkey.charCodeAt(i % this.secretkey.length); - const dataChar = data.charCodeAt(i); - result += String.fromCharCode(dataChar ^ keyChar); + let decryptedText = ''; + for (let i = 0; i < encryptedData.length; i++) { + let charCode = encryptedData.charCodeAt(i); + decryptedText += String.fromCharCode(charCode - this.secretkey.length); } - return result; - } - - /** 异或解密 */ - private xorDecrypt(encryptedData: string): string { - return this.xorEncrypt(encryptedData); // 异或操作是可逆的 + return decryptedText; } encryptKey(str: string): string { diff --git a/assets/core/common/timer/TimerManager.ts b/assets/core/common/timer/TimerManager.ts index dc89178..21b09f1 100644 --- a/assets/core/common/timer/TimerManager.ts +++ b/assets/core/common/timer/TimerManager.ts @@ -194,7 +194,7 @@ export class TimerManager extends Component { } } - /** 游戏最大化时回复时间数据 */ + /** 游戏最大化时恢复时间数据 */ load(): void { for (let key in this.times) { let data = this.times[key]; @@ -204,9 +204,6 @@ export class TimerManager extends Component { data.object[data.field] = 0; this.onTimerComplete(data); } - else { - data.object[data.field] = 0; - } } } } \ No newline at end of file diff --git a/assets/core/game/GameManager.ts b/assets/core/game/GameManager.ts index 678ad23..9ad8917 100644 --- a/assets/core/game/GameManager.ts +++ b/assets/core/game/GameManager.ts @@ -5,9 +5,9 @@ * @LastEditTime: 2022-09-02 12:09:55 */ import { Node, director } from 'cc'; -import { ViewUtil } from '../utils/ViewUtil'; -import { resLoader } from '../common/loader/ResLoader'; import { GameComponent } from '../../module/common/GameComponent'; +import { resLoader } from '../common/loader/ResLoader'; +import { ViewUtil } from '../utils/ViewUtil'; /** 游戏元素打开参数 */ export interface ElementParams { @@ -41,10 +41,11 @@ export class GameManager { else { bundleName = resLoader.defaultBundleName; } + let node: Node = null!; // 自动内存管理 if (parent instanceof GameComponent) { - node = await parent.createPrefabNodeAsync(prefabPath, bundleName); + node = await parent.createPrefabNode(prefabPath, bundleName); node.parent = parent.node; } // 手动内存管理 diff --git a/assets/core/gui/layer/LayerGame.ts b/assets/core/gui/layer/LayerGame.ts index 0299ba4..3b4425c 100644 --- a/assets/core/gui/layer/LayerGame.ts +++ b/assets/core/gui/layer/LayerGame.ts @@ -4,7 +4,7 @@ * @LastEditors: dgflash * @LastEditTime: 2025-08-15 10:06:47 */ -import { Node, NodePool, Prefab, Vec3, warn } from "cc"; +import { Node, NodePool, Vec3, warn } from "cc"; import { resLoader } from "../../common/loader/ResLoader"; import { ViewUtil } from "../../utils/ViewUtil"; import { LayerCustomType } from "./LayerEnum"; @@ -22,74 +22,50 @@ export class LayerGame extends Node { LayerHelper.setFullScreen(this); } - /** - * 添加游戏元素 - * @param prefab 资源地址 - * @param config 游戏元素自定义配置 - */ - add(prefab: string, config: GameElementConfig = {}): Node { - let params = this.setParams(prefab, config, false); - let node = ViewUtil.createPrefabNode(prefab, params.config.bundle); - if (node) { - // 设置自定义属性 - this.setNode(node, config); - - let lge = node.addComponent(LayerGameElement); - lge.params = params; - params.nodes.push(node); - } - return node; - } - /** * 加载资源并添加游戏元素 * @param prefab 资源地址 * @param config 游戏元素自定义配置 */ - addAsync(prefab: string, config: GameElementConfig = {}): Promise { + add(prefab: string, config: GameElementConfig = {}): Promise { return new Promise(async (resolve, reject) => { - let bundleName = config.bundle ? config.bundle : resLoader.defaultBundleName; - await resLoader.loadAsync(bundleName, prefab, Prefab); - let node = this.add(prefab, config); + let params = this.setParams(prefab, config, false); + let node = await ViewUtil.createPrefabNodeAsync(prefab, params.config.bundle); + if (node) { + // 设置自定义属性 + this.setNode(node, config); + + let lge = node.addComponent(LayerGameElement); + lge.params = params; + params.nodes.push(node); + } resolve(node); }); } - /** - * 添加游戏元素 - 支持对象池 - * @param prefab 资源地址 - * @param config 游戏元素自定义配置 - */ - addPool(prefab: string, config: GameElementConfig = {}): Node { - let params = this.setParams(prefab, config, true); - let node: Node = null!; - if (params.pool.size() > 0) { - node = params.pool.get()!; - } - else { - node = ViewUtil.createPrefabNode(prefab, params.config.bundle); - node.addComponent(LayerGameElement); - } - - // 设置自定义属性 - this.setNode(node, config); - - let lge = node.getComponent(LayerGameElement)!; - lge.params = params; - - return node; - } - /** * 加载资源并添加游戏元素 - 支持对象池 * @param prefab 资源地址 * @param config 游戏元素自定义配置 */ - addPoolAsync(prefab: string, config: GameElementConfig = {}): Promise { + addPool(prefab: string, config: GameElementConfig = {}): Promise { return new Promise(async (resolve, reject) => { - let bundleName = config.bundle ? config.bundle : resLoader.defaultBundleName; - await resLoader.loadAsync(bundleName, prefab, Prefab); - let node = this.addPool(prefab, config); + let params = this.setParams(prefab, config, true); + let node: Node = null!; + if (params.pool.size() > 0) { + node = params.pool.get()!; + } + else { + node = await ViewUtil.createPrefabNodeAsync(prefab, params.config.bundle); + node.addComponent(LayerGameElement); + } + + // 设置自定义属性 + this.setNode(node, config); + + let lge = node.getComponent(LayerGameElement)!; + lge.params = params; + resolve(node); }); } @@ -123,7 +99,7 @@ export class LayerGame extends Node { resLoader.release(lge.params.config.prefab!, lge.params.config.bundle); } } - node.removeFromParent(); + node.destroy(); } } else { @@ -149,6 +125,7 @@ export class LayerGame extends Node { } this.elements.set(uuid, params); } + params.config.bundle = bundleName; return params; } diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index c209c13..802e7fa 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -92,7 +92,7 @@ export class LayerUI extends Node { let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 - const res = await resLoader.loadAsync(state.config.bundle!, state.config.prefab, Prefab); + const res = await resLoader.load(state.config.bundle!, state.config.prefab, Prefab); if (res) { state.node = instantiate(res); diff --git a/assets/core/gui/prompt/CommonPrompt.ts b/assets/core/gui/prompt/CommonPrompt.ts deleted file mode 100644 index e365ba8..0000000 --- a/assets/core/gui/prompt/CommonPrompt.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Component, _decorator } from "cc"; -import { LanguageLabel } from "../../../libs/gui/language/LanguageLabel"; -import { oops } from "../../Oops"; - -const { ccclass, property } = _decorator; - -/** 公共提示窗口 */ -@ccclass("CommonPrompt") -export class CommonPrompt extends Component { - /** 窗口标题多语言组件 */ - @property(LanguageLabel) - private lab_title: LanguageLabel | null = null; - - /** 提示内容多语言组件 */ - @property(LanguageLabel) - private lab_content: LanguageLabel | null = null; - - /** 确认按钮文本多语言组件 */ - @property(LanguageLabel) - private lab_ok: LanguageLabel | null = null - - /** 取消按钮文本多语言组件 */ - @property(LanguageLabel) - private lab_cancel: LanguageLabel | null = null; - - private config: any = {}; - - /** - * - * - * @param params 参数 - * { - * title: 标题 - * content: 内容 - * okWord: ok按钮上的文字 - * okFunc: 确认时执行的方法 - * cancelWord: 取消按钮的文字 - * cancelFunc: 取消时执行的方法 - * needCancel: 是否需要取消按钮 - * } - */ - onAdded(params: any): boolean { - this.config = params || {}; - this.setTitle(); - this.setContent(); - this.setBtnOkLabel(); - this.setBtnCancelLabel(); - this.node.active = true; - return true; - } - - private setTitle() { - this.lab_title!.dataID = this.config.title; - } - - private setContent() { - this.lab_content!.dataID = this.config.content; - } - - private setBtnOkLabel() { - this.lab_ok!.dataID = this.config.okWord; - } - - private setBtnCancelLabel() { - if (this.lab_cancel) { - this.lab_cancel.dataID = this.config.cancelWord; - this.lab_cancel.node.parent!.active = this.config.needCancel || false; - } - } - - private onOk() { - if (typeof this.config.okFunc == "function") { - this.config.okFunc(); - } - this.close(); - } - - private onClose() { - if (typeof this.config.closeFunc == "function") { - this.config.closeFunc(); - } - this.close(); - } - - private onCancel() { - if (typeof this.config.cancelFunc == "function") { - this.config.cancelFunc(); - } - this.close(); - } - - private close() { - oops.gui.removeByNode(this.node); - } - - onDestroy() { - this.config = null; - } -} \ No newline at end of file diff --git a/assets/core/gui/prompt/CommonPrompt.ts.meta b/assets/core/gui/prompt/CommonPrompt.ts.meta deleted file mode 100644 index 3057038..0000000 --- a/assets/core/gui/prompt/CommonPrompt.ts.meta +++ /dev/null @@ -1,13 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "653bff15-3c2e-459f-8f73-14916a5d5831", - "files": [], - "subMetas": {}, - "userData": { - "moduleId": "project:///assets/script/core/gui/prompt/CommonPrompt.js", - "importerSettings": 4, - "simulateGlobals": [] - } -} diff --git a/assets/core/utils/EncryptUtil.ts b/assets/core/utils/EncryptUtil.ts index 222d8ae..597aa1c 100644 --- a/assets/core/utils/EncryptUtil.ts +++ b/assets/core/utils/EncryptUtil.ts @@ -1,11 +1,4 @@ -// /* -// * @Author: dgflash -// * @Date: 2022-09-02 09:28:00 -// * @LastEditors: dgflash -// * @LastEditTime: 2022-10-21 09:46:39 -// */ - -// import CryptoES from "crypto-es"; +// import { AES, MD5, Utf8, WordArray } from 'crypto-es'; // /** // * CryptoES 加密库封装 @@ -16,81 +9,47 @@ // * yarn add crypto-es // */ // export class EncryptUtil { -// private static key: string = null!; -// private static iv: CryptoES.lib.WordArray = null!; +// // 将key和iv存储为WordArray类型,这是CryptoES库需要的格式 +// private static key: WordArray; +// private static iv: WordArray; // /** // * MD5加密 // * @param msg 加密信息 // */ // static md5(msg: string): string { -// return CryptoES.MD5(msg).toString(); +// return MD5(msg).toString(); // } // /** 初始化加密库 */ // static initCrypto(key: string, iv: string) { -// this.key = key; -// this.iv = CryptoES.enc.Hex.parse(iv); +// this.key = Utf8.parse(key); +// this.iv = Utf8.parse(iv); // } // /** // * AES 加密 -// * @param msg 加密信息 -// * @param key aes加密的key -// * @param iv aes加密的iv +// * @param msg 待加密的明文 // */ -// static aesEncrypt(msg: string, key: string, iv: string): string { -// return CryptoES.AES.encrypt( -// msg, -// this.key, -// { -// iv: this.iv, -// format: this.JsonFormatter -// }, -// ).toString(); +// static aesEncrypt(msg: string): string { +// const encrypted = AES.encrypt(msg, this.key, { +// iv: this.iv +// }); + +// // 返回Base64格式的密文字符串 +// return encrypted.toString(); // } // /** // * AES 解密 -// * @param str 解密字符串 -// * @param key aes加密的key -// * @param iv aes加密的iv +// * @param cipherText 待解密的密文 // */ -// static aesDecrypt(str: string, key: string, iv: string): string { -// const decrypted = CryptoES.AES.decrypt( -// str, -// this.key, -// { -// iv: this.iv, -// format: this.JsonFormatter -// }, -// ); -// return decrypted.toString(CryptoES.enc.Utf8); -// } +// static aesDecrypt(cipherText: string): string { +// const decrypted = AES.decrypt(cipherText, this.key, { +// iv: this.iv +// }); -// private static JsonFormatter = { -// stringify: function (cipherParams: any) { -// const jsonObj: any = { ct: cipherParams.ciphertext.toString(CryptoES.enc.Base64) }; -// if (cipherParams.iv) { -// jsonObj.iv = cipherParams.iv.toString(); -// } -// if (cipherParams.salt) { -// jsonObj.s = cipherParams.salt.toString(); -// } -// return JSON.stringify(jsonObj); -// }, -// parse: function (jsonStr: any) { -// const jsonObj = JSON.parse(jsonStr); -// const cipherParams = CryptoES.lib.CipherParams.create( -// { ciphertext: CryptoES.enc.Base64.parse(jsonObj.ct) }, -// ); -// if (jsonObj.iv) { -// cipherParams.iv = CryptoES.enc.Hex.parse(jsonObj.iv) -// } -// if (jsonObj.s) { -// cipherParams.salt = CryptoES.enc.Hex.parse(jsonObj.s) -// } -// return cipherParams; -// }, -// }; +// // 将解密结果从WordArray转换为UTF-8字符串 +// return decrypted.toString(Utf8); +// } // } \ No newline at end of file diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 2a1f1c8..3e638d8 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -46,7 +46,7 @@ export class JsonUtil { content = await ZipLoader.getJson(pathZip, `${name}.json`); } else { - content = await resLoader.loadAsync(url, JsonAsset); + content = await resLoader.load(url, JsonAsset); } if (content) { @@ -66,13 +66,14 @@ export class JsonUtil { * @param isZip 是否为压缩包 * @param zipNames 压缩包内的资源名列表 */ - static loadDir(zipNames?: string[]): Promise { + static loadDir(): Promise { return new Promise(async (resolve, reject) => { - if (this.zip && zipNames) { - await ZipLoader.load(pathZip); - zipNames.forEach(name => { + if (this.zip) { + let zip = await ZipLoader.load(pathZip); + for (let key in zip.files) { + let name = key.replace(".json", ""); data.set(name, ZipLoader.getJson(pathZip, `${name}.json`)); - }); + } ZipLoader.release(pathZip); resolve(); } diff --git a/assets/core/utils/TimeUtils.ts b/assets/core/utils/TimeUtils.ts index dfd2161..dfa57e1 100644 --- a/assets/core/utils/TimeUtils.ts +++ b/assets/core/utils/TimeUtils.ts @@ -35,4 +35,32 @@ export class TimeUtil { }, ms) }); } + + /** 格式化字符串 */ + static format(countDown: number) { + let result: string = ""; + let c: number = countDown; + let date: number = Math.floor(c / 86400); + c = c - date * 86400; + let hours: number = Math.floor(c / 3600); + c = c - hours * 3600; + let minutes: number = Math.floor(c / 60); + c = c - minutes * 60; + let seconds: number = c; + + if (date == 0 && hours == 0 && minutes == 0 && seconds == 0) { + result = "00:00:00"; + } + else { + hours += date * 24; + result = `${this.coverString(hours)}:${this.coverString(minutes)}:${this.coverString(seconds)}`; + } + return result; + } + + /** 个位数的时间数据将字符串补位 */ + private static coverString(value: number) { + if (value < 10) return "0" + value; + return value.toString(); + } } \ No newline at end of file diff --git a/assets/core/utils/ViewUtil.ts b/assets/core/utils/ViewUtil.ts index 2cc3d0b..495959c 100644 --- a/assets/core/utils/ViewUtil.ts +++ b/assets/core/utils/ViewUtil.ts @@ -107,7 +107,7 @@ export class ViewUtil { */ static createPrefabNodeAsync(path: string, bundleName: string = resLoader.defaultBundleName): Promise { return new Promise(async (resolve, reject) => { - const p = await resLoader.loadAsync(bundleName, path, Prefab); + const p = await resLoader.load(bundleName, path, Prefab); if (p) { resolve(instantiate(p)); } diff --git a/assets/libs/animator-effect/2d/SpineFinishedRelease.ts b/assets/libs/animator-effect/2d/SpineFinishedRelease.ts index 5f71a21..e8b59a4 100644 --- a/assets/libs/animator-effect/2d/SpineFinishedRelease.ts +++ b/assets/libs/animator-effect/2d/SpineFinishedRelease.ts @@ -5,7 +5,7 @@ * @LastEditTime: 2022-04-08 15:42:16 */ -import { Component, sp, _decorator } from 'cc'; +import { _decorator, Component, sp } from 'cc'; import { oops } from '../../../core/Oops'; const { ccclass, property } = _decorator; @@ -28,21 +28,21 @@ export class SpineFinishedRelease extends Component { this.spine.setCompleteListener(this.onSpineComplete.bind(this)); if (this.resPath) { - oops.res.load(this.resPath, sp.SkeletonData, (err: Error | null, sd: sp.SkeletonData) => { - if (err) { - console.error(`加载【${this.resPath}】的 SPINE 资源不存在`); - return; - } - - this.spine.skeletonData = sd; - this.spine.setAnimation(0, "animation", false); - }); + this.loadSkeletonData(); } else { this.spine.setAnimation(0, "animation", false); } } + private async loadSkeletonData() { + let sd = await oops.res.load(this.resPath, sp.SkeletonData); + if (sd) { + this.spine.skeletonData = sd; + this.spine.setAnimation(0, "animation", false); + } + } + private onSpineComplete() { if (this.isDestroy) { this.node.destroy(); diff --git a/assets/libs/animator-effect/EffectSingleCase.ts b/assets/libs/animator-effect/EffectSingleCase.ts index 6f3cf47..53c8d2c 100644 --- a/assets/libs/animator-effect/EffectSingleCase.ts +++ b/assets/libs/animator-effect/EffectSingleCase.ts @@ -87,7 +87,7 @@ export class EffectSingleCase { } this.res.set(path, bundleName); - await resLoader.loadAsync(bundleName, path, Prefab); + await resLoader.load(bundleName, path, Prefab); for (let i = 0; i < count; i++) { let node = ViewUtil.createPrefabNode(path, bundleName); @@ -111,11 +111,11 @@ export class EffectSingleCase { if (np == undefined) { if (params && params.bundleName) { this.res.set(path, params.bundleName); - await resLoader.loadAsync(params.bundleName, path, Prefab); + await resLoader.load(params.bundleName, path, Prefab); } else { this.res.set(path, resLoader.defaultBundleName); - await resLoader.loadAsync(path, Prefab); + await resLoader.load(path, Prefab); } const node = this.show(path, parent, params); diff --git a/assets/libs/extension/DateExt.ts b/assets/libs/extension/DateExt.ts index 36a44a5..f4c437d 100644 --- a/assets/libs/extension/DateExt.ts +++ b/assets/libs/extension/DateExt.ts @@ -32,7 +32,7 @@ Date.prototype.format = function (format: string): string { let r = format .replace('yy', year.toString()) - .replace('mm', (month < 10 ? '0' : '') + month) + .replace('MM', (month < 10 ? '0' : '') + month) .replace('dd', (day < 10 ? '0' : '') + day) .replace('hh', (hours < 10 ? '0' : '') + hours) .replace('mm', (minutes < 10 ? '0' : '') + minutes) diff --git a/assets/libs/gui/language/LanguagePack.ts b/assets/libs/gui/language/LanguagePack.ts index 1d22726..e092556 100644 --- a/assets/libs/gui/language/LanguagePack.ts +++ b/assets/libs/gui/language/LanguagePack.ts @@ -73,7 +73,7 @@ export class LanguagePack { private loadJson(lang: string): Promise { return new Promise(async (resolve, reject) => { const path = `${LanguageData.path_json}/${lang}`; - const jsonAsset = await resLoader.loadAsync(path, JsonAsset); + const jsonAsset = await resLoader.load(path, JsonAsset); if (jsonAsset) { LanguageData.language.set(LanguageDataType.Json, jsonAsset.json); Logger.instance.logConfig(path, "下载语言包 json 资源"); @@ -83,11 +83,12 @@ export class LanguagePack { return; } - resLoader.load(path, TTFFont, (err: Error | null, font: TTFFont) => { - if (err == null) Logger.instance.logConfig(path, "下载语言包 ttf 资源"); + const font = await resLoader.load(path, TTFFont); + if (font) { LanguageData.font = font; - resolve(); - }); + Logger.instance.logConfig(path, "下载语言包 ttf 资源"); + } + resolve(); }); } diff --git a/assets/libs/gui/window.meta b/assets/libs/gui/window.meta new file mode 100644 index 0000000..5bfeb9a --- /dev/null +++ b/assets/libs/gui/window.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "26bbcb1a-b407-4d25-b9e9-8676f614312a", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/libs/gui/window/PromptBase.ts b/assets/libs/gui/window/PromptBase.ts new file mode 100644 index 0000000..aa8cd46 --- /dev/null +++ b/assets/libs/gui/window/PromptBase.ts @@ -0,0 +1,89 @@ +import { _decorator } from "cc"; +import { GameComponent } from "db://oops-framework/module/common/GameComponent"; +import { LanguageLabel } from "../language/LanguageLabel"; + +const { ccclass, property } = _decorator; + +/** + * 基础提示窗口 + * 1. 自定义提示标题、按钮名 + * 2. 自定义确认、取消事件回调 + * 3. 自定义提示内容 + * 4. 支持文本多语言 + */ +@ccclass("PromptBase") +export class PromptBase extends GameComponent { + /** 窗口标题多语言组件 */ + @property(LanguageLabel) + private labTitle: LanguageLabel = null!; + + /** 提示内容多语言组件 */ + @property(LanguageLabel) + private labContent: LanguageLabel = null!; + + /** 确认按钮文本多语言组件 */ + @property(LanguageLabel) + private labOk: LanguageLabel = null!; + + /** 取消按钮文本多语言组件 */ + @property(LanguageLabel) + private labCancel: LanguageLabel = null!; + + /** 窗口配置 */ + protected config: any = null!; + + /** + * 窗口打开事件 + * @param params 参数 + * { + * title: 标题 + * content: 内容 + * okWord: ok按钮上的文字 + * okFunc: 确认时执行的方法 + * cancelWord: 取消按钮的文字 + * cancelFunc: 取消时执行的方法 + * needCancel: 是否需要取消按钮 + * } + */ + onAdded(params: any): boolean { + this.config = params; + if (this.config == null) return false; + + this.labTitle.dataID = this.config.title; // 窗口标题 + this.labContent.dataID = this.config.content; // 提示内容 + this.labOk.dataID = this.config.okWord; // 确定按钮文字 + if (this.labCancel) { + this.labCancel.dataID = this.config.cancelWord || ""; // 取消按钮文字 + this.labCancel.node.parent!.active = this.config.needCancel || false; + } + this.node.active = true; + return true; + } + + protected onLoad(): void { + this.setButton(); + } + + private btnOk() { + if (typeof this.config.onOk == "function") { + this.config.onOk(); + } + this.remove(); + } + + private btnCancel() { + if (typeof this.config.onCancel == "function") { + this.config.onCancel(); + } + this.remove(); + } + + private btnClose() { + this.remove(); + } + + onDestroy() { + this.config = null!; + super.onDestroy(); + } +} \ No newline at end of file diff --git a/assets/libs/gui/window/PromptBase.ts.meta b/assets/libs/gui/window/PromptBase.ts.meta new file mode 100644 index 0000000..1013dc6 --- /dev/null +++ b/assets/libs/gui/window/PromptBase.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "62d1c492-8247-4e77-8216-462f64c6a296", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/libs/gui/window/PromptSkip.ts b/assets/libs/gui/window/PromptSkip.ts new file mode 100644 index 0000000..34d0d4a --- /dev/null +++ b/assets/libs/gui/window/PromptSkip.ts @@ -0,0 +1,47 @@ +import { _decorator, Toggle } from "cc"; +import { oops } from "db://oops-framework/core/Oops"; +import { GameStorage } from "db://oops-framework/module/common/GameStorage"; +import { PromptBase } from "./PromptBase"; + +const { ccclass, property } = _decorator; + +/** 不同类型的提示窗口状态数据 */ +var content: any = null; + +/** 可设置指定时间内跳过提示 */ +@ccclass("PromptSkip") +export class PromptSkip extends PromptBase { + /** 是否可提示 */ + static isPrompt(id: string): boolean { + if (content == null) content = oops.storage.getJson(GameStorage.PromptSkip, {}); // 第一次打开窗口从本地数据中获取窗口状态信息 + + let r = content[id]; + let c = oops.timer.getClientTime(); + if (r == null || c > r) { + return true; + } + return false; + } + + protected start(): void { + // 界面打开,删除昨天调协的不提示时间 + if (content[this.config.id]) { + delete content[this.config.id]; + oops.storage.set(GameStorage.PromptSkip, JSON.stringify(content)); + } + } + + /** 设置是否今天日内不提示 */ + private onSetSkip(toggle: Toggle) { + if (toggle.isChecked) { + const t = oops.timer.getClientDate(); + t.setDate(t.getDate() + this.config.skipDay); + t.setHours(0, 0, 0, 0); + content[this.config.id] = t.getTime(); + } + else { + content[this.config.id] = null; + } + oops.storage.set(GameStorage.PromptSkip, JSON.stringify(content)); + } +} \ No newline at end of file diff --git a/assets/libs/gui/window/PromptSkip.ts.meta b/assets/libs/gui/window/PromptSkip.ts.meta new file mode 100644 index 0000000..c906b46 --- /dev/null +++ b/assets/libs/gui/window/PromptSkip.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "ae0c193b-a70c-474f-8e66-eeb20024039e", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/libs/model-view/JsonOb.ts b/assets/libs/model-view/JsonOb.ts index b1ab1a3..d902ffd 100644 --- a/assets/libs/model-view/JsonOb.ts +++ b/assets/libs/model-view/JsonOb.ts @@ -30,7 +30,7 @@ export class JsonOb { private _callback; - /**对象属性劫持 */ + /** 对象属性劫持 */ private observe(obj: T, path?: any) { if (OP.toString.call(obj) === types.array) { this.overrideArrayProto(obj, path); @@ -55,7 +55,7 @@ export class JsonOb { set: function (newVal) { //cc.log(newVal); if (oldVal !== newVal) { - if (OP.toString.call(newVal) === '[object Object]') { + if (OP.toString.call(newVal) === types.obj) { self.observe(newVal, pathArray); } @@ -67,11 +67,11 @@ export class JsonOb { }) // @ts-ignore - if (OP.toString.call(obj[key]) === types.obj || OP.toString.call(obj[key]) === types.array) { - // @ts-ignore - this.observe(obj[key], pathArray); + const o = obj[key]; + if (OP.toString.call(o) === types.obj || OP.toString.call(o) === types.array) { + this.observe(o, pathArray); } - }, this) + }, this); } /** @@ -92,9 +92,9 @@ export class JsonOb { Object.defineProperty(overrideProto, method, { value: function () { var oldVal = this.slice(); - //调用原始原型上的方法 + // 调用原始原型上的方法 result = originalProto[method].apply(this, arguments); - //继续监听新数组 + // 继续监听新数组 self.observe(this, path); self._callback(this, oldVal, path); return result; diff --git a/assets/libs/model-view/StringFormat.ts b/assets/libs/model-view/StringFormat.ts index 24b8d8e..5b24aae 100644 --- a/assets/libs/model-view/StringFormat.ts +++ b/assets/libs/model-view/StringFormat.ts @@ -2,15 +2,14 @@ import { LanguageData } from "../gui/language/LanguageData"; /** * 数值格式化函数, 通过语义解析自动设置值的范围 - * //整数 - * 1:def(0)//显示一个默认值 + * 1:def(0) // 显示一个默认值 */ class StringFormat { deal(value: number | string, format: string): string { if (format === '') return value as string; format = format.toLowerCase().trim(); // 不区分大小 - let match_func = format.match(/^[a-z|A-Z]+/gi); // 匹配到 format 中的 函数名 + let match_func = format.match(/^[a-z|A-Z]+/gi); // 匹配到 format 中的函数名 let match_num = format.match(/\d+$/gi); // 匹配到 format 中的参数 let func: string = ''; let num: number = 0; diff --git a/assets/libs/model-view/VMBase.ts b/assets/libs/model-view/VMBase.ts index da623a3..b1ba08d 100644 --- a/assets/libs/model-view/VMBase.ts +++ b/assets/libs/model-view/VMBase.ts @@ -1,4 +1,4 @@ -import { Component, log, _decorator } from 'cc'; +import { _decorator, Component, log } from 'cc'; import { DEBUG } from 'cc/env'; import { VM } from './ViewModel'; import { VMEnv } from './VMEnv'; diff --git a/assets/libs/model-view/VMLabel.ts b/assets/libs/model-view/VMLabel.ts index 6b4da4e..9f5c1c6 100644 --- a/assets/libs/model-view/VMLabel.ts +++ b/assets/libs/model-view/VMLabel.ts @@ -1,4 +1,4 @@ -import { _decorator, CCString, error } from 'cc'; +import { _decorator, CCString, error, Node } from 'cc'; import { StringFormatFunction } from './StringFormat'; import { VMBase } from './VMBase'; import { VMEnv } from './VMEnv'; @@ -22,6 +22,22 @@ const LABEL_TYPE = { @menu('OopsFramework/Mvvm/VM-Label (标签)') @help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037641&doc_id=2873565') export default class VMLabel extends VMBase { + /** + * 动态绑定组件 + * @param node 目标节点 + * @param watchPath 监听数据路径 + */ + static bind(node: Node, watchPath: string | string[]) { + let label = node.addComponent(VMLabel); + if (watchPath instanceof Array) { + label.templateMode = true; + label.watchPathArr = watchPath; + } + else { + label.watchPath = watchPath; + } + } + @property({ tooltip: '是否启用模板代码,只能在运行时之前设置,\n将会动态解析模板语法 {{0}},并且自动设置监听的路径' }) diff --git a/assets/libs/model-view/VMParent.ts b/assets/libs/model-view/VMParent.ts index f176b49..abcd52f 100644 --- a/assets/libs/model-view/VMParent.ts +++ b/assets/libs/model-view/VMParent.ts @@ -1,15 +1,16 @@ import { Component, _decorator } from 'cc'; import { GameComponent } from '../../module/common/GameComponent'; import { VM } from './ViewModel'; +import { VMBase } from './VMBase'; const { ccclass, help, executionOrder } = _decorator; /** * 提供VM环境,控制旗下所有VM节点 - * 一般用于 非全局的 VM绑定,VM 环境与 组件紧密相连 + * 一般用于 非全局的 VM绑定,VM 环境与组件紧密相连 * (Prefab 模式绑定) * VMParent 必须必其他组件优先执行 - * v0.1 修复bug ,现在可以支持 Parent 嵌套 (但是注意性能问题,不要频繁嵌套) + * 现在可以支持 Parent 嵌套(但是注意性能问题,不要频繁嵌套) */ @ccclass @executionOrder(-1) @@ -21,9 +22,6 @@ export default class VMParent extends GameComponent { /** 需要绑定的私有数据 */ protected data: any = {}; - /**VM 管理 */ - public VM = VM; - /** * [注意]不能直接覆盖此方法,如果需要覆盖。 * 只能在该方法内部调用父类的实现 @@ -32,7 +30,6 @@ export default class VMParent extends GameComponent { * super.onLoad(); * } * ``` - * */ onLoad() { if (this.data == null) return; @@ -46,20 +43,16 @@ export default class VMParent extends GameComponent { // console.group(); for (let i = 0; i < comps.length; i++) { const comp = comps[i]; - this.replaceVMPath(comp, this.tag) + this.replaceVMPath(comp, this.tag); } // console.groupEnd() } /**在 onLoad 完成 和 start() 之前调用,你可以在这里进行初始化数据等操作 */ - protected onBind() { - - } + protected onBind() { } /**在 onDestroy() 后调用,此时仍然可以获取绑定的 data 数据*/ - protected onUnBind() { - - } + protected onUnBind() { } private replaceVMPath(comp: Component, tag: string) { // @ts-ignore @@ -88,13 +81,13 @@ export default class VMParent extends GameComponent { /** 未优化的遍历节点,获取VM 组件 */ private getVMComponents() { - let comps = this.node.getComponentsInChildren('VMBase'); - let parents = this.node.getComponentsInChildren('VMParent').filter(v => v.uuid !== this.uuid); // 过滤掉自己 + let comps = this.node.getComponentsInChildren(VMBase); + let parents = this.node.getComponentsInChildren(VMParent).filter(v => v.uuid !== this.uuid); // 过滤掉自己 //过滤掉不能赋值的parent let filters: any[] = []; parents.forEach((node: Component) => { - filters = filters.concat(node.getComponentsInChildren('VMBase')); + filters = filters.concat(node.getComponentsInChildren(VMBase)); }) comps = comps.filter((v) => filters.indexOf(v) < 0); diff --git a/assets/libs/model-view/VMProgress.ts b/assets/libs/model-view/VMProgress.ts index d41a043..192477a 100644 --- a/assets/libs/model-view/VMProgress.ts +++ b/assets/libs/model-view/VMProgress.ts @@ -27,7 +27,7 @@ export default class VMProgress extends VMCustom { }) protected watchPathArr: string[] = ['[min]', '[max]']; - public templateMode: boolean = true; + templateMode: boolean = true; @property({ visible: function () { diff --git a/assets/libs/model-view/ViewModel.ts b/assets/libs/model-view/ViewModel.ts index 1d1af9c..ea77da9 100644 --- a/assets/libs/model-view/ViewModel.ts +++ b/assets/libs/model-view/ViewModel.ts @@ -61,12 +61,12 @@ class ViewModel { if (this.emitToRootPath) director.emit(VM_EMIT_HEAD + this._tag, n, o, path); // 通知主路径 - if (path.length >= 2) { - for (let i = 0; i < path.length - 1; i++) { - const e = path[i]; - //log('中端路径'); - } - } + // if (path.length >= 2) { + // for (let i = 0; i < path.length - 1; i++) { + // const e = path[i]; + // log('中端路径', e); + // } + // } } } diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index 3f4dc74..e83e6bc 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -10,6 +10,7 @@ import { CompType } from "../../libs/ecs/ECSModel"; import { CCBusiness } from "./CCBusiness"; import { CCView } from "./CCView"; import { CCViewVM } from "./CCViewVM"; +import { GameComponent } from "./GameComponent"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; export type ECSView = CCViewVM | CCView; @@ -20,21 +21,39 @@ export abstract class CCEntity extends ecs.Entity { /** 单例子实体 */ private singletons: Map = null!; - /** 添加单例子实体 */ - addChildSingleton(cls: any): T { + /** + * 批量添加单例子实体 + * @param clss 单例子实体类数组 + */ + addChildSingletons(...clss: any[]) { + for (let ctor of clss) { + this.addChildSingleton(ctor); + } + } + + /** + * 添加单例子实体 + * @param cls 单例子实体类 + * @returns 单例子实体 + */ + addChildSingleton(cls: any): T { if (this.singletons == null) this.singletons = new Map(); if (this.singletons.has(cls)) { console.error(`${cls.name} 单例子实体已存在`); return null!; } - let entity = cls.create(); + let entity = ecs.getEntity(cls); this.singletons.set(cls, entity); this.addChild(entity); return entity as T; } - /** 获取单例子实体 */ - getChildSingleton(cls: any): T { + /** + * 获取单例子实体 + * @param cls 单例子实体类 + * @returns 单例子实体 + */ + getChildSingleton(cls: any): T { return this.singletons.get(cls) as T; } @@ -56,11 +75,25 @@ export abstract class CCEntity extends ecs.Entity { * @param path 显示资源地址 * @param bundleName 资源包名称 */ - addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { - const node = ViewUtil.createPrefabNode(path, bundleName); - const comp = node.getComponent(ctor)!; - this.add(comp); - node.parent = parent; + addPrefab(ctor: ECSCtor, parent: Node | GameComponent, path: string, bundleName: string = resLoader.defaultBundleName): Promise { + return new Promise(async (resolve, reject) => { + let node: Node = null!; + // 跟随父节点施放自动释放当前资源 + if (parent instanceof GameComponent) { + node = await parent.createPrefabNode(path, bundleName); + const comp = node.getComponent(ctor)!; + this.add(comp); + node.parent = parent.node; + } + // 手动内存管理 + else { + node = await ViewUtil.createPrefabNodeAsync(path, bundleName); + const comp = node.getComponent(ctor)!; + this.add(comp); + node.parent = parent; + } + resolve(node); + }); } /** @@ -87,7 +120,7 @@ export abstract class CCEntity extends ecs.Entity { resolve(node); } else { - console.error(`${key} 界面组件未使用 gui.register 注册`); + console.error(`${ctor.name} 界面组件未使用 gui.register 注册`); } }); } @@ -157,6 +190,7 @@ export abstract class CCEntity extends ecs.Entity { * @returns 业务逻辑组件实例 */ getBusiness>(cls: any): T { + if (this.businesss == null) return null!; return this.businesss.get(cls) as T; } @@ -165,8 +199,10 @@ export abstract class CCEntity extends ecs.Entity { * @param cls 业务逻辑组件类 */ removeBusiness(cls: any) { - let business = this.businesss.get(cls); - if (business) this.businesss.delete(cls); + if (this.businesss) { + let business = this.businesss.get(cls); + if (business) this.businesss.delete(cls); + } } //#endregion diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 031ce00..c9ad13c 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -4,7 +4,7 @@ * @LastEditors: dgflash * @LastEditTime: 2022-12-13 11:36:00 */ -import { Asset, Button, Component, EventHandler, EventKeyboard, EventTouch, Input, Node, Prefab, Sprite, SpriteFrame, __private, _decorator, input, isValid } from "cc"; +import { Asset, Button, Component, EventHandler, EventKeyboard, EventTouch, Input, Node, Prefab, Sprite, SpriteFrame, __private, _decorator, input, instantiate, isValid } from "cc"; import { oops } from "../../core/Oops"; import { AudioEffect } from "../../core/common/audio/AudioEffect"; import { IAudioParams } from "../../core/common/audio/IAudio"; @@ -99,19 +99,10 @@ export class GameComponent extends Component { * 从资源缓存中找到预制资源名并创建一个显示对象 * @param path 资源路径 */ - createPrefabNode(path: string, bundleName: string = oops.res.defaultBundleName): Node { - return ViewUtil.createPrefabNode(path, bundleName); - } - - /** - * 加载预制并创建预制节点 - * @param path 资源路径 - * @param bundleName 资源包名 - */ - createPrefabNodeAsync(path: string, bundleName: string = oops.res.defaultBundleName): Promise { + createPrefabNode(path: string, bundleName: string = oops.res.defaultBundleName): Promise { return new Promise(async (resolve, reject) => { - await this.loadAsync(bundleName, path, Prefab); - let node = ViewUtil.createPrefabNode(path, bundleName); + const prefab = await this.load(bundleName, path, Prefab); + const node = instantiate(prefab); resolve(node); }); } @@ -197,42 +188,27 @@ export class GameComponent extends Component { * @param paths 资源路径 * @param type 资源类型 * @param onProgress 加载进度回调 - * @param onComplete 加载完成回调 */ - load(bundleName: string, paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void; - load(bundleName: string, paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; - load(paths: Paths, type: AssetType, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void; - load(paths: Paths, onComplete?: CompleteCallback): void; - load(paths: Paths, type: AssetType, onComplete?: CompleteCallback): void; - load( - bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback, - onProgress?: ProgressCallback | CompleteCallback, - onComplete?: CompleteCallback, - ) { + load(bundleName: string, paths: Paths | AssetType, type?: AssetType) { this.addPathToRecord(ResType.Load, bundleName, paths); - oops.res.load(bundleName, paths, type, onProgress, onComplete); + return oops.res.load(bundleName, paths, type); } /** - * 异步加载一个资源 + * 加载指定资源包中的多个任意类型资源 * @param bundleName 远程包名 * @param paths 资源路径 - * @param type 资源类型 + * @param onProgress 加载进度回调 + * @param onComplete 加载完成回调 */ - loadAsync(bundleName: string, paths: Paths, type: AssetType): Promise; - loadAsync(bundleName: string, paths: Paths): Promise; - loadAsync(paths: Paths, type: AssetType): Promise; - loadAsync(paths: Paths): Promise; - loadAsync(bundleName: string, - paths?: Paths | AssetType | ProgressCallback | CompleteCallback, - type?: AssetType | ProgressCallback | CompleteCallback): Promise { - this.addPathToRecord(ResType.Load, bundleName, paths); - return oops.res.loadAsync(bundleName, paths, type); + loadAny(bundleName: string | string[], paths: string[] | ProgressCallback, onProgress?: ProgressCallback | CompleteCallback, onComplete?: CompleteCallback): void { + if (typeof bundleName === "string" && paths instanceof Array) { + this.addPathToRecord(ResType.Load, bundleName, paths); + } + else { + this.addPathToRecord(ResType.Load, resLoader.defaultBundleName, bundleName); + } + oops.res.loadAny(bundleName, paths, onProgress, onComplete); } /** @@ -307,7 +283,7 @@ export class GameComponent extends Component { * @param bundle 资源包名 */ async setSprite(target: Sprite, path: string, bundle: string = resLoader.defaultBundleName) { - const spriteFrame = await this.loadAsync(bundle, path, SpriteFrame); + const spriteFrame = await this.load(bundle, path, SpriteFrame); if (!spriteFrame || !isValid(target)) { const rps = this.resPaths.get(ResType.Load); if (rps) { @@ -337,13 +313,23 @@ export class GameComponent extends Component { * @param url 资源地址 * @param params 音效播放参数 */ - async playEffect(url: string, params?: IAudioParams): Promise { + playEffect(url: string, params?: IAudioParams): Promise { return new Promise(async (resolve, reject) => { // 音效播放完,关闭正在播放状态的音乐效果 - if (params == null) params = {}; + if (params == null) { + params = { bundle: resLoader.defaultBundleName }; + } + else if (params.bundle == null) { + params.bundle = resLoader.defaultBundleName; + } let ae = await oops.audio.playEffect(url, params); - this.addPathToRecord(ResType.Load, ae.params!.bundle!, url); - resolve(ae); + if (ae) { + this.addPathToRecord(ResType.Load, ae.params.bundle!, url); + resolve(ae); + } + else { + resolve(null!); + } }); } //#endregion diff --git a/assets/module/common/GameStorage.ts b/assets/module/common/GameStorage.ts new file mode 100644 index 0000000..59a8bca --- /dev/null +++ b/assets/module/common/GameStorage.ts @@ -0,0 +1,7 @@ +/** 框架内本地存储键值 */ +export enum GameStorage { + /** 设置音频音量、开关 */ + Audio = "OopsFrameworkAudio", + /** 可设置指定时间内跳过提示 */ + PromptSkip = "OopsFrameworkPromptSkip", +} \ No newline at end of file diff --git a/assets/module/common/GameStorage.ts.meta b/assets/module/common/GameStorage.ts.meta new file mode 100644 index 0000000..9ff2c79 --- /dev/null +++ b/assets/module/common/GameStorage.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "7cefb56b-a388-4cd0-9952-209b7554c044", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/src/create-script.ts b/src/create-script.ts index 2638b06..816df97 100644 --- a/src/create-script.ts +++ b/src/create-script.ts @@ -2,7 +2,7 @@ import { existsSync } from 'fs'; import path from 'path'; /** 写入文件 */ -export function createView(directoryPath: string, fileName: string, content: string, isEcsComp: boolean = true): Promise { +export function createView(directoryPath: string, fileName: string, content: string, moduleName: string, isEcsComp: boolean = true): Promise { return new Promise(async (resolve, reject) => { // 创建脚本 let className = fileName + "View"; @@ -16,6 +16,7 @@ export function createView(directoryPath: string, fileName: string, content: str if (!existsSync(scriptUrl)) { content = content.replace(/<%Name%>/g, className); + content = content.replace(/<%ModuleName%>/g, moduleName); await Editor.Message.request('asset-db', 'create-asset', scriptUrl, content); } diff --git a/src/default/index.ts b/src/default/index.ts index 40d99aa..7490d97 100644 --- a/src/default/index.ts +++ b/src/default/index.ts @@ -46,9 +46,11 @@ module.exports = Editor.Panel.define({ break; case "View": title = `i18n:oops-framework.createView`; + showModule = true; break; case "ViewMvvm": title = `i18n:oops-framework.createViewMvvm`; + showModule = true; break; } @@ -82,7 +84,7 @@ module.exports = Editor.Panel.define({ switch (type) { case "GameComponent": - await createView(path, filename, TemplateGameComponent, false); + await createView(path, filename, TemplateGameComponent, null!, false); break; case "Module": await createScriptModule(path, filename, TemplateModule); @@ -94,10 +96,10 @@ module.exports = Editor.Panel.define({ await createScriptBll(path, filename, TemplateBll, moduleName); break; case "View": - await createView(path, filename, TemplateView); + await createView(path, filename, TemplateView, moduleName); break; case "ViewMvvm": - await createView(path, filename, TemplateViewMvvm); + await createView(path, filename, TemplateViewMvvm, moduleName); break; } close(); diff --git a/src/template/Module.ts b/src/template/Module.ts index 65920e7..3191c48 100644 --- a/src/template/Module.ts +++ b/src/template/Module.ts @@ -1,8 +1,9 @@ export const TemplateModule = `import { ecs } from "db://oops-framework/libs/ecs/ECS"; +import { CCEntity } from 'db://oops-framework/module/common/CCEntity'; /** <%Name%> 模块 */ @ecs.register('<%Name%>') -export class <%Name%> extends ecs.Entity { +export class <%Name%> extends CCEntity { /** ---------- 数据层 ---------- */ // <%Name%>Model!: <%Name%>ModelComp; @@ -14,6 +15,6 @@ export class <%Name%> extends ecs.Entity { /** 初始添加的数据层组件 */ protected init() { - // this.addComponents(); + // this.addComponents(); } }`; \ No newline at end of file diff --git a/src/template/ModuleView.ts b/src/template/ModuleView.ts index c829ae5..a0918b5 100644 --- a/src/template/ModuleView.ts +++ b/src/template/ModuleView.ts @@ -1,20 +1,16 @@ export const TemplateView = `import { _decorator } from "cc"; import { ecs } from "db://oops-framework/libs/ecs/ECS"; -import { CCComp } from "db://oops-framework/module/common/CCComp"; +import { CCView } from "db://oops-framework/module/common/CCView"; const { ccclass, property } = _decorator; /** 视图层对象 */ @ccclass('<%Name%>Comp') @ecs.register('<%Name%>', false) -export class <%Name%>Comp extends CCComp { - /** 视图层逻辑代码分离演示 */ - start() { - // const entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 - } +export class <%Name%>Comp extends CCView<<%ModuleName%>> { + - /** 视图对象通过 ecs.Entity.remove(<%Name%>Comp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { - this.node.destroy(); + } }`; \ No newline at end of file diff --git a/src/template/ModuleViewVM.ts b/src/template/ModuleViewVM.ts index 6a66236..afbbc4e 100644 --- a/src/template/ModuleViewVM.ts +++ b/src/template/ModuleViewVM.ts @@ -1,23 +1,19 @@ export const TemplateViewMvvm = `import { _decorator } from "cc"; +import { gui } from "db://oops-framework/core/gui/Gui"; +import { LayerType } from "db://oops-framework/core/gui/layer/LayerEnum"; import { ecs } from "db://oops-framework/libs/ecs/ECS"; -import { CCVMParentComp } from "db://oops-framework/module/common/CCVMParentComp"; +import { CCViewVM } from "db://oops-framework/module/common/CCViewVM"; const { ccclass, property } = _decorator; /** 视图层对象 - 支持 MVVM 框架的数据绑定 */ @ccclass('<%Name%>Comp') @ecs.register('<%Name%>', false) -export class <%Name%>Comp extends CCVMParentComp { - /** 脚本控制的界面 MVVM 框架绑定数据 */ +@gui.register('<%Name%>', { layer: LayerType.UI, prefab: "界面预制路径" }) +export class <%Name%>Comp extends CCViewVM<<%ModuleName%>> { data: any = {}; - /** 视图层逻辑代码分离演示 */ - start() { - // const entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 - } - - /** 视图对象通过 ecs.Entity.remove(<%Name%>Comp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { - this.node.destroy(); + } }` \ No newline at end of file