mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-07 19:07:30 +08:00
1. CCEntity.addPrefab方法修改为返回节点
2. TimeUtili添加将秒数格式化为时间格式 3. 修复时间管理从后台恢复时计算错误问题 4. 修复DateExt时间格式化转化错误问题 5. 修复StorageSecuritySimple在真机上解码错误问题 6. 修复音效循环播放功能无效问题 7. 优化加载模块 8. 优化CCEntity.addUi错误提示信息 9. CommonPrompt对象修改为PromptBase,并优化代码,适合继承使用
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()}】`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export class AudioMusic extends Node {
|
||||
clip = await resLoader.loadRemote<AudioClip>(path, { ext: `.${extension}` });
|
||||
}
|
||||
else {
|
||||
clip = await resLoader.loadAsync(params.bundle!, path, AudioClip);
|
||||
clip = await resLoader.load(params.bundle!, path, AudioClip);
|
||||
}
|
||||
|
||||
this._isLoading = false;
|
||||
|
||||
@@ -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<T = Asset> = __private.__types_globals__Constructor<T> | 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<ImageAsset>(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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
preload<T extends Asset>(paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
preload<T extends Asset>(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
preload<T extends Asset>(paths: Paths, onComplete?: CompleteCallback): void;
|
||||
preload<T extends Asset>(paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onProgress: ProgressCallback): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, onProgress: ProgressCallback): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(paths: Paths, type: AssetType<T>, onProgress: ProgressCallback): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(paths: Paths, onProgress: ProgressCallback): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(paths: Paths): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(paths: Paths, type: AssetType<T>): Promise<AssetManager.RequestItem>;
|
||||
preload<T extends Asset>(
|
||||
bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
onProgress?: ProgressCallback | CompleteCallback,
|
||||
onComplete?: CompleteCallback,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback,
|
||||
type?: AssetType<T> | ProgressCallback,
|
||||
onProgress?: ProgressCallback
|
||||
) {
|
||||
let args: ILoadResArgs<Asset> | 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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>): Promise<AssetManager.RequestItem>;
|
||||
preloadAsync<T extends Asset>(bundleName: string, paths: Paths): Promise<AssetManager.RequestItem>;
|
||||
preloadAsync<T extends Asset>(paths: Paths, type: AssetType<T>): Promise<AssetManager.RequestItem>;
|
||||
preloadAsync<T extends Asset>(paths: Paths): Promise<AssetManager.RequestItem>;
|
||||
preloadAsync<T extends Asset>(bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback): Promise<AssetManager.RequestItem> {
|
||||
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<Asset> | 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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(
|
||||
bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
onProgress?: ProgressCallback | CompleteCallback,
|
||||
onComplete?: CompleteCallback,
|
||||
) {
|
||||
let args: ILoadResArgs<T> | 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<T extends Asset>(bundleName: string, paths: Paths | AssetType<T>, type?: AssetType<T>) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
let onComplete = (err: Error | null, data: T) => {
|
||||
if (err) {
|
||||
resolve(null!);
|
||||
return;
|
||||
}
|
||||
resolve(data);
|
||||
}
|
||||
|
||||
let args: ILoadResArgs<T> | 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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>): Promise<T>;
|
||||
loadAsync<T extends Asset>(bundleName: string, paths: Paths): Promise<T>;
|
||||
loadAsync<T extends Asset>(paths: Paths, type: AssetType<T>): Promise<T>;
|
||||
loadAsync<T extends Asset>(paths: Paths): Promise<T>;
|
||||
loadAsync<T extends Asset>(bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.load(bundleName, paths, type, (err: Error | null, asset: T) => {
|
||||
if (err) {
|
||||
warn(err.message);
|
||||
}
|
||||
resolve(asset);
|
||||
});
|
||||
});
|
||||
loadAny<T extends Asset>(bundleName: string | string[], paths: string[] | ProgressCallback, onProgress?: ProgressCallback | CompleteCallback, onComplete?: CompleteCallback): void {
|
||||
let args: ILoadResArgs<T> | 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<T extends Asset>(bundleName: string, dir: string, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
loadDir<T extends Asset>(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<T extends Asset>(
|
||||
paths: Paths,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
onProgress?: AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
onComplete?: ProgressCallback | CompleteCallback
|
||||
) {
|
||||
private parseLoadResArgs<T extends Asset>(paths: Paths, type?: AssetType<T> | ProgressCallback | CompleteCallback, onProgress?: AssetType<T> | 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<T extends Asset>(args: ILoadResArgs<T>) {
|
||||
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();
|
||||
@@ -17,14 +17,11 @@ export class ZipLoader {
|
||||
* @returns
|
||||
*/
|
||||
static load(url: string): Promise<JSZip> {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
// 手动内存管理
|
||||
|
||||
@@ -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<Node> {
|
||||
add(prefab: string, config: GameElementConfig = {}): Promise<Node> {
|
||||
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<Node> {
|
||||
addPool(prefab: string, config: GameElementConfig = {}): Promise<Node> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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": []
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
// }
|
||||
// }
|
||||
@@ -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<void> {
|
||||
static loadDir(): Promise<void> {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ export class ViewUtil {
|
||||
*/
|
||||
static createPrefabNodeAsync(path: string, bundleName: string = resLoader.defaultBundleName): Promise<Node> {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -73,7 +73,7 @@ export class LanguagePack {
|
||||
private loadJson(lang: string): Promise<void> {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
9
assets/libs/gui/window.meta
Normal file
9
assets/libs/gui/window.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "26bbcb1a-b407-4d25-b9e9-8676f614312a",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
89
assets/libs/gui/window/PromptBase.ts
Normal file
89
assets/libs/gui/window/PromptBase.ts
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
9
assets/libs/gui/window/PromptBase.ts.meta
Normal file
9
assets/libs/gui/window/PromptBase.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "62d1c492-8247-4e77-8216-462f64c6a296",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
47
assets/libs/gui/window/PromptSkip.ts
Normal file
47
assets/libs/gui/window/PromptSkip.ts
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
9
assets/libs/gui/window/PromptSkip.ts.meta
Normal file
9
assets/libs/gui/window/PromptSkip.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ae0c193b-a70c-474f-8e66-eeb20024039e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export class JsonOb<T> {
|
||||
|
||||
private _callback;
|
||||
|
||||
/**对象属性劫持 */
|
||||
/** 对象属性劫持 */
|
||||
private observe<T>(obj: T, path?: any) {
|
||||
if (OP.toString.call(obj) === types.array) {
|
||||
this.overrideArrayProto(obj, path);
|
||||
@@ -55,7 +55,7 @@ export class JsonOb<T> {
|
||||
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<T> {
|
||||
})
|
||||
|
||||
// @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<T> {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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}},并且自动设置监听的路径'
|
||||
})
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -61,12 +61,12 @@ class ViewModel<T> {
|
||||
|
||||
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);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T extends ecs.Comp> = __private.__types_globals__Constructor<T> | __private.__types_globals__AbstractedConstructor<T>;
|
||||
export type ECSView = CCViewVM<CCEntity> | CCView<CCEntity>;
|
||||
@@ -20,21 +21,39 @@ export abstract class CCEntity extends ecs.Entity {
|
||||
/** 单例子实体 */
|
||||
private singletons: Map<any, ECSEntity> = null!;
|
||||
|
||||
/** 添加单例子实体 */
|
||||
addChildSingleton<T>(cls: any): T {
|
||||
/**
|
||||
* 批量添加单例子实体
|
||||
* @param clss 单例子实体类数组
|
||||
*/
|
||||
addChildSingletons<T extends CCEntity>(...clss: any[]) {
|
||||
for (let ctor of clss) {
|
||||
this.addChildSingleton<T>(ctor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加单例子实体
|
||||
* @param cls 单例子实体类
|
||||
* @returns 单例子实体
|
||||
*/
|
||||
addChildSingleton<T extends CCEntity>(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<T>(cls);
|
||||
this.singletons.set(cls, entity);
|
||||
this.addChild(entity);
|
||||
return entity as T;
|
||||
}
|
||||
|
||||
/** 获取单例子实体 */
|
||||
getChildSingleton<T>(cls: any): T {
|
||||
/**
|
||||
* 获取单例子实体
|
||||
* @param cls 单例子实体类
|
||||
* @returns 单例子实体
|
||||
*/
|
||||
getChildSingleton<T extends CCEntity>(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<T extends ECSView>(ctor: ECSCtor<T>, 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<T extends ECSView>(ctor: ECSCtor<T>, parent: Node | GameComponent, path: string, bundleName: string = resLoader.defaultBundleName): Promise<Node> {
|
||||
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<T extends CCBusiness<CCEntity>>(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
|
||||
|
||||
|
||||
@@ -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<Node> {
|
||||
createPrefabNode(path: string, bundleName: string = oops.res.defaultBundleName): Promise<Node> {
|
||||
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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, type: AssetType<T>, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, onProgress: ProgressCallback, onComplete: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(paths: Paths, type: AssetType<T>, onComplete?: CompleteCallback): void;
|
||||
load<T extends Asset>(
|
||||
bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
onProgress?: ProgressCallback | CompleteCallback,
|
||||
onComplete?: CompleteCallback,
|
||||
) {
|
||||
load<T extends Asset>(bundleName: string, paths: Paths | AssetType<T>, type?: AssetType<T>) {
|
||||
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<T extends Asset>(bundleName: string, paths: Paths, type: AssetType<T>): Promise<T>;
|
||||
loadAsync<T extends Asset>(bundleName: string, paths: Paths): Promise<T>;
|
||||
loadAsync<T extends Asset>(paths: Paths, type: AssetType<T>): Promise<T>;
|
||||
loadAsync<T extends Asset>(paths: Paths): Promise<T>;
|
||||
loadAsync<T extends Asset>(bundleName: string,
|
||||
paths?: Paths | AssetType<T> | ProgressCallback | CompleteCallback,
|
||||
type?: AssetType<T> | ProgressCallback | CompleteCallback): Promise<T> {
|
||||
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<AudioEffect> {
|
||||
playEffect(url: string, params?: IAudioParams): Promise<AudioEffect> {
|
||||
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
|
||||
|
||||
7
assets/module/common/GameStorage.ts
Normal file
7
assets/module/common/GameStorage.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/** 框架内本地存储键值 */
|
||||
export enum GameStorage {
|
||||
/** 设置音频音量、开关 */
|
||||
Audio = "OopsFrameworkAudio",
|
||||
/** 可设置指定时间内跳过提示 */
|
||||
PromptSkip = "OopsFrameworkPromptSkip",
|
||||
}
|
||||
9
assets/module/common/GameStorage.ts.meta
Normal file
9
assets/module/common/GameStorage.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7cefb56b-a388-4cd0-9952-209b7554c044",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -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<void> {
|
||||
export function createView(directoryPath: string, fileName: string, content: string, moduleName: string, isEcsComp: boolean = true): Promise<void> {
|
||||
return new Promise<void>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<ecs.Comp>();
|
||||
// this.addComponents();
|
||||
}
|
||||
}`;
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}`;
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}`
|
||||
Reference in New Issue
Block a user