first commit
This commit is contained in:
16
extensions/app/README-CN.md
Executable file
16
extensions/app/README-CN.md
Executable file
@@ -0,0 +1,16 @@
|
||||
# 项目简介
|
||||
|
||||
框架核心。
|
||||
|
||||
## 开发环境
|
||||
|
||||
Node.js
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 安装依赖模块
|
||||
npm install
|
||||
# 构建
|
||||
npm run build
|
||||
```
|
||||
16
extensions/app/README-EN.md
Executable file
16
extensions/app/README-EN.md
Executable file
@@ -0,0 +1,16 @@
|
||||
# Project Title
|
||||
|
||||
The core of the framework
|
||||
|
||||
## Development Environment
|
||||
|
||||
Node.js
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# Install dependent modules
|
||||
npm install
|
||||
# build
|
||||
npm run build
|
||||
```
|
||||
142
extensions/app/assets/Core.ts
Normal file
142
extensions/app/assets/Core.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { Component, Director, director, EventTarget, js } from 'cc';
|
||||
import { DEV, EDITOR } from 'cc/env';
|
||||
import * as debug from './lib/debug/debug';
|
||||
import logger from './lib/logger/logger';
|
||||
import storage from './lib/storage/storage';
|
||||
import task from './lib/task/task';
|
||||
import EventManager from './manager/event/EventManager';
|
||||
import LoaderManager from './manager/loader/LoaderManager';
|
||||
import SoundManager from './manager/sound/SoundManager';
|
||||
import TimerManager from './manager/timer/TimerManager';
|
||||
import UIManager from './manager/ui/UIManager';
|
||||
|
||||
enum EventType {
|
||||
/**AppInit准备完毕 */
|
||||
EVENT_APPINIT_FINISHED = 'EVENT_APPINIT_FINISHED',
|
||||
/**系统Manager初始化完毕 */
|
||||
EVENT_SYS_MANAGER_INITED = 'EVENT_SYS_MANAGER_INITED',
|
||||
/**用户Manager初始化完毕 */
|
||||
EVENT_USER_MANAGER_INITED = 'EVENT_USER_MANAGER_INITED',
|
||||
/**所有Manager初始化完毕 */
|
||||
EVENT_MANAGER_INITED = 'EVENT_MANAGER_INITED',
|
||||
/**所有Manager准备完毕 */
|
||||
EVENT_MANAGER_FINISHED = 'EVENT_MANAGER_FINISHED'
|
||||
}
|
||||
|
||||
type IData = { [key in string]: any };
|
||||
type IConfig = { [key in string]: any };
|
||||
type IStore = { [key in string]: any };
|
||||
type ICtrl = { [key in string]: any };
|
||||
|
||||
interface ITypeofManager {
|
||||
Loader: Omit<typeof LoaderManager, keyof Component>,
|
||||
Event: Omit<typeof EventManager, keyof Component>,
|
||||
Sound: Omit<typeof SoundManager, keyof Component>,
|
||||
Timer: Omit<typeof TimerManager, keyof Component>,
|
||||
UI: Omit<typeof UIManager, keyof Component>
|
||||
}
|
||||
|
||||
interface IManager {
|
||||
loader: Omit<LoaderManager, keyof Component>,
|
||||
event: Omit<EventManager, keyof Component>,
|
||||
sound: Omit<SoundManager<any, any>, keyof Component>,
|
||||
timer: Omit<TimerManager, keyof Component>,
|
||||
ui: Omit<UIManager<any, any>, keyof Component>
|
||||
}
|
||||
|
||||
interface ICore {
|
||||
data: IData,
|
||||
config: IConfig,
|
||||
store: IStore,
|
||||
controller: ICtrl,
|
||||
Controller: ICtrl,
|
||||
manager: IManager,
|
||||
Manager: ITypeofManager
|
||||
}
|
||||
|
||||
const Lib = { task, storage, debug, logger };
|
||||
const Config = {};
|
||||
const Data = {};
|
||||
const Store = {};
|
||||
const controller = {};
|
||||
const Controller = {};
|
||||
const Manager = {};
|
||||
const manager = {};
|
||||
|
||||
const eventTarget = new EventTarget();
|
||||
let EventMap = {};
|
||||
|
||||
director.on(Director.EVENT_RESET, () => {
|
||||
js.clear(Config);
|
||||
js.clear(Data);
|
||||
js.clear(Store);
|
||||
js.clear(controller);
|
||||
js.clear(Controller);
|
||||
js.clear(Manager);
|
||||
js.clear(manager);
|
||||
|
||||
EventMap = {};
|
||||
});
|
||||
|
||||
export default class Core<T extends ICore> {
|
||||
static EventType = EventType;
|
||||
|
||||
protected static _inst: Core<ICore> | undefined;
|
||||
static get inst() {
|
||||
if (!this._inst) this._inst = new Core();
|
||||
return this._inst;
|
||||
}
|
||||
|
||||
lib = Lib;
|
||||
config: T['config'] = null;
|
||||
data: T['data'] = null;
|
||||
store: T['store'] = null;
|
||||
Controller: T['Controller'] = null;
|
||||
controller: T['controller'] = null;
|
||||
Manager: T['Manager'] = null;
|
||||
manager: T['manager'] = null;
|
||||
|
||||
constructor() {
|
||||
this.config = Config;
|
||||
this.data = Data;
|
||||
this.store = Store;
|
||||
this.Controller = Controller;
|
||||
this.controller = controller;
|
||||
this.Manager = Manager as any;
|
||||
this.manager = manager as any;
|
||||
if (!EDITOR || DEV) {
|
||||
if (this.constructor !== Core && !js.getClassById('App')) {
|
||||
js.setClassAlias(this.constructor as any, 'App');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
on(event: keyof typeof EventType, callback: (...any: any[]) => void, target?: any): any {
|
||||
if (EventMap[event]) callback.call(target);
|
||||
eventTarget.on(event, callback, target);
|
||||
}
|
||||
|
||||
once(event: keyof typeof EventType, callback: Function, target?: any): any {
|
||||
if (EventMap[event]) {
|
||||
callback.call(target);
|
||||
} else {
|
||||
eventTarget.once(event, callback as any, target);
|
||||
}
|
||||
}
|
||||
|
||||
off(event: keyof typeof EventType, callback: (...any: any[]) => void, target?: any): any {
|
||||
eventTarget.off(event, callback, target);
|
||||
}
|
||||
|
||||
targetOff(target: any) {
|
||||
eventTarget.targetOff(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请不要手动调用
|
||||
*/
|
||||
static emit(event: keyof typeof EventType, ...args: any[]): any {
|
||||
EventMap[event] = true;
|
||||
eventTarget.emit(event, ...args);
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/Core.ts.meta
Normal file
9
extensions/app/assets/Core.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b4a49372-fa9e-4448-b91b-29bc9701d9ff",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
extensions/app/assets/app.ts.meta
Normal file
9
extensions/app/assets/app.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0ceacfb9-e86a-4e83-bd5d-15a4a27185c8",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/base.meta
Normal file
12
extensions/app/assets/base.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "2fb050e0-159f-4a3b-b24c-3d76e43ac54d",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
275
extensions/app/assets/base/BaseAppInit.ts
Normal file
275
extensions/app/assets/base/BaseAppInit.ts
Normal file
@@ -0,0 +1,275 @@
|
||||
import { Button, Component, EventTouch, Node, Settings, _decorator, assetManager, isValid, settings, warn } from 'cc';
|
||||
import { EDITOR } from 'cc/env';
|
||||
import Core from '../Core';
|
||||
import BaseManager from './BaseManager';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
const AdminBundleName = 'app-admin';
|
||||
const ModelBundleName = 'app-model';
|
||||
const ControlBundleName = 'app-control';
|
||||
const ControllerBundleName = 'app-controller';
|
||||
const ManagerBundleName = 'app-manager';
|
||||
const DontRewriteFuns = ['startInit', 'nextInit'];
|
||||
|
||||
@ccclass('BaseAppInit')
|
||||
export default abstract class BaseAppInit extends Component {
|
||||
private get _base_mgr_total() {
|
||||
return Math.max(0, BaseManager.getTotalAssetNum(assetManager.getBundle(ManagerBundleName)));
|
||||
}
|
||||
private get _base_user_total() {
|
||||
return Math.max(0, this.getUserAssetNum());
|
||||
}
|
||||
private get _base_total() {
|
||||
return this._base_mgr_total + this._base_user_total;
|
||||
}
|
||||
|
||||
private _base_mgr_completed = 0;
|
||||
private _base_user_completed = 0;
|
||||
private get _base_completed() {
|
||||
return this._base_mgr_completed + Math.min(this._base_user_total, this._base_user_completed);
|
||||
}
|
||||
|
||||
private _base_inited = false;
|
||||
private _base_finished = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (EDITOR) {
|
||||
DontRewriteFuns.forEach((funName) => {
|
||||
if (BaseAppInit.prototype[funName] !== this[funName]) {
|
||||
warn(`[AppInit] 不应该重写父类方法{${funName}}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [避免重写] 开始初始化
|
||||
*/
|
||||
protected startInit() {
|
||||
const projectBundles = settings.querySettings(Settings.Category.ASSETS, 'projectBundles') as string[];
|
||||
Core.inst.lib.task.createAny()
|
||||
// 预加载control、model、admin、manager
|
||||
.add([
|
||||
(next, retry) => {
|
||||
// 预加载control(废弃)
|
||||
if (projectBundles.indexOf(ControlBundleName) === -1) return next();
|
||||
assetManager.preloadAny({ url: ControlBundleName }, { ext: 'bundle' }, null, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next, retry) => {
|
||||
// 预加载controller
|
||||
if (projectBundles.indexOf(ControllerBundleName) === -1) return next();
|
||||
assetManager.preloadAny({ url: ControllerBundleName }, { ext: 'bundle' }, null, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next, retry) => {
|
||||
// 预加载model
|
||||
if (projectBundles.indexOf(ModelBundleName) === -1) return next();
|
||||
assetManager.preloadAny({ url: ModelBundleName }, { ext: 'bundle' }, null, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next, retry) => {
|
||||
// 预加载admin
|
||||
if (projectBundles.indexOf(AdminBundleName) === -1) return next();
|
||||
assetManager.preloadAny({ url: AdminBundleName }, { ext: 'bundle' }, null, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next, retry) => {
|
||||
// 预加载manage
|
||||
if (projectBundles.indexOf(ManagerBundleName) === -1) return next();
|
||||
assetManager.preloadAny({ url: ManagerBundleName }, { ext: 'bundle' }, null, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
}
|
||||
])
|
||||
// 加载control(废弃)
|
||||
.add((next, retry) => {
|
||||
if (projectBundles.indexOf(ControlBundleName) === -1) return next();
|
||||
assetManager.loadBundle(ControlBundleName, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
})
|
||||
// 加载controller
|
||||
.add((next, retry) => {
|
||||
if (projectBundles.indexOf(ControllerBundleName) === -1) return next();
|
||||
assetManager.loadBundle(ControllerBundleName, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
})
|
||||
// 加载model
|
||||
.add((next, retry) => {
|
||||
if (projectBundles.indexOf(ModelBundleName) === -1) return next();
|
||||
assetManager.loadBundle(ModelBundleName, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
})
|
||||
// 加载admin
|
||||
.add((next, retry) => {
|
||||
if (projectBundles.indexOf(AdminBundleName) === -1) return next();
|
||||
assetManager.loadBundle(AdminBundleName, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
})
|
||||
// 加载manager
|
||||
.add((next, retry) => {
|
||||
if (projectBundles.indexOf(ManagerBundleName) === -1) return next();
|
||||
assetManager.loadBundle(ManagerBundleName, (err) => {
|
||||
if (err) return retry(0.1);
|
||||
next();
|
||||
});
|
||||
})
|
||||
.start(() => {
|
||||
this._base_inited = true;
|
||||
this.onProgress(0, this._base_total);
|
||||
|
||||
// 初始化app, 使用complete来实现onUserInit的切换以确保manager已完全加载
|
||||
BaseManager.init(
|
||||
assetManager.getBundle(ManagerBundleName),
|
||||
() => {
|
||||
this.innerNextInit();
|
||||
},
|
||||
() => {
|
||||
this.onUserInit();
|
||||
if (this._base_completed < this._base_total) return;
|
||||
// 全部加载完成
|
||||
this.innerFinished();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [不可重写] 用于内部初始化完成
|
||||
*/
|
||||
private innerFinished() {
|
||||
if (this._base_finished) return;
|
||||
this._base_finished = true;
|
||||
Core.emit(Core.EventType.EVENT_APPINIT_FINISHED);
|
||||
// 默认音效(Button点击触发, 这个方案可以正常触发input事件)
|
||||
if (Core.inst.Manager.Sound.setting.defaultEffectName) {
|
||||
const playDefaultEffect = function (e: EventTouch) {
|
||||
// SoundManager.setButtonEffect会将Button所在节点的useDefaultEffect设为false
|
||||
if (e.target['useDefaultEffect'] === false) return;
|
||||
Core.inst.manager.ui.onceUserInterface(Node.EventType.TOUCH_END, function (event: EventTouch) {
|
||||
if (!event.target.getComponent(Button)) return;
|
||||
setTimeout(() => {
|
||||
if (!isValid(Core.inst.manager.sound)) return;
|
||||
// 如果是scrollView中的button,在滑动后不播放点击音效
|
||||
if (event.eventPhase === EventTouch.CAPTURING_PHASE) return;
|
||||
Core.inst.manager.sound.playDefaultEffect();
|
||||
});
|
||||
}, null, true);
|
||||
};
|
||||
const onEnable = Button.prototype.onEnable;
|
||||
Button.prototype.onEnable = function () {
|
||||
onEnable.call(this);
|
||||
this.node.on(Node.EventType.TOUCH_START, playDefaultEffect);
|
||||
};
|
||||
const onDisable = Button.prototype.onDisable;
|
||||
Button.prototype.onDisable = function () {
|
||||
this.node.off(Node.EventType.TOUCH_START, playDefaultEffect);
|
||||
onDisable.call(this);
|
||||
};
|
||||
}
|
||||
return Core.inst.manager.ui.showDefault(() => {
|
||||
// 初始化完成
|
||||
this.onFinish();
|
||||
// 默认音乐(默认播放)
|
||||
if (Core.inst.Manager.Sound.setting.defaultMusicName) {
|
||||
const onTouch = function () {
|
||||
if (!isValid(Core.inst.manager.sound)) return;
|
||||
if (Core.inst.manager.sound.isMusicPlaying && !Core.inst.manager.sound.isMusicPaused) {
|
||||
Core.inst.manager.sound.replayMusic(() => {
|
||||
Core.inst.manager.ui.offUserInterface(Node.EventType.TOUCH_START, onTouch, this, true);
|
||||
});
|
||||
} else {
|
||||
Core.inst.manager.ui.offUserInterface(Node.EventType.TOUCH_START, onTouch, this, true);
|
||||
}
|
||||
};
|
||||
Core.inst.manager.ui.onUserInterface(Node.EventType.TOUCH_START, onTouch, this, true);
|
||||
Core.inst.manager.sound.playDefaultMusic(() => {
|
||||
Core.inst.manager.ui.offUserInterface(Node.EventType.TOUCH_START, onTouch, this, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [不可重写] 用于内部初始化
|
||||
*/
|
||||
private innerNextInit() {
|
||||
// 完成+1
|
||||
this._base_mgr_completed += 1;
|
||||
// 进度回调
|
||||
this.onProgress(this._base_completed, this._base_total);
|
||||
}
|
||||
|
||||
/**
|
||||
* [避免重写] 初始化下一步,用户部分每完成一步需要调用一次
|
||||
*/
|
||||
protected nextInit(): any {
|
||||
if (this._base_finished) return;
|
||||
|
||||
if (!this._base_inited) {
|
||||
// 完成+1
|
||||
this._base_user_completed += 1;
|
||||
// 进度回调
|
||||
this.onProgress(this._base_completed, this._base_total);
|
||||
return;
|
||||
}
|
||||
|
||||
// 完成+1
|
||||
this._base_user_completed += 1;
|
||||
// 进度回调
|
||||
this.onProgress(this._base_completed, this._base_total);
|
||||
|
||||
// 全部加载完成
|
||||
if (this._base_completed >= this._base_total) {
|
||||
this.innerFinished();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////// 以下可重写 ////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* [可以重写] 默认start调用startInit,可以重写后自定义时机
|
||||
*/
|
||||
protected start(): any { this.startInit(); }
|
||||
|
||||
/**
|
||||
* [可以重写] 获得用户资源总量,这里返回几,就需要用户自行调用几次nextInit
|
||||
*/
|
||||
protected getUserAssetNum(): number { return 0; }
|
||||
|
||||
/**
|
||||
* [可以重写] 用户初始化函数,会在框架初始化完成后调用
|
||||
*/
|
||||
protected onUserInit(): any { return 0; }
|
||||
|
||||
/**
|
||||
* [可以重写] 监听进度
|
||||
* @param {Number} completed
|
||||
* @param {Number} total
|
||||
*/
|
||||
protected onProgress(completed: number, total: number): any { return completed / total; }
|
||||
|
||||
/**
|
||||
* [可以重写] 初始化完成
|
||||
*/
|
||||
protected onFinish() { }
|
||||
}
|
||||
9
extensions/app/assets/base/BaseAppInit.ts.meta
Normal file
9
extensions/app/assets/base/BaseAppInit.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2110b07a-1c6c-430e-b9d9-926db06c8b30",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
179
extensions/app/assets/base/BaseControl.ts
Normal file
179
extensions/app/assets/base/BaseControl.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
class CallbackInfo {
|
||||
public callback: Function = null;
|
||||
public target: unknown = null;
|
||||
public once = false;
|
||||
|
||||
public constructor(callback: Function, target: unknown = null, once: boolean = false) {
|
||||
this.callback = callback;
|
||||
this.target = target;
|
||||
this.once = once;
|
||||
}
|
||||
}
|
||||
|
||||
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : any;
|
||||
type AnyFunc = (...args: any[]) => any;
|
||||
|
||||
class CallbackList {
|
||||
private callbacks: CallbackInfo[] = [];
|
||||
|
||||
public size() {
|
||||
return this.callbacks.length;
|
||||
}
|
||||
|
||||
public add(callback: Function, target: unknown = null, once: boolean = false) {
|
||||
this.callbacks.push(new CallbackInfo(callback, target, once));
|
||||
}
|
||||
|
||||
public emit(args: any[]) {
|
||||
for (let index = 0; index < this.callbacks.length; index++) {
|
||||
const info = this.callbacks[index];
|
||||
// 先移除
|
||||
if (info.once) {
|
||||
this.callbacks.splice(index, 1);
|
||||
--index;
|
||||
}
|
||||
if (info.callback) {
|
||||
info.callback.apply(info.target, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public call(args: any[]) {
|
||||
if (this.callbacks.length === 0) return;
|
||||
const info = this.callbacks[0];
|
||||
|
||||
// 先移除
|
||||
if (info.once) this.callbacks.splice(0, 1);
|
||||
if (!info.callback) return;
|
||||
|
||||
return info.callback.apply(info.target, args);
|
||||
}
|
||||
|
||||
public remove(callback: Function, target: unknown = null) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.callback !== callback || info.target !== target) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public removeByCallback(callback: Function) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.callback !== callback) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public removeByTarget(target: unknown) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.target !== target) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EventEmitter {
|
||||
private listeners: { [key in string]: CallbackList } = {};
|
||||
|
||||
public on(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) this.listeners[event] = new CallbackList();
|
||||
this.listeners[event].add(cb, target);
|
||||
}
|
||||
|
||||
public once(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) this.listeners[event] = new CallbackList();
|
||||
this.listeners[event].add(cb, target, true);
|
||||
}
|
||||
|
||||
public off(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) return;
|
||||
|
||||
this.listeners[event].remove(cb, target);
|
||||
}
|
||||
|
||||
public targetOff(target?: unknown) {
|
||||
if (!target) return;
|
||||
|
||||
for (const key in this.listeners) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.listeners, key)) {
|
||||
const element = this.listeners[key];
|
||||
element.removeByTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public emit(event: string | number, args: any[]) {
|
||||
if (!event.toString()) return;
|
||||
if (!this.listeners[event]) return;
|
||||
this.listeners[event].emit(args);
|
||||
}
|
||||
|
||||
public call(event: string | number, args: any[]) {
|
||||
if (!event.toString()) return;
|
||||
if (!this.listeners[event]) return;
|
||||
return this.listeners[event].call(args);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBaseControl<C, E, T extends { [key in keyof E]?: AnyFunc }> {
|
||||
readonly inst: Readonly<C>
|
||||
|
||||
//用于类型提示推导////////////////
|
||||
new(): SuperBaseControl<E, T>//
|
||||
///////////////////////////////
|
||||
}
|
||||
|
||||
class SuperBaseControl<E, T extends { [key in keyof E]?: AnyFunc }> {
|
||||
//用于类型提示推导//
|
||||
private e: E;////
|
||||
private t: T;////
|
||||
/////////////////
|
||||
|
||||
private event = new EventEmitter();
|
||||
|
||||
protected call<K extends keyof E & keyof T>(key: E[K], ...args: Parameters<T[K]>): ReturnType<T[K]> {
|
||||
return this.event.call.call(this.event, key, args);
|
||||
}
|
||||
|
||||
protected emit<K extends keyof E & keyof T>(key: E[K], ...args: Parameters<T[K]>): void {
|
||||
return this.event.emit.call(this.event, key, args);
|
||||
}
|
||||
|
||||
private on(...args: any[]): void {
|
||||
return this.event.on.apply(this.event, args);
|
||||
}
|
||||
|
||||
private once(...args: any[]): void {
|
||||
return this.event.once.apply(this.event, args);
|
||||
}
|
||||
|
||||
private off(...args: any[]): void {
|
||||
return this.event.off.apply(this.event, args);
|
||||
}
|
||||
|
||||
private targetOff(target: any): void {
|
||||
return this.event.targetOff.call(this.event, target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 废弃,请使用Controller代替Control
|
||||
*/
|
||||
export default function BaseControl<C, E = any, T extends { [key in keyof E & string]?: AnyFunc } = any>(Event?: E) {
|
||||
return class BaseControl extends SuperBaseControl<E, T> {
|
||||
public static Event = Event;
|
||||
|
||||
private static _base_inst: Readonly<C> = null;
|
||||
public static get inst() {
|
||||
if (this._base_inst === null) {
|
||||
this._base_inst = new this() as C;
|
||||
}
|
||||
return this._base_inst;
|
||||
}
|
||||
};
|
||||
}
|
||||
9
extensions/app/assets/base/BaseControl.ts.meta
Normal file
9
extensions/app/assets/base/BaseControl.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "fb1039b9-17f2-43b5-ad26-8d74e691b4f5",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
211
extensions/app/assets/base/BaseController.ts
Normal file
211
extensions/app/assets/base/BaseController.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import { DEV } from 'cc/env';
|
||||
import { IReadOnly } from '../../../../assets/app-builtin/app-admin/executor';
|
||||
import { Logger } from '../lib/logger/logger';
|
||||
|
||||
class CallbackInfo {
|
||||
public callback: Function = null;
|
||||
public target: unknown = null;
|
||||
public once = false;
|
||||
|
||||
public constructor(callback: Function, target: unknown = null, once: boolean = false) {
|
||||
this.callback = callback;
|
||||
this.target = target;
|
||||
this.once = once;
|
||||
}
|
||||
}
|
||||
|
||||
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : any;
|
||||
type AnyFunc = (...args: any[]) => any;
|
||||
|
||||
class CallbackList {
|
||||
private callbacks: CallbackInfo[] = [];
|
||||
|
||||
public size() {
|
||||
return this.callbacks.length;
|
||||
}
|
||||
|
||||
public add(callback: Function, target: unknown = null, once: boolean = false) {
|
||||
this.callbacks.push(new CallbackInfo(callback, target, once));
|
||||
}
|
||||
|
||||
public emit(args: any[]) {
|
||||
for (let index = 0; index < this.callbacks.length; index++) {
|
||||
const info = this.callbacks[index];
|
||||
// 先移除
|
||||
if (info.once) {
|
||||
this.callbacks.splice(index, 1);
|
||||
--index;
|
||||
}
|
||||
if (info.callback) {
|
||||
info.callback.apply(info.target, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public call(args: any[]) {
|
||||
if (this.callbacks.length === 0) return;
|
||||
const info = this.callbacks[0];
|
||||
|
||||
// 先移除
|
||||
if (info.once) this.callbacks.splice(0, 1);
|
||||
if (!info.callback) return;
|
||||
|
||||
return info.callback.apply(info.target, args);
|
||||
}
|
||||
|
||||
public remove(callback: Function, target: unknown = null) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.callback !== callback || info.target !== target) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public removeByCallback(callback: Function) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.callback !== callback) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public removeByTarget(target: unknown) {
|
||||
for (let index = this.callbacks.length - 1; index >= 0; index--) {
|
||||
const info = this.callbacks[index];
|
||||
if (info.target !== target) continue;
|
||||
this.callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EventEmitter {
|
||||
private listeners: { [key in string]: CallbackList } = {};
|
||||
|
||||
public on(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) this.listeners[event] = new CallbackList();
|
||||
this.listeners[event].add(cb, target);
|
||||
}
|
||||
|
||||
public once(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) this.listeners[event] = new CallbackList();
|
||||
this.listeners[event].add(cb, target, true);
|
||||
}
|
||||
|
||||
public off(event: string | number, cb: (...data: any[]) => void, target?: unknown) {
|
||||
if (!event.toString() || !cb) return;
|
||||
if (!this.listeners[event]) return;
|
||||
|
||||
this.listeners[event].remove(cb, target);
|
||||
}
|
||||
|
||||
public targetOff(target?: unknown) {
|
||||
if (!target) return;
|
||||
|
||||
for (const key in this.listeners) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.listeners, key)) {
|
||||
const element = this.listeners[key];
|
||||
element.removeByTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public emit(event: string | number, args: any[]) {
|
||||
if (!event.toString()) return;
|
||||
if (!this.listeners[event]) return;
|
||||
this.listeners[event].emit(args);
|
||||
}
|
||||
|
||||
public call(event: string | number, args: any[]) {
|
||||
if (!event.toString()) return;
|
||||
if (!this.listeners[event]) return;
|
||||
return this.listeners[event].call(args);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBaseController<C, T extends { [key in string]?: AnyFunc }> {
|
||||
readonly inst: Readonly<C>
|
||||
|
||||
//用于类型提示推导////////////////
|
||||
new(): SuperBaseController<T>//
|
||||
///////////////////////////////
|
||||
}
|
||||
|
||||
class SuperBaseController<T extends { [key in string]?: AnyFunc }> {
|
||||
//用于类型提示推导//
|
||||
private t: T;////
|
||||
/////////////////
|
||||
|
||||
private event = new EventEmitter();
|
||||
|
||||
/**获取第一个事件回调的返回值 */
|
||||
protected call<K extends keyof T>(key: K, ...args: Parameters<T[K]>): ReturnType<T[K]> {
|
||||
return this.event.call.call(this.event, key, args);
|
||||
}
|
||||
|
||||
/**发射事件 */
|
||||
protected emit<K extends keyof T>(key: K, ...args: Parameters<T[K]>): void {
|
||||
return this.event.emit.call(this.event, key, args);
|
||||
}
|
||||
|
||||
private on(...args: any[]): void {
|
||||
return this.event.on.apply(this.event, args);
|
||||
}
|
||||
|
||||
private once(...args: any[]): void {
|
||||
return this.event.once.apply(this.event, args);
|
||||
}
|
||||
|
||||
private off(...args: any[]): void {
|
||||
return this.event.off.apply(this.event, args);
|
||||
}
|
||||
|
||||
private targetOff(target: any): void {
|
||||
return this.event.targetOff.call(this.event, target);
|
||||
}
|
||||
|
||||
/**打印日志 */
|
||||
protected get log(): Function {
|
||||
return Logger.create('log', '#4682b4', DEV ? `[${this['constructor'].name}] LOG` : `[${this['constructor'].name}] [LOG]`);
|
||||
}
|
||||
|
||||
/**打印警告 */
|
||||
protected get warn(): Function {
|
||||
return Logger.create('warn', '#ff7f50', DEV ? `[${this['constructor'].name}] WARN` : `[${this['constructor'].name}] [WARN]`);
|
||||
}
|
||||
|
||||
/**打印错误 */
|
||||
protected get error(): Function {
|
||||
return Logger.create('error', '#ff4757', DEV ? `[${this['constructor'].name}] ERROR` : `[${this['constructor'].name}] [ERROR]`);
|
||||
}
|
||||
}
|
||||
|
||||
export default function BaseController<C, T extends { [key in string]?: AnyFunc } = any>() {
|
||||
return class BaseController extends SuperBaseController<T> {
|
||||
/**
|
||||
* 控制器事件
|
||||
*/
|
||||
public static Event: { [key in keyof T]: key } = new Proxy({} as any, {
|
||||
get: function (target, key) {
|
||||
if (target[key]) return target[key];
|
||||
target[key] = key;
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
private static _base_inst: IReadOnly<C> = null;
|
||||
/**
|
||||
* 控制器单例
|
||||
* - 尽量使用app.controller,可以避免因跨Bundle引用导致的问题,也可以避免Controller之间循环引用的问题
|
||||
*/
|
||||
public static get inst() {
|
||||
return this._base_inst;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
BaseController._base_inst = this as any;
|
||||
}
|
||||
};
|
||||
}
|
||||
9
extensions/app/assets/base/BaseController.ts.meta
Normal file
9
extensions/app/assets/base/BaseController.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a7da7081-e604-487e-8e0c-7d458fdbb356",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
359
extensions/app/assets/base/BaseManager.ts
Normal file
359
extensions/app/assets/base/BaseManager.ts
Normal file
@@ -0,0 +1,359 @@
|
||||
import { AssetManager, Component, EventTarget, Prefab, Widget, _decorator, error, instantiate, js, path, warn } from 'cc';
|
||||
import { DEBUG, DEV, EDITOR } from 'cc/env';
|
||||
import Core from '../Core';
|
||||
import { Logger } from '../lib/logger/logger';
|
||||
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
const UserManagerPath = 'UserManager';
|
||||
const DontRewriteFuns = ['emit', 'on', 'once', 'off', 'targetOff'];
|
||||
|
||||
const uuid = new class UUID {
|
||||
private index = 0;
|
||||
|
||||
public create(): string {
|
||||
if (this.index++ > 10000000) {
|
||||
this.index = 0;
|
||||
}
|
||||
return `${Date.now()}-${this.index}`;
|
||||
}
|
||||
};
|
||||
|
||||
const loadBegin = Logger.create('log', '#32cd32', DEV ? '[BaseManager] 下载开始' : '[BaseManager] [下载开始]');
|
||||
|
||||
const loadFinish = Logger.create('log', '#00ae9d', DEV ? '[BaseManager] 下载完成' : '[BaseManager] [下载完成]');
|
||||
|
||||
const loadError = Logger.create('log', '#ff4757', DEV ? '[BaseManager] 下载失败' : '[BaseManager] [下载失败]');
|
||||
|
||||
const initBegin = Logger.create('log', '#3e4145', DEV ? '[BaseManager] 初始化开始' : '[BaseManager] [初始化开始]');
|
||||
|
||||
const initFinish = Logger.create('log', '#008080', DEV ? '[BaseManager] 初始化完成' : '[BaseManager] [初始化完成]');
|
||||
|
||||
@ccclass('BaseManager')
|
||||
export default class BaseManager extends Component {
|
||||
// 事件管理器
|
||||
private _base_event: EventTarget = new EventTarget();
|
||||
|
||||
// manager名字
|
||||
private _base_manager_name: string = js.getClassName(this);
|
||||
public get managerName() {
|
||||
return this._base_manager_name;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (EDITOR) {
|
||||
DontRewriteFuns.forEach((funName) => {
|
||||
if (BaseManager.prototype[funName] !== this[funName]) {
|
||||
warn(`[${this._base_manager_name}] 不应该重写父类方法{${funName}}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this._base_manager_name !== 'Manager' && this._base_manager_name.slice(-7) === 'Manager') {
|
||||
const managerName = this._base_manager_name.slice(0, - 7);
|
||||
Core.inst.Manager[managerName] = this.constructor;
|
||||
Core.inst.manager[managerName.toLowerCase()] = this;
|
||||
} else if (EDITOR) {
|
||||
error(`[${this._base_manager_name}] manager命名错误(应为 xxxxManager 以Manager结尾)`);
|
||||
} else if (DEBUG) {
|
||||
error(`[${this._base_manager_name}] manager命名错误(应为 xxxxManager 以Manager结尾)`);
|
||||
}
|
||||
}
|
||||
|
||||
// 用来初始化组件或节点的一些属性,当该组件被第一次添加到节点上或用户点击了它的 Reset 菜单时调用。这个回调只会在编辑器下调用。
|
||||
resetInEditor() {
|
||||
const widget = this.node.getComponent(Widget) || this.node.addComponent(Widget);
|
||||
widget.isAlignBottom = true;
|
||||
widget.isAlignLeft = true;
|
||||
widget.isAlignRight = true;
|
||||
widget.isAlignTop = true;
|
||||
widget.top = 0;
|
||||
widget.left = 0;
|
||||
widget.right = 0;
|
||||
widget.bottom = 0;
|
||||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* [无序] 自身初始化完成, init执行完毕后被调用
|
||||
*/
|
||||
protected onInited() {
|
||||
}
|
||||
|
||||
/**
|
||||
* [无序] 所有manager初始化完成
|
||||
*/
|
||||
protected onFinished() {
|
||||
}
|
||||
|
||||
/**
|
||||
* [无序] 初始化manager,在初始化完成后,调用finish方法
|
||||
* @param {Function} finish
|
||||
*/
|
||||
protected init(finish?: Function) {
|
||||
finish && finish();
|
||||
}
|
||||
|
||||
protected createUUID() {
|
||||
return uuid.create();
|
||||
}
|
||||
|
||||
/**打印日志 */
|
||||
protected get log() {
|
||||
if (DEV) {
|
||||
return window.console.log.bind(window.console,
|
||||
'%c %s %c %s ',
|
||||
'background:#4169e1; padding: 2px; border-radius: 5px 0 0 5px; border: 1px solid #4169e1; color: #fff; font-weight: normal;',
|
||||
`[${this._base_manager_name}] LOG ${new Date().toLocaleString()}`,
|
||||
'background:#ffffff ; padding: 2px; border-radius: 0 5px 5px 0; border: 1px solid #4169e1; color: #4169e1; font-weight: normal;'
|
||||
);
|
||||
}
|
||||
return window.console.log.bind(window.console,
|
||||
`[${this._base_manager_name}] [LOG] [${new Date().toLocaleString()}]`,
|
||||
);
|
||||
}
|
||||
|
||||
/**打印警告 */
|
||||
protected get warn() {
|
||||
if (DEV) {
|
||||
return window.console.warn.bind(window.console,
|
||||
'%c %s %c %s ',
|
||||
'background:#ff7f50; padding: 2px; border-radius: 5px 0 0 5px; border: 1px solid #ff7f50; color: #fff; font-weight: normal;',
|
||||
`[${this._base_manager_name}] WARN ${new Date().toLocaleString()}`,
|
||||
'background:#ffffff ; padding: 2px; border-radius: 0 5px 5px 0; border: 1px solid #ff7f50; color: #ff7f50; font-weight: normal;'
|
||||
);
|
||||
}
|
||||
return window.console.warn.bind(window.console,
|
||||
`[${this._base_manager_name}] [WARN] [${new Date().toLocaleString()}]`,
|
||||
);
|
||||
}
|
||||
|
||||
/**打印错误 */
|
||||
protected get error() {
|
||||
if (DEV) {
|
||||
return window.console.error.bind(window.console,
|
||||
'%c %s %c %s ',
|
||||
'background:#ff4757; padding: 2px; border-radius: 5px 0 0 5px; border: 1px solid #ff4757; color: #fff; font-weight: normal;',
|
||||
`[${this._base_manager_name}] ERROR ${new Date().toLocaleString()}`,
|
||||
'background:#ffffff ; padding: 2px; border-radius: 0 5px 5px 0; border: 1px solid #ff4757; color: #ff4757; font-weight: normal;'
|
||||
);
|
||||
}
|
||||
return window.console.error.bind(window.console,
|
||||
`[${this._base_manager_name}] [ERROR] [${new Date().toLocaleString()}]`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* [系统内置] 事件分发
|
||||
*/
|
||||
public emit(event: string | number, ...data: any[]) {
|
||||
this._base_event.emit(event as any, ...data);
|
||||
}
|
||||
|
||||
/**
|
||||
* [系统内置] 事件监听
|
||||
*/
|
||||
public on(event: string | number, cb: (...any: any[]) => void, target?: any) {
|
||||
this._base_event.on(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* [系统内置] 事件监听
|
||||
*/
|
||||
public once(event: string | number, cb: (...any: any[]) => void, target?: any) {
|
||||
this._base_event.once(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* [系统内置] 事件移除监听
|
||||
*/
|
||||
public off(event: string | number, cb?: (...any: any[]) => void, target?: any) {
|
||||
this._base_event.off(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* [系统内置] 事件移除监听
|
||||
*/
|
||||
public targetOff(target: any) {
|
||||
this._base_event.targetOff(target);
|
||||
}
|
||||
|
||||
/***********************************静态***********************************/
|
||||
/**
|
||||
* 框架内置Manager的数量
|
||||
* @private
|
||||
*/
|
||||
public static get sysMgrCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得初始化资源的数量(包括sysMgrCount)
|
||||
* @private
|
||||
*/
|
||||
public static getTotalAssetNum(bundle: AssetManager.Bundle) {
|
||||
let count = this.sysMgrCount;
|
||||
|
||||
if (!bundle) return count;
|
||||
|
||||
const array = bundle.getDirWithPath('/', Prefab) as { uuid: string, path: string, ctor: Function }[];
|
||||
|
||||
array.forEach(function (item) {
|
||||
if (item.path.endsWith('Manager')) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得初始化资源的数量
|
||||
* @private
|
||||
*/
|
||||
public static getUserAssetUrls(bundle: AssetManager.Bundle) {
|
||||
const pathArr: string[] = [];
|
||||
|
||||
if (!bundle) return pathArr;
|
||||
|
||||
const array = bundle.getDirWithPath('/', Prefab) as { uuid: string, path: string, ctor: Function }[];
|
||||
|
||||
array.forEach(function (item) {
|
||||
if (item.path.endsWith('Manager')) {
|
||||
pathArr.push(item.path);
|
||||
}
|
||||
});
|
||||
|
||||
return pathArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态方法,初始化manager,该方法必须在场景初始化完毕之后调用
|
||||
* @private
|
||||
*/
|
||||
public static init(
|
||||
bundle: AssetManager.Bundle,
|
||||
progress: (completeAsset: Number, totalAsset: Number) => any,
|
||||
complete: (totalAsset: Number) => any) {
|
||||
const urls = this.getUserAssetUrls(bundle);
|
||||
|
||||
const totalAsset = urls.length + this.sysMgrCount;
|
||||
let completeAsset = 0;
|
||||
|
||||
const onProgress = function (next: Function, manager: BaseManager) {
|
||||
if (DEBUG) {
|
||||
const startTime = window?.performance?.now ? performance.now() : Date.now();
|
||||
initBegin(manager.managerName);
|
||||
return function () {
|
||||
manager.onInited();
|
||||
if (DEBUG) {
|
||||
const endTime = window?.performance?.now ? performance.now() : Date.now();
|
||||
initFinish(`${manager.managerName} 耗时:${(endTime - startTime).toFixed(6)} ms`);
|
||||
}
|
||||
progress && progress(++completeAsset, totalAsset);
|
||||
next();
|
||||
};
|
||||
}
|
||||
return function () {
|
||||
manager.onInited();
|
||||
progress && progress(++completeAsset, totalAsset);
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
// 用户manager(动态添加)
|
||||
const userMgrList: BaseManager[] = [];
|
||||
// 系统manager(静态内置)
|
||||
const sysMgrList: BaseManager[] = [Core.inst.manager.event, Core.inst.manager.timer, Core.inst.manager.loader, Core.inst.manager.ui, Core.inst.manager.sound] as any as BaseManager[];
|
||||
|
||||
// 初始化系统manager
|
||||
const initSysMgrTask = Core.inst.lib.task.createASync();
|
||||
sysMgrList.forEach(function (manager: BaseManager) {
|
||||
initSysMgrTask.add(function (next) {
|
||||
manager.init(onProgress(next, manager));
|
||||
});
|
||||
});
|
||||
|
||||
// 加载用户manager
|
||||
const loadUserMgrTask = Core.inst.lib.task.createASync();
|
||||
const UserManagerRoot = Core.inst.manager.ui.root.getChildByPath(UserManagerPath);
|
||||
urls.forEach(function (url) {
|
||||
loadUserMgrTask.add(function (next, retry) {
|
||||
if (DEBUG) {
|
||||
const managerName = path.basename(url);
|
||||
const startTime = window?.performance?.now ? performance.now() : Date.now();
|
||||
loadBegin(managerName);
|
||||
bundle.load(url, Prefab, function (err, prefab: Prefab) {
|
||||
if (err || !prefab) {
|
||||
loadError(managerName, '重试...');
|
||||
retry(1);
|
||||
} else {
|
||||
const endTime = window?.performance?.now ? performance.now() : Date.now();
|
||||
loadFinish(`${managerName} 耗时:${(endTime - startTime).toFixed(6)} ms`);
|
||||
const node = instantiate(prefab);
|
||||
node.parent = UserManagerRoot;
|
||||
node.active = true;
|
||||
userMgrList.push(node.getComponent(BaseManager));
|
||||
next();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
bundle.load(url, Prefab, function (err, prefab: Prefab) {
|
||||
if (err || !prefab) {
|
||||
loadError(path.basename(url), '重试...');
|
||||
retry(1);
|
||||
} else {
|
||||
const node = instantiate(prefab);
|
||||
node.parent = UserManagerRoot;
|
||||
node.active = true;
|
||||
userMgrList.push(node.getComponent(BaseManager));
|
||||
next();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Core.inst.lib.task.createAny()
|
||||
.add([
|
||||
next => initSysMgrTask.start(next),
|
||||
next => loadUserMgrTask.start(next),
|
||||
])
|
||||
.add(function (next) {
|
||||
Core.emit(Core.EventType.EVENT_SYS_MANAGER_INITED);
|
||||
next();
|
||||
})
|
||||
.add(function (next) {
|
||||
// 初始化用户manager
|
||||
const initUserMgrTask = Core.inst.lib.task.createASync();
|
||||
userMgrList.forEach(manager => {
|
||||
initUserMgrTask.add(function (next) {
|
||||
manager.init(onProgress(next, manager));
|
||||
});
|
||||
});
|
||||
initUserMgrTask.start(next);
|
||||
})
|
||||
.add(function (next) {
|
||||
Core.emit(Core.EventType.EVENT_USER_MANAGER_INITED);
|
||||
Core.emit(Core.EventType.EVENT_MANAGER_INITED);
|
||||
next();
|
||||
})
|
||||
.add(function (next) {
|
||||
// 所有manager初始化完成后,触发回调
|
||||
sysMgrList.forEach(function (manager) {
|
||||
manager.onFinished();
|
||||
});
|
||||
userMgrList.forEach(function (manager) {
|
||||
manager.onFinished();
|
||||
});
|
||||
next();
|
||||
})
|
||||
.start(function () {
|
||||
Core.emit(Core.EventType.EVENT_MANAGER_FINISHED);
|
||||
complete && complete(totalAsset);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
9
extensions/app/assets/base/BaseManager.ts.meta
Normal file
9
extensions/app/assets/base/BaseManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "30205eac-9b1e-4f44-8081-7b70ff8d6c52",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
43
extensions/app/assets/base/BaseModel.ts
Normal file
43
extensions/app/assets/base/BaseModel.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// export type IModel<T> = {
|
||||
// [P in keyof T]: T[P] extends Function
|
||||
// ? '❌此处不能定义任何方法'
|
||||
// : (
|
||||
// T[P] extends Array<infer R>
|
||||
// ? (
|
||||
// R extends Function
|
||||
// ? '❌此处不能定义任何方法'
|
||||
// : T[P]
|
||||
// )
|
||||
// : T[P] // IModel<T[P]> 性能消耗大
|
||||
// );
|
||||
// };
|
||||
|
||||
// export type IStore<T> = {
|
||||
// [P in keyof T]: T[P] extends Function
|
||||
// ? T[P]
|
||||
// : (
|
||||
// T[P] extends Array<infer R>
|
||||
// ? (
|
||||
// R extends Function
|
||||
// ? '❌此处不能定义任何方法'
|
||||
// : IModel<T[P]>
|
||||
// )
|
||||
// : IModel<T[P]>
|
||||
// );
|
||||
// };
|
||||
|
||||
export type IModel<T> = {
|
||||
[P in keyof T]: T[P] extends Function
|
||||
? '❌此处不能定义任何方法'
|
||||
: T[P];
|
||||
};
|
||||
|
||||
// export type IStore<T> = {
|
||||
// [P in keyof T]: T[P] extends Function
|
||||
// ? T[P]
|
||||
// : IModel<T[P]>;
|
||||
// };
|
||||
|
||||
export type IStore<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
};
|
||||
9
extensions/app/assets/base/BaseModel.ts.meta
Normal file
9
extensions/app/assets/base/BaseModel.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7a377ceb-e086-4e71-99bd-f44dab40d24f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
1035
extensions/app/assets/base/BaseView.ts
Normal file
1035
extensions/app/assets/base/BaseView.ts
Normal file
@@ -0,0 +1,1035 @@
|
||||
import { Asset, Component, Enum, EventTouch, Font, Label, Node, Scene, Sprite, SpriteFrame, UITransform, Widget, _decorator, director, isValid, js, sp } from 'cc';
|
||||
import { DEV, EDITOR } from 'cc/env';
|
||||
import { IMiniViewName, IMiniViewNames, IViewName } from '../../../../assets/app-builtin/app-admin/executor';
|
||||
import Core from '../Core';
|
||||
import { Logger } from '../lib/logger/logger';
|
||||
import { IBaseControl } from './BaseControl';
|
||||
import { IBaseController } from './BaseController';
|
||||
|
||||
const { ccclass, property, disallowMultiple } = _decorator;
|
||||
|
||||
const BlockEvents = [
|
||||
Node.EventType.TOUCH_START, Node.EventType.TOUCH_MOVE, Node.EventType.TOUCH_END, Node.EventType.TOUCH_CANCEL,
|
||||
Node.EventType.MOUSE_DOWN, Node.EventType.MOUSE_MOVE, Node.EventType.MOUSE_UP,
|
||||
Node.EventType.MOUSE_ENTER, Node.EventType.MOUSE_LEAVE, Node.EventType.MOUSE_WHEEL
|
||||
];
|
||||
|
||||
const HideEvent = Enum({
|
||||
destroy: 1,
|
||||
active: 2
|
||||
});
|
||||
|
||||
export type IShade = {
|
||||
/**等待 默认0秒 */
|
||||
delay?: number,
|
||||
/**开始透明度 默认60 */
|
||||
begin?: number,
|
||||
/**结束透明度 默认180 */
|
||||
end?: number,
|
||||
/**透明变化速度 默认100 */
|
||||
speed?: number,
|
||||
/**
|
||||
* 毛玻璃效果 默认false
|
||||
* - 开启后其它参数将无效
|
||||
*/
|
||||
blur?: boolean,
|
||||
};
|
||||
|
||||
export interface IShowParamAttr {
|
||||
zIndex?: number,
|
||||
siblingIndex?: number,
|
||||
}
|
||||
|
||||
export interface IShowParamOnShow<T = any> {
|
||||
(result: T): any
|
||||
}
|
||||
|
||||
export interface IShowParamOnHide<T = any> {
|
||||
(result: T): any
|
||||
}
|
||||
|
||||
export interface IShowParamBeforeShow {
|
||||
(error: string): any
|
||||
}
|
||||
|
||||
export interface IShowParamInnerLoad {
|
||||
(name: string, path: string, type: { prototype: Asset }, callback: (result: Asset) => any): void
|
||||
}
|
||||
|
||||
export interface IHideParamOnHide<T = any> {
|
||||
(result: T): any
|
||||
}
|
||||
|
||||
export type IViewType = 'Page' | 'Paper' | 'Pop' | 'Top';
|
||||
|
||||
export enum ViewType {
|
||||
Page = 'Page',
|
||||
Paper = 'Paper',
|
||||
PaperAll = 'PaperAll',
|
||||
Pop = 'Pop',
|
||||
Top = 'Top'
|
||||
}
|
||||
|
||||
interface IMiniOnShow {
|
||||
(name: IMiniViewName, data?: any): any
|
||||
}
|
||||
interface IMiniOnHide {
|
||||
(name: IMiniViewName, data?: any): any
|
||||
}
|
||||
interface IMiniOnFinish {
|
||||
(): any
|
||||
}
|
||||
type IPick<T> = {
|
||||
-readonly [P in keyof T]: T[P] extends Function
|
||||
? T[P]
|
||||
: (T[P] extends Object
|
||||
? IPick<T[P]>
|
||||
: T[P]);
|
||||
};
|
||||
interface IBaseViewController<C, T extends { [key in string]: any }> {
|
||||
new(): BaseView & {
|
||||
readonly controller: IPick<C> & Readonly<{
|
||||
/**获取第一个事件回调的返回值 */
|
||||
emit<K extends keyof T>(key: K, ...args: Parameters<T[K]>): void;
|
||||
/**发射事件 */
|
||||
call<K extends keyof T & keyof T>(key: K, ...args: Parameters<T[K]>): ReturnType<T[K]>;
|
||||
/**注册事件回调 */
|
||||
on<K extends keyof T>(key: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, target?: any): void;
|
||||
/**注册一次性事件回调 */
|
||||
once<K extends keyof T>(key: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, target?: any): void;
|
||||
/**取消事件回调 */
|
||||
off(key: keyof T, callback: Function, target?: any): void;
|
||||
/**取消事件回调 */
|
||||
targetOff(target: any): void;
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
BeforeShow,
|
||||
Showing,
|
||||
Showed,
|
||||
BeforeHide,
|
||||
Hiding,
|
||||
Hid,
|
||||
}
|
||||
|
||||
const Group = { id: 'BaseView', name: 'Settings', displayOrder: -Infinity, style: 'section' };
|
||||
|
||||
// 记录PaperAll的owner
|
||||
const PaperAllToOwner: Map<IMiniViewName, string> = new Map();
|
||||
|
||||
@ccclass('BaseView')
|
||||
@disallowMultiple()
|
||||
export default class BaseView extends Component {
|
||||
/**
|
||||
* @deprecated 废弃,请使用BindController代替BindControl
|
||||
*/
|
||||
static BindControl<C, E, T extends { [key in keyof E]?: any }>(Control: IBaseControl<C, E, T>) {
|
||||
return class BindControl extends BaseView {
|
||||
protected get control(): Pick<C, keyof C> & Readonly<{
|
||||
call<K extends keyof E>(key: E[K], ...args: Parameters<T[K]>): ReturnType<T[K]>;
|
||||
emit<K extends keyof E>(key: E[K], ...args: Parameters<T[K]>): void;
|
||||
on<K extends keyof E>(key: E[K], callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, target?: any): void;
|
||||
once<K extends keyof E>(key: E[K], callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, target?: any): void;
|
||||
off(key: E[keyof E], callback: Function, target?: any): void;
|
||||
targetOff(target: any): void;
|
||||
}> {
|
||||
return Control ? Control.inst as any : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 给UI绑定一个控制器,绑定后可以通过this.controller访问,并能访问一些内部方法(emit、on、once、off、targetOff)
|
||||
*/
|
||||
static BindController<C, T extends { [key in string]: any }>(Controller: IBaseController<C, T>) {
|
||||
@disallowMultiple()
|
||||
class BindController extends BaseView {
|
||||
protected get controller() {
|
||||
return Controller ? Controller.inst as any : null;
|
||||
}
|
||||
}
|
||||
return BindController as any as IBaseViewController<C, T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有效,如果返回false的话,app.manager.ui.show会触发onError回调
|
||||
*/
|
||||
public static isViewValid(next: (valid: boolean) => void, data: any) {
|
||||
data;
|
||||
next && next(true);
|
||||
}
|
||||
|
||||
public static isPage(name: string) {
|
||||
return name.indexOf(ViewType.Page) === 0;
|
||||
}
|
||||
|
||||
public static isPaper(name: string) {
|
||||
return name.indexOf(ViewType.Paper) === 0;
|
||||
}
|
||||
|
||||
public static isPaperAll(name: string) {
|
||||
return name.indexOf(ViewType.PaperAll) === 0;
|
||||
}
|
||||
|
||||
public static isPop(name: string) {
|
||||
return name.indexOf(ViewType.Pop) === 0;
|
||||
}
|
||||
|
||||
public static isTop(name: string) {
|
||||
return name.indexOf(ViewType.Top) === 0;
|
||||
}
|
||||
|
||||
// 是否被调用过
|
||||
private _base_view_created = false;
|
||||
// view状态
|
||||
private _base_view_state = ViewState.Hid;
|
||||
// 当前view的名字
|
||||
private _base_view_name: IViewName | IMiniViewName = js.getClassName(this) as any;
|
||||
// 触摸是否有效
|
||||
private _base_touch_enable = true;
|
||||
// show/hide等待列表
|
||||
private _base_show_hide_delays: Function[] = [];
|
||||
// 子界面融合相关
|
||||
private _base_mini_show: Set<IMiniViewName> = new Set();
|
||||
|
||||
protected isPage() {
|
||||
return BaseView.isPage(this._base_view_name);
|
||||
}
|
||||
|
||||
protected isPaper() {
|
||||
return BaseView.isPaper(this._base_view_name);
|
||||
}
|
||||
|
||||
protected isPaperAll() {
|
||||
return BaseView.isPaperAll(this._base_view_name);
|
||||
}
|
||||
|
||||
protected isPop() {
|
||||
return BaseView.isPop(this._base_view_name);
|
||||
}
|
||||
|
||||
protected isTop() {
|
||||
return BaseView.isTop(this._base_view_name);
|
||||
}
|
||||
|
||||
protected is2D() {
|
||||
return !this.is3D();
|
||||
}
|
||||
|
||||
protected is3D() {
|
||||
if (this.node.parent instanceof Scene) {
|
||||
return this.node.parent.name === this.viewName;
|
||||
}
|
||||
const scene = director.getScene();
|
||||
return scene.name === this.viewName;
|
||||
}
|
||||
|
||||
@property
|
||||
private _hideEvent = HideEvent.destroy;
|
||||
@property({
|
||||
group: Group,
|
||||
type: HideEvent,
|
||||
tooltip: '何种模式隐藏节点\n1、destroy: 销毁UI并释放对应的所有资源\n2、active: 缓存UI并加速下次的打开速度',
|
||||
})
|
||||
public get hideEvent() {
|
||||
if (this.is3D()) return HideEvent.destroy;
|
||||
return this._hideEvent;
|
||||
}
|
||||
public set hideEvent(value) {
|
||||
if (this.is3D() && value !== HideEvent.destroy) {
|
||||
this.log('3D模式下只能是destroy模式');
|
||||
return;
|
||||
}
|
||||
this._hideEvent = value;
|
||||
}
|
||||
|
||||
@property
|
||||
private _singleton = true;
|
||||
private static _singleton = true;
|
||||
@property({
|
||||
group: Group,
|
||||
tooltip: '是否是单例模式\n1、单例模式: UI只会被创建一次(onShow会被重复触发)\n2、非单例模式: UI会被重复创建',
|
||||
})
|
||||
protected get singleton(): boolean {
|
||||
if (this.isPage()) return true;
|
||||
if (this.isPaperAll()) return true;
|
||||
if (this.isPaper()) return true;
|
||||
return this._singleton && (<typeof BaseView>this.constructor)._singleton;
|
||||
}
|
||||
protected set singleton(value) {
|
||||
if (!value) {
|
||||
if (this.isPage()) {
|
||||
this.log('Page只能是单例模式');
|
||||
return;
|
||||
}
|
||||
if (this.isPaper()) {
|
||||
this.log('Paper只能是单例模式');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._singleton = (<typeof BaseView>this.constructor)._singleton = !!value;
|
||||
}
|
||||
|
||||
@property
|
||||
private _captureFocus = true;
|
||||
@property({
|
||||
group: Group,
|
||||
tooltip: '是否捕获焦点<响应onLostFocus和onFocus>\n1、当一个捕获焦点的UI处于最上层并展示时\n下层的UI永远不会响应focus事件',
|
||||
visible(this: BaseView) {
|
||||
if (this.is3D()) return false;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
protected get captureFocus() {
|
||||
if (this.is3D()) return false;
|
||||
return this._captureFocus;
|
||||
}
|
||||
protected set captureFocus(value) {
|
||||
if (value && this.is3D()) {
|
||||
this.log('只有2D模式下才可以捕获焦点');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EDITOR && this._captureFocus !== value) {
|
||||
this._captureFocus = value;
|
||||
Core.inst?.manager?.ui?.refreshShade();
|
||||
} else {
|
||||
this._captureFocus = value;
|
||||
}
|
||||
}
|
||||
|
||||
@property
|
||||
private _shade = true;
|
||||
@property({
|
||||
group: Group,
|
||||
tooltip: '是否需要底层遮罩',
|
||||
visible(this: BaseView) {
|
||||
if (this.is3D()) return false;
|
||||
if (this.isPage()) return false;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
protected get shade() {
|
||||
if (this.is3D()) return false;
|
||||
if (this.isPage()) return false;
|
||||
return this._shade;
|
||||
}
|
||||
protected set shade(value) {
|
||||
if (value) {
|
||||
if (this.is3D()) {
|
||||
this.log('只有2D模式下才可以设置底层遮罩');
|
||||
return;
|
||||
}
|
||||
if (this.isPage()) {
|
||||
this.log('Page不可以设置底层遮罩');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EDITOR && this._shade !== value) {
|
||||
this._shade = value;
|
||||
Core.inst?.manager?.ui?.refreshShade();
|
||||
} else {
|
||||
this._shade = value;
|
||||
}
|
||||
}
|
||||
|
||||
@property
|
||||
private _blockInput = true;
|
||||
@property({
|
||||
group: Group,
|
||||
tooltip: '是否禁止点击事件向下层传递',
|
||||
visible(this: BaseView) {
|
||||
if (this.is3D()) return false;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
protected get blockInput() {
|
||||
if (this.is3D()) return false;
|
||||
return this._blockInput;
|
||||
}
|
||||
protected set blockInput(value) {
|
||||
if (value && this.is3D()) {
|
||||
this.log('只有2D模式下才可以设置阻断点击事件');
|
||||
return;
|
||||
}
|
||||
this._blockInput = value;
|
||||
}
|
||||
|
||||
/** 修改框架、新增isAlwaysExist选项,如果勾选,则不会自动隐藏旧页面 */
|
||||
@property
|
||||
private _alwaysExist = false;
|
||||
@property({
|
||||
group: Group,
|
||||
tooltip: '界面是否始终存在\- 打开另外界面后不会被关闭',
|
||||
visible(this: BaseView) {
|
||||
if (this.is3D()) return false;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
protected get alwaysExist() {
|
||||
if (this.is3D()) return false;
|
||||
return this._alwaysExist;
|
||||
}
|
||||
protected set alwaysExist(value) {
|
||||
if (value && this.is3D()) {
|
||||
this.log('只有2D模式下才可以设置界面是否始终存在');
|
||||
return;
|
||||
}
|
||||
this._alwaysExist = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 子界面(只能用于Page)
|
||||
*/
|
||||
protected miniViews: IMiniViewNames = [];
|
||||
|
||||
/**
|
||||
* 当前view名字
|
||||
*/
|
||||
public get viewName() {
|
||||
return this._base_view_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础名字, 如PageHome => Home
|
||||
*/
|
||||
public get baseName() {
|
||||
return this._base_view_name.slice(this.typeName.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型名字, 如PageHome => Page
|
||||
*/
|
||||
public get typeName() {
|
||||
if (this._base_view_name.indexOf(ViewType.Paper) === 0) return ViewType.Paper;
|
||||
if (this._base_view_name.indexOf(ViewType.Pop) === 0) return ViewType.Pop;
|
||||
if (this._base_view_name.indexOf(ViewType.Top) === 0) return ViewType.Top;
|
||||
return ViewType.Page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是单例模式
|
||||
*/
|
||||
public get isSingleton(): boolean {
|
||||
return this.singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否捕获焦点
|
||||
*/
|
||||
public get isCaptureFocus(): boolean {
|
||||
return this.captureFocus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要遮罩
|
||||
*/
|
||||
public get isNeedShade(): boolean {
|
||||
return this.shade;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否展示了(不为Hid状态)
|
||||
*/
|
||||
public get isShow(): boolean {
|
||||
return this._base_view_state != ViewState.Hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开其他界面时,此界面不关闭
|
||||
*/
|
||||
public get isAlwaysExist(): boolean {
|
||||
return this._alwaysExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否show了某个子界面
|
||||
*/
|
||||
protected isMiniViewShow(name: IMiniViewName) {
|
||||
return this._base_mini_show.has(name);
|
||||
}
|
||||
|
||||
// 用来初始化组件或节点的一些属性,当该组件被第一次添加到节点上或用户点击了它的 Reset 菜单时调用。这个回调只会在编辑器下调用。
|
||||
resetInEditor(): any {
|
||||
if (EDITOR) {
|
||||
const is3D = this.is3D();
|
||||
if (this.viewName.indexOf(ViewType.Page) >= 0) {
|
||||
this.shade = false;
|
||||
this.blockInput = is3D ? false : true;
|
||||
this.captureFocus = is3D ? false : true;
|
||||
} else if (this.viewName.indexOf(ViewType.Paper) >= 0) {
|
||||
this.shade = false;
|
||||
this.captureFocus = false;
|
||||
this.blockInput = false;
|
||||
}
|
||||
|
||||
if (is3D) return;
|
||||
this.node.getComponent(UITransform) || this.node.addComponent(UITransform);
|
||||
|
||||
const widget = this.node.getComponent(Widget) || this.node.addComponent(Widget);
|
||||
widget.isAlignBottom = true;
|
||||
widget.isAlignLeft = true;
|
||||
widget.isAlignRight = true;
|
||||
widget.isAlignTop = true;
|
||||
widget.top = 0;
|
||||
widget.left = 0;
|
||||
widget.right = 0;
|
||||
widget.bottom = 0;
|
||||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否可点击
|
||||
*/
|
||||
protected setTouchEnabled(enabled: boolean = true): any {
|
||||
this._base_touch_enable = !!enabled;
|
||||
}
|
||||
|
||||
private blockPropagation(event: EventTouch) {
|
||||
if (this.blockInput) {
|
||||
event.propagationStopped = true;
|
||||
if (event.type === Node.EventType.TOUCH_START) {
|
||||
this.log('阻断触摸向下层传递');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private stopPropagation(event: EventTouch) {
|
||||
if (!this._base_touch_enable) {
|
||||
event.propagationStopped = true;
|
||||
event.propagationImmediateStopped = true;
|
||||
if (event.type === Node.EventType.TOUCH_START) {
|
||||
this.log('屏蔽触摸');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onBaseViewCreate(): any {
|
||||
if (this.is3D()) return;
|
||||
const uiTransform = this.getComponent(UITransform);
|
||||
if (uiTransform) uiTransform.hitTest = (...args: any[]): boolean => {
|
||||
if (this.blockInput) {
|
||||
return UITransform.prototype.hitTest.apply(uiTransform, args);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (let i = 0; i < BlockEvents.length; i++) {
|
||||
this.node.on(BlockEvents[i], this.blockPropagation, this);
|
||||
this.node.on(BlockEvents[i], this.stopPropagation, this, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭所有子界面
|
||||
*/
|
||||
protected hideAllMiniViews(data?: any) {
|
||||
this._base_mini_show.forEach((name) => {
|
||||
Core.inst.manager.ui.hide({ name, data });
|
||||
});
|
||||
this._base_mini_show.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭子界面
|
||||
*/
|
||||
protected hideMiniViews({ data, views }: { data?: any, views: IMiniViewNames }) {
|
||||
if (this.miniViews.length === 0) return;
|
||||
if (views.length === 0) return;
|
||||
|
||||
views.forEach(name => {
|
||||
if (this.miniViews.indexOf(name) === -1) {
|
||||
this.warn('hideMiniViews', `${name}不在miniViews中, 已跳过`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证
|
||||
if (!this._base_mini_show.has(name)) return;
|
||||
// 关闭
|
||||
Core.inst.manager.ui.hide({ name, data });
|
||||
});
|
||||
// TODO 手动刷新一下Paper下的UI顺序(原因是原生环境,显示层级正确但触摸层级可能会不正确)
|
||||
Core.inst.manager.ui.sortUserInterface('Paper');
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示子界面
|
||||
*/
|
||||
protected showMiniViews({ data, views, onShow, onHide, onFinish }: {
|
||||
/**传递给子界面的数据 */
|
||||
data?: any,
|
||||
/**子界面名字列表 */
|
||||
views: Array<IMiniViewName | IMiniViewNames>,
|
||||
/**子界面展示回调 */
|
||||
onShow?: IMiniOnShow,
|
||||
/**子界面关闭回调 */
|
||||
onHide?: IMiniOnHide,
|
||||
/**子界面融合完成回调 */
|
||||
onFinish?: IMiniOnFinish
|
||||
}) {
|
||||
if (views.length === 0) return false;
|
||||
if (this.typeName !== ViewType.Page) {
|
||||
this.warn('showMiniViews', '仅支持Page类型');
|
||||
return false;
|
||||
}
|
||||
|
||||
const task = Core.inst.lib.task.createSync();
|
||||
|
||||
for (let index = 0; index < views.length; index++) {
|
||||
const names = views[index];
|
||||
if (names instanceof Array) {
|
||||
task.add(next => {
|
||||
this.createMixMiniViewsTask(names, data, onShow, onHide).start(next);
|
||||
});
|
||||
} else {
|
||||
task.add(next => {
|
||||
this.createMixMiniViewsTask([names], data, onShow, onHide).start(next);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
task.start(onFinish && function () {
|
||||
onFinish();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义加载任务
|
||||
*/
|
||||
private createMixMiniViewsTask(views: IMiniViewNames = [], data?: any, onShow?: IMiniOnShow, onHide?: IMiniOnHide) {
|
||||
const task = Core.inst.lib.task.createSync();
|
||||
|
||||
if (this.typeName !== ViewType.Page) {
|
||||
this.warn('showMiniViews', '仅支持Page类型');
|
||||
return task;
|
||||
}
|
||||
|
||||
views = views.filter(name => {
|
||||
if (!name) {
|
||||
this.warn('showMiniViews', 'name不能为空');
|
||||
return false;
|
||||
}
|
||||
if (this._base_mini_show.has(name)) {
|
||||
this.warn('showMiniViews', `重复融合${name}, 已跳过`);
|
||||
return false;
|
||||
}
|
||||
if (this.miniViews.indexOf(name) === -1) {
|
||||
this.warn('showMiniViews', `${name}不在miniViews中, 已跳过`);
|
||||
return false;
|
||||
}
|
||||
if (name.indexOf(this.baseName) !== ViewType.Paper.length && name.indexOf(ViewType.PaperAll) !== 0) {
|
||||
this.warn('showMiniViews', `${name}不属于当前Page, 已跳过`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this._base_mini_show.add(name);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (views.length === 0) return task;
|
||||
|
||||
// 先load全部
|
||||
task.add((next) => {
|
||||
const aSync = Core.inst.lib.task.createASync();
|
||||
views.forEach(name => {
|
||||
aSync.add((next, retry) => {
|
||||
this.log(`下载子页面: ${name}`);
|
||||
Core.inst.manager.ui.load(name as any, result => {
|
||||
result ? next() : this.scheduleOnce(retry, 0.1);
|
||||
});
|
||||
});
|
||||
});
|
||||
aSync.start(next);
|
||||
});
|
||||
|
||||
// 再show全部
|
||||
task.add((next) => {
|
||||
const aSync = Core.inst.lib.task.createASync();
|
||||
views.forEach(name => {
|
||||
aSync.add((next) => {
|
||||
if (!this._base_mini_show?.has(name)) return next();
|
||||
|
||||
this.log(`展示子页面: ${name}`);
|
||||
// 是PaperAll,设置owner
|
||||
if (BaseView.isPaperAll(name)) {
|
||||
PaperAllToOwner.set(name, this.uuid);
|
||||
}
|
||||
Core.inst.manager.ui.show({
|
||||
name, data,
|
||||
silent: true,
|
||||
attr: { zIndex: this.miniViews.indexOf(name) },
|
||||
onShow: (result) => {
|
||||
if (onShow) onShow(name, result);
|
||||
next();
|
||||
},
|
||||
onHide: (result) => {
|
||||
if (BaseView.isPaperAll(name)) {
|
||||
// 验证PaperAll是否属于当前Page
|
||||
const owner = PaperAllToOwner.get(name);
|
||||
if (owner && owner === this.uuid) {
|
||||
PaperAllToOwner.delete(name);
|
||||
}
|
||||
}
|
||||
this._base_mini_show?.delete(name);
|
||||
if (onHide) onHide(name, result);
|
||||
},
|
||||
onError: (result, code) => {
|
||||
if (code === Core.inst.Manager.UI.ErrorCode.LoadError) return true;
|
||||
if (BaseView.isPaperAll(name)) {
|
||||
// 验证PaperAll是否属于当前Page
|
||||
const owner = PaperAllToOwner.get(name);
|
||||
if (owner && owner === this.uuid) {
|
||||
PaperAllToOwner.delete(name);
|
||||
Core.inst.manager.ui.hide({ name });
|
||||
}
|
||||
}
|
||||
this._base_mini_show?.delete(name);
|
||||
this.warn('忽略子页面', name, result);
|
||||
next();
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
aSync.start(() => {
|
||||
// TODO 手动刷新一下Paper下的UI顺序(原因是原生环境,显示层级正确但触摸层级可能会不正确)
|
||||
Core.inst.manager.ui.sortUserInterface('Paper');
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置节点属性
|
||||
*/
|
||||
private setNodeAttr(attr: IShowParamAttr) {
|
||||
if (!attr) return;
|
||||
if (typeof attr.zIndex === 'number') {
|
||||
// 以z坐标来代替2.x时代的zIndex
|
||||
this.node.setPosition(this.node.position.x, this.node.position.y, attr.zIndex);
|
||||
}
|
||||
|
||||
if (typeof attr.siblingIndex === 'number') {
|
||||
this.node.setSiblingIndex(attr.siblingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private show(data?: any, attr?: IShowParamAttr, onShow?: IShowParamOnShow, onHide?: IShowParamOnHide, beforeShow?: IShowParamBeforeShow) {
|
||||
// 当前show操作需要等待其它流程
|
||||
if (this._base_view_state !== ViewState.Showed &&
|
||||
this._base_view_state !== ViewState.Hid) {
|
||||
this._base_show_hide_delays.push(
|
||||
this.show.bind(this, data, attr, onShow, onHide, beforeShow)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// show流程
|
||||
const changeState = this._base_view_state === ViewState.Hid;
|
||||
if (changeState) this._base_view_state = ViewState.BeforeShow;
|
||||
const next = (error: string) => {
|
||||
if (!error) {
|
||||
// 所有Paper只会是单例,而且所有Paper都不允许被当前Page重复show
|
||||
// 但PaprAll比较特殊,会被不同的Page使用,在PaperAll被不同的Page重复show时,清除之前的onHide
|
||||
if (this.isPaperAll()) this.node.emit('onHide');
|
||||
}
|
||||
beforeShow && beforeShow(error);
|
||||
if (!error) {
|
||||
// 设置展示中
|
||||
if (changeState) this._base_view_state = ViewState.Showing;
|
||||
onHide && this.node.once('onHide', onHide);
|
||||
|
||||
// 触发onCreate
|
||||
if (this._base_view_created === false) {
|
||||
this._base_view_created = true;
|
||||
this.onBaseViewCreate();
|
||||
}
|
||||
|
||||
// 设置属性
|
||||
this.setNodeAttr(attr);
|
||||
|
||||
// 触发onLoad、onEnable
|
||||
if (this.node.active !== true) { this.node.active = true; }
|
||||
|
||||
this.log('onShow');
|
||||
let result = null;
|
||||
try {
|
||||
result = this.onShow(data);
|
||||
} catch (err) {
|
||||
this.onError();
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
// 设置遮罩,触发focus逻辑
|
||||
Core.inst.manager.ui.refreshShade();
|
||||
|
||||
try {
|
||||
onShow && onShow(result);
|
||||
this.node.emit('onShow', result);
|
||||
Core.inst.manager.ui.emit(this._base_view_name, { event: 'onShow', result: result });
|
||||
Core.inst.manager.ui.emit('onShow', { name: this._base_view_name, result: result });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
if (changeState) this._base_view_state = ViewState.Showed;
|
||||
} else {
|
||||
if (changeState) this._base_view_state = ViewState.Hid;
|
||||
}
|
||||
|
||||
if (this._base_show_hide_delays.length > 0) {
|
||||
this._base_show_hide_delays.shift()();
|
||||
}
|
||||
};
|
||||
|
||||
this.log('beforeShow');
|
||||
let isNextCalled = false;
|
||||
this.beforeShow((error) => {
|
||||
if (isNextCalled) return this.error('beforeShow', 'next被重复调用');
|
||||
isNextCalled = true;
|
||||
next(error || null);
|
||||
}, data);
|
||||
}
|
||||
|
||||
protected hide(
|
||||
//@ts-ignore
|
||||
data?: Parameters<this['onHide']>[0],
|
||||
onHide?: IHideParamOnHide) {
|
||||
|
||||
// 当前hide操作需要等待其它流程
|
||||
if (this._base_view_state !== ViewState.Hid &&
|
||||
this._base_view_state !== ViewState.Showed) {
|
||||
this._base_show_hide_delays.push(
|
||||
this.hide.bind(this, data, onHide)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// hide流程
|
||||
const changeState = this._base_view_state === ViewState.Showed;
|
||||
if (changeState) this._base_view_state = ViewState.BeforeHide;
|
||||
this.log('beforeHide');
|
||||
const error = this.beforeHide(data);
|
||||
if (!error) {
|
||||
this.log('onHide');
|
||||
if (changeState) this._base_view_state = ViewState.Hiding;
|
||||
this.hideAllMiniViews(data);
|
||||
|
||||
let result = null;
|
||||
try {
|
||||
result = this.onHide(data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
try {
|
||||
onHide && onHide(result);
|
||||
this.node.emit('onHide', result);
|
||||
Core.inst.manager.ui.emit(this._base_view_name, { event: 'onHide', result: result });
|
||||
Core.inst.manager.ui.emit('onHide', { name: this._base_view_name, result: result });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
if (changeState) this._base_view_state = ViewState.Hid;
|
||||
|
||||
if (this.hideEvent === HideEvent.active) { this.node.active = false; }
|
||||
else if (this.hideEvent === HideEvent.destroy) { Core.inst.manager.ui.release(this); }
|
||||
Core.inst.manager.ui.refreshShade();
|
||||
} else {
|
||||
if (changeState) this._base_view_state = ViewState.Showed;
|
||||
}
|
||||
|
||||
if (this._base_show_hide_delays.length > 0) {
|
||||
this._base_show_hide_delays.shift()();
|
||||
}
|
||||
}
|
||||
|
||||
private focus(boo: boolean): any {
|
||||
let result = null;
|
||||
let event = '';
|
||||
if (boo) {
|
||||
result = this.onFocus();
|
||||
event = 'onFocus';
|
||||
} else {
|
||||
result = this.onLostFocus();
|
||||
event = 'onLostFocus';
|
||||
}
|
||||
|
||||
this.node.emit(event, result);
|
||||
Core.inst.manager.ui.emit(this._base_view_name, { event: event, result: result });
|
||||
Core.inst.manager.ui.emit(event, { name: this._base_view_name, result: result });
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载UI目录下resources里面的资源
|
||||
* @param path 相对于resources的路径
|
||||
* @param callback 回调
|
||||
* this.loadRes('Bag', Prefab, function(asset){})
|
||||
*/
|
||||
protected loadRes<T extends typeof Asset>(path: string, type: T, callback?: (result: InstanceType<T> | null) => any) {
|
||||
Core.inst.manager.ui.loadRes(this, path, type, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载UI目录下resources里面的资源
|
||||
* @param path 相对于resources的路径
|
||||
* this.preloadRes('Bag', Prefab)
|
||||
*/
|
||||
protected preloadRes<T extends typeof Asset>(path: string, type: T) {
|
||||
Core.inst.manager.ui.preloadRes(this, path, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载UI目录下resources里面的资源
|
||||
* @param path 相对于resources的路径
|
||||
* @param callback 回调
|
||||
* this.loadResDir('Bag', Prefab, function(asset){})
|
||||
*/
|
||||
protected loadResDir<T extends typeof Asset>(path: string, type: T, callback?: (result: InstanceType<T>[] | null) => any) {
|
||||
Core.inst.manager.ui.loadResDir(this, path, type, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载UI目录下resources里面的资源
|
||||
* @param path 相对于resources的路径
|
||||
* this.preloadResDir('Bag', Prefab)
|
||||
*/
|
||||
protected preloadResDir<T extends typeof Asset>(path: string, type: T) {
|
||||
Core.inst.manager.ui.preloadResDir(this, path, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体资源
|
||||
* @param path UI的resources目录下的相对路径
|
||||
*/
|
||||
protected setFont(target: Label, path: string, onComplete?: (success: boolean) => any) {
|
||||
this.loadRes(path, Font, (font) => {
|
||||
if (!font || !isValid(target)) {
|
||||
return onComplete && onComplete(false);
|
||||
}
|
||||
target.font = font;
|
||||
onComplete && onComplete(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Spine资源
|
||||
* @param path UI的resources目录下的相对路径
|
||||
*/
|
||||
protected setSpine(target: sp.Skeleton, path: string, onComplete?: (success: boolean) => any) {
|
||||
this.loadRes(path, sp.SkeletonData, (skeletonData) => {
|
||||
if (!skeletonData || !isValid(target)) {
|
||||
return onComplete && onComplete(false);
|
||||
}
|
||||
target.skeletonData = skeletonData;
|
||||
onComplete && onComplete(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片资源
|
||||
* @param path UI的resources目录下的相对路径(必须以/spriteFrame结尾)
|
||||
*
|
||||
* @example
|
||||
* setSprite(sprite, 'img/a/spriteFrame', onComplete:(succ)=>{})
|
||||
*/
|
||||
protected setSprite(target: Sprite, path: string, onComplete?: (success: boolean) => any) {
|
||||
this.loadRes(path, SpriteFrame, (spriteFrame) => {
|
||||
if (!spriteFrame || !isValid(target)) {
|
||||
return onComplete && onComplete(false);
|
||||
}
|
||||
target.spriteFrame = spriteFrame;
|
||||
onComplete && onComplete(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**打印日志 */
|
||||
protected get log() {
|
||||
return Logger.create('log', '#1e90ff', DEV ? `[${this._base_view_name}] LOG` : `[${this._base_view_name}] [LOG]`);
|
||||
}
|
||||
|
||||
/**打印警告 */
|
||||
protected get warn() {
|
||||
return Logger.create('warn', '#ff7f50', DEV ? `[${this._base_view_name}] WARN` : `[${this._base_view_name}] [WARN]`);
|
||||
}
|
||||
|
||||
/**打印错误 */
|
||||
protected get error() {
|
||||
return Logger.create('error', '#ff4757', DEV ? `[${this._base_view_name}] ERROR` : `[${this._base_view_name}] [ERROR]`);
|
||||
}
|
||||
|
||||
//////////////以下为可重写//////////////
|
||||
/**
|
||||
* 展示
|
||||
* @param data 传递给onShow的参数
|
||||
* @returns
|
||||
*/
|
||||
protected onShow(data?: any): any {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏
|
||||
* @param data 传递给onHide的参数
|
||||
* @returns
|
||||
*/
|
||||
protected onHide(data?: any): any {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 失去焦点
|
||||
* @returns
|
||||
*/
|
||||
protected onLostFocus(): any {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得焦点
|
||||
* @returns
|
||||
*/
|
||||
protected onFocus(): any {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* onShow前调用
|
||||
* @param next 回调,传递的error不为空时,表示错误,onShow不会执行
|
||||
* @param data 传递给onShow的参数
|
||||
*/
|
||||
protected beforeShow(next: (error?: string) => void, data?: any): any {
|
||||
next(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* hide前调用
|
||||
* @param data 传递给onHide的参数
|
||||
* @returns 如果返回字符串,则表示错误信息
|
||||
*/
|
||||
protected beforeHide(data?: any): string | void {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* onShow报错会执行
|
||||
*/
|
||||
protected onError(): any {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景遮照的参数
|
||||
*/
|
||||
protected onShade(): IShade {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/base/BaseView.ts.meta
Normal file
9
extensions/app/assets/base/BaseView.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "eddc0411-4239-423d-8710-77fdf92affc2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/lib.meta
Normal file
12
extensions/app/assets/lib.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "6ff04fb4-44cd-4fc4-a4b8-28ac28d83a0b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
12
extensions/app/assets/lib/debug.meta
Normal file
12
extensions/app/assets/lib/debug.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "e939f63c-c853-403c-aed7-b8f0925106f0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
40
extensions/app/assets/lib/debug/debug.ts
Normal file
40
extensions/app/assets/lib/debug/debug.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { DEBUG, DEV } from 'cc/env';
|
||||
|
||||
function jsGetSet(obj: unknown, prop: string, getter: Function, setter?: Function) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: getter as any,
|
||||
set: setter as any,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
});
|
||||
}
|
||||
function clear(object: Record<string | number, any>) {
|
||||
if (!object) return;
|
||||
for (const key of Object.keys(object)) {
|
||||
delete object[key];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 将某个变量设置为不可观测(不可在浏览器中打印)
|
||||
* @param owner object | string | number | boolean | Array | Function | ...
|
||||
* @param callback 被观测时触发回调
|
||||
* @returns
|
||||
*/
|
||||
export function unobservable(owner: unknown, callback?: Function) {
|
||||
if (DEV || DEBUG) return;
|
||||
if (!owner) return;
|
||||
function define() {
|
||||
function accessor() {
|
||||
if (callback) {
|
||||
callback();
|
||||
} else {
|
||||
clear(owner);
|
||||
}
|
||||
}
|
||||
try {
|
||||
jsGetSet(owner, 'unobservable', accessor.bind(null, 'de' + 'bu' + 'gg' + 'er'));
|
||||
}
|
||||
catch (e) { !0; }
|
||||
}
|
||||
define();
|
||||
}
|
||||
9
extensions/app/assets/lib/debug/debug.ts.meta
Normal file
9
extensions/app/assets/lib/debug/debug.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "c0d5da3b-23f0-400e-85bb-6c754b9c08eb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
extensions/app/assets/lib/logger.meta
Normal file
9
extensions/app/assets/lib/logger.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "140d98c1-6885-4e37-bf16-2ee67ffe087e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
77
extensions/app/assets/lib/logger/logger.ts
Normal file
77
extensions/app/assets/lib/logger/logger.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { DEV } from 'cc/env';
|
||||
|
||||
interface ILog {
|
||||
(title: string, ...args: any[]): void
|
||||
}
|
||||
|
||||
function empty() { }
|
||||
|
||||
/**
|
||||
* 日志管理类,用于统一日志输出格式
|
||||
*/
|
||||
export class Logger {
|
||||
static setting: {
|
||||
filter: Array<'log' | 'warn' | 'error'>
|
||||
} = {
|
||||
filter: ['error', 'log', 'warn']
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建日志输出函数
|
||||
*/
|
||||
static create(level: 'log' | 'warn' | 'error', styleColor: string, title: string, titleColor = '#fff') {
|
||||
if (this.setting.filter.indexOf(level) == -1) {
|
||||
return empty;
|
||||
}
|
||||
|
||||
if (DEV) {
|
||||
return window.console[level].bind(window.console,
|
||||
'%c %s %c %s ',
|
||||
`background:${styleColor}; padding: 2px; border-radius: 5px 0 0 5px; border: 1px solid ${styleColor}; color: ${titleColor}; font-weight: normal;`,
|
||||
`${title} ${new Date().toLocaleString()}`,
|
||||
`background:#ffffff ; padding: 2px; border-radius: 0 5px 5px 0; border: 1px solid ${styleColor}; color: ${styleColor}; font-weight: normal;`
|
||||
);
|
||||
}
|
||||
return window.console[level].bind(window.console,
|
||||
`${title} [${new Date().toLocaleString()}]`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于输出一般信息
|
||||
*/
|
||||
get log() {
|
||||
return Logger.create('log', '#6495ed', '[LOG]', '#000') as ILog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于输出警告信息
|
||||
*/
|
||||
|
||||
get warn() {
|
||||
return Logger.create('warn', '#ff7f50', '[WARN]', '#000') as ILog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于输出错误信息
|
||||
*/
|
||||
get error() {
|
||||
return Logger.create('error', '#ff4757', '[ERROR]', '#000') as ILog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于输出调试信息
|
||||
*/
|
||||
get debug() {
|
||||
return Logger.create('log', '#ff6347', '[DEBUG]', '#000') as ILog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于输出成功信息
|
||||
*/
|
||||
get success() {
|
||||
return Logger.create('log', '#00ae9d', '[SUCC]', '#000') as ILog;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Logger();
|
||||
9
extensions/app/assets/lib/logger/logger.ts.meta
Normal file
9
extensions/app/assets/lib/logger/logger.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0b5812e8-b67d-4ba9-83d8-12ca1e46cfd0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/lib/storage.meta
Normal file
12
extensions/app/assets/lib/storage.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "0c157f59-fd16-449c-b42c-d0efa2dc1401",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
236
extensions/app/assets/lib/storage/storage.ts
Normal file
236
extensions/app/assets/lib/storage/storage.ts
Normal file
@@ -0,0 +1,236 @@
|
||||
import { error, js, log, sys } from 'cc';
|
||||
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
|
||||
function encode(text: string, key: string) {
|
||||
key = key || chars;
|
||||
let encrypted = '';
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length);
|
||||
encrypted += String.fromCharCode(charCode);
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
function decode(encryptedText: string, key: string) {
|
||||
key = key || chars;
|
||||
let decrypted = '';
|
||||
for (let i = 0; i < encryptedText.length; i++) {
|
||||
const charCode = encryptedText.charCodeAt(i) ^ key.charCodeAt(i % key.length);
|
||||
decrypted += String.fromCharCode(charCode);
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
const weekOfYear = function (curDate?: Date) {
|
||||
/*
|
||||
date1是当前日期
|
||||
date2是当年第一天
|
||||
d是当前日期是今年第多少天
|
||||
用d + 当前年的第一天的周差距的和在除以7就是本年第几周
|
||||
*/
|
||||
curDate = curDate || new Date();
|
||||
let a = curDate.getFullYear();
|
||||
let b = curDate.getMonth() + 1;
|
||||
let c = curDate.getDate();
|
||||
|
||||
let date1 = new Date(a, b - 1, c), date2 = new Date(a, 0, 1),
|
||||
d = Math.round((date1.valueOf() - date2.valueOf()) / 86400000);
|
||||
return Math.ceil(
|
||||
(d + ((date2.getDay() + 1) - 1)) / 7
|
||||
);
|
||||
};
|
||||
|
||||
const getWeekUpdateTime = function () {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const week = weekOfYear(date);
|
||||
return year + '' + week;
|
||||
};
|
||||
|
||||
const getDayUpdateTime = function (curDate?: Date) {
|
||||
curDate = curDate || new Date();
|
||||
return curDate.toLocaleDateString();
|
||||
};
|
||||
|
||||
export class Storage {
|
||||
static setting: {
|
||||
/**
|
||||
* 加密密钥
|
||||
* - 如果需要加密内容,请设置密钥的值
|
||||
*/
|
||||
secretKey: string
|
||||
} = {
|
||||
secretKey: ''
|
||||
};
|
||||
|
||||
private _cache = {};
|
||||
|
||||
/**
|
||||
* 返回值为false代表调用失败
|
||||
*/
|
||||
set(key: string, value: unknown) {
|
||||
if (typeof key === 'string' && typeof value !== 'undefined') {
|
||||
try {
|
||||
const data = JSON.stringify(value);
|
||||
if (Storage.setting.secretKey) {
|
||||
sys.localStorage.setItem(key, encode(data, Storage.setting.secretKey));
|
||||
} else {
|
||||
sys.localStorage.setItem(key, data);
|
||||
}
|
||||
// 设置缓存
|
||||
this._cache[key] = data;
|
||||
return true;
|
||||
} catch (err) { log(err); }
|
||||
} else {
|
||||
error('storage set error');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值为undefined代表调用失败
|
||||
*/
|
||||
get(key: string) {
|
||||
// 先读取缓存
|
||||
if (typeof this._cache[key] !== 'undefined') {
|
||||
return JSON.parse(this._cache[key]);
|
||||
}
|
||||
|
||||
let result = null;
|
||||
try {
|
||||
let data = sys.localStorage.getItem(key);
|
||||
if (data && typeof data === 'string') {
|
||||
if (Storage.setting.secretKey) data = decode(data, Storage.setting.secretKey);
|
||||
// 设置缓存
|
||||
this._cache[key] = data;
|
||||
result = JSON.parse(data);
|
||||
} else if (data !== '' && data !== null) {
|
||||
result = undefined;
|
||||
}
|
||||
} catch (e) {
|
||||
result = undefined;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值为false代表调用失败
|
||||
*/
|
||||
add(key: string, value: number = 1) {
|
||||
let result = this.get(key);
|
||||
if (result !== undefined) {
|
||||
result = result || 0;
|
||||
result += value;
|
||||
if (this.set(key, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值为false代表调用失败
|
||||
*/
|
||||
remove(key: string) {
|
||||
try {
|
||||
sys.localStorage.removeItem(key);
|
||||
delete this._cache[key];
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值为false代表调用失败
|
||||
*/
|
||||
clear() {
|
||||
try {
|
||||
sys.localStorage.clear();
|
||||
js.clear(this._cache);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置本周数据 [返回值为false代表调用失败]
|
||||
* @param {Function} cb 当已存在本周的数据时,会根据cb的返回决定是否存储,true代表存储
|
||||
*/
|
||||
setWeek(key: string, value: unknown, cb?: (oldValue: unknown, newValue: unknown) => boolean) {
|
||||
const updateTime = getWeekUpdateTime();
|
||||
|
||||
if (cb) {
|
||||
const data = this.getWeek(key);
|
||||
if (data !== undefined) {
|
||||
if (data === null || cb(data, value)) {
|
||||
return this.set(key, {
|
||||
data: value,
|
||||
updateTime: updateTime
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.set(key, {
|
||||
data: value,
|
||||
updateTime: updateTime
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本周数据 [返回值为undefined代表调用失败]
|
||||
*/
|
||||
getWeek(key: string) {
|
||||
const data = this.get(key);
|
||||
if (data && data.updateTime == getWeekUpdateTime()) {
|
||||
return data.data;
|
||||
}
|
||||
return data && null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置本天数据 [返回值为false代表调用失败]
|
||||
* @param {Function} cb 当已存在本天的数据时,会根据cb的返回决定是否存储,true代表存储
|
||||
*/
|
||||
setDay(key: string, value: unknown, cb?: (oldValue: unknown, newValue: unknown) => boolean) {
|
||||
const updateTime = getDayUpdateTime();
|
||||
|
||||
if (cb) {
|
||||
const data = this.getDay(key);
|
||||
if (data !== undefined) {
|
||||
if (data === null || cb(data, value)) {
|
||||
return this.set(key, {
|
||||
data: value,
|
||||
updateTime: updateTime
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.set(key, {
|
||||
data: value,
|
||||
updateTime: updateTime
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本天数据 [返回值为undefined代表调用失败]
|
||||
* @param {*} key
|
||||
*/
|
||||
getDay(key: string) {
|
||||
const data = this.get(key);
|
||||
if (data && data.updateTime == getDayUpdateTime()) {
|
||||
return data.data;
|
||||
}
|
||||
return data && null;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Storage();
|
||||
9
extensions/app/assets/lib/storage/storage.ts.meta
Normal file
9
extensions/app/assets/lib/storage/storage.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "be3da7ca-1bb5-4a41-894b-f82751c78ef2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/lib/task.meta
Normal file
12
extensions/app/assets/lib/task.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "54e30e53-aef2-4e16-8969-e38bea0ea336",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
440
extensions/app/assets/lib/task/task.ts
Normal file
440
extensions/app/assets/lib/task/task.ts
Normal file
@@ -0,0 +1,440 @@
|
||||
interface IHandle {
|
||||
(next: (data?: any) => boolean, retry: (timeout?: number) => Promise<boolean>, end: (data?: any) => boolean): void
|
||||
}
|
||||
|
||||
interface IFinish<T> {
|
||||
(results?: T, success?: boolean): any
|
||||
}
|
||||
|
||||
export interface ITask<T extends Array<any> = any[]> {
|
||||
readonly results: Readonly<T>;
|
||||
size(): number;
|
||||
add(handle: IHandle): this;
|
||||
start(finish?: IFinish<T> | Function): this;
|
||||
stop(): boolean;
|
||||
isRunning(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序执行
|
||||
*/
|
||||
export class Sync<T extends Array<any>> implements ITask<T> {
|
||||
private running = false;
|
||||
private index: number = -1;
|
||||
private list: IHandle[] = [];
|
||||
private finish: IFinish<T> | Function = null;
|
||||
|
||||
/**
|
||||
* 每个handle的返回值,通过next或end存储
|
||||
*/
|
||||
public results: T = [] as T;
|
||||
|
||||
/**
|
||||
* 任务数量
|
||||
* @returns
|
||||
*/
|
||||
public size(): number {
|
||||
return this.list.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个任务
|
||||
* @param handle
|
||||
* @returns
|
||||
*/
|
||||
public add(handle: IHandle) {
|
||||
this.list.push(handle);
|
||||
this.results.push(undefined);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始执行所有任务
|
||||
* @param finish 执行完毕回调
|
||||
* @returns
|
||||
*/
|
||||
public start(finish?: IFinish<T> | Function) {
|
||||
if (this.running) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.running = true;
|
||||
this.index = -1;
|
||||
this.finish = finish;
|
||||
|
||||
this.next(this.index);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有任务
|
||||
* @returns
|
||||
*/
|
||||
public stop(): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.running = false;
|
||||
if (this.finish) {
|
||||
this.finish(this.results, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在执行
|
||||
* @returns
|
||||
*/
|
||||
public isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @returns
|
||||
*/
|
||||
public isStop() {
|
||||
return !this.running;
|
||||
}
|
||||
|
||||
private end(data?: any): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof data !== 'undefined') {
|
||||
this.results[this.index] = data;
|
||||
}
|
||||
|
||||
this.running = false;
|
||||
if (this.finish) {
|
||||
this.finish(this.results, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private next(index: number, data?: any): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index !== this.index) return false;
|
||||
|
||||
if (typeof data !== 'undefined') {
|
||||
this.results[this.index] = data;
|
||||
}
|
||||
|
||||
if (++this.index < this.list.length) {
|
||||
this.retry(this.index);
|
||||
} else {
|
||||
this.end();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private retry(index: number): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index !== this.index) return false;
|
||||
|
||||
const handle = this.list[index];
|
||||
handle && handle(
|
||||
(data?: any) => this.next(index, data),
|
||||
(timeout = 0) => {
|
||||
return new Promise(resolve => {
|
||||
if (timeout > 0) {
|
||||
setTimeout(() => {
|
||||
resolve(this.retry(index));
|
||||
}, timeout * 1000);
|
||||
} else {
|
||||
resolve(this.retry(index));
|
||||
}
|
||||
});
|
||||
},
|
||||
(data?: any) => this.end(data)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同时执行
|
||||
*/
|
||||
export class ASync<T extends Array<any>> implements ITask<T> {
|
||||
private running = false;
|
||||
private count: number = 0;
|
||||
private list: IHandle[] = [];
|
||||
private finish: IFinish<T> | Function = null;
|
||||
|
||||
/**
|
||||
* 每个handle的返回值,通过next或end存储
|
||||
*/
|
||||
public results: T = [] as T;
|
||||
|
||||
/**
|
||||
* 任务数量
|
||||
* @returns
|
||||
*/
|
||||
public size(): number {
|
||||
return this.list.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个任务
|
||||
* @param handle
|
||||
* @returns
|
||||
*/
|
||||
public add(handle: IHandle) {
|
||||
this.list.push(handle);
|
||||
this.results.push(undefined);
|
||||
|
||||
if (this.running) {
|
||||
this.retry(this.list.length - 1);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始执行所有任务
|
||||
* @param finish 执行完毕回调
|
||||
* @returns
|
||||
*/
|
||||
public start(finish?: IFinish<T> | Function) {
|
||||
if (this.running) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.running = true;
|
||||
this.count = 0;
|
||||
this.finish = finish;
|
||||
|
||||
if (this.list.length) {
|
||||
for (let index = 0; index < this.list.length; index++) {
|
||||
this.retry(index);
|
||||
}
|
||||
} else {
|
||||
this.end && this.end(this.count);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有任务
|
||||
* @returns
|
||||
*/
|
||||
public stop(): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
this.running = false;
|
||||
if (this.finish) {
|
||||
this.finish(this.results, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在执行
|
||||
* @returns
|
||||
*/
|
||||
public isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @returns
|
||||
*/
|
||||
public isStop() {
|
||||
return !this.running;
|
||||
}
|
||||
|
||||
private end(index: number, data?: any): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= 0 && index < this.results.length) {
|
||||
if (this.results[index] || this.results[index] === null) return false;
|
||||
this.results[index] = typeof data !== 'undefined' ? data : null;
|
||||
}
|
||||
|
||||
this.running = false;
|
||||
if (this.finish) {
|
||||
this.finish(this.results, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private next(index: number, data?: any): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= 0 && index < this.results.length) {
|
||||
if (this.results[index] || this.results[index] === null) return false;
|
||||
this.results[index] = typeof data !== 'undefined' ? data : null;
|
||||
}
|
||||
|
||||
if (++this.count === this.list.length) {
|
||||
this.end && this.end(this.count);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private retry(index: number): boolean {
|
||||
if (!this.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const handle = this.list[index];
|
||||
handle && handle(
|
||||
(data?: any) => this.next(index, data),
|
||||
(timeout = 0) => {
|
||||
return new Promise(resolve => {
|
||||
if (timeout > 0) {
|
||||
setTimeout(() => {
|
||||
resolve(this.retry(index));
|
||||
}, timeout * 1000);
|
||||
} else {
|
||||
resolve(this.retry(index));
|
||||
}
|
||||
});
|
||||
},
|
||||
(data?: any) => this.end(index, data)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class Any<T extends Array<any>> implements ITask<T> {
|
||||
private task = new Sync();
|
||||
|
||||
/**
|
||||
* 每个handle的返回值,通过next或end存储
|
||||
*/
|
||||
public get results(): T {
|
||||
return this.task.results as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务数量
|
||||
* @returns
|
||||
*/
|
||||
public size() {
|
||||
return this.task.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个任务
|
||||
* @param handle
|
||||
* @returns
|
||||
*/
|
||||
public add(handles: IHandle | IHandle[]) {
|
||||
if (handles instanceof Array) {
|
||||
const async = new ASync();
|
||||
handles.forEach(handle => async.add(handle));
|
||||
this.task.add(async.start.bind(async));
|
||||
} else {
|
||||
this.task.add(handles);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始执行所有任务
|
||||
* @param finish 执行完毕回调
|
||||
* @returns
|
||||
*/
|
||||
public start(finish?: IFinish<T> | Function) {
|
||||
this.task.start(finish);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有任务
|
||||
* @returns
|
||||
*/
|
||||
public stop() {
|
||||
return this.task.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在执行
|
||||
* @returns
|
||||
*/
|
||||
public isRunning() {
|
||||
return this.task.isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @returns
|
||||
*/
|
||||
public isStop() {
|
||||
return this.task.isStop();
|
||||
}
|
||||
}
|
||||
|
||||
interface IExecuteCallBack {
|
||||
(retry: (timeout?: number) => void): void
|
||||
}
|
||||
|
||||
const task = {
|
||||
/**
|
||||
* 任务顺序执行
|
||||
*/
|
||||
createSync<T extends Array<any>>(): Sync<T> {
|
||||
return new Sync<T>();
|
||||
},
|
||||
|
||||
/**
|
||||
* 任务同时执行
|
||||
*/
|
||||
createASync<T extends Array<any>>(): ASync<T> {
|
||||
return new ASync<T>();
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据参数指定执行顺序
|
||||
* @example
|
||||
* createAny()
|
||||
* .add(1).add(2).add(3).add(4)
|
||||
* .add([5,6,7])
|
||||
* .add(8)
|
||||
* 执行顺序,1,2,3,4依次执行,然后同时执行5,6,7,最后执行8
|
||||
*/
|
||||
createAny<T extends Array<any>>() {
|
||||
return new Any<T>();
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行单个任务
|
||||
*/
|
||||
execute(fun: IExecuteCallBack, retryMax = -1, retryFinish?: Function) {
|
||||
fun(function retry(timeout = 0) {
|
||||
if (retryMax === 0) return retryFinish && retryFinish();
|
||||
retryMax = retryMax > 0 ? retryMax - 1 : retryMax;
|
||||
if (timeout > 0) {
|
||||
setTimeout(() => task.execute(fun, retryMax, retryFinish), timeout * 1000);
|
||||
} else {
|
||||
task.execute(fun, retryMax, retryFinish);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default task;
|
||||
9
extensions/app/assets/lib/task/task.ts.meta
Normal file
9
extensions/app/assets/lib/task/task.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "721e6dcc-aab3-48d6-aa4e-e1baf821263b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager.meta
Normal file
12
extensions/app/assets/manager.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "b50df186-2646-40b3-83c5-5dca8bf01803",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
626
extensions/app/assets/manager/MainManager.prefab
Normal file
626
extensions/app/assets/manager/MainManager.prefab
Normal file
@@ -0,0 +1,626 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "MainManager",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "MainManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 6
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 26
|
||||
},
|
||||
{
|
||||
"__id__": 28
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 30
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "EventManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 5
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "b4ea6NEN3hCPZiqp3hRVbvU",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "38T7Dsd1BPcZKW0ht+pktn"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "d6NoKoYv9Gk4UlM7XwQPMZ",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "TimerManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "b5636+NNRZFEKq6dPkgK4qf",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "1dkZGh7HlMao6WFTkih0ky"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "48d9+lep1ML4jLQU06pY4T",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "LoaderManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "b3bf5M3DHNHcYe1nnNZYr6B",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "8eHWii+rhPFp6edhCSGQYK"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "f2JbolDiVMXbduKISlIjVg",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "SoundManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 15
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "58002Ha2adOWbt2LDr8rmBT",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 14
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 16
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "8bj+DC16xOWa/0aihp7pcS"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "54fbQjsl1HwJD2+SejsBvm",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "UIManager",
|
||||
"_objFlags": 512,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 19
|
||||
},
|
||||
{
|
||||
"__id__": 21
|
||||
},
|
||||
{
|
||||
"__id__": 23
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 25
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "234f6Lx69NNFJ9vC2nHCWRJ",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 18
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 20
|
||||
},
|
||||
"loadingPre": {
|
||||
"__uuid__": "fe542035-b018-493e-bea8-084fe4e01905",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"shadePre": {
|
||||
"__uuid__": "000cee21-922c-4fcd-bd39-6f80ac2436a4",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"toastPre": {
|
||||
"__uuid__": "b2a00c44-d199-4031-8fa7-ea681618b9d4",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "67aJm34PdM/ItCntR8+zcy"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 18
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 22
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 750,
|
||||
"height": 1334
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c3fJug795H8Zpvt/9PivC1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 18
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 24
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 750,
|
||||
"_originalHeight": 1334,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "152XoOPG1D3KEcrikGio7Z"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "4d13DruoVK/5VWhsBYQS/E",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 27
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 750,
|
||||
"height": 1334
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "bab8wNsgZHRICm9NXgLsKC"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 29
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 100,
|
||||
"_originalHeight": 100,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "12csQGnuVJRr1L+07HdNSc"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "09f6AV8NhG8amoujtBeGc3",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
13
extensions/app/assets/manager/MainManager.prefab.meta
Normal file
13
extensions/app/assets/manager/MainManager.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "5e43bb09-848f-434a-b3a5-a6b6602e00af",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "MainManager"
|
||||
}
|
||||
}
|
||||
12
extensions/app/assets/manager/event.meta
Normal file
12
extensions/app/assets/manager/event.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "4f12d0c8-895c-48a5-8805-79653aadb7e4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
89
extensions/app/assets/manager/event/EventManager.ts
Normal file
89
extensions/app/assets/manager/event/EventManager.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { EventTarget, _decorator } from 'cc';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
class Event {
|
||||
static destroy(event: Event) {
|
||||
if (!event) return;
|
||||
event._event = null;
|
||||
}
|
||||
|
||||
// 事件管理器
|
||||
private _event: EventTarget = new EventTarget();
|
||||
|
||||
/**
|
||||
* 事件分发
|
||||
*/
|
||||
public emit(event: string | number, ...data: any[]) {
|
||||
if (!this._event) {
|
||||
throw Error('当前event已销毁,无法继续调用');
|
||||
}
|
||||
this._event.emit(event as any, ...data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件监听
|
||||
*/
|
||||
public on(event: string | number, cb: (...any: any[]) => void, target?: any) {
|
||||
if (!this._event) {
|
||||
throw Error('当前event已销毁,无法继续调用');
|
||||
}
|
||||
this._event.on(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件监听
|
||||
*/
|
||||
public once(event: string | number, cb: (...any: any[]) => void, target?: any) {
|
||||
if (!this._event) {
|
||||
throw Error('当前event已销毁,无法继续调用');
|
||||
}
|
||||
this._event.once(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件移除监听
|
||||
*/
|
||||
public off(event: string | number, cb?: (...any: any[]) => void, target?: any) {
|
||||
if (!this._event) {
|
||||
throw Error('当前event已销毁,无法继续调用');
|
||||
}
|
||||
this._event.off(event as any, cb, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件移除监听
|
||||
*/
|
||||
public targetOff(target: any) {
|
||||
if (!this._event) {
|
||||
throw Error('当前event已销毁,无法继续调用');
|
||||
}
|
||||
this._event.targetOff(target);
|
||||
}
|
||||
}
|
||||
|
||||
@ccclass('EventManager')
|
||||
export default class EventManager extends BaseManager {
|
||||
private events: Map<string | number | Symbol, Event> = new Map();
|
||||
|
||||
clear() {
|
||||
this.events.forEach(event => Event.destroy(event));
|
||||
return this.events.clear();
|
||||
}
|
||||
|
||||
delete(key: string | number | Symbol) {
|
||||
Event.destroy(this.events.get(key));
|
||||
return this.events.delete(key);
|
||||
}
|
||||
|
||||
get(key: string | number | Symbol): Event {
|
||||
if (this.events.has(key)) {
|
||||
return this.events.get(key);
|
||||
}
|
||||
|
||||
const event = new Event();
|
||||
this.events.set(key, event);
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/event/EventManager.ts.meta
Normal file
9
extensions/app/assets/manager/event/EventManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b4ea6344-3778-423d-98aa-a7785155bbd4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/loader.meta
Normal file
12
extensions/app/assets/manager/loader.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "d8954580-884f-4927-b59a-dfb9553d4ce6",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
869
extensions/app/assets/manager/loader/LoaderManager.ts
Normal file
869
extensions/app/assets/manager/loader/LoaderManager.ts
Normal file
@@ -0,0 +1,869 @@
|
||||
import { Asset, AssetManager, Font, ImageAsset, JsonAsset, Label, SceneAsset, Sprite, SpriteFrame, Texture2D, TextureCube, _decorator, assetManager, isValid, path, sp } from 'cc';
|
||||
import { MINIGAME } from 'cc/env';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
import Core from '../../Core';
|
||||
const { ccclass } = _decorator;
|
||||
const REGEX = /^https?:\/\/.*/;
|
||||
|
||||
class Command {
|
||||
private static cache: Command[] = [];
|
||||
|
||||
static create(onComplete: (items: unknown) => void, onProgress: (finish: number, total: number, item: AssetManager.RequestItem) => void = null) {
|
||||
const command = Command.cache.pop() || new Command();
|
||||
onProgress && command.onProgress.push(onProgress);
|
||||
onComplete && command.onComplete.push(onComplete);
|
||||
return command;
|
||||
}
|
||||
|
||||
static put(command: Command) {
|
||||
command.onProgress.length = 0;
|
||||
command.onComplete.length = 0;
|
||||
Command.cache.push(command);
|
||||
}
|
||||
|
||||
onProgress: Array<(finish: number, total: number, item: AssetManager.RequestItem) => void> = [];
|
||||
onComplete: Array<(items: unknown) => void> = [];
|
||||
|
||||
private constructor() { }
|
||||
}
|
||||
|
||||
class Loader {
|
||||
private assetMap = new Map<string, Asset>();
|
||||
private loadingMap = new Map<string, Command>();
|
||||
|
||||
/**
|
||||
* 预加载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public preload(params: { path: string, bundle?: string, version?: string, type?: typeof Asset, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (item: AssetManager.RequestItem[] | null) => void }) {
|
||||
return Core.inst.manager.loader.preload(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public preloadDir(params: { path: string, bundle?: string, version?: string, type?: typeof Asset, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (items: AssetManager.RequestItem[] | null) => void }) {
|
||||
return Core.inst.manager.loader.preloadDir(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundel名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public load<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (item: InstanceType<T> | null) => void }) {
|
||||
const key = `${params.bundle || 'resources'}-${params.type.name}-${params.path}-${params.version || ''}`;
|
||||
|
||||
if (this.loadingMap.has(key)) {
|
||||
const command = this.loadingMap.get(key);
|
||||
params.onProgress && command.onProgress.push(params.onProgress);
|
||||
params.onComplete && command.onComplete.push(params.onComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载中
|
||||
const command = Command.create(params.onComplete, params.onProgress);
|
||||
this.loadingMap.set(key, command);
|
||||
|
||||
// 有缓存
|
||||
if (this.assetMap.has(key)) {
|
||||
const asset = this.assetMap.get(key);
|
||||
// 有缓存的情况下不触发onProgress回调
|
||||
setTimeout(() => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(key)) return;
|
||||
this.loadingMap.delete(key);
|
||||
command.onComplete.forEach(cb => cb(asset));
|
||||
Command.put(command);
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Core.inst.manager.loader.load({
|
||||
...params,
|
||||
onProgress: (finish, total, item) => {
|
||||
if (!this.loadingMap.has(key)) return;
|
||||
command.onProgress.forEach(cb => cb(finish, total, item));
|
||||
},
|
||||
onComplete: (asset) => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(key)) {
|
||||
asset.addRef();
|
||||
asset.decRef();
|
||||
return;
|
||||
}
|
||||
this.loadingMap.delete(key);
|
||||
if (asset) {
|
||||
asset.addRef();
|
||||
this.assetMap.set(key, asset);
|
||||
}
|
||||
command.onComplete.forEach(cb => cb(asset));
|
||||
Command.put(command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadAsync<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void }): Promise<InstanceType<T> | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.load({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundel名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadDir<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (items: InstanceType<T>[] | null) => void }) {
|
||||
const key = `${params.bundle || 'resources'}-${params.type.name}-${params.path}-${params.version || ''}:`;
|
||||
|
||||
if (this.loadingMap.has(key)) {
|
||||
const command = this.loadingMap.get(key);
|
||||
params.onProgress && command.onProgress.push(params.onProgress);
|
||||
params.onComplete && command.onComplete.push(params.onComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载中
|
||||
const command = Command.create(params.onComplete, params.onProgress);
|
||||
this.loadingMap.set(key, command);
|
||||
|
||||
const results = [] as InstanceType<T>[];
|
||||
this.assetMap.forEach((asset, path) => {
|
||||
if (path.indexOf(key) === 0) {
|
||||
results.push(asset as InstanceType<T>);
|
||||
}
|
||||
});
|
||||
|
||||
// 有缓存
|
||||
if (results.length) {
|
||||
// 有缓存的情况下不触发onProgress回调
|
||||
setTimeout(() => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(key)) return;
|
||||
this.loadingMap.delete(key);
|
||||
command.onComplete.forEach(cb => cb(results));
|
||||
Command.put(command);
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Core.inst.manager.loader.loadDir({
|
||||
...params,
|
||||
onProgress: (finish, total, item) => {
|
||||
if (!this.loadingMap.has(key)) return;
|
||||
command.onProgress.forEach(cb => cb(finish, total, item));
|
||||
},
|
||||
onComplete: (assets) => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(key)) {
|
||||
assets?.forEach((asset) => {
|
||||
asset.addRef();
|
||||
asset.decRef();
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.loadingMap.delete(key);
|
||||
assets?.forEach((asset) => {
|
||||
asset.addRef();
|
||||
this.assetMap.set(key + asset.uuid, asset);
|
||||
});
|
||||
command.onComplete.forEach(cb => cb(assets));
|
||||
Command.put(command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadDirAsync<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void }): Promise<InstanceType<T>[] | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.loadDir({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载远程资源
|
||||
* @example
|
||||
* loadRemote({url:'', ext:'.png', onComplete:(result){ }})
|
||||
*/
|
||||
public loadRemote({ url, ext, onComplete }: { url: string, ext?: string, onComplete?: (result: Asset | null) => void }) {
|
||||
if (this.loadingMap.has(url)) {
|
||||
const command = this.loadingMap.get(url);
|
||||
onComplete && command.onComplete.push(onComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载中
|
||||
const command = Command.create(onComplete);
|
||||
this.loadingMap.set(url, command);
|
||||
|
||||
// 有缓存
|
||||
if (this.assetMap.has(url)) {
|
||||
const asset = this.assetMap.get(url);
|
||||
// 有缓存的情况下不触发onProgress回调
|
||||
setTimeout(() => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(url)) return;
|
||||
this.loadingMap.delete(url);
|
||||
command.onComplete.forEach(cb => cb(asset));
|
||||
Command.put(command);
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Core.inst.manager.loader.loadRemote({
|
||||
url, ext,
|
||||
onComplete: (asset) => {
|
||||
// 加载无效
|
||||
if (!this.loadingMap.has(url)) {
|
||||
asset.addRef();
|
||||
asset.decRef();
|
||||
return;
|
||||
}
|
||||
this.loadingMap.delete(url);
|
||||
if (asset) {
|
||||
asset.addRef();
|
||||
this.assetMap.set(url, asset);
|
||||
}
|
||||
command.onComplete.forEach(cb => cb(asset));
|
||||
Command.put(command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载远程资源
|
||||
* @example
|
||||
* await loadRemoteAsync({url:'', ext:'.png'})
|
||||
*/
|
||||
public loadRemoteAsync(params: { url: string, ext?: string }): Promise<Asset | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.loadRemote({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setFont({target:label, path:'font/num', bundle:'resources', onComplete:(succ)=>{}})
|
||||
* setFont({target:label, url:'http://img/a/font',ext:'.ttf', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setFont(params: { target: Label, url: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setFont(params: { target: Label, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setFont(params: { target: Label, path?: string, bundle?: string, url?: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
if (params.url) {
|
||||
this.loadRemote({
|
||||
url: params.url,
|
||||
ext: params.ext,
|
||||
onComplete: (font: Font) => {
|
||||
if (!font || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.font = font;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: Font,
|
||||
onComplete: (font) => {
|
||||
if (!font || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.font = font;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Spine资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setSpine({target:spine, path:'spine/role', bundle:'resources', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setSpine(params: { target: sp.Skeleton, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: sp.SkeletonData,
|
||||
onComplete: (skeletonData) => {
|
||||
if (!skeletonData || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.skeletonData = skeletonData;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setSprite({target:sprite, path:'img/a/spriteFrame', bundle:'resources', onComplete:(succ)=>{}})
|
||||
* setSprite({target:sprite, url:'http://img/a/avatar',ext:'.png', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setSprite(params: { target: Sprite, url: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setSprite(params: { target: Sprite, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setSprite(params: { target: Sprite, path?: string, bundle?: string, url?: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
if (params.url) {
|
||||
this.loadRemote({
|
||||
url: params.url,
|
||||
ext: params.ext,
|
||||
onComplete: (imageAsset: ImageAsset) => {
|
||||
if (!imageAsset || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
const spriteFrame = SpriteFrame.createWithImage(imageAsset);
|
||||
params.target.spriteFrame = spriteFrame;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: SpriteFrame,
|
||||
onComplete: (spriteFrame) => {
|
||||
if (!spriteFrame || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.spriteFrame = spriteFrame;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放所有资源
|
||||
*/
|
||||
public releaseAll() {
|
||||
const assetList: Asset[] = [];
|
||||
this.assetMap.forEach(asset => assetList.push(asset));
|
||||
this.assetMap.clear();
|
||||
this.loadingMap.clear();
|
||||
// 延迟一秒释放资源
|
||||
setTimeout(() => {
|
||||
assetList.forEach(asset => asset.decRef());
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ccclass('LoaderManager')
|
||||
export default class LoaderManager extends BaseManager {
|
||||
/**
|
||||
* `Loader`的目的是对资源加载进行分组引用计数管理。比如两个`Loader`实例都加载了同一个资源,当某个实例执行releaseAll后,并不会让引擎资源释放资源,只有两个实例都执行了释放资源后,才会让引擎资源释放资源。
|
||||
* @example
|
||||
* // 创建Loader实例
|
||||
* const loader = new LoaderManager.Loader();
|
||||
* // 加载资源
|
||||
* loader.load({path:'img/a/spriteFrame', bundle:'resources', type:SpriteFrame, onComplete:(spriteFrame)=>{}})
|
||||
* // 加载远程图片资源
|
||||
* loader.loadRemote({url:'http://img/a/avatar',ext:'.png', onComplete:(imageAsset)=>{}})
|
||||
* // 释放所有资源
|
||||
* loader.releaseAll();
|
||||
*/
|
||||
static Loader = Loader;
|
||||
|
||||
private handle(handle: string, { bundle, version, path, type, onProgress, onComplete }: { bundle?: string, version?: string, path: string, type?: typeof Asset, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (result: unknown | null) => void }) {
|
||||
if (!handle) {
|
||||
this.error('handle is empty');
|
||||
return onComplete && onComplete(null);
|
||||
}
|
||||
if (!path) {
|
||||
this.error(`${handle} fail. path is empty`);
|
||||
return onComplete && onComplete(null);
|
||||
}
|
||||
if (!bundle) bundle = 'resources';
|
||||
|
||||
const args: any[] = [path];
|
||||
if (type) args.push(type);
|
||||
if (onProgress) args.push(onProgress);
|
||||
args.push((err: string, res: any) => {
|
||||
if (err) {
|
||||
this.error(`${handle} "${path}" fail`, err);
|
||||
if (type === SpriteFrame && path.slice(-12) !== '/spriteFrame') {
|
||||
this.warn(`加载SpriteFrame类型的资源, 路径可能需要以/spriteFrame结尾, 如: 「${path}」 -> 「${path}/spriteFrame」`);
|
||||
} else if (type === Texture2D && path.slice(-8) !== '/texture') {
|
||||
this.warn(`加载Texture2D类型的资源, 路径可能需要以/texture结尾, 如: 「${path}」 -> 「${path}/texture」`);
|
||||
} else if (type === TextureCube && path.slice(-12) !== '/textureCube') {
|
||||
this.warn(`加载TextureCube类型的资源, 路径可能需要以/textureCube结尾, 如: 「${path}」 -> 「${path}/textureCube」`);
|
||||
}
|
||||
onComplete && onComplete(null);
|
||||
} else {
|
||||
onComplete && onComplete(res);
|
||||
}
|
||||
});
|
||||
|
||||
this.loadBundle({
|
||||
bundle, version,
|
||||
onComplete(bundle) {
|
||||
if (!bundle) return onComplete && onComplete(null);
|
||||
bundle[handle](args[0], args[1], args[2], args[3]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public preload(params: { path: string, bundle?: string, version?: string, type?: typeof Asset, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (item: AssetManager.RequestItem[] | null) => void }) {
|
||||
if (SceneAsset === params.type as typeof Asset) {
|
||||
this.handle('preloadScene', { path: params.path, bundle: params.bundle, version: params.version, onProgress: params.onProgress, onComplete: params.onComplete });
|
||||
} else {
|
||||
this.handle('preload', params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public preloadDir(params: { path: string, bundle?: string, version?: string, type?: typeof Asset, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (items: AssetManager.RequestItem[] | null) => void }) {
|
||||
this.handle('preloadDir', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public load<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (item: InstanceType<T> | null) => void }) {
|
||||
if (SceneAsset === params.type as typeof Asset) {
|
||||
this.handle('loadScene', { path: params.path, bundle: params.bundle, version: params.version, onProgress: params.onProgress, onComplete: params.onComplete });
|
||||
} else {
|
||||
this.handle('load', params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadAsync<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void }): Promise<InstanceType<T> | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.load({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadDir<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void, onComplete?: (items: InstanceType<T>[] | null) => void }) {
|
||||
this.handle('loadDir', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载bundle下的资源
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public loadDirAsync<T extends typeof Asset>(params: { path: string, bundle?: string, version?: string, type?: T, onProgress?: (finish: number, total: number, item: AssetManager.RequestItem) => void }): Promise<InstanceType<T>[] | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.loadDir({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁一个bundle中对应path和type的资源
|
||||
* @param params.bundle 默认为resources,如果是远程bundle,则使用url末位作为bundle名
|
||||
* @param params.path bundle下的相对路径
|
||||
* @param params.type 资源类型
|
||||
*/
|
||||
public release({ path, bundle, type }: { path: string, bundle?: string, type?: typeof Asset }) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
assetManager.getBundle(bundle)?.release(path, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁一个bundle中所有的资源
|
||||
* @param bundle 默认为resources,如果是远程bundle,则使用url末位作为bundle名
|
||||
*/
|
||||
public releaseAll(bundle?: string) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
const _bundle = assetManager.getBundle(bundle);
|
||||
if (!_bundle) return;
|
||||
// 只释放自己内部的资源,依赖的资源只减少引用计数
|
||||
_bundle.getDirWithPath('/', Asset).forEach((asset) => {
|
||||
_bundle.release(asset.path, asset.ctor);
|
||||
});
|
||||
// cocos提供的方法会将依赖的资源也卸载(这个设计很奇怪)
|
||||
// _bundle?.releaseAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁一个bundle中未使用的资源
|
||||
* @param bundle 默认为resources,如果是远程bundle,则使用url末位作为bundle名
|
||||
*/
|
||||
public releaseUnused(bundle?: string) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
//@ts-ignore
|
||||
assetManager.getBundle(bundle)?.releaseUnusedAssets();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载一个bundle
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public loadBundle({ bundle, version, onComplete }: { bundle?: string, version?: string, onComplete?: (bundle: AssetManager.Bundle | null) => any }) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
|
||||
if (MINIGAME) {
|
||||
if (REGEX.test(bundle)) {
|
||||
this.warn('小游戏环境下只支持加载远程Bundle的资源数据, 不会加载脚本');
|
||||
this.reloadBundle({ bundle, version, onComplete });
|
||||
return;
|
||||
}
|
||||
if (version && assetManager.downloader.bundleVers[bundle] !== version) {
|
||||
this.warn('小游戏环境下只支持更新Bundle的远程资源数据, 不会更新脚本');
|
||||
// 先加载本地bundle运行脚本
|
||||
assetManager.loadBundle(bundle, (err: Error, b: AssetManager.Bundle) => {
|
||||
if (err || !b) return onComplete?.(null);
|
||||
// 然后再走重载逻辑更新资源
|
||||
this.reloadBundle({ bundle, version, onComplete });
|
||||
});
|
||||
} else {
|
||||
assetManager.loadBundle(bundle, (err: Error, bundle: AssetManager.Bundle) => {
|
||||
onComplete && onComplete(err ? null : bundle);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
assetManager.loadBundle(bundle, { version }, (err: Error, bundle: AssetManager.Bundle) => {
|
||||
onComplete && onComplete(err ? null : bundle);
|
||||
});
|
||||
} else {
|
||||
assetManager.loadBundle(bundle, (err: Error, bundle: AssetManager.Bundle) => {
|
||||
onComplete && onComplete(err ? null : bundle);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载一个bundle
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public loadBundleAsync(params: { bundle?: string, version?: string }): Promise<AssetManager.Bundle | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.loadBundle({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个已经加载的bundle
|
||||
* @param bundle 默认为resources,如果是远程bundle,则使用url末位作为bundle名
|
||||
*/
|
||||
public getBundle(bundle?: string) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
return assetManager.getBundle(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个已经加载的bundle
|
||||
* @param bundle 默认为resources,如果是远程bundle,则使用url末位作为bundle名
|
||||
*/
|
||||
public removeBundle(bundle?: string) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
const b = assetManager.getBundle(bundle);
|
||||
if (b) assetManager.removeBundle(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载一个bundle(只重载资源列表)
|
||||
* - 只有远程bundle支持重载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public reloadBundle({ bundle, version, onComplete }: { bundle?: string, version?: string, onComplete?: (bundle: AssetManager.Bundle | null) => any }) {
|
||||
if (!bundle) bundle = 'resources';
|
||||
|
||||
let baseUrl = '';
|
||||
let configUrl = '';
|
||||
|
||||
if (REGEX.test(bundle)) {
|
||||
baseUrl = bundle;
|
||||
const suffix = version ? `${version}.` : '';
|
||||
configUrl = `${baseUrl}config.${suffix}json`;
|
||||
}
|
||||
else {
|
||||
baseUrl = `${assetManager.downloader.remoteServerAddress}remote/${bundle}/`;
|
||||
const suffix = version ? `${version}.` : '';
|
||||
configUrl = `${baseUrl}config.${suffix}json`;
|
||||
}
|
||||
|
||||
// 清除可能存在的config缓存
|
||||
assetManager.cacheManager?.removeCache(configUrl);
|
||||
assetManager.loadRemote(configUrl, (err: Error, data: JsonAsset) => {
|
||||
if (err) {
|
||||
this.error(`下载Bundle配置失败: ${configUrl}`);
|
||||
onComplete?.(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.releaseAll(path.basename(bundle));
|
||||
this.removeBundle(path.basename(bundle));
|
||||
|
||||
const ab = new AssetManager.Bundle();
|
||||
const config = data.json as any;
|
||||
config.base = baseUrl;
|
||||
ab.init(config);
|
||||
onComplete?.(ab);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载一个bundle(只重载资源列表)
|
||||
* - 只有远程bundle支持重载
|
||||
* @param params.bundle 默认为resources, 可以是项目中的bundle名,也可以是远程bundle的url(url末位作为bundle名),参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#%E5%8A%A0%E8%BD%BD-asset-bundle
|
||||
* @param params.version 远程bundle的版本,参考https://docs.cocos.com/creator/manual/zh/asset/bundle.html#asset-bundle-%E7%9A%84%E7%89%88%E6%9C%AC
|
||||
*/
|
||||
public reloadBundleAsync(params: { bundle?: string, version?: string }): Promise<AssetManager.Bundle | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.reloadBundle({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载远程资源
|
||||
* @example
|
||||
* loadRemote({url:'', ext:'.png', onComplete:(result){ }})
|
||||
*/
|
||||
public loadRemote({ url, ext, onComplete }: { url: string, ext?: string, onComplete?: (result: Asset | null) => void }) {
|
||||
if (ext) {
|
||||
assetManager.loadRemote(url, { ext }, (error, res) => {
|
||||
if (error) {
|
||||
this.error(`loadRemote ${url} fail`);
|
||||
return onComplete && onComplete(null);
|
||||
}
|
||||
onComplete && onComplete(res);
|
||||
});
|
||||
} else {
|
||||
assetManager.loadRemote(url, (error, res) => {
|
||||
if (error) {
|
||||
this.error(`loadRemote ${url} fail`);
|
||||
return onComplete && onComplete(null);
|
||||
}
|
||||
onComplete && onComplete(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载远程资源
|
||||
* @example
|
||||
* await loadRemoteAsync({url:'', ext:'.png'})
|
||||
*/
|
||||
public loadRemoteAsync(params: { url: string, ext?: string }): Promise<Asset | null> {
|
||||
return new Promise((resolve) => {
|
||||
this.loadRemote({
|
||||
...params,
|
||||
onComplete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setFont({target:label, path:'font/num', bundle:'resources', onComplete:(succ)=>{}})
|
||||
* setFont({target:label, url:'http://img/a/font',ext:'.ttf', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setFont(params: { target: Label, url: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setFont(params: { target: Label, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setFont(params: { target: Label, path?: string, bundle?: string, url?: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
if (params.url) {
|
||||
this.loadRemote({
|
||||
url: params.url,
|
||||
ext: params.ext,
|
||||
onComplete: (font: Font) => {
|
||||
if (!font || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.font = font;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: Font,
|
||||
onComplete: (font) => {
|
||||
if (!font || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.font = font;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Spine资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setSpine({target:spine, path:'spine/role', bundle:'resources', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setSpine(params: { target: sp.Skeleton, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: sp.SkeletonData,
|
||||
onComplete: (skeletonData) => {
|
||||
if (!skeletonData || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.skeletonData = skeletonData;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片资源
|
||||
* @param params.bundle 默认为resources
|
||||
* @param params.path bundle下的相对路径
|
||||
*
|
||||
* @example
|
||||
* setSprite({target:sprite, path:'img/a/spriteFrame', bundle:'resources', onComplete:(succ)=>{}})
|
||||
* setSprite({target:sprite, url:'http://img/a/avatar',ext:'.png', onComplete:(succ)=>{}})
|
||||
*/
|
||||
public setSprite(params: { target: Sprite, url: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setSprite(params: { target: Sprite, path: string, bundle?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }): void;
|
||||
public setSprite(params: { target: Sprite, path?: string, bundle?: string, url?: string, ext?: string, onComplete?: (success: boolean) => any, onSuccess?: () => void, onFail?: () => void }) {
|
||||
if (params.url) {
|
||||
this.loadRemote({
|
||||
url: params.url,
|
||||
ext: params.ext,
|
||||
onComplete: (imageAsset: ImageAsset) => {
|
||||
if (!imageAsset || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
const spriteFrame = SpriteFrame.createWithImage(imageAsset);
|
||||
params.target.spriteFrame = spriteFrame;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.load({
|
||||
path: params.path,
|
||||
bundle: params.bundle,
|
||||
type: SpriteFrame,
|
||||
onComplete: (spriteFrame) => {
|
||||
if (!spriteFrame || !isValid(params.target)) {
|
||||
params.onFail && params.onFail();
|
||||
params.onComplete && params.onComplete(false);
|
||||
return;
|
||||
}
|
||||
params.target.spriteFrame = spriteFrame;
|
||||
params.onSuccess && params.onSuccess();
|
||||
params.onComplete && params.onComplete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b3bf5337-0c73-4771-87b5-9e735962be81",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/sound.meta
Normal file
12
extensions/app/assets/manager/sound.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "a99e9a5e-e037-428c-b8f4-e5ad266db8ee",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
152
extensions/app/assets/manager/sound/Audio.ts
Normal file
152
extensions/app/assets/manager/sound/Audio.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { AudioClip, AudioSource, Node } from 'cc';
|
||||
|
||||
export default class Audio {
|
||||
private volume = 1;
|
||||
private volumeScale = 1;
|
||||
private mute = false;
|
||||
private endedCallback: Function = null;
|
||||
private startedCallback: Function = null;
|
||||
|
||||
private _playing = false;
|
||||
public get playing() {
|
||||
return this._playing;
|
||||
}
|
||||
private set playing(value) {
|
||||
this._playing = value;
|
||||
}
|
||||
|
||||
private _paused = false;
|
||||
public get paused() {
|
||||
return this._paused;
|
||||
}
|
||||
private set paused(value) {
|
||||
this._paused = value;
|
||||
}
|
||||
|
||||
private audioSource: AudioSource = null;
|
||||
constructor() {
|
||||
const node = new Node('audio');
|
||||
this.audioSource = node.addComponent(AudioSource);
|
||||
node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
|
||||
node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this);
|
||||
}
|
||||
|
||||
private onAudioEnded() {
|
||||
if (this.endedCallback) {
|
||||
const endedCallback = this.endedCallback;
|
||||
this.endedCallback = null;
|
||||
endedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
private onAudioStarted() {
|
||||
if (this.startedCallback) {
|
||||
const startedCallback = this.startedCallback;
|
||||
this.startedCallback = null;
|
||||
startedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
play(clip: AudioClip, onEnded: Function = null, onStarted: Function = null) {
|
||||
this.audioSource.clip = clip;
|
||||
this.endedCallback = onEnded;
|
||||
this.startedCallback = onStarted;
|
||||
this.audioSource.play();
|
||||
this.playing = true;
|
||||
this.paused = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.playing = false;
|
||||
this.paused = false;
|
||||
this.audioSource.stop();
|
||||
this.audioSource.node.emit(AudioSource.EventType.ENDED);
|
||||
return this;
|
||||
}
|
||||
|
||||
pause() {
|
||||
if (!this.playing) return this;
|
||||
|
||||
this.paused = true;
|
||||
this.audioSource.pause();
|
||||
return this;
|
||||
}
|
||||
|
||||
resume() {
|
||||
if (!this.playing) return this;
|
||||
if (!this.paused) return this;
|
||||
|
||||
this.paused = false;
|
||||
this.audioSource.play();
|
||||
return this;
|
||||
}
|
||||
|
||||
setVolume(volume = 1, scale?: number) {
|
||||
this.volume = volume;
|
||||
if (typeof scale === 'number') this.volumeScale = scale;
|
||||
this.audioSource.volume = volume * this.volumeScale * (this.mute ? 0 : 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
getVolume() {
|
||||
return this.volume;
|
||||
}
|
||||
|
||||
setVolumeScale(scale = 1) {
|
||||
this.volumeScale = scale;
|
||||
this.audioSource.volume = this.volume * scale * (this.mute ? 0 : 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
getVolumeScale() {
|
||||
return this.volumeScale;
|
||||
}
|
||||
|
||||
setLoop(loop: boolean) {
|
||||
this.audioSource.loop = loop;
|
||||
return this;
|
||||
}
|
||||
|
||||
getLoop() {
|
||||
return this.audioSource.loop;
|
||||
}
|
||||
|
||||
setMute(mute = true) {
|
||||
this.mute = mute;
|
||||
this.setVolume(this.volume);
|
||||
return this;
|
||||
}
|
||||
|
||||
getMute() {
|
||||
return this.mute;
|
||||
}
|
||||
|
||||
onEnded(endedCallback: Function) {
|
||||
this.endedCallback = endedCallback;
|
||||
return this;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.volume = 1;
|
||||
this.volumeScale = 1;
|
||||
this.mute = false;
|
||||
this.paused = false;
|
||||
this.endedCallback = null;
|
||||
this.startedCallback = null;
|
||||
if (this.audioSource) {
|
||||
this.audioSource.stop();
|
||||
this.audioSource.volume = 1;
|
||||
this.audioSource.clip = null;
|
||||
this.audioSource.loop = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.clear();
|
||||
this.audioSource.destroy();
|
||||
this.audioSource.node.destroy();
|
||||
this.audioSource = null;
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/sound/Audio.ts.meta
Normal file
9
extensions/app/assets/manager/sound/Audio.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a40e77a6-cdac-445c-a50c-a8ced2411dbc",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
287
extensions/app/assets/manager/sound/AudioEngine.ts
Normal file
287
extensions/app/assets/manager/sound/AudioEngine.ts
Normal file
@@ -0,0 +1,287 @@
|
||||
import { AudioClip } from 'cc';
|
||||
import Audio from './Audio';
|
||||
import AudioManager from './AudioManager';
|
||||
|
||||
export default class AudioEngine {
|
||||
private static _inst: AudioEngine = null;
|
||||
static get inst() {
|
||||
if (!this._inst) this._inst = new AudioEngine();
|
||||
return this._inst;
|
||||
}
|
||||
private constructor() { }
|
||||
|
||||
/**effect的id从1开始,music的id始终为0 */
|
||||
private audioID = 1;
|
||||
private endedCallbackMap: Map<number, Function> = new Map();
|
||||
private effectMap: Map<number, Audio> = new Map();
|
||||
private music: Audio = null;
|
||||
|
||||
private musicMute = false;
|
||||
private musicVolumeScale = 1;
|
||||
|
||||
private effectMute = false;
|
||||
private effectVolumeScale = 1;
|
||||
|
||||
////////////////////////////////
|
||||
// 音效 //
|
||||
////////////////////////////////
|
||||
playEffect(audioClip: AudioClip, volume = 1, loop = false, onStarted: (audioID: number) => any = null, onEnded: Function = null) {
|
||||
if (this.audioID > 100000) this.audioID = 1;
|
||||
|
||||
const audioID = this.audioID++;
|
||||
const audio = AudioManager.inst.getAudio();
|
||||
this.effectMap.set(audioID, audio);
|
||||
if (onEnded) this.endedCallbackMap.set(audioID, onEnded);
|
||||
|
||||
audio.setLoop(loop)
|
||||
.setMute(this.effectMute)
|
||||
.setVolume(volume, this.effectVolumeScale)
|
||||
.play(audioClip, () => {
|
||||
AudioManager.inst.putAudio(audio);
|
||||
this.effectMap.delete(audioID);
|
||||
const callback = this.endedCallbackMap.get(audioID);
|
||||
if (callback) {
|
||||
this.endedCallbackMap.delete(audioID);
|
||||
callback();
|
||||
}
|
||||
}, () => {
|
||||
onStarted && onStarted(audioID);
|
||||
});
|
||||
|
||||
return audioID;
|
||||
}
|
||||
|
||||
stopEffect(id: number) {
|
||||
return !!this.effectMap.get(id)?.stop();
|
||||
}
|
||||
|
||||
stopAllEffects() {
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.stop();
|
||||
});
|
||||
}
|
||||
|
||||
pauseEffect(id: number) {
|
||||
return !!this.effectMap.get(id)?.pause();
|
||||
}
|
||||
|
||||
pauseAllEffects() {
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.pause();
|
||||
});
|
||||
}
|
||||
|
||||
resumeEffect(id: number) {
|
||||
return !!this.effectMap.get(id)?.resume();
|
||||
}
|
||||
|
||||
resumeAllEffects() {
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.resume();
|
||||
});
|
||||
}
|
||||
|
||||
setEffectMute(id: number, mute: boolean) {
|
||||
return !!this.effectMap.get(id)?.setMute(mute);
|
||||
}
|
||||
|
||||
getEffectMute(id: number) {
|
||||
return !!this.effectMap.get(id)?.getMute();
|
||||
}
|
||||
|
||||
setEffectVolume(id: number, volume: number) {
|
||||
return !!this.effectMap.get(id)?.setVolume(volume);
|
||||
}
|
||||
|
||||
getEffectVolume(id: number) {
|
||||
return this.effectMap.get(id)?.getVolume() || 0;
|
||||
}
|
||||
|
||||
setAllEffectsVolume(volume: number) {
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.setVolume(volume);
|
||||
});
|
||||
}
|
||||
|
||||
setEffectVolumeScale(id: number, volume: number) {
|
||||
return !!this.effectMap.get(id)?.setVolumeScale(volume);
|
||||
}
|
||||
|
||||
getEffectVolumeScale(id: number) {
|
||||
return this.effectMap.get(id)?.getVolumeScale() || 0;
|
||||
}
|
||||
|
||||
setGlobalEffectsVolumeScale(scale: number) {
|
||||
this.effectVolumeScale = scale;
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.setVolumeScale(scale);
|
||||
});
|
||||
}
|
||||
|
||||
getGlobalEffectsVolumeScale() {
|
||||
return this.effectVolumeScale;
|
||||
}
|
||||
|
||||
setGlobalEffectsMute(mute: boolean) {
|
||||
this.effectMute = mute;
|
||||
this.effectMap.forEach((audio) => {
|
||||
audio.setMute(mute);
|
||||
});
|
||||
}
|
||||
|
||||
getGlobalEffectsMute() {
|
||||
return this.effectMute;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// 音乐 //
|
||||
////////////////////////////////
|
||||
playMusic(audioClip: AudioClip, volume = 1, onStarted: Function = null) {
|
||||
this.stopMusic();
|
||||
|
||||
this.music = AudioManager.inst.getAudio();
|
||||
this.music
|
||||
.setLoop(true)
|
||||
.setMute(this.musicMute)
|
||||
.setVolume(volume, this.musicVolumeScale)
|
||||
.play(audioClip, null, onStarted);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stopMusic() {
|
||||
if (!this.music) return false;
|
||||
this.music.destroy();
|
||||
this.music = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
pauseMusic() {
|
||||
if (!this.music) return false;
|
||||
this.music.pause();
|
||||
return true;
|
||||
}
|
||||
|
||||
resumeMusic() {
|
||||
if (!this.music) return false;
|
||||
this.music.resume();
|
||||
return true;
|
||||
}
|
||||
|
||||
setMusicVolume(volume: number) {
|
||||
if (!this.music) return false;
|
||||
this.music.setVolume(volume);
|
||||
return true;
|
||||
}
|
||||
|
||||
getMusicVolume() {
|
||||
if (!this.music) return -1;
|
||||
return this.music.getVolume();
|
||||
}
|
||||
|
||||
setMusicVolumeScale(scale: number) {
|
||||
this.musicVolumeScale = scale;
|
||||
this.music?.setVolumeScale(scale);
|
||||
return true;
|
||||
}
|
||||
|
||||
getMusicVolumeScale() {
|
||||
return this.musicVolumeScale;
|
||||
}
|
||||
|
||||
setMusicMute(mute: boolean) {
|
||||
this.musicMute = mute;
|
||||
this.music?.setMute(mute);
|
||||
return true;
|
||||
}
|
||||
|
||||
getMusicMute() {
|
||||
return this.musicMute;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// 通用 //
|
||||
////////////////////////////////
|
||||
setEndedCallback(audioID: number, callback: Function) {
|
||||
if (audioID === 0) {
|
||||
return !!this.music?.onEnded(callback);
|
||||
} else {
|
||||
if (this.effectMap.has(audioID)) {
|
||||
this.endedCallbackMap.set(audioID, callback);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stop(audioID: number) {
|
||||
if (audioID === 0) {
|
||||
return this.stopMusic();
|
||||
} else {
|
||||
return this.stopEffect(audioID);
|
||||
}
|
||||
}
|
||||
|
||||
pause(audioID: number) {
|
||||
if (audioID === 0) {
|
||||
return this.pauseMusic();
|
||||
} else {
|
||||
return this.pauseEffect(audioID);
|
||||
}
|
||||
}
|
||||
|
||||
resume(audioID: number) {
|
||||
if (audioID === 0) {
|
||||
return this.resumeMusic();
|
||||
} else {
|
||||
return this.resumeEffect(audioID);
|
||||
}
|
||||
}
|
||||
|
||||
pauseAll() {
|
||||
this.pauseMusic();
|
||||
this.pauseAllEffects();
|
||||
}
|
||||
|
||||
resumeAll() {
|
||||
this.resumeMusic();
|
||||
this.resumeAllEffects();
|
||||
}
|
||||
|
||||
stopAll() {
|
||||
this.stopMusic();
|
||||
this.stopAllEffects();
|
||||
}
|
||||
|
||||
setVolume(audioID: number, volume: number) {
|
||||
if (audioID === 0) {
|
||||
return this.setMusicVolume(volume);
|
||||
} else {
|
||||
return this.setEffectVolume(audioID, volume);
|
||||
}
|
||||
}
|
||||
|
||||
getVolume(audioID: number) {
|
||||
if (audioID === 0) {
|
||||
return this.getMusicVolume();
|
||||
} else {
|
||||
return this.getEffectVolume(audioID);
|
||||
}
|
||||
}
|
||||
|
||||
setVolumeScale(audioID: number, scale: number) {
|
||||
if (audioID === 0) {
|
||||
return this.setMusicVolumeScale(scale);
|
||||
} else {
|
||||
return this.setEffectVolumeScale(audioID, scale);
|
||||
}
|
||||
}
|
||||
|
||||
getVolumeScale(audioID: number) {
|
||||
if (audioID === 0) {
|
||||
return this.getMusicVolumeScale();
|
||||
} else {
|
||||
return this.getEffectVolumeScale(audioID);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/sound/AudioEngine.ts.meta
Normal file
9
extensions/app/assets/manager/sound/AudioEngine.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7a638f5c-801f-4e69-88cc-3fc72e1be985",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
24
extensions/app/assets/manager/sound/AudioManager.ts
Normal file
24
extensions/app/assets/manager/sound/AudioManager.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import Audio from './Audio';
|
||||
|
||||
export default class AudioManager {
|
||||
private static _inst: AudioManager = null;
|
||||
static get inst() {
|
||||
if (!this._inst) this._inst = new AudioManager();
|
||||
return this._inst;
|
||||
}
|
||||
private constructor() { }
|
||||
|
||||
private audioArray: Audio[] = [];
|
||||
|
||||
getAudio() {
|
||||
if (this.audioArray.length) {
|
||||
return this.audioArray.pop();
|
||||
}
|
||||
return new Audio();
|
||||
}
|
||||
|
||||
putAudio(audio: Audio) {
|
||||
audio.clear();
|
||||
this.audioArray.push(audio);
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/sound/AudioManager.ts.meta
Normal file
9
extensions/app/assets/manager/sound/AudioManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "5902cecf-4966-4675-95a9-ab0f0f271857",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
717
extensions/app/assets/manager/sound/SoundManager.ts
Normal file
717
extensions/app/assets/manager/sound/SoundManager.ts
Normal file
@@ -0,0 +1,717 @@
|
||||
import { AssetManager, AudioClip, Button, Game, _decorator, game, isValid, sys } from 'cc';
|
||||
import { IEffectName, IMusicName } from '../../../../../assets/app-builtin/app-admin/executor';
|
||||
import Core from '../../Core';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
import AudioEngine from './AudioEngine';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
interface playMusic<T> { name: T, volume?: number, force?: boolean, onPlay?: Function, onError?: Function }
|
||||
interface playEffect<T> { name: T, volume?: number, loop?: boolean, interval?: number, onPlay?: (audioID: number) => any, onError?: Function, onEnded?: Function }
|
||||
interface playMusicAsync<T> { name: T, volume?: number, force?: boolean }
|
||||
interface playEffectAsync<T> { name: T, volume?: number, loop?: boolean, interval?: number, onEnded?: Function }
|
||||
|
||||
interface playMusicWidthBundle { name: string, bundle: string, volume?: number, force?: boolean, onPlay?: Function, onError?: Function }
|
||||
interface playEffectWidthBundle { name: string, bundle: string, volume?: number, loop?: boolean, interval?: number, onPlay?: (audioID: number) => any, onError?: Function, onEnded?: Function }
|
||||
interface playMusicWidthBundleAsync { name: string, bundle: string, volume?: number, force?: boolean }
|
||||
interface playEffectWidthBundleAsync { name: string, bundle: string, volume?: number, loop?: boolean, interval?: number, onEnded?: Function }
|
||||
|
||||
const storage = {
|
||||
set(key: string, value: any) {
|
||||
sys.localStorage.setItem(key, JSON.stringify(value));
|
||||
},
|
||||
get(key: string) {
|
||||
const data = sys.localStorage.getItem(key);
|
||||
if (data && typeof data === 'string') {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 音乐名字枚举
|
||||
*/
|
||||
const MusicName: { [key in IMusicName]: key } = new Proxy({} as any, {
|
||||
get: function (target, key) {
|
||||
if (target[key]) return target[key];
|
||||
target[key] = key;
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 音效名字枚举
|
||||
*/
|
||||
const EffectName: { [key in IEffectName]: key } = new Proxy({} as any, {
|
||||
get: function (target, key) {
|
||||
if (target[key]) return target[key];
|
||||
target[key] = key;
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
const BundleName = 'app-sound';
|
||||
@ccclass('SoundManager')
|
||||
export default class SoundManager<E extends string, M extends string> extends BaseManager {
|
||||
/**静态设置 */
|
||||
static setting: {
|
||||
/**预加载 */
|
||||
preload?: (IMusicName | IEffectName)[],
|
||||
|
||||
/**默认播放的音乐名 */
|
||||
defaultMusicName?: IMusicName | '',
|
||||
/**默认音乐的音量 */
|
||||
defaultMusicVolume?: number,
|
||||
|
||||
/**默认按钮的音效名 */
|
||||
defaultEffectName?: IEffectName | '',
|
||||
/**默认按钮音效的音量 */
|
||||
defaultEffectVolume?: number
|
||||
} = {};
|
||||
|
||||
/**音乐名字枚举 */
|
||||
static MusicName = MusicName;
|
||||
/**音效名字枚举 */
|
||||
static EffectName = EffectName;
|
||||
|
||||
private musicMuteCacheKey = 'SoundManager:MusicMute';
|
||||
private effectMuteCacheKey = 'SoundManager:EffectMute';
|
||||
private musicVolumeScaleCacheKey = 'SoundManager:MusicVolumeScale';
|
||||
private effectVolumeScaleCacheKey = 'SoundManager:EffectVolumeScale';
|
||||
|
||||
private defaultMusicName = '';
|
||||
private defaultMusicVolume = 0.2;
|
||||
private defaultEffectName = '';
|
||||
private defaultEffectVolume = 1;
|
||||
|
||||
private audioCache = {};
|
||||
private effectInterval: { [key in string]: number } = {};
|
||||
private playingMusic = { uuid: '', id: -1, name: '', volume: 1, playing: false, paused: false };
|
||||
|
||||
protected init(finish: Function) {
|
||||
const setting = SoundManager.setting;
|
||||
|
||||
// 默认音乐
|
||||
if (setting.defaultMusicName) this.defaultMusicName = setting.defaultMusicName;
|
||||
if (typeof setting.defaultMusicVolume === 'number') this.defaultMusicVolume = setting.defaultMusicVolume;
|
||||
|
||||
// 默认按钮音效
|
||||
if (setting.defaultEffectName) this.defaultEffectName = setting.defaultEffectName;
|
||||
if (typeof setting.defaultEffectVolume === 'number') this.defaultEffectVolume = setting.defaultEffectVolume;
|
||||
|
||||
if (this.musicMuteCacheKey) {
|
||||
const musicMute = storage.get(this.musicMuteCacheKey) === true;
|
||||
AudioEngine.inst.setMusicMute(musicMute);
|
||||
} else {
|
||||
this.warn('musicMuteCacheKey不能为空');
|
||||
}
|
||||
if (this.effectMuteCacheKey) {
|
||||
const effectMute = storage.get(this.effectMuteCacheKey) === true;
|
||||
AudioEngine.inst.setGlobalEffectsMute(effectMute);
|
||||
} else {
|
||||
this.warn('effectMuteCacheKey不能为空');
|
||||
}
|
||||
if (this.musicVolumeScaleCacheKey) {
|
||||
const musicVolumeScale = storage.get(this.musicVolumeScaleCacheKey);
|
||||
if (typeof musicVolumeScale === 'number') AudioEngine.inst.setMusicVolumeScale(musicVolumeScale);
|
||||
} else {
|
||||
this.warn('musicVolumeScaleCacheKey不能为空');
|
||||
}
|
||||
if (this.effectVolumeScaleCacheKey) {
|
||||
const effectVolumeScale = storage.get(this.effectVolumeScaleCacheKey);
|
||||
if (typeof effectVolumeScale === 'number') AudioEngine.inst.setGlobalEffectsVolumeScale(effectVolumeScale);
|
||||
} else {
|
||||
this.warn('effectVolumeScaleCacheKey不能为空');
|
||||
}
|
||||
|
||||
super.init(finish);
|
||||
|
||||
// 预加载
|
||||
setting.preload?.forEach((path: string) => {
|
||||
Core.inst.manager.loader.preload({
|
||||
bundle: BundleName,
|
||||
type: AudioClip,
|
||||
path: path
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected onLoad() {
|
||||
game.on(Game.EVENT_HIDE, function () {
|
||||
AudioEngine.inst.pauseAll();
|
||||
});
|
||||
game.on(Game.EVENT_SHOW, function () {
|
||||
AudioEngine.inst.resumeAll();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载声音资源
|
||||
* @param name sound路径
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
*/
|
||||
public preload(name: string, bundle: string, complete?: (item: AssetManager.RequestItem[] | null) => any): void;
|
||||
public preload(name: (E | M), complete?: (item: AssetManager.RequestItem[] | null) => any): void;
|
||||
public preload(name: string, ...args: any[]) {
|
||||
const bundleName = (args.length >= 1
|
||||
&& (typeof args[0] === 'string')
|
||||
? (args[0] || BundleName)
|
||||
: BundleName
|
||||
) as string;
|
||||
const complete = (args.length >= 1
|
||||
&& (args[args.length - 1] instanceof Function)
|
||||
? args[args.length - 1]
|
||||
: null
|
||||
) as (item: AssetManager.RequestItem[] | null) => any;
|
||||
|
||||
if (!name) {
|
||||
this.error('preload', 'fail');
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.indexOf('effect') !== 0 && name.indexOf('music') !== 0) {
|
||||
this.error('preload', 'fail', name);
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 远程加载
|
||||
Core.inst.manager.loader.preload({
|
||||
bundle: bundleName,
|
||||
path: name,
|
||||
type: AudioClip,
|
||||
onComplete: complete
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载声音资源
|
||||
* @param name sound路径
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
* @param progress 加载进度回调
|
||||
* @param complete 加载完成回调
|
||||
*/
|
||||
public load(name: string, bundle: string): void;
|
||||
public load(name: string, bundle: string, complete: (result: AudioClip | null) => any): void;
|
||||
public load(name: string, bundle: string, progress: (finish: number, total: number, item: AssetManager.RequestItem) => void, complete: (result: AudioClip | null) => any): void;
|
||||
public load(name: (E | M)): void;
|
||||
public load(name: (E | M), complete: (result: AudioClip | null) => any): void;
|
||||
public load(name: (E | M), progress: (finish: number, total: number, item: AssetManager.RequestItem) => void, complete: (result: AudioClip | null) => any): void;
|
||||
public load(name: string, ...args: any[]): void {
|
||||
const bundleName = (args.length >= 1
|
||||
&& (typeof args[0] === 'string')
|
||||
? (args[0] || BundleName)
|
||||
: BundleName
|
||||
) as string;
|
||||
const progress = (args.length >= 2
|
||||
&& (args[args.length - 1] instanceof Function)
|
||||
&& (args[args.length - 2] instanceof Function)
|
||||
? args[args.length - 2]
|
||||
: null
|
||||
) as (finish: number, total: number, item: AssetManager.RequestItem) => void;
|
||||
const complete = (args.length >= 1
|
||||
&& (args[args.length - 1] instanceof Function)
|
||||
? args[args.length - 1]
|
||||
: null
|
||||
) as (result: AudioClip | null) => any;
|
||||
|
||||
if (!name) {
|
||||
this.error('load', 'fail');
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const soundName = `${bundleName}://${name}`;
|
||||
|
||||
// 判断有无缓存
|
||||
const audio = this.audioCache[soundName];
|
||||
if (audio) {
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(audio);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 远程加载
|
||||
Core.inst.manager.loader.load({
|
||||
path: name,
|
||||
bundle: bundleName,
|
||||
type: AudioClip,
|
||||
onProgress: progress,
|
||||
onComplete: (audioClip) => {
|
||||
if (!isValid(this)) return;
|
||||
if (audioClip) {
|
||||
this.audioCache[soundName] = audioClip;
|
||||
complete && complete(audioClip);
|
||||
} else {
|
||||
complete && complete(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放声音资源
|
||||
* @param name 声音路径
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
*/
|
||||
public release(name: string, bundle: string): void;
|
||||
public release(name: E | M): void;
|
||||
public release(name: string, bundle?: string) {
|
||||
const bundleName = bundle || BundleName;
|
||||
const soundName = `${bundleName}://${name}`;
|
||||
|
||||
delete this.audioCache[soundName];
|
||||
Core.inst.manager.loader.release({ bundle: bundleName, path: name, type: AudioClip });
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放默认音乐
|
||||
*/
|
||||
public playDefaultMusic(onPlay?: Function) {
|
||||
if (this.defaultMusicName) {
|
||||
this.playMusic({ name: <M>this.defaultMusicName, volume: this.defaultMusicVolume, onPlay });
|
||||
} else {
|
||||
this.warn('defaultMusicName 不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放默认音效
|
||||
*/
|
||||
public playDefaultEffect(onPlay?: (audioID: number) => void) {
|
||||
if (this.defaultEffectName) {
|
||||
this.playEffect({ name: <E>this.defaultEffectName, volume: this.defaultEffectVolume, onPlay });
|
||||
} else {
|
||||
this.warn('defaultEffectName 不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮点击播放的音效,优先级高于默认音效
|
||||
* @param name 音效(如果为空,则使用默认音效)
|
||||
* @param opts.volume 音量
|
||||
* @param opts.interval 多少秒内不会重复播放
|
||||
*/
|
||||
public setButtonEffect(target: Button, name?: E, opts?: {
|
||||
volume: number,
|
||||
interval: number
|
||||
}) {
|
||||
if (name) {
|
||||
const { volume = 1, interval = 0 } = opts || {};
|
||||
//@ts-ignore
|
||||
target.node['useDefaultEffect'] = false;
|
||||
target.node.targetOff(this);
|
||||
target.node.on(Button.EventType.CLICK, function (this: SoundManager<E, M>) {
|
||||
this.playEffect({ name, volume, interval });
|
||||
}, this);
|
||||
} else {
|
||||
//@ts-ignore
|
||||
target.node['useDefaultEffect'] = true;
|
||||
target.node.targetOff(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param name 音效
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
* @param loop 循环播放
|
||||
* @param volume 音量
|
||||
* @param interval 多少秒内不会重复播放
|
||||
*/
|
||||
public playEffect({ name, volume, loop, interval, onEnded, onPlay, onError }: playEffect<E>): void;
|
||||
public playEffect({ name, bundle, volume, loop, interval, onEnded, onPlay, onError }: playEffectWidthBundle): void;
|
||||
public playEffect({ name, bundle, volume = 1, loop = false, interval = 0, onEnded, onPlay, onError }) {
|
||||
if (!name) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
|
||||
const bundleName = bundle || BundleName;
|
||||
const soundName = `${bundleName}://${name}`;
|
||||
|
||||
// 静音不允许播放
|
||||
if (this.isEffectMute) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 正在播放中,不允许重复播放
|
||||
if (this.effectInterval[soundName] && Date.now() < this.effectInterval[soundName]) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载音乐
|
||||
this.load(name, bundleName, (audioClip) => {
|
||||
if (!isValid(this)) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 静音不允许播放
|
||||
if (this.isEffectMute) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 正在播放中,不允许重复播放
|
||||
if (this.effectInterval[soundName] && Date.now() < this.effectInterval[soundName]) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
if (!audioClip) {
|
||||
this.error(`playEffect ${name} 不存在或加载失败`);
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (interval > 0) {
|
||||
this.effectInterval[soundName] = Date.now() + interval * 1000;
|
||||
}
|
||||
|
||||
AudioEngine.inst.playEffect(audioClip, volume, loop, onPlay, onEnded);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param name 音效
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
* @param loop 循环播放
|
||||
* @param volume 音量
|
||||
* @param interval 多少秒内不会重复播放
|
||||
* @returns 如果Promise返回值是null(非真),则播放失败
|
||||
*/
|
||||
public async playEffectAsync(params: playEffectAsync<E>): Promise<number>;
|
||||
public async playEffectAsync(params: playEffectWidthBundleAsync): Promise<number>;
|
||||
public async playEffectAsync(params: any): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
this.playEffect({
|
||||
...params,
|
||||
onPlay: (audioID) => {
|
||||
resolve(audioID);
|
||||
},
|
||||
onError: () => {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停音效
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public pauseEffect(id: number) {
|
||||
return AudioEngine.inst.pauseEffect(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停所有音效
|
||||
* @returns
|
||||
*/
|
||||
public pauseAllEffects() {
|
||||
return AudioEngine.inst.pauseAllEffects();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复音效
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public resumeEffect(id: number) {
|
||||
return AudioEngine.inst.resumeEffect(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复所有音效
|
||||
* @returns
|
||||
*/
|
||||
public resumeAllEffects() {
|
||||
return AudioEngine.inst.resumeAllEffects();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音效
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public stopEffect(id: number) {
|
||||
return AudioEngine.inst.stopEffect(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有音效
|
||||
* @returns
|
||||
*/
|
||||
public stopAllEffects() {
|
||||
return AudioEngine.inst.stopAllEffects();
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐
|
||||
* @param volume 音量
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
* @param force 是否强制重新播放
|
||||
*/
|
||||
public playMusic(params: playMusic<M>): void;
|
||||
public playMusic(params: playMusicWidthBundle): void;
|
||||
public playMusic({ name, bundle, volume = 1, force = false, onPlay, onError }): void {
|
||||
if (!name) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
|
||||
const bundleName = bundle || BundleName;
|
||||
const soundName = `${bundleName}://${name}`;
|
||||
|
||||
// 该音乐正在播放中
|
||||
if (!force && this.playingMusic.id !== -1 && this.playingMusic.name === soundName) {
|
||||
AudioEngine.inst.setMusicVolume(volume);
|
||||
onPlay && onPlay();
|
||||
return;
|
||||
}
|
||||
|
||||
// 先停止当前音乐
|
||||
this.stopMusic();
|
||||
|
||||
// 播放操作uuid
|
||||
const uuid = this.createUUID();
|
||||
this.playingMusic.uuid = uuid;
|
||||
// 记录要播放音乐的名字
|
||||
this.playingMusic.name = soundName;
|
||||
// 记录要播放音乐的音量
|
||||
this.playingMusic.volume = volume;
|
||||
// 记录音乐状态
|
||||
this.playingMusic.playing = true;
|
||||
this.playingMusic.paused = false;
|
||||
|
||||
// 静音
|
||||
if (this.isMusicMute) {
|
||||
onPlay && onPlay();
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载音乐
|
||||
this.load(name, bundleName, (audioClip) => {
|
||||
if (!isValid(this)) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 不合法
|
||||
if (this.playingMusic.id !== -1) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
if (this.playingMusic.name !== soundName) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
if (this.playingMusic.uuid !== this.playingMusic.uuid) {
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 不存在
|
||||
if (!audioClip) {
|
||||
this.error(`playMusic ${name} 不存在或加载失败`);
|
||||
onError && onError();
|
||||
return;
|
||||
}
|
||||
// 静音
|
||||
if (this.isMusicMute) {
|
||||
onPlay && onPlay();
|
||||
return;
|
||||
}
|
||||
|
||||
this.playingMusic.id = AudioEngine.inst.playMusic(audioClip, volume, onPlay);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐
|
||||
* @param volume 音量
|
||||
* @param bundle Bundle名,默认为app-sound
|
||||
* @param force 是否强制重新播放
|
||||
* @returns 如果Promise返回值是false,则播放失败
|
||||
*/
|
||||
public playMusicAsync(params: playMusicAsync<M>): Promise<boolean>;
|
||||
public playMusicAsync(params: playMusicWidthBundleAsync): Promise<boolean>;
|
||||
public playMusicAsync(params: any): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
this.playMusic({
|
||||
...params,
|
||||
onPlay: () => {
|
||||
resolve(true);
|
||||
},
|
||||
onError: () => {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新播放音乐
|
||||
*/
|
||||
public replayMusic(onPlay?: Function) {
|
||||
if (!this.playingMusic.playing) return;
|
||||
if (!this.playingMusic.name) return;
|
||||
if (this.playingMusic.name.indexOf('://') > 0) {
|
||||
const [bundle, name] = this.playingMusic.name.split('://');
|
||||
this.playMusic({
|
||||
name,
|
||||
bundle,
|
||||
volume: this.playingMusic.volume,
|
||||
force: true,
|
||||
onPlay
|
||||
});
|
||||
} else {
|
||||
this.playMusic({
|
||||
name: this.playingMusic.name as any,
|
||||
volume: this.playingMusic.volume,
|
||||
force: true,
|
||||
onPlay
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停音乐
|
||||
*/
|
||||
public pauseMusic() {
|
||||
if (!this.playingMusic.playing) return false;
|
||||
this.playingMusic.paused = true;
|
||||
return AudioEngine.inst.pauseMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复音乐
|
||||
*/
|
||||
public resumeMusic() {
|
||||
if (!this.playingMusic.playing) return false;
|
||||
this.playingMusic.paused = false;
|
||||
return AudioEngine.inst.resumeMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音乐
|
||||
*/
|
||||
public stopMusic() {
|
||||
this.playingMusic.playing = false;
|
||||
this.playingMusic.paused = false;
|
||||
this.playingMusic.volume = 1;
|
||||
this.playingMusic.name = '';
|
||||
this.playingMusic.uuid = '';
|
||||
this.playingMusic.id = -1;
|
||||
return AudioEngine.inst.stopMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音乐静音
|
||||
* @param mute 是否静音
|
||||
* @param isCache 静音状态是否写入缓存(通过localstorage)
|
||||
*/
|
||||
public setMusicMute(mute: boolean, isCache = false) {
|
||||
isCache && storage.set(this.musicMuteCacheKey, mute);
|
||||
AudioEngine.inst.setMusicMute(mute);
|
||||
if (!mute && this.playingMusic.name) {
|
||||
if (this.playingMusic.name.indexOf('://') > 0) {
|
||||
const [bundle, name] = this.playingMusic.name.split('://');
|
||||
this.playMusic({
|
||||
name,
|
||||
bundle,
|
||||
volume: this.playingMusic.volume,
|
||||
|
||||
});
|
||||
} else {
|
||||
this.playMusic({
|
||||
name: this.playingMusic.name as any,
|
||||
volume: this.playingMusic.volume
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐是否正在播放
|
||||
*/
|
||||
get isMusicPlaying() {
|
||||
return this.playingMusic.playing;
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐是否暂停
|
||||
*/
|
||||
get isMusicPaused() {
|
||||
return this.playingMusic.paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐是否静音
|
||||
*/
|
||||
public get isMusicMute() {
|
||||
return AudioEngine.inst.getMusicMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音效静音
|
||||
* @param mute 是否静音
|
||||
* @param isCache 静音状态是否写入缓存(通过localstorage)
|
||||
*/
|
||||
public setEffectMute(mute: boolean, isCache = false) {
|
||||
AudioEngine.inst.setGlobalEffectsMute(mute);
|
||||
isCache && storage.set(this.effectMuteCacheKey, mute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 音效是否静音
|
||||
*/
|
||||
public get isEffectMute() {
|
||||
return AudioEngine.inst.getGlobalEffectsMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音乐音量倍率
|
||||
* @param scale
|
||||
* @param isCache 音量倍率是否写入缓存(通过localstorage)
|
||||
*/
|
||||
public setMusicVolumeScale(scale: number, isCache = false) {
|
||||
AudioEngine.inst.setMusicVolumeScale(scale);
|
||||
isCache && storage.set(this.musicVolumeScaleCacheKey, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐音量倍率
|
||||
*/
|
||||
public get musicVolumeScale() {
|
||||
return AudioEngine.inst.getMusicVolumeScale();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置音效音量倍率
|
||||
* @param scale
|
||||
* @param isCache 音量倍率是否写入缓存(通过localstorage)
|
||||
*/
|
||||
public setEffectVolumeScale(scale: number, isCache = false) {
|
||||
AudioEngine.inst.setGlobalEffectsVolumeScale(scale);
|
||||
isCache && storage.set(this.effectVolumeScaleCacheKey, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 音效音量倍率
|
||||
*/
|
||||
public get effectVolumeScale() {
|
||||
return AudioEngine.inst.getGlobalEffectsVolumeScale();
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/sound/SoundManager.ts.meta
Normal file
9
extensions/app/assets/manager/sound/SoundManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "580021da-d9a7-4e59-bb76-2c3afcae6053",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/timer.meta
Normal file
12
extensions/app/assets/manager/timer.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "ea45b442-c58f-49d1-9b11-edc7bc719a73",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
276
extensions/app/assets/manager/timer/TimerManager.ts
Normal file
276
extensions/app/assets/manager/timer/TimerManager.ts
Normal file
@@ -0,0 +1,276 @@
|
||||
import { _decorator } from 'cc';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
type ICallback = (...args: any[]) => any;
|
||||
|
||||
class DailyTimer {
|
||||
// 获取当前时间相对于当日零点的毫秒数
|
||||
private static getDayTimeMs(date: Date): number {
|
||||
return (
|
||||
date.getHours() * 3600 +
|
||||
date.getMinutes() * 60 +
|
||||
date.getSeconds()
|
||||
) * 1000 + date.getMilliseconds();
|
||||
}
|
||||
|
||||
// 静态方法解析时间为毫秒数
|
||||
private static parseTimeToMs(h: number, m: number, s: number): number {
|
||||
return ((h * 3600 + m * 60 + s) * 1000) % 86400000;
|
||||
}
|
||||
|
||||
private readonly startMs: number; // 起始时间毫秒数(相对于当日零点)
|
||||
private readonly endMs: number; // 结束时间毫秒数
|
||||
|
||||
// 用于检查当前时间是否可触发回调
|
||||
private checkDay = 0;
|
||||
|
||||
constructor(
|
||||
time: string,
|
||||
public readonly callback: ICallback,
|
||||
public readonly target?: unknown,
|
||||
public readonly once: boolean = false
|
||||
) {
|
||||
// 使用解构赋值提高可读性
|
||||
const [startSegment, endSegment = startSegment] = time.split('-');
|
||||
|
||||
// 开始时间
|
||||
const [startH = 0, startM = 0, startS = 0] = startSegment.split(':').map(
|
||||
part => Math.max(0, parseInt(part, 10) || 0)
|
||||
);
|
||||
this.startMs = DailyTimer.parseTimeToMs(startH, startM, startS);
|
||||
|
||||
// 结束时间
|
||||
const [endH = 0, endM = 0, endS = 0] = endSegment.split(':').map(
|
||||
part => Math.max(0, parseInt(part, 10) || 0)
|
||||
);
|
||||
this.endMs = DailyTimer.parseTimeToMs(endH, endM, endS);
|
||||
// 结束时间与开始时间不能相同
|
||||
if (this.endMs === this.startMs) {
|
||||
if (startM === 0 && startS === 0) {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH + 1, startM, startS);
|
||||
} else if (startS === 0) {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH, startM + 1, startS);
|
||||
} else {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH, startM, startS + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前时间是否在时间范围内
|
||||
private isInRange(now: Date): boolean {
|
||||
const currentMs = DailyTimer.getDayTimeMs(now);
|
||||
|
||||
// 处理跨天时间段(如 23:00-01:00)
|
||||
return this.startMs <= this.endMs
|
||||
? currentMs >= this.startMs && currentMs < this.endMs
|
||||
: currentMs >= this.startMs || currentMs < this.endMs;
|
||||
}
|
||||
|
||||
update(now: Date): boolean {
|
||||
const dateDay = now.getDay();
|
||||
|
||||
if (this.checkDay === dateDay) return false;
|
||||
if (!this.isInRange(now)) return false;
|
||||
|
||||
this.checkDay = dateDay;
|
||||
this.callback.call(this.target);
|
||||
|
||||
return this.once;
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalTimer {
|
||||
private elapsed: number = 0;
|
||||
|
||||
constructor(
|
||||
public readonly interval: number,
|
||||
public readonly callback: ICallback,
|
||||
public readonly target?: unknown,
|
||||
public readonly once: boolean = false
|
||||
) { }
|
||||
|
||||
update(dt: number): boolean {
|
||||
this.elapsed += dt;
|
||||
let completed = false;
|
||||
|
||||
// 处理可能多次触发的情况(当dt > interval时)
|
||||
while (this.elapsed >= this.interval) {
|
||||
this.callback.call(this.target);
|
||||
this.elapsed -= this.interval;
|
||||
|
||||
if (this.once) {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
class Timer {
|
||||
static update(timer: Timer, dt: number) {
|
||||
return timer.update(dt);
|
||||
}
|
||||
|
||||
private intervalTimer: IntervalTimer[] = [];
|
||||
|
||||
/**
|
||||
* 注册定时器
|
||||
* @param interval
|
||||
* @param callback
|
||||
* @param target
|
||||
* @param once
|
||||
*/
|
||||
register(
|
||||
interval: number,
|
||||
callback: ICallback,
|
||||
target?: unknown,
|
||||
once?: boolean
|
||||
): void {
|
||||
const timer = new IntervalTimer(interval, callback, target, once || false);
|
||||
this.intervalTimer.push(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消定时器
|
||||
* @param callback
|
||||
* @param target
|
||||
*/
|
||||
unregister(callback: ICallback, target?: unknown): void {
|
||||
if (typeof target === 'undefined') {
|
||||
this.intervalTimer = this.intervalTimer.filter(
|
||||
timer => timer.callback !== callback
|
||||
);
|
||||
} else {
|
||||
this.intervalTimer = this.intervalTimer.filter(
|
||||
timer => !(timer.callback === callback && timer.target === target)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消所有定时器
|
||||
*/
|
||||
unregisterAll() {
|
||||
this.intervalTimer = [];
|
||||
}
|
||||
|
||||
private dailyTimers: DailyTimer[] = [];
|
||||
|
||||
/**
|
||||
* 注册每日触发器
|
||||
* @param time 24小时制,精确到秒
|
||||
*
|
||||
* @example
|
||||
* registerDailyTrigger('16', ...) 等同于 registerDailyTrigger('16-17', ...)
|
||||
* registerDailyTrigger('8-9:00', ...) 等同于 registerDailyTrigger('8', ...)
|
||||
* registerDailyTrigger('8:00:01-24', ...)
|
||||
*/
|
||||
registerDailyTrigger(
|
||||
time: string,
|
||||
callback: ICallback,
|
||||
target?: unknown,
|
||||
once?: boolean
|
||||
) {
|
||||
const timer = new DailyTimer(time, callback, target, once || false);
|
||||
this.dailyTimers.push(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消每日触发器
|
||||
*/
|
||||
unregisterDailyTrigger(callback: ICallback, target?: unknown) {
|
||||
if (typeof target === 'undefined') {
|
||||
this.dailyTimers = this.dailyTimers.filter(
|
||||
timer => timer.callback !== callback
|
||||
);
|
||||
} else {
|
||||
this.dailyTimers = this.dailyTimers.filter(
|
||||
timer => !(timer.callback === callback && timer.target === target)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消所有每日触发器
|
||||
*/
|
||||
unregisterAllDailyTrigger() {
|
||||
this.dailyTimers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有定时器和触发器
|
||||
*/
|
||||
clear() {
|
||||
this.intervalTimer = [];
|
||||
this.dailyTimers = [];
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
for (let index = 0; index < this.intervalTimer.length; index++) {
|
||||
const timer = this.intervalTimer[index];
|
||||
if (timer.update(dt)) {
|
||||
this.intervalTimer.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
for (let index = 0; index < this.dailyTimers.length; index++) {
|
||||
const timer = this.dailyTimers[index];
|
||||
if (timer.update(date)) {
|
||||
this.dailyTimers.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ccclass('TimerManager')
|
||||
export default class TimerManager extends BaseManager {
|
||||
private timers: Map<string | number | Symbol, Timer> = new Map();
|
||||
|
||||
/**
|
||||
* 清除所有定时器
|
||||
*/
|
||||
clear() {
|
||||
this.timers.forEach((timer) => {
|
||||
timer.clear();
|
||||
});
|
||||
this.timers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时器
|
||||
* @param key 定时器key
|
||||
*/
|
||||
delete(key: string | number | Symbol) {
|
||||
const timer = this.timers.get(key);
|
||||
if (!timer) return;
|
||||
|
||||
this.timers.delete(key);
|
||||
timer.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时器
|
||||
* @param key 定时器key
|
||||
*/
|
||||
get(key: string | number | Symbol): Timer {
|
||||
if (this.timers.has(key)) {
|
||||
return this.timers.get(key);
|
||||
}
|
||||
|
||||
const timer = new Timer();
|
||||
this.timers.set(key, timer);
|
||||
return timer;
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
this.timers.forEach((timer) => {
|
||||
Timer.update(timer, dt);
|
||||
});
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/timer/TimerManager.ts.meta
Normal file
9
extensions/app/assets/manager/timer/TimerManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b5636f8d-3516-4510-aaba-74f9202b8a9f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/ui.meta
Normal file
12
extensions/app/assets/manager/ui.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "714739c4-f4c0-4313-bc98-2d350df6b208",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
BIN
extensions/app/assets/manager/ui/.DS_Store
vendored
Normal file
BIN
extensions/app/assets/manager/ui/.DS_Store
vendored
Normal file
Binary file not shown.
1617
extensions/app/assets/manager/ui/UIManager.ts
Normal file
1617
extensions/app/assets/manager/ui/UIManager.ts
Normal file
@@ -0,0 +1,1617 @@
|
||||
import { Asset, AssetManager, Camera, Canvas, Component, Event, Layers, Node, Prefab, RenderTexture, ResolutionPolicy, Scene, SceneAsset, Settings, UITransform, Widget, _decorator, director, instantiate, isValid, js, screen, settings, size, view } from 'cc';
|
||||
import { DEV } from 'cc/env';
|
||||
import { IMiniViewName, IViewName } from '../../../../../assets/app-builtin/app-admin/executor';
|
||||
import Core from '../../Core';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
import BaseView, { IHideParamOnHide, IShade, IShowParamAttr, IShowParamOnHide, IShowParamOnShow, IViewType, ViewType } from '../../base/BaseView';
|
||||
import UIMgrLoading from './comp/UIMgrLoading';
|
||||
import UIMgrShade from './comp/UIMgrShade';
|
||||
import UIMgrToast from './comp/UIMgrToast';
|
||||
import UIMgrZOrder from './comp/UIMgrZOrder';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface IShowParams<T, IShow = any, IShowReturn = any, IHideReturn = any> {
|
||||
/**UI名 */
|
||||
name: T,
|
||||
/**
|
||||
* 数据
|
||||
* - 被onShow接收
|
||||
*/
|
||||
data?: IShow,
|
||||
/**
|
||||
* 是否将UI显示在最上
|
||||
* - 默认true
|
||||
*/
|
||||
top?: boolean,
|
||||
/**
|
||||
* 队列模式,一个UI关闭后,是否展示下一个UI
|
||||
* - join: 排队
|
||||
* - jump: 插队(到首位)
|
||||
*/
|
||||
queue?: 'join' | 'jump',
|
||||
/**静默 默认false(不显示加载loading,也不屏蔽触摸) */
|
||||
silent?: boolean,
|
||||
/**UI触发onShow后 */
|
||||
onShow?: IShowParamOnShow<IShowReturn>,
|
||||
/**UI触发onHide后 */
|
||||
onHide?: IShowParamOnHide<IHideReturn>,
|
||||
/**当code的值为ErrorCode.LogicError时,如果返回true,则自动重试 */
|
||||
onError?: (result: string, code: ErrorCode) => true | void,
|
||||
/**
|
||||
* @private
|
||||
* @deprecated
|
||||
*/
|
||||
attr?: IShowParamAttr,
|
||||
}
|
||||
|
||||
interface IShowAsyncParams<T, IShow = any, IShowReturn = any> {
|
||||
/**UI名 */
|
||||
name: T,
|
||||
/**
|
||||
* 数据
|
||||
* - 被onShow接收
|
||||
*/
|
||||
data?: IShow,
|
||||
/**
|
||||
* 是否将UI显示在最上
|
||||
* - 默认true
|
||||
*/
|
||||
top?: boolean,
|
||||
/**
|
||||
* 队列模式,一个UI关闭后,是否展示下一个UI
|
||||
* - join: 排队
|
||||
* - jump: 插队(到首位)
|
||||
*/
|
||||
queue?: 'join' | 'jump',
|
||||
/**静默 默认false(不显示加载loading,也不屏蔽触摸) */
|
||||
silent?: boolean,
|
||||
/**UI触发onShow后 */
|
||||
onShow?: IShowParamOnShow<IShowReturn>,
|
||||
/**当code的值为ErrorCode.LogicError时,如果返回true,则自动重试 */
|
||||
onError?: (result: string, code: ErrorCode) => true | void,
|
||||
/**
|
||||
* @private
|
||||
* @deprecated
|
||||
*/
|
||||
attr?: IShowParamAttr,
|
||||
}
|
||||
|
||||
interface IHideParams<T, IHide = any, IHideReturn = any> {
|
||||
name: T,
|
||||
data?: IHide,
|
||||
onHide?: IHideParamOnHide<IHideReturn>
|
||||
}
|
||||
|
||||
const UIScene = 'UIScene';
|
||||
const UserInterfacePath = 'UserInterface';
|
||||
const ViewTypes = [ViewType.Page, ViewType.Paper, ViewType.Pop, ViewType.Top];
|
||||
|
||||
const BlockEvents = [
|
||||
Node.EventType.TOUCH_START, Node.EventType.TOUCH_MOVE, Node.EventType.TOUCH_END, Node.EventType.TOUCH_CANCEL,
|
||||
Node.EventType.MOUSE_DOWN, Node.EventType.MOUSE_MOVE, Node.EventType.MOUSE_UP,
|
||||
Node.EventType.MOUSE_ENTER, Node.EventType.MOUSE_LEAVE, Node.EventType.MOUSE_WHEEL
|
||||
];
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
enum ErrorCode {
|
||||
/**加载失败 */
|
||||
LoadError,
|
||||
/**beforeShow返回错误 */
|
||||
LogicError,
|
||||
/**UI无效(UI的isViewValid返回false) */
|
||||
InvalidError,
|
||||
}
|
||||
|
||||
/**
|
||||
* 界面名字枚举
|
||||
*/
|
||||
const ViewName: { [key in IViewName]: key } = new Proxy({} as any, {
|
||||
get: function (target, key) {
|
||||
if (target[key]) return target[key];
|
||||
target[key] = key;
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 子界面名字枚举
|
||||
*/
|
||||
const MiniViewName: { [key in IMiniViewName]: key } = new Proxy({} as any, {
|
||||
get: function (target, key) {
|
||||
if (target[key]) return target[key];
|
||||
target[key] = key;
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 将驼峰命名转成串式命名
|
||||
* @param str 驼峰字符串
|
||||
* @returns
|
||||
*/
|
||||
function stringCaseNegate(str: string) {
|
||||
return str.replace(/[A-Z]/g, (searchStr, startIndex) => {
|
||||
if (startIndex === 0) {
|
||||
return searchStr.toLowerCase();
|
||||
} else {
|
||||
return '-' + searchStr.toLowerCase();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ccclass('UIManager')
|
||||
export default class UIManager<UIName extends string, MiniName extends string> extends BaseManager {
|
||||
/**静态设置 */
|
||||
static setting: {
|
||||
/**预加载列表,会在UI初始化阶段进行 */
|
||||
preload?: (IViewName | IMiniViewName | Array<IViewName | IMiniViewName>)[],
|
||||
/**默认UI,框架初始化完毕后会自动加载 */
|
||||
defaultUI?: IViewName,
|
||||
/**给默认UI传递的数据 */
|
||||
defaultData?: any,
|
||||
/**弹窗背景遮罩的参数 */
|
||||
shade?: IShade,
|
||||
/**
|
||||
* 是否自动适配分辨率策略
|
||||
* - 开启后会弃用当前的适配策略,并根据实际设备分辨率与设计分辨率的比值,计算出新的适配策略(宽适配或高适配),保证游戏区域不会被裁减只会扩边
|
||||
* - 当实际设备分辨率「高/宽」>= 设计分辨率「高/宽」时,为宽适配
|
||||
* - 当实际设备分辨率「高/宽」< 设计分辨率「高/宽」时,为高适配
|
||||
*/
|
||||
autoFit?: boolean,
|
||||
} = {};
|
||||
|
||||
/**错误码 */
|
||||
static ErrorCode = ErrorCode;
|
||||
|
||||
/**界面名字枚举 */
|
||||
static ViewName = ViewName;
|
||||
|
||||
/**子界面名字枚举 */
|
||||
static MiniViewName = MiniViewName;
|
||||
|
||||
@property({
|
||||
type: Prefab,
|
||||
tooltip: '位置: app://manager/ui/prefab/UIMgrLoading'
|
||||
})
|
||||
private loadingPre: Prefab = null;
|
||||
|
||||
@property({
|
||||
type: Prefab,
|
||||
tooltip: '位置: app://manager/ui/prefab/UIMgrShade'
|
||||
})
|
||||
private shadePre: Prefab = null;
|
||||
|
||||
@property({
|
||||
type: Prefab,
|
||||
tooltip: '位置: app://manager/ui/prefab/UIMgrToast'
|
||||
})
|
||||
private toastPre: Prefab = null;
|
||||
|
||||
// UI根节点
|
||||
private UserInterface: Node = null;
|
||||
|
||||
// 加载和遮罩节点
|
||||
private loading: Node = null;
|
||||
private shade: Node = null;
|
||||
private toast: Node = null;
|
||||
|
||||
private defaultUI: UIName = null;
|
||||
private defaultData: string = '';
|
||||
|
||||
private currScene: string = '';
|
||||
private currPage: BaseView = null;
|
||||
private currFocus: BaseView = null;
|
||||
|
||||
// 预制体缓存
|
||||
private prefabCache: { [name in string]: Prefab } = {};
|
||||
private sceneCache: { [name in string]: SceneAsset } = {};
|
||||
|
||||
// 全局触摸有效
|
||||
private touchEnabled: boolean = true;
|
||||
|
||||
// 记录触摸屏蔽
|
||||
private touchMaskMap = new Map<string, boolean>();
|
||||
// 记录展示加载
|
||||
private showLoadingMap = new Map<string, boolean>();
|
||||
|
||||
// 记录正在加载中的有效的ui
|
||||
private uiLoadingMap: Map<UIName, string[]> = new Map();
|
||||
// 记录正在展示中的有效的ui
|
||||
private uiShowingMap: Map<BaseView, UIName> = new Map();
|
||||
|
||||
private showQueue: IShowParams<UIName>[] = [];
|
||||
|
||||
/**UI根节点 */
|
||||
public get root() {
|
||||
return this.node.parent.parent;
|
||||
}
|
||||
|
||||
/**相机 */
|
||||
public get camera() {
|
||||
return this.canvas.cameraComponent;
|
||||
}
|
||||
|
||||
/**画布*/
|
||||
public get canvas() {
|
||||
return this.root.getComponent(Canvas);
|
||||
}
|
||||
|
||||
protected init(finish: Function) {
|
||||
const setting = UIManager.setting;
|
||||
|
||||
this.defaultUI = setting.defaultUI as UIName;
|
||||
this.defaultData = setting.defaultData;
|
||||
|
||||
super.init(finish);
|
||||
|
||||
// 预加载,符合AnyTask规则
|
||||
if (setting.preload?.length) {
|
||||
const task = Core.inst.lib.task.createAny();
|
||||
setting.preload.forEach((preload) => {
|
||||
if (preload instanceof Array) {
|
||||
task.add(preload.map(name => {
|
||||
return next => this.preload(name as any, next);
|
||||
}));
|
||||
} else {
|
||||
task.add(next => this.preload(preload as any, next));
|
||||
}
|
||||
});
|
||||
task.start();
|
||||
}
|
||||
}
|
||||
|
||||
protected onLoad() {
|
||||
this.UserInterface = this.root.getChildByName(UserInterfacePath);
|
||||
|
||||
this.root.getComponentsInChildren(Camera).forEach(camera => {
|
||||
// 避免camera.priority<0的情况,否则会造成渲染异常
|
||||
if (camera.priority < 0) camera.priority = 0;
|
||||
// 避免camera.far<=camera.near的情况,否则会造成渲染异常
|
||||
if (camera.far <= camera.near) camera.far = camera.near + 1;
|
||||
});
|
||||
director.addPersistRootNode(this.root);
|
||||
|
||||
this.createTypeRoot();
|
||||
|
||||
this.shade = instantiate(this.shadePre);
|
||||
this.shade.parent = this.UserInterface;
|
||||
this.shade.active = false;
|
||||
this.shade.getComponent(Widget).target = this.root;
|
||||
|
||||
this.loading = instantiate(this.loadingPre);
|
||||
this.loading.parent = this.node;
|
||||
this.loading.active = false;
|
||||
|
||||
// toast是后面加的,需要做容错
|
||||
if (this.toastPre) {
|
||||
this.toast = instantiate(this.toastPre);
|
||||
this.toast.parent = this.node;
|
||||
}
|
||||
|
||||
// 自动适配分辨率策略
|
||||
if (UIManager.setting.autoFit) {
|
||||
const designResolution = settings.querySettings(Settings.Category.SCREEN, 'designResolution') as { width: number, height: number, policy: number };
|
||||
const windowSize = size(screen.windowSize);
|
||||
let resolutionPolicy = designResolution.policy;
|
||||
const autoFitResolutionPolicy = function () {
|
||||
if (windowSize.width / windowSize.height > designResolution.width / designResolution.height) {
|
||||
if (resolutionPolicy === ResolutionPolicy.FIXED_HEIGHT) return;
|
||||
view.setResolutionPolicy(ResolutionPolicy.FIXED_HEIGHT);
|
||||
resolutionPolicy = ResolutionPolicy.FIXED_HEIGHT;
|
||||
} else {
|
||||
if (resolutionPolicy === ResolutionPolicy.FIXED_WIDTH) return;
|
||||
view.setResolutionPolicy(ResolutionPolicy.FIXED_WIDTH);
|
||||
resolutionPolicy = ResolutionPolicy.FIXED_WIDTH;
|
||||
}
|
||||
};
|
||||
autoFitResolutionPolicy();
|
||||
this.schedule(() => {
|
||||
if (windowSize.equals(screen.windowSize)) return;
|
||||
windowSize.set(screen.windowSize);
|
||||
autoFitResolutionPolicy();
|
||||
}, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
private createTypeRoot() {
|
||||
ViewTypes.forEach((type) => {
|
||||
const d2 = new Node(type);
|
||||
d2.layer = Layers.Enum.UI_2D;
|
||||
d2.addComponent(UIMgrZOrder);
|
||||
d2.parent = this.UserInterface;
|
||||
d2.addComponent(UITransform);
|
||||
const widget = d2.addComponent(Widget);
|
||||
widget.isAlignBottom = true;
|
||||
widget.isAlignLeft = true;
|
||||
widget.isAlignRight = true;
|
||||
widget.isAlignTop = true;
|
||||
widget.top = 0;
|
||||
widget.left = 0;
|
||||
widget.right = 0;
|
||||
widget.bottom = 0;
|
||||
widget.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
|
||||
|
||||
if (DEV) {
|
||||
d2.on(Node.EventType.CHILD_ADDED, (child: Node) => {
|
||||
if (!child) return;
|
||||
if (child === this.shade) return;
|
||||
if (this.getBaseView(child)) return;
|
||||
this.warn(`${UserInterfacePath}/${type}下非必要请不要添加非UI节点:`, child?.name);
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private addTouchMaskListener() {
|
||||
if (!this.touchEnabled) return;
|
||||
if (this.touchMaskMap.size > 0) return;
|
||||
|
||||
for (let i = 0; i < BlockEvents.length; i++) {
|
||||
this.root.on(BlockEvents[i], this.stopPropagation, this, true);
|
||||
}
|
||||
}
|
||||
|
||||
private removeTouchMaskListener() {
|
||||
if (!this.touchEnabled) return;
|
||||
if (this.touchMaskMap.size > 0) return;
|
||||
|
||||
for (let i = 0; i < BlockEvents.length; i++) {
|
||||
this.root.off(BlockEvents[i], this.stopPropagation, this, true);
|
||||
}
|
||||
}
|
||||
|
||||
private stopPropagation(event: Event) {
|
||||
if (!this.touchEnabled || this.touchMaskMap.size > 0) {
|
||||
event.propagationStopped = true;
|
||||
if (event.type !== Node.EventType.MOUSE_MOVE) {
|
||||
this.log('屏蔽触摸');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个节点上的BaseView组件, 获取不到返回null
|
||||
*/
|
||||
private getBaseView(node: Node): BaseView {
|
||||
if (!node) return null;
|
||||
return node.components.find(component => component instanceof BaseView) as BaseView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在所有父节点中找到一个最近的view组件
|
||||
* @param target
|
||||
* @returns
|
||||
*/
|
||||
private getViewInParents(target: Node) {
|
||||
let node = target;
|
||||
let com: BaseView = null;
|
||||
|
||||
while (node.parent && !(node.parent instanceof Scene)) {
|
||||
com = this.getBaseView(node.parent);
|
||||
if (!com) {
|
||||
node = node.parent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return com;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在子节点中找到一个最近的view组件
|
||||
* @param target
|
||||
* @returns
|
||||
*/
|
||||
private getViewInChildren(target: Node) {
|
||||
for (let index = 0; index < target.children.length; index++) {
|
||||
const node = target.children[index];
|
||||
const com = this.getBaseView(node);
|
||||
if (com) return com;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据UI名字获取它的脚本类
|
||||
*/
|
||||
private getUIClass(name: string): typeof BaseView {
|
||||
return js.getClassByName(name) as (typeof BaseView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据UI名字获取UI路径
|
||||
* @param name ui名字
|
||||
* @returns
|
||||
*/
|
||||
private getUIPath(name: string) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前缀
|
||||
* @param name ui名字
|
||||
*/
|
||||
private getUIPrefix(name: string): ViewType {
|
||||
for (let index = 0; index < ViewTypes.length; index++) {
|
||||
const typeName = ViewTypes[index];
|
||||
if (name.indexOf(typeName) === 0) {
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
this.error('getUIPrefix', `${name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据UI名字查询父节点
|
||||
* @param name ui名字
|
||||
*/
|
||||
private getUIParent(name: string): Node {
|
||||
if (this.currScene === name) {
|
||||
return director.getScene();
|
||||
}
|
||||
|
||||
const prefix = this.getUIPrefix(name);
|
||||
for (let index = 0; index < ViewTypes.length; index++) {
|
||||
const viewType = ViewTypes[index];
|
||||
if (viewType === prefix) {
|
||||
return this.UserInterface.getChildByName(viewType);
|
||||
}
|
||||
}
|
||||
|
||||
this.error('getUIParent', `找不到${name}对应的Parent`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据UI名字获取场景内的节点
|
||||
* @param name ui名字
|
||||
*/
|
||||
private getUIInScene(name: string): Node;
|
||||
private getUIInScene(name: string, multiple: false): Node;
|
||||
private getUIInScene(name: string, multiple: true): Node[];
|
||||
private getUIInScene(name: string, multiple = false) {
|
||||
const parent = this.getUIParent(name);
|
||||
|
||||
if (multiple) {
|
||||
const result = parent.children.filter(node => node.name === name);
|
||||
if (result.length) return result.filter(node => isValid(node, true));
|
||||
} else {
|
||||
const result = parent.children.find(node => node.name === name);
|
||||
if (result) return isValid(result, true) ? result : null;
|
||||
}
|
||||
|
||||
return multiple ? [] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据UI名字获取展示中的节点
|
||||
* @param name ui名字
|
||||
*/
|
||||
private getUIInShowing(name: string): Node;
|
||||
private getUIInShowing(name: string, multiple: false): Node;
|
||||
private getUIInShowing(name: string, multiple: true): Node[];
|
||||
private getUIInShowing(name: string, multiple = false) {
|
||||
if (multiple) {
|
||||
const result: Node[] = [];
|
||||
this.uiShowingMap.forEach((_name, com) => {
|
||||
if (_name === name) result.push(com.node);
|
||||
});
|
||||
return result;
|
||||
} else {
|
||||
let result: Node = null;
|
||||
this.uiShowingMap.forEach((_name, com) => {
|
||||
if (!result && _name === name) result = com.node;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取UI骨架Bundle名字
|
||||
* @deprecated 将会移除,请改为其它方案
|
||||
*/
|
||||
public getNativeBundleName(uiName: UIName | MiniName) {
|
||||
// 兼容旧版本
|
||||
const oldBundleName = `app-view_${uiName}`;
|
||||
const projectBundles = settings.querySettings(Settings.Category.ASSETS, 'projectBundles') as string[];
|
||||
if (projectBundles && projectBundles.indexOf(oldBundleName) >= 0) {
|
||||
return oldBundleName;
|
||||
}
|
||||
|
||||
return stringCaseNegate(uiName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取UI资源Bundle名字
|
||||
* @deprecated 将会移除,请改为其它方案
|
||||
*/
|
||||
public getResBundleName(uiName: UIName | MiniName) {
|
||||
// 兼容旧版本
|
||||
const oldBundleName = `app-view_${uiName}_Res`;
|
||||
const projectBundles = settings.querySettings(Settings.Category.ASSETS, 'projectBundles') as string[];
|
||||
if (projectBundles && projectBundles.indexOf(oldBundleName) >= 0) {
|
||||
return oldBundleName;
|
||||
}
|
||||
|
||||
return `${stringCaseNegate(uiName)}-res`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Bundle
|
||||
*/
|
||||
private initBundle(name: UIName | MiniName, onFinish: (result: [AssetManager.Bundle, AssetManager.Bundle]) => any) {
|
||||
Core.inst.lib.task.createASync<[AssetManager.Bundle, AssetManager.Bundle]>()
|
||||
.add((next) => {
|
||||
Core.inst.manager.loader.loadBundle({
|
||||
bundle: this.getNativeBundleName(name),
|
||||
onComplete: next
|
||||
});
|
||||
})
|
||||
.add((next) => {
|
||||
Core.inst.manager.loader.loadBundle({
|
||||
bundle: this.getResBundleName(name),
|
||||
onComplete: next
|
||||
});
|
||||
})
|
||||
.start(onFinish);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装UI
|
||||
*/
|
||||
private installUI(name: UIName | MiniName, complete?: (result: Prefab | SceneAsset | null) => any, progress?: (finish: number, total: number, item: AssetManager.RequestItem) => void) {
|
||||
if (this.sceneCache[name]) {
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(this.sceneCache[name]);
|
||||
});
|
||||
return;
|
||||
} else if (this.prefabCache[name]) {
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(this.prefabCache[name]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const task = Core.inst.lib.task.createSync<[[AssetManager.Bundle, AssetManager.Bundle], Prefab | SceneAsset]>()
|
||||
.add(next => {
|
||||
this.initBundle(name, next);
|
||||
})
|
||||
.add((next) => {
|
||||
// 失败
|
||||
const uiBundles = task.results[0];
|
||||
if (!uiBundles || !uiBundles[0] || !uiBundles[1]) return next(null);
|
||||
|
||||
const isScene = uiBundles[0].getSceneInfo(name);
|
||||
Core.inst.manager.loader.load({
|
||||
bundle: this.getNativeBundleName(name),
|
||||
path: this.getUIPath(name),
|
||||
type: isScene ? SceneAsset : Prefab,
|
||||
onProgress: progress,
|
||||
onComplete: next
|
||||
});
|
||||
})
|
||||
.start((results) => {
|
||||
if (!isValid(this)) return;
|
||||
// 验证缓存
|
||||
const cache = this.sceneCache[name] || this.prefabCache[name];
|
||||
if (cache) {
|
||||
return complete && complete(cache);
|
||||
}
|
||||
// 验证有效
|
||||
const asset = results[1];
|
||||
if (!asset) {
|
||||
return complete && complete(null);
|
||||
}
|
||||
// 添加引用计数
|
||||
asset.addRef();
|
||||
// 添加缓存
|
||||
if (asset instanceof Prefab) {
|
||||
this.prefabCache[name] = asset;
|
||||
} else {
|
||||
this.sceneCache[name] = asset;
|
||||
}
|
||||
this.log(`加载: ${name}`);
|
||||
return complete && complete(asset);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载UI
|
||||
*/
|
||||
private uninstallUI(name: UIName | MiniName) {
|
||||
if (this.sceneCache[name]) {
|
||||
// 释放引用计数
|
||||
this.sceneCache[name].decRef();
|
||||
// 删除缓存
|
||||
delete this.sceneCache[name];
|
||||
} else if (this.prefabCache[name]) {
|
||||
// 释放引用计数
|
||||
this.prefabCache[name].decRef();
|
||||
// 删除缓存
|
||||
delete this.prefabCache[name];
|
||||
}
|
||||
|
||||
const resBundle = this.getResBundleName(name);
|
||||
const naBundle = this.getNativeBundleName(name);
|
||||
Core.inst.manager.loader.releaseAll(resBundle);
|
||||
Core.inst.manager.loader.releaseAll(naBundle);
|
||||
Core.inst.manager.loader.removeBundle(resBundle);
|
||||
Core.inst.manager.loader.removeBundle(naBundle);
|
||||
this.log(`卸载: ${name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载ui内部资源
|
||||
*/
|
||||
public loadRes<T extends typeof Asset>(target: Component, path: string, type: T, callback?: (item: InstanceType<T> | null) => any) {
|
||||
if (typeof target === 'string') {
|
||||
Core.inst.manager.loader.load({
|
||||
bundle: this.getResBundleName(target),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: callback
|
||||
});
|
||||
} else {
|
||||
const view = this.getBaseView(target.node) || this.getViewInParents(target.node) || this.getViewInChildren(director.getScene());
|
||||
if (view) {
|
||||
Core.inst.manager.loader.load({
|
||||
bundle: this.getResBundleName(view.viewName as UIName | MiniName),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: callback
|
||||
});
|
||||
} else {
|
||||
this.error('loadRes', target.name, path);
|
||||
callback && callback(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载ui内部资源
|
||||
*/
|
||||
public preloadRes<T extends typeof Asset>(target: Component | UIName | MiniName, path: string, type: T, complete?: (item: AssetManager.RequestItem[] | null) => any) {
|
||||
if (typeof target === 'string') {
|
||||
Core.inst.manager.loader.preload({
|
||||
bundle: this.getResBundleName(target),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: complete
|
||||
});
|
||||
} else {
|
||||
const view = this.getBaseView(target.node) || this.getViewInParents(target.node) || this.getViewInChildren(director.getScene());
|
||||
if (view) {
|
||||
Core.inst.manager.loader.preload({
|
||||
bundle: this.getResBundleName(view.viewName as UIName | MiniName),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: complete
|
||||
});
|
||||
} else {
|
||||
this.error('preloadRes', target.name, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载ui内部资源
|
||||
*/
|
||||
public loadResDir<T extends typeof Asset>(target: Component, path: string, type: T, callback?: (items: InstanceType<T>[] | null) => any) {
|
||||
if (typeof target === 'string') {
|
||||
Core.inst.manager.loader.loadDir({
|
||||
bundle: this.getResBundleName(target),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: callback
|
||||
});
|
||||
} else {
|
||||
const view = this.getBaseView(target.node) || this.getViewInParents(target.node) || this.getViewInChildren(director.getScene());
|
||||
if (view) {
|
||||
Core.inst.manager.loader.loadDir({
|
||||
bundle: this.getResBundleName(view.viewName as UIName | MiniName),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: callback
|
||||
});
|
||||
} else {
|
||||
this.error('loadResDir', target.name, path);
|
||||
callback && callback([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载ui内部资源
|
||||
*/
|
||||
public preloadResDir<T extends typeof Asset>(target: Component | UIName | MiniName, path: string, type: T, complete?: (item: AssetManager.RequestItem[] | null) => any) {
|
||||
if (typeof target === 'string') {
|
||||
Core.inst.manager.loader.preloadDir({
|
||||
bundle: this.getResBundleName(target),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: complete
|
||||
});
|
||||
} else {
|
||||
const view = this.getBaseView(target.node) || this.getViewInParents(target.node) || this.getViewInChildren(director.getScene());
|
||||
if (view) {
|
||||
Core.inst.manager.loader.preloadDir({
|
||||
bundle: this.getResBundleName(view.viewName as UIName | MiniName),
|
||||
path: path,
|
||||
type: type,
|
||||
onComplete: complete
|
||||
});
|
||||
} else {
|
||||
this.error('preloadResDir', target.name, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载UI
|
||||
*/
|
||||
public preload(name: UIName | MiniName, complete?: (item: AssetManager.RequestItem[] | null) => any) {
|
||||
// 验证name是否为真
|
||||
if (!name) {
|
||||
this.error('preload', 'fail');
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.initBundle(name, ([naBundle]) => {
|
||||
const isScene = naBundle.getSceneInfo(name);
|
||||
Core.inst.manager.loader.preload({
|
||||
bundle: this.getNativeBundleName(name),
|
||||
path: this.getUIPath(name),
|
||||
type: isScene ? SceneAsset : Prefab,
|
||||
onComplete: complete
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载UI
|
||||
*/
|
||||
public load(name: UIName | MiniName): void;
|
||||
public load(name: UIName | MiniName, complete: (result: Prefab | SceneAsset | null) => any): void;
|
||||
public load(name: UIName | MiniName, progress: (finish: number, total: number, item: AssetManager.RequestItem) => void, complete: (result: Prefab | SceneAsset | null) => any): void;
|
||||
public load(name: UIName | MiniName, ...args: Function[]): void {
|
||||
const progress = (args[1] && args[0]) as (finish: number, total: number, item: AssetManager.RequestItem) => void;
|
||||
const complete = (args[1] || args[0]) as (result: any) => any;
|
||||
|
||||
// 验证name是否为真
|
||||
if (!name) {
|
||||
this.error('load', 'fail');
|
||||
complete && setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
complete(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 异步加载
|
||||
this.installUI(name, (result) => {
|
||||
if (!result) return complete && complete(null);
|
||||
return complete && complete(result);
|
||||
}, progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁UI,释放资源
|
||||
* - 直接销毁,不管是否是show状态
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public release(nameOrCom: UIName | MiniName | BaseView) {
|
||||
const uiName = typeof nameOrCom === 'string' ? nameOrCom : nameOrCom.viewName;
|
||||
|
||||
if (!uiName) {
|
||||
this.error('release', `${nameOrCom} fail`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 传入字符串是释放所有
|
||||
if (typeof nameOrCom === 'string') {
|
||||
this.getUIInScene(uiName, true).forEach((node) => {
|
||||
const com = this.getBaseView(node);
|
||||
if (!com) {
|
||||
this.error('release', `${uiName}不存在BaseView组件`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (com.isShow) {
|
||||
this.warn('release', `${uiName}正处于show状态, 此处将直接销毁`);
|
||||
}
|
||||
if (com === this.currPage) {
|
||||
this.currPage = null;
|
||||
}
|
||||
if (com === this.currFocus) {
|
||||
this.currFocus = null;
|
||||
}
|
||||
|
||||
this.uiShowingMap.delete(com);
|
||||
|
||||
if (node && isValid(node, true)) {
|
||||
node.parent = null;
|
||||
node.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
// 传入组件是释放单个
|
||||
else {
|
||||
if (nameOrCom.isShow) {
|
||||
this.warn('release', `${uiName}正处于show状态, 此处将直接销毁`);
|
||||
}
|
||||
if (nameOrCom === this.currPage) {
|
||||
this.currPage = null;
|
||||
}
|
||||
if (nameOrCom === this.currFocus) {
|
||||
this.currFocus = null;
|
||||
}
|
||||
|
||||
this.uiShowingMap.delete(nameOrCom);
|
||||
|
||||
const node = nameOrCom.node;
|
||||
if (node && isValid(node, true)) {
|
||||
node.parent = null;
|
||||
node.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// 当全部释放时才清除缓存
|
||||
const nodes = this.getUIInScene(uiName, true);
|
||||
if (nodes.length === 0 || nodes.every(node => !isValid(node, true))) {
|
||||
this.uninstallUI(uiName as UIName | MiniName);
|
||||
this.log(`释放资源: ${uiName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁全部UI,释放资源
|
||||
* - 直接销毁,不管是否是show状态
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public releaseAll(exclude?: UIName[]) {
|
||||
Object.keys(this.prefabCache).forEach((name: UIName) => {
|
||||
if (exclude && exclude.indexOf(name) !== -1) return;
|
||||
this.release(name);
|
||||
});
|
||||
Object.keys(this.sceneCache).forEach((name: UIName) => {
|
||||
if (exclude && exclude.indexOf(name) !== -1) return;
|
||||
this.release(name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查UI是否有效
|
||||
* - -1: 加载失败
|
||||
* - 0: UI无效
|
||||
* - 1: UI有效
|
||||
*/
|
||||
private checkUIValid(name: UIName | MiniName, data: any, callback: (valid: -1 | 0 | 1) => any) {
|
||||
this.installUI(name, (result) => {
|
||||
if (!result) return callback(-1);
|
||||
const View = this.getUIClass(name);
|
||||
if (!View) return callback(0);
|
||||
if (!View.isViewValid) return callback(1);
|
||||
View.isViewValid((valid: boolean) => {
|
||||
callback(valid ? 1 : 0);
|
||||
}, data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新阴影的层级及显示
|
||||
*/
|
||||
public refreshShade() {
|
||||
// 借助refreshShade实现onFocus、onLostFocus(onFocus不会被每次都触发,只有产生变化时才触发)
|
||||
let onFocus = false;
|
||||
// 倒序遍历uiRoots
|
||||
let uiRoots = this.UserInterface.children;
|
||||
for (let index = uiRoots.length - 1; index >= 0; index--) {
|
||||
const uiRoot = uiRoots[index];
|
||||
if (uiRoot !== this.shade && uiRoot !== this.loading) {
|
||||
// 倒序遍历uiRoot
|
||||
let children = uiRoot.children;
|
||||
for (let i = children.length - 1; i >= 0; i--) {
|
||||
const node = children[i];
|
||||
if (node === this.shade) continue;
|
||||
|
||||
const com = this.getBaseView(node);
|
||||
if (!com) continue;
|
||||
|
||||
// 触发onFocus
|
||||
if (!onFocus && com.isCaptureFocus && com.isShow) {
|
||||
onFocus = true;
|
||||
if (this.currFocus !== com) {
|
||||
isValid(this.currFocus, true) && this.currFocus.constructor.prototype.focus.call(this.currFocus, false);
|
||||
this.currFocus = com;
|
||||
this.currFocus.constructor.prototype.focus.call(this.currFocus, true);
|
||||
}
|
||||
}
|
||||
// 添加遮罩
|
||||
if (com.isNeedShade && com.isShow) {
|
||||
const shadeSetting = Object.assign({}, UIManager.setting.shade, com.constructor.prototype.onShade.call(com));
|
||||
if (shadeSetting.blur) {
|
||||
this.shade.getComponent(UIMgrShade).init(0, 255, 255, 0, true);
|
||||
} else {
|
||||
this.shade.getComponent(UIMgrShade).init(
|
||||
typeof shadeSetting.delay !== 'number' ? 0 : shadeSetting.delay,
|
||||
typeof shadeSetting.begin !== 'number' ? 60 : shadeSetting.begin,
|
||||
typeof shadeSetting.end !== 'number' ? 180 : shadeSetting.end,
|
||||
typeof shadeSetting.speed !== 'number' ? 100 : shadeSetting.speed,
|
||||
false,
|
||||
);
|
||||
}
|
||||
this.shade.layer = node.layer;
|
||||
this.shade.parent = uiRoot;
|
||||
this.shade.active = true;
|
||||
// 以z坐标来代替2.x时代的zIndex
|
||||
this.shade.setPosition(this.shade.position.x, this.shade.position.y, node.position.z);
|
||||
|
||||
let shadeIndex = this.shade.getSiblingIndex();
|
||||
let nodeIndex = node.getSiblingIndex();
|
||||
if (shadeIndex > nodeIndex) {
|
||||
this.shade.setSiblingIndex(nodeIndex);
|
||||
} else {
|
||||
this.shade.setSiblingIndex(nodeIndex - 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.shade.active = false;
|
||||
this.shade.getComponent(UIMgrShade).clear();
|
||||
if (!onFocus) {
|
||||
isValid(this.currFocus, true) && this.currFocus.constructor.prototype.focus.call(this.currFocus, false);
|
||||
this.currFocus = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 解析prefab
|
||||
private parsingPrefab(prefab: Prefab, name: string) {
|
||||
if (!prefab) return null;
|
||||
|
||||
const node = instantiate(prefab);
|
||||
|
||||
node.active = false;
|
||||
if (node.name !== name) {
|
||||
this.warn('parsingPrefab', `节点名与UI名不一致, 已重置为UI名: ${this.getUIPath(name)}`);
|
||||
node.name = name;
|
||||
}
|
||||
|
||||
node.parent = this.getUIParent(name);
|
||||
node.getComponent(Widget)?.updateAlignment();
|
||||
return node;
|
||||
}
|
||||
|
||||
// 解析scene
|
||||
private parsingScene(asset: SceneAsset, name: string) {
|
||||
if (!asset || !asset.scene) return null;
|
||||
|
||||
if (asset.scene.name !== name) {
|
||||
this.warn('parsingScene', `场景名与UI名不一致, 已重置为UI名: ${this.getUIPath(name)}`);
|
||||
asset.scene.name = name;
|
||||
}
|
||||
|
||||
const view = this.getViewInChildren(asset.scene);
|
||||
if (!view) {
|
||||
this.error('parsingScene', `解析场景时未查询到根节点存在BaseView: ${this.getUIPath(name)}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
view.node.active = false;
|
||||
if (view.node.name !== name) {
|
||||
this.warn('parsingScene', `节点名与UI名不一致, 已重置为UI名: ${this.getUIPath(name)}`);
|
||||
view.node.name = name;
|
||||
}
|
||||
return view.node;
|
||||
}
|
||||
|
||||
private addUILoadingUuid(name: UIName, loadingUuid?: string) {
|
||||
const uuid = loadingUuid || this.createUUID();
|
||||
if (!this.uiLoadingMap.has(name)) {
|
||||
this.uiLoadingMap.set(name, [uuid]);
|
||||
} else {
|
||||
this.uiLoadingMap.get(name).push(uuid);
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
private removeUILoadingUuid(name: UIName, uuid: string) {
|
||||
if (!this.uiLoadingMap.has(name)) return false;
|
||||
const index = this.uiLoadingMap.get(name).indexOf(uuid);
|
||||
if (index === -1) return false;
|
||||
this.uiLoadingMap.get(name).splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建UI
|
||||
*/
|
||||
private createUI(name: UIName, silent: boolean, callback: (node: Node, scene?: Scene) => any) {
|
||||
// 生成一个UI加载的UUID
|
||||
const loadingUuid = silent ? '' : this.showLoading();
|
||||
const uiLoadingUuid = this.addUILoadingUuid(name, loadingUuid);
|
||||
|
||||
// 验证name
|
||||
if (!name) {
|
||||
setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
// 验证本次加载是否有效
|
||||
if (this.removeUILoadingUuid(name, uiLoadingUuid) === false) {
|
||||
return this.hideLoading(loadingUuid);
|
||||
}
|
||||
callback(null);
|
||||
this.hideLoading(loadingUuid);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否已经存在节点并且是单例模式
|
||||
const node = this.getUIInScene(name);
|
||||
if (isValid(node, true) && this.getBaseView(node).isSingleton === true) {
|
||||
setTimeout(() => {
|
||||
if (!isValid(this)) return;
|
||||
|
||||
// 验证本次加载是否有效
|
||||
if (this.removeUILoadingUuid(name, uiLoadingUuid) === false) {
|
||||
return this.hideLoading(loadingUuid);
|
||||
}
|
||||
|
||||
// 验证节点是否有效
|
||||
if (isValid(node, true)) {
|
||||
if (this.currScene === name) {
|
||||
callback(node, director.getScene());
|
||||
} else {
|
||||
callback(node);
|
||||
}
|
||||
this.hideLoading(loadingUuid);
|
||||
} else {
|
||||
this.createUI(name, silent, callback);
|
||||
this.hideLoading(loadingUuid);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载UI
|
||||
this.load(name, (asset) => {
|
||||
if (!isValid(this)) return;
|
||||
|
||||
// 验证本次加载是否有效
|
||||
if (this.removeUILoadingUuid(name, uiLoadingUuid) === false) {
|
||||
return this.hideLoading(loadingUuid);
|
||||
}
|
||||
|
||||
// 是场景
|
||||
if (asset instanceof SceneAsset) {
|
||||
callback(this.parsingScene(asset, name), asset.scene);
|
||||
this.hideLoading(loadingUuid);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证是否是单例(一个单例会有被同时load多次的情况,因为判断一个ui是否是单例,必须要至少实例化一个后才能获取)
|
||||
const node = this.getUIInScene(name);
|
||||
if (!isValid(node, true) || this.getBaseView(node).isSingleton === false) {
|
||||
callback(this.parsingPrefab(asset, name));
|
||||
this.hideLoading(loadingUuid);
|
||||
} else {
|
||||
callback(node);
|
||||
this.hideLoading(loadingUuid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示默认View
|
||||
*/
|
||||
public showDefault(onShow?: (result?: any) => any) {
|
||||
if (this.defaultUI) {
|
||||
this.show({
|
||||
name: this.defaultUI,
|
||||
data: this.defaultData,
|
||||
onShow
|
||||
});
|
||||
} else {
|
||||
Core.inst.manager.ui.showToast('请先设置首界面\n在setting.ts中修改defaultUI', 100);
|
||||
onShow && onShow();
|
||||
this.warn('defaultUI不存在,请在setting.ts中修改');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否展示了(包括加载中和队列中)
|
||||
*/
|
||||
public isShow(name: UIName) {
|
||||
return !!this.getUIInShowing(name) ||
|
||||
this.isInQueue(name) ||
|
||||
this.isLoading(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在队列中
|
||||
*/
|
||||
public isInQueue(name: UIName) {
|
||||
return !!this.showQueue.find((v) => { return v.name == name; });
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在加载中
|
||||
*/
|
||||
public isLoading(name: UIName) {
|
||||
return this.uiLoadingMap.has(name) && this.uiLoadingMap.get(name).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 放入队列
|
||||
*/
|
||||
private putInShowQueue(data: IShowParams<UIName>) {
|
||||
if (data.queue === 'join' || this.showQueue.length === 0) {
|
||||
this.showQueue.push(data);
|
||||
} else {
|
||||
this.showQueue.splice(1, 0, data);
|
||||
}
|
||||
if (this.showQueue.length === 1) {
|
||||
this.consumeShowQueue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗队列
|
||||
*/
|
||||
private consumeShowQueue() {
|
||||
if (this.showQueue.length === 0) return;
|
||||
const data = this.showQueue[0];
|
||||
this.show({
|
||||
name: data.name,
|
||||
data: data.data,
|
||||
onShow: data.onShow,
|
||||
onHide: (result: any) => {
|
||||
data.onHide && data.onHide(result);
|
||||
this.showQueue.shift();
|
||||
this.consumeShowQueue();
|
||||
},
|
||||
onError: data.onError ? (error: string, code: 0 | 1) => {
|
||||
const ret = data.onError(error, code);
|
||||
this.showQueue.shift();
|
||||
this.consumeShowQueue();
|
||||
return ret;
|
||||
} : undefined,
|
||||
top: data.top,
|
||||
attr: data.attr,
|
||||
silent: data.silent
|
||||
});
|
||||
}
|
||||
|
||||
private showUI(params: IShowParams<UIName>) {
|
||||
const { name, data, onShow, onHide, onError, top = true, attr = null, silent = false } = params;
|
||||
|
||||
this.createUI(name, silent, (node, scene) => {
|
||||
if (!node) {
|
||||
this.error('show', `${name} 不存在或加载失败`);
|
||||
// 「没有指定onError」或「onError返回true」会自动发起重试
|
||||
if (onError && onError(`${name} 不存在或加载失败`, UIManager.ErrorCode.LoadError) !== true) {
|
||||
return;
|
||||
}
|
||||
this.scheduleOnce(() => this.showUI(params), 1);
|
||||
if (!silent) this.showLoading(1);
|
||||
return;
|
||||
}
|
||||
|
||||
!scene && top && node.setSiblingIndex(-1);
|
||||
|
||||
const com = this.getBaseView(node);
|
||||
this.uiShowingMap.set(com, name);
|
||||
com.constructor.prototype.show.call(com, data, attr,
|
||||
// onShow
|
||||
(result: any) => {
|
||||
this.uiShowingMap.set(com, name);
|
||||
onShow && onShow(result);
|
||||
},
|
||||
// onHide
|
||||
(result: any) => {
|
||||
this.uiShowingMap.delete(com);
|
||||
onHide && onHide(result);
|
||||
},
|
||||
// beforeShow
|
||||
(error: string) => {
|
||||
if (error) {
|
||||
this.uiShowingMap.delete(com);
|
||||
onError && onError(error, UIManager.ErrorCode.LogicError);
|
||||
} else if (BaseView.isPage(name)) {
|
||||
this.uiShowingMap.set(com, name);
|
||||
const oldCom = this.currPage;
|
||||
this.currPage = com;
|
||||
if (isValid(oldCom, true) && oldCom !== com && oldCom.isShow && oldCom.isAlwaysExist === false) {
|
||||
oldCom.constructor.prototype.hide.call(oldCom, { name });
|
||||
}
|
||||
if (scene) {
|
||||
if (oldCom !== com) {
|
||||
this.currScene = name;
|
||||
director.runSceneImmediate(scene, null, () => {
|
||||
this.log(`切换场景: ${name}`);
|
||||
});
|
||||
}
|
||||
} else if (this.currScene !== UIScene) {
|
||||
this.currScene = UIScene;
|
||||
const scene = new Scene(UIScene);
|
||||
scene.autoReleaseAssets = true;
|
||||
director.runSceneImmediate(scene, null, () => {
|
||||
this.log(`切换场景: ${UIScene}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示一个UI
|
||||
* - 此流程一定是异步的
|
||||
*/
|
||||
public show<UI extends BaseView>(params
|
||||
// @ts-ignore
|
||||
: IShowParams<UIName, Parameters<UI['onShow']>[0], ReturnType<UI['onShow']>, ReturnType<UI['onHide']>>) {
|
||||
const { name, data, queue, onError, silent = false } = params;
|
||||
|
||||
// 加入队列中
|
||||
if (queue) {
|
||||
this.putInShowQueue(params);
|
||||
return;
|
||||
}
|
||||
|
||||
this.log(`show: ${name}`);
|
||||
|
||||
// 生成一个UI加载的UUID
|
||||
const loadingUuid = silent ? '' : this.showLoading();
|
||||
const uiLoadingUuid = this.addUILoadingUuid(name, loadingUuid);
|
||||
// 判断ui是否有效
|
||||
Core.inst.lib.task.execute((retry) => {
|
||||
this.checkUIValid(name, data, (valid) => {
|
||||
// 验证本次加载是否有效
|
||||
if (this.removeUILoadingUuid(name, uiLoadingUuid) === false) {
|
||||
this.hideLoading(loadingUuid);
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载失败
|
||||
if (valid === -1) {
|
||||
this.error('show', `${name} 不存在或加载失败`);
|
||||
// 「没有指定onError」或「onError返回true」会自动发起重试
|
||||
if (onError && onError(`${name} 不存在或加载失败`, UIManager.ErrorCode.LoadError) !== true) {
|
||||
return this.hideLoading(loadingUuid);
|
||||
}
|
||||
return retry(1);
|
||||
}
|
||||
|
||||
// ui无效
|
||||
if (valid === 0) {
|
||||
this.warn('show', `${name} 无效`);
|
||||
this.uninstallUI(name);
|
||||
onError && onError(`${name} 无效`, UIManager.ErrorCode.InvalidError);
|
||||
this.hideLoading(loadingUuid);
|
||||
return;
|
||||
}
|
||||
|
||||
this.showUI(params);
|
||||
this.hideLoading(loadingUuid);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示一个UI
|
||||
* - 此流程一定是异步的
|
||||
*/
|
||||
public showAsync<UI extends BaseView>(params
|
||||
// @ts-ignore
|
||||
: IShowAsyncParams<UIName, Parameters<UI['onShow']>[0], ReturnType<UI['onShow']>>): Promise<ReturnType<UI['onHide']>> {
|
||||
return new Promise((resolve) => {
|
||||
this.show({
|
||||
...params,
|
||||
onHide(result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭View
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public hide<UI extends BaseView>({ name, data, onHide }
|
||||
// @ts-ignore
|
||||
: IHideParams<UIName, Parameters<UI['onHide']>[0], ReturnType<UI['onHide']>>) {
|
||||
const nodes = this.getUIInShowing(name, true);
|
||||
|
||||
this.log(`hide: ${name}`);
|
||||
|
||||
if (nodes.length === 0) {
|
||||
if (!this.uiLoadingMap.has(name) || this.uiLoadingMap.get(name).length === 0) {
|
||||
return this.warn('hide', `${name} 不存在`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.uiLoadingMap.has(name)) {
|
||||
this.uiLoadingMap.get(name).forEach((loadingUuid) => this.hideLoading(loadingUuid));
|
||||
this.uiLoadingMap.get(name).length = 0;
|
||||
}
|
||||
|
||||
for (let index = nodes.length - 1; index >= 0; index--) {
|
||||
const node = nodes[index];
|
||||
const com = this.getBaseView(node);
|
||||
|
||||
if (this.currPage === com) {
|
||||
this.currPage = null;
|
||||
}
|
||||
|
||||
com.constructor.prototype.hide.call(com, data, onHide);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从顶部关闭一个View(不会重复关闭节点)
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public pop<UI extends BaseView>({ name, data, onHide }
|
||||
// @ts-ignore
|
||||
: IHideParams<UIName, Parameters<UI['onHide']>[0], ReturnType<UI['onHide']>>) {
|
||||
const nodes = this.getUIInShowing(name, true);
|
||||
|
||||
if (this.uiLoadingMap.has(name) && this.uiLoadingMap.get(name).length) {
|
||||
const loadingUuid = this.uiLoadingMap.get(name).pop();
|
||||
this.hideLoading(loadingUuid);
|
||||
this.log(`pop: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodes.length) {
|
||||
const node = nodes.pop();
|
||||
const com = this.getBaseView(node);
|
||||
|
||||
if (this.currPage === com) {
|
||||
this.currPage = null;
|
||||
}
|
||||
|
||||
com.constructor.prototype.hide.call(com, data, onHide);
|
||||
this.log(`pop: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.warn('pop', `${name} 不存在`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从底部关闭一个View(不会重复关闭节点)
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public shift<UI extends BaseView>({ name, data, onHide }
|
||||
// @ts-ignore
|
||||
: IHideParams<UIName, Parameters<UI['onHide']>[0], ReturnType<UI['onHide']>>) {
|
||||
const nodes = this.getUIInShowing(name, true);
|
||||
|
||||
if (nodes.length) {
|
||||
const node = nodes[0];
|
||||
const com = this.getBaseView(node);
|
||||
|
||||
if (this.currPage === com) {
|
||||
this.currPage = null;
|
||||
}
|
||||
|
||||
com.constructor.prototype.hide.call(com, data, onHide);
|
||||
this.log(`shift: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.uiLoadingMap.has(name) && this.uiLoadingMap.get(name).length) {
|
||||
const loadingUuid = this.uiLoadingMap.get(name).shift();
|
||||
this.hideLoading(loadingUuid);
|
||||
this.log(`shift: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.warn('shift', `${name} 不存在`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭全部View
|
||||
* - 不关闭展示中的Page(加载中的会停止)
|
||||
* - 此流程一定是同步的
|
||||
*/
|
||||
public hideAll({ data, exclude }: { data?: any, exclude?: UIName[] } = {}): void {
|
||||
this.log('hideAll');
|
||||
// 展示中的
|
||||
this.uiShowingMap.forEach((name, com) => {
|
||||
if (BaseView.isPaper(name)) return;
|
||||
if (exclude && exclude.indexOf(name) !== -1) return;
|
||||
if (com === this.currPage) return;
|
||||
com.constructor.prototype.hide.call(com, data);
|
||||
});
|
||||
// 加载中的
|
||||
this.uiLoadingMap.forEach((value, name) => {
|
||||
if (BaseView.isPaper(name)) return;
|
||||
if (exclude && exclude.indexOf(name) !== -1) return;
|
||||
value.forEach((loadingUuid) => this.hideLoading(loadingUuid));
|
||||
value.length = 0;
|
||||
});
|
||||
}
|
||||
|
||||
public showLoading(timeout = 0) {
|
||||
this.loading.active = true;
|
||||
this.loading.setSiblingIndex(-1);
|
||||
if (this.loading.getComponent(UIMgrLoading)) {
|
||||
this.loading.getComponent(UIMgrLoading).init();
|
||||
} else {
|
||||
// 兼容旧版本
|
||||
this.loading.getComponentInChildren(UIMgrLoading)?.init();
|
||||
}
|
||||
const uuid = this.createUUID();
|
||||
this.showLoadingMap.set(uuid, true);
|
||||
if (timeout > 0) this.scheduleOnce(() => {
|
||||
this.hideLoading(uuid);
|
||||
}, timeout);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public hideLoading(uuid: string) {
|
||||
if (!uuid) return;
|
||||
this.showLoadingMap.delete(uuid);
|
||||
if (this.showLoadingMap.size === 0) {
|
||||
if (this.loading.getComponent(UIMgrLoading)) {
|
||||
this.loading.getComponent(UIMgrLoading).clear();
|
||||
} else {
|
||||
// 兼容旧版本
|
||||
this.loading.getComponentInChildren(UIMgrLoading)?.clear();
|
||||
}
|
||||
this.loading.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加触摸屏蔽
|
||||
*/
|
||||
public addTouchMask(timeout = 0) {
|
||||
this.addTouchMaskListener();
|
||||
const uuid = this.createUUID();
|
||||
this.touchMaskMap.set(uuid, true);
|
||||
if (timeout > 0) this.scheduleOnce(() => {
|
||||
this.removeTouchMask(uuid);
|
||||
}, timeout);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除触摸屏蔽
|
||||
* @param uuid addTouchMask的返回值
|
||||
*/
|
||||
public removeTouchMask(uuid: string) {
|
||||
if (!uuid) return;
|
||||
this.touchMaskMap.delete(uuid);
|
||||
this.removeTouchMaskListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示Toast
|
||||
* @param message 文本
|
||||
* @param timeout 持续时间(秒),默认2秒
|
||||
*/
|
||||
public showToast(message: string, timeout?: number) {
|
||||
if (!this.toast) {
|
||||
return this.error('showToast', '请确认首场景中「Canvas/Manager/UIManager」的「Toast Pre」属性存在');
|
||||
}
|
||||
this.toast.setSiblingIndex(-1);
|
||||
this.toast.getComponent(UIMgrToast).add({
|
||||
message, timeout
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理Toast
|
||||
*/
|
||||
public clearToast() {
|
||||
if (!this.toast) return;
|
||||
this.toast.getComponent(UIMgrToast).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置触摸是否启用
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
public setTouchEnabled(enabled: boolean) {
|
||||
if (enabled) {
|
||||
this.touchEnabled = true;
|
||||
this.removeTouchMaskListener();
|
||||
} else {
|
||||
this.addTouchMaskListener();
|
||||
this.touchEnabled = false;
|
||||
}
|
||||
this.warn('setTouchEnabled', this.touchEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在2DUI根节点上处理事件
|
||||
*/
|
||||
public onUserInterface(...args: Parameters<Node['on']>) {
|
||||
Node.prototype.on.apply(this.UserInterface, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在2DUI根节点上处理事件
|
||||
*/
|
||||
public onceUserInterface(...args: Parameters<Node['once']>) {
|
||||
Node.prototype.once.apply(this.UserInterface, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在2DUI根节点上处理事件
|
||||
*/
|
||||
public offUserInterface(...args: Parameters<Node['off']>) {
|
||||
Node.prototype.off.apply(this.UserInterface, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在2DUI根节点上处理事件
|
||||
*/
|
||||
public targetOffUserInterface(...args: Parameters<Node['targetOff']>) {
|
||||
Node.prototype.targetOff.apply(this.UserInterface, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即给2DUI的子节点排序
|
||||
*/
|
||||
public sortUserInterface(name: IViewType) {
|
||||
this.UserInterface
|
||||
?.getChildByName(name)
|
||||
?.getComponent(UIMgrZOrder)
|
||||
?.updateZOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 屏幕截图
|
||||
* - 需要在Director.EVENT_BEFORE_RENDER事件中调用
|
||||
* @example
|
||||
* director.once(Director.EVENT_BEFORE_RENDER, () => {
|
||||
* const renderTexture = new RenderTexture();
|
||||
* const size = view.getVisibleSize();
|
||||
* renderTexture.reset({ width: size.width, height: size.height });
|
||||
* app.manager.ui.screenshot(renderTexture);
|
||||
* });
|
||||
*/
|
||||
public screenshot(renderTexture: RenderTexture, opts?: {
|
||||
/**摄像机筛选 */
|
||||
cameraFilter?: (camera: Camera) => boolean;
|
||||
/**摄像机列表 */
|
||||
cameraList?: Camera[];
|
||||
}) {
|
||||
const cameras = opts?.cameraList || director.getScene().getComponentsInChildren(Camera);
|
||||
|
||||
const cameraList = cameras.sort((a, b) => a.priority - b.priority)
|
||||
.filter(camera => {
|
||||
if (!camera.enabledInHierarchy) return false;
|
||||
if (camera.targetTexture) return false;
|
||||
return opts?.cameraFilter ? opts.cameraFilter(camera) : true;
|
||||
});
|
||||
const cameraList2 = cameraList.map(camera => camera.camera);
|
||||
|
||||
cameraList.forEach(camera => {
|
||||
camera.targetTexture = renderTexture;
|
||||
});
|
||||
director.root.pipeline.render(cameraList2);
|
||||
cameraList.forEach(camera => {
|
||||
camera.targetTexture = null;
|
||||
});
|
||||
|
||||
return renderTexture;
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/ui/UIManager.ts.meta
Normal file
9
extensions/app/assets/manager/ui/UIManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "234f62f1-ebd3-4d14-9f6f-0b69c7096449",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/ui/comp.meta
Normal file
12
extensions/app/assets/manager/ui/comp.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "cc9c8895-27f9-49df-aca5-a0d1b9ba6480",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
114
extensions/app/assets/manager/ui/comp/UIMgrLoading.ts
Normal file
114
extensions/app/assets/manager/ui/comp/UIMgrLoading.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Component, Graphics, Node, Size, UITransform, _decorator } from 'cc';
|
||||
const { ccclass, property, requireComponent } = _decorator;
|
||||
|
||||
@ccclass('UIMgrLoading')
|
||||
@requireComponent(UITransform)
|
||||
export default class UIMgrLoading extends Component {
|
||||
@property(Node)
|
||||
private loading: Node;
|
||||
|
||||
@property({ tooltip: '动画的尺寸' })
|
||||
private size: Size = new Size(60, 60);
|
||||
|
||||
@property({ tooltip: '等待几秒后开始动画' })
|
||||
private delay = 0;
|
||||
|
||||
private progress = 0;
|
||||
private ringScale = 1;
|
||||
private reverse = false;
|
||||
|
||||
private angleSpeed = 120;
|
||||
private ringSpeed = 0.02;
|
||||
|
||||
private inited = false;
|
||||
private drawing = false;
|
||||
private timedown = 0;
|
||||
|
||||
init() {
|
||||
if (this.inited) return;
|
||||
this.inited = true;
|
||||
|
||||
this.progress = 0;
|
||||
this.ringScale = 1;
|
||||
this.loading.angle = 0;
|
||||
this.reverse = false;
|
||||
|
||||
this.drawing = false;
|
||||
this.timedown = this.delay;
|
||||
this.loading.getComponent(Graphics).clear();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.inited = false;
|
||||
this.drawing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 需要重写
|
||||
*/
|
||||
private onDraw() {
|
||||
const graphics = this.loading.getComponent(Graphics);
|
||||
const uiTransform = this.loading.getComponent(UITransform);
|
||||
|
||||
const centerX = this.size.width * (0.5 - uiTransform.anchorX);
|
||||
const centerY = this.size.height * (0.5 - uiTransform.anchorY);
|
||||
|
||||
const r = Math.min(this.size.width / 2, this.size.height / 2);
|
||||
|
||||
const allPI = Math.PI;
|
||||
const offst = 0;
|
||||
|
||||
graphics.clear();
|
||||
if (this.reverse) {
|
||||
const start = 0.5 * Math.PI + offst;
|
||||
const end = 0.5 * Math.PI + this.progress * 2 * allPI + offst;
|
||||
graphics.arc(centerX, centerY, r, start, end, true);
|
||||
} else {
|
||||
const start = 0.5 * Math.PI - offst;
|
||||
const end = 0.5 * Math.PI - this.progress * 2 * allPI - offst;
|
||||
graphics.arc(centerX, centerY, r, start, end, false);
|
||||
}
|
||||
graphics.stroke();
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
if (!this.inited) return;
|
||||
|
||||
// 倒计时
|
||||
if (!this.drawing) {
|
||||
if (this.timedown > 0) {
|
||||
this.timedown -= dt;
|
||||
}
|
||||
if (this.timedown <= 0) {
|
||||
this.drawing = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 旋转
|
||||
this.loading.angle -= this.angleSpeed * dt;
|
||||
if (this.loading.angle >= 360 || this.loading.angle <= -360) {
|
||||
this.loading.angle = this.loading.angle % 360;
|
||||
}
|
||||
|
||||
// 进度
|
||||
if (this.ringScale > 0) {
|
||||
this.progress = Math.min(1, this.progress + this.ringSpeed * this.ringScale);
|
||||
|
||||
if (this.progress == 1) {
|
||||
this.ringScale = -1;
|
||||
this.reverse = !this.reverse;
|
||||
}
|
||||
} else {
|
||||
this.progress = Math.max(0, this.progress + this.ringSpeed * this.ringScale);
|
||||
|
||||
if (this.progress == 0) {
|
||||
this.ringScale = 1;
|
||||
this.reverse = !this.reverse;
|
||||
}
|
||||
}
|
||||
|
||||
this.onDraw();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "4a8e5697-ae78-4a4a-8d08-17acc6823a27",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
167
extensions/app/assets/manager/ui/comp/UIMgrShade.ts
Normal file
167
extensions/app/assets/manager/ui/comp/UIMgrShade.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { Camera, Color, Component, Director, Material, RenderTexture, Sprite, SpriteFrame, UIOpacity, UITransform, _decorator, director } from 'cc';
|
||||
import Core from '../../../Core';
|
||||
const { ccclass, property, requireComponent } = _decorator;
|
||||
|
||||
@ccclass('UIMgrShade')
|
||||
@requireComponent(Sprite)
|
||||
@requireComponent(UIOpacity)
|
||||
export default class UIMgrShade extends Component {
|
||||
@property(Material)
|
||||
private blurMaterial: Material = null;
|
||||
|
||||
@property(SpriteFrame)
|
||||
private shadeFrame: SpriteFrame = null;
|
||||
|
||||
@property
|
||||
private _delay = 0;
|
||||
@property
|
||||
get delay() { return this._delay; }
|
||||
set delay(v) { this._delay = Math.max(v, 0); }
|
||||
|
||||
@property
|
||||
private _begin = 0;
|
||||
@property
|
||||
get begin() { return this._begin; }
|
||||
set begin(v) { if (v >= 0 && v <= 255) this._begin = v; }
|
||||
|
||||
@property
|
||||
private _end = 255;
|
||||
@property
|
||||
get end() { return this._end; }
|
||||
set end(v) { if (v >= 0 && v <= 255) this._end = v; }
|
||||
|
||||
@property
|
||||
private _speed = 10;
|
||||
@property
|
||||
get speed() {
|
||||
if (this.begin == this.end) {
|
||||
return 0;
|
||||
} else if (this.begin > this.end) {
|
||||
return this._speed > 0 ? -this._speed : this._speed;
|
||||
} else {
|
||||
return this._speed >= 0 ? this._speed : -this._speed;
|
||||
}
|
||||
}
|
||||
set speed(v) { this._speed = v; }
|
||||
|
||||
private get sprite() {
|
||||
return this.node.getComponent(Sprite);
|
||||
}
|
||||
private get opacity() {
|
||||
return this.node.getComponent(UIOpacity);
|
||||
}
|
||||
|
||||
private inited = false;
|
||||
private drawing = false;
|
||||
private timedown = 0;
|
||||
|
||||
private blurFrame: SpriteFrame = null;
|
||||
|
||||
init(delay: number, begin: number, end: number, speed: number, blur: boolean) {
|
||||
if (blur) {
|
||||
director.targetOff(this);
|
||||
this.inited = false;
|
||||
this.drawing = false;
|
||||
|
||||
this.sprite.color = Color.WHITE;
|
||||
this.sprite.customMaterial = null;
|
||||
this.sprite.spriteFrame = this.blurFrame;
|
||||
if (this.blurFrame) this.blurFrame.flipUVY = false;
|
||||
|
||||
let count = 0;
|
||||
const cameras = director.getScene().getComponentsInChildren(Camera);
|
||||
director.on(Director.EVENT_BEFORE_RENDER, () => {
|
||||
count++;
|
||||
|
||||
const renderTexture = new RenderTexture();
|
||||
const size = this.node.getComponent(UITransform);
|
||||
renderTexture.reset({ width: size.width / 2, height: size.height / 2 });
|
||||
renderTexture.addRef();
|
||||
|
||||
Core.inst.manager.ui.screenshot(renderTexture, {
|
||||
cameraList: cameras
|
||||
});
|
||||
|
||||
if (count === 1) {
|
||||
this.blurFrame = new SpriteFrame();
|
||||
this.blurFrame?.texture?.decRef();
|
||||
this.blurFrame.texture = renderTexture;
|
||||
this.blurFrame.flipUVY = true;
|
||||
this.sprite.spriteFrame = this.blurFrame;
|
||||
this.sprite.customMaterial = this.blurMaterial;
|
||||
this.blurMaterial.setProperty('blurLevel', 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count === 5) {
|
||||
director.targetOff(this);
|
||||
this.sprite.spriteFrame.flipUVY = false;
|
||||
this.sprite.customMaterial = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.blurFrame?.texture?.decRef();
|
||||
this.blurFrame.texture = renderTexture;
|
||||
this.blurFrame.flipUVY = true;
|
||||
this.sprite.spriteFrame = this.blurFrame;
|
||||
this.sprite.customMaterial = this.blurMaterial;
|
||||
this.blurMaterial.setProperty('blurLevel', count === 2 ? 3 : 1);
|
||||
}, this);
|
||||
} else {
|
||||
director.targetOff(this);
|
||||
this.sprite.spriteFrame = this.shadeFrame;
|
||||
this.sprite.color = Color.BLACK;
|
||||
this.sprite.customMaterial = null;
|
||||
}
|
||||
|
||||
this.delay = delay;
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.speed = speed;
|
||||
this.drawing = true;
|
||||
|
||||
if (this.inited) return;
|
||||
this.inited = true;
|
||||
this.timedown = this.delay;
|
||||
// 初始透明度
|
||||
this.opacity.opacity = this.timedown > 0 ? 0 : this.begin;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.inited = false;
|
||||
this.drawing = false;
|
||||
director.targetOff(this);
|
||||
this.blurFrame?.texture?.decRef();
|
||||
this.blurFrame?.destroy();
|
||||
this.blurFrame = null;
|
||||
this.sprite.spriteFrame = null;
|
||||
}
|
||||
|
||||
protected update(dt: number) {
|
||||
if (!this.inited) return;
|
||||
if (!this.drawing) return;
|
||||
|
||||
if (this.timedown > 0) {
|
||||
this.timedown -= dt;
|
||||
if (this.timedown > 0) return;
|
||||
// 初始透明度
|
||||
this.opacity.opacity = this.begin;
|
||||
}
|
||||
|
||||
const uiOpacity = this.opacity;
|
||||
if (this.speed > 0) {
|
||||
uiOpacity.opacity += this.speed * dt;
|
||||
if (uiOpacity.opacity > this.end) {
|
||||
uiOpacity.opacity = this.end;
|
||||
}
|
||||
} else if (this.speed < 0) {
|
||||
uiOpacity.opacity += this.speed * dt;
|
||||
if (uiOpacity.opacity < this.end) {
|
||||
uiOpacity.opacity = this.end;
|
||||
}
|
||||
}
|
||||
if (uiOpacity.opacity == this.end) {
|
||||
this.drawing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/ui/comp/UIMgrShade.ts.meta
Normal file
9
extensions/app/assets/manager/ui/comp/UIMgrShade.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d0295d9b-b01d-493c-9e31-5ed78e6c33ab",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
111
extensions/app/assets/manager/ui/comp/UIMgrToast.ts
Normal file
111
extensions/app/assets/manager/ui/comp/UIMgrToast.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { Component, NodePool, Prefab, Tween, UIOpacity, UITransform, _decorator, instantiate, tween, view } from 'cc';
|
||||
import UIMgrToastCell from './UIMgrToastCell';
|
||||
const { property, ccclass, requireComponent } = _decorator;
|
||||
|
||||
@ccclass('UIMgrToast')
|
||||
@requireComponent(UITransform)
|
||||
export default class UIMgrToast extends Component {
|
||||
@property(Prefab)
|
||||
private cell: Prefab = null;
|
||||
|
||||
/**每条信息显示几秒 */
|
||||
private lifeTime = 2;
|
||||
|
||||
/**消失时花费几秒渐隐 */
|
||||
private outTime = 0.2;
|
||||
|
||||
/**挤压基础速度 */
|
||||
private squeezeSpeed = 200;
|
||||
|
||||
/**节点缓存池子 */
|
||||
private pool = new NodePool();
|
||||
|
||||
add(data: {
|
||||
message: string,
|
||||
timeout?: number
|
||||
}) {
|
||||
const cell = this.pool.get() || instantiate(this.cell);
|
||||
cell.setPosition(0, 0, 0);
|
||||
cell.parent = this.node;
|
||||
cell.active = true;
|
||||
|
||||
cell.getComponent(UIMgrToastCell).init(data.message);
|
||||
|
||||
cell.getComponent(UIOpacity).opacity = 255;
|
||||
tween(cell.getComponent(UIOpacity))
|
||||
.delay(data.timeout || this.lifeTime)
|
||||
.to(this.outTime, { opacity: 0 })
|
||||
.call(() => {
|
||||
this.pool.put(cell);
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
clear() {
|
||||
const children = this.node.children;
|
||||
for (let index = children.length - 1; index >= 0; index--) {
|
||||
Tween.stopAllByTarget(children[index].getComponent(UIOpacity));
|
||||
children[index].destroy();
|
||||
}
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.node.children.length;
|
||||
}
|
||||
|
||||
protected onDestroy() {
|
||||
this.pool.clear();
|
||||
}
|
||||
|
||||
protected update(dt: number) {
|
||||
const children = this.node.children;
|
||||
for (let index = children.length - 1, recovery = false; index >= 0; index--) {
|
||||
const zero = index === children.length - 1;
|
||||
const curr = children[index];
|
||||
|
||||
// 直接触发回收逻辑
|
||||
if (recovery) {
|
||||
Tween.stopAllByTarget(curr.getComponent(UIOpacity));
|
||||
this.pool.put(curr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zero) {
|
||||
const currUT = curr.getComponent(UITransform);
|
||||
|
||||
const lastMaxY = 0 - currUT.height / 2;
|
||||
const currMinY = curr.position.y + lastMaxY;
|
||||
|
||||
if (currMinY > lastMaxY) {
|
||||
// 存在空隙
|
||||
const addLen = Math.max(-this.squeezeSpeed * dt * (children.length - index), lastMaxY - currMinY);
|
||||
curr.setPosition(curr.position.x, curr.position.y + addLen, curr.position.z);
|
||||
}
|
||||
} else {
|
||||
const last = children[index + 1];
|
||||
const currUT = curr.getComponent(UITransform);
|
||||
const lastUT = last.getComponent(UITransform);
|
||||
|
||||
const currMinY = curr.position.y - currUT.height / 2 - 6;//6像素的间隔
|
||||
const lastMaxY = last.position.y + lastUT.height / 2;
|
||||
|
||||
if (currMinY < lastMaxY) {
|
||||
// 存在重叠
|
||||
const addLen = Math.min(this.squeezeSpeed * dt * (children.length - index - 1), lastMaxY - currMinY);
|
||||
curr.setPosition(curr.position.x, curr.position.y + addLen, curr.position.z);
|
||||
const winSize = view.getVisibleSize();
|
||||
if (currMinY > winSize.height / 2) {
|
||||
// 触发回收逻辑
|
||||
recovery = true;
|
||||
Tween.stopAllByTarget(curr.getComponent(UIOpacity));
|
||||
this.pool.put(curr);
|
||||
}
|
||||
} else if (currMinY > lastMaxY) {
|
||||
// 存在空隙
|
||||
const addLen = Math.max(-this.squeezeSpeed * dt * (children.length - index), lastMaxY - currMinY);
|
||||
curr.setPosition(curr.position.x, curr.position.y + addLen, curr.position.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/ui/comp/UIMgrToast.ts.meta
Normal file
9
extensions/app/assets/manager/ui/comp/UIMgrToast.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "cde1528c-f66c-40f4-bdd2-27bf138ce1df",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
26
extensions/app/assets/manager/ui/comp/UIMgrToastCell.ts
Normal file
26
extensions/app/assets/manager/ui/comp/UIMgrToastCell.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Component, Label, UIOpacity, UITransform, _decorator } from 'cc';
|
||||
const { ccclass, property, requireComponent } = _decorator;
|
||||
|
||||
@ccclass('UIMgrToastCell')
|
||||
@requireComponent(UIOpacity)
|
||||
@requireComponent(UITransform)
|
||||
export default class UIMgrToastCell extends Component {
|
||||
@property(Label)
|
||||
private title: Label = null;
|
||||
|
||||
init(title: string) {
|
||||
if (title.split('\n').find((v) => v.length > 30)) {
|
||||
this.title.overflow = Label.Overflow.RESIZE_HEIGHT;
|
||||
this.title.getComponent(UITransform).width = 600;
|
||||
} else {
|
||||
this.title.overflow = Label.Overflow.NONE;
|
||||
}
|
||||
this.title.string = title;
|
||||
this.title.updateRenderData(true);
|
||||
}
|
||||
|
||||
unuse() {
|
||||
this.title.string = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6cc631d6-b08e-4ee3-8bde-e307c4288734",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
68
extensions/app/assets/manager/ui/comp/UIMgrZOrder.ts
Normal file
68
extensions/app/assets/manager/ui/comp/UIMgrZOrder.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { _decorator, Component, Director, director, Node } from 'cc';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
@ccclass('UIMgrZOrder')
|
||||
export default class UIMgrZOrder extends Component {
|
||||
private zOrder = false;
|
||||
private tempArr: Node[] = [];
|
||||
|
||||
protected onLoad() {
|
||||
this.checkUpdateZOrder();
|
||||
this.node.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
|
||||
this.node.on(Node.EventType.CHILD_REMOVED, this.onChildRemoveed, this);
|
||||
if (Node.EventType.CHILDREN_ORDER_CHANGED) {
|
||||
this.node.on(Node.EventType.CHILDREN_ORDER_CHANGED, this.checkUpdateZOrder, this);
|
||||
} else {
|
||||
this.node.on(Node.EventType.SIBLING_ORDER_CHANGED, this.checkUpdateZOrder, this);
|
||||
}
|
||||
}
|
||||
|
||||
protected onDestroy() {
|
||||
director.off(Director.EVENT_AFTER_UPDATE, this.updateZOrder, this);
|
||||
this.node.off(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
|
||||
this.node.off(Node.EventType.CHILD_REMOVED, this.onChildRemoveed, this);
|
||||
if (Node.EventType.CHILDREN_ORDER_CHANGED) {
|
||||
this.node.off(Node.EventType.CHILDREN_ORDER_CHANGED, this.checkUpdateZOrder, this);
|
||||
} else {
|
||||
this.node.off(Node.EventType.SIBLING_ORDER_CHANGED, this.checkUpdateZOrder, this);
|
||||
}
|
||||
}
|
||||
|
||||
private onChildAdded(child: Node) {
|
||||
this.checkUpdateZOrder();
|
||||
child.on(Node.EventType.TRANSFORM_CHANGED, this.checkUpdateZOrder, this);
|
||||
}
|
||||
|
||||
private onChildRemoveed(child: Node) {
|
||||
child.off(Node.EventType.TRANSFORM_CHANGED, this.checkUpdateZOrder, this);
|
||||
}
|
||||
|
||||
private checkUpdateZOrder() {
|
||||
if (this.zOrder) return;
|
||||
this.zOrder = true;
|
||||
director.once(Director.EVENT_AFTER_UPDATE, this.updateZOrder, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节点树排序
|
||||
*/
|
||||
public updateZOrder() {
|
||||
if (!this.zOrder) return;
|
||||
Array.prototype.push.apply(this.tempArr, this.node.children);
|
||||
this.tempArr
|
||||
.sort((a, b) => {
|
||||
return (a.position.z - b.position.z)
|
||||
|| (a.getSiblingIndex() - b.getSiblingIndex());
|
||||
})
|
||||
.forEach((child, index) => {
|
||||
child.setSiblingIndex(index);
|
||||
});
|
||||
|
||||
// 一定要放到最后再设置false,
|
||||
// 避免更新过程中设置siblingIndex,
|
||||
// 导致无限重复调用
|
||||
this.zOrder = false;
|
||||
this.tempArr.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ad5cb510-639e-40c2-acdd-399ad00629b9",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
extensions/app/assets/manager/ui/effect.meta
Normal file
9
extensions/app/assets/manager/ui/effect.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "e3ac29f9-11a4-461c-a404-9e478271b953",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
119
extensions/app/assets/manager/ui/effect/blur.effect
Normal file
119
extensions/app/assets/manager/ui/effect/blur.effect
Normal file
@@ -0,0 +1,119 @@
|
||||
CCEffect %{
|
||||
techniques:
|
||||
- name: opaque
|
||||
passes:
|
||||
- vert: vs:vert
|
||||
frag: fs:frag
|
||||
depthStencilState:
|
||||
depthTest: false
|
||||
depthWrite: false
|
||||
blendState:
|
||||
targets:
|
||||
- blend: true
|
||||
blendSrc: src_alpha
|
||||
blendSrcAlpha: src_alpha
|
||||
blendDst: one_minus_src_alpha
|
||||
blendDstAlpha: one_minus_src_alpha
|
||||
rasterizerState:
|
||||
cullMode: none
|
||||
properties:
|
||||
blurSize: { value: [750, 1334] }
|
||||
blurriness: { value: 1, editor: {range:[0, 1, 0.01], slide: true} }
|
||||
blurLevel: { value: 1, editor: {range:[1, 3, 1], slide: true} }
|
||||
|
||||
}%
|
||||
|
||||
CCProgram vs %{
|
||||
precision highp float;
|
||||
#include <cc-global>
|
||||
|
||||
in vec4 a_position;
|
||||
in vec2 a_texCoord;
|
||||
out vec2 v_texCoord;
|
||||
|
||||
vec4 vert() {
|
||||
vec4 pos = cc_matViewProj * a_position;
|
||||
v_texCoord = a_texCoord;
|
||||
return pos;
|
||||
}
|
||||
}%
|
||||
|
||||
CCProgram fs %{
|
||||
precision highp float;
|
||||
|
||||
in vec2 v_texCoord;
|
||||
#pragma builtin(local)
|
||||
layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;
|
||||
|
||||
uniform Constant {
|
||||
vec2 blurSize;
|
||||
float blurriness;
|
||||
float blurLevel;
|
||||
};
|
||||
|
||||
// 模糊处理函数
|
||||
vec4 blur (vec2 pos) {
|
||||
float sum = 0.0;
|
||||
vec4 color = vec4(0);
|
||||
|
||||
if (blurLevel == 1.0) {
|
||||
const float blurRadius = 10.0;
|
||||
const float blurStep = 1.0;
|
||||
// 采样周边像素并求出加权平均值,得到最终的像素值
|
||||
for (float rx = -blurRadius; rx <= blurRadius; rx += blurStep) {
|
||||
for (float ry = -blurRadius; ry <= blurRadius; ry += blurStep) {
|
||||
vec2 target = pos + vec2(rx / blurSize[0], ry / blurSize[1]);
|
||||
float weight = (blurRadius - abs(rx)) * (blurRadius - abs(ry));
|
||||
target.x = clamp(target.x, 0.0, 1.0);
|
||||
target.y = clamp(target.y, 0.0, 1.0);
|
||||
color += texture(cc_spriteTexture, target) * weight;
|
||||
sum += weight;
|
||||
}
|
||||
}
|
||||
} else if(blurLevel == 2.0) {
|
||||
const float blurRadius = 20.0;
|
||||
const float blurStep = 2.0;
|
||||
// 采样周边像素并求出加权平均值,得到最终的像素值
|
||||
for (float rx = -blurRadius; rx <= blurRadius; rx += blurStep) {
|
||||
for (float ry = -blurRadius; ry <= blurRadius; ry += blurStep) {
|
||||
vec2 target = pos + vec2(rx / blurSize[0], ry / blurSize[1]);
|
||||
float weight = (blurRadius - abs(rx)) * (blurRadius - abs(ry));
|
||||
target.x = clamp(target.x, 0.0, 1.0);
|
||||
target.y = clamp(target.y, 0.0, 1.0);
|
||||
color += texture(cc_spriteTexture, target) * weight;
|
||||
sum += weight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const float blurRadius = 30.0;
|
||||
const float blurStep = 3.0;
|
||||
// 采样周边像素并求出加权平均值,得到最终的像素值
|
||||
for (float rx = -blurRadius; rx <= blurRadius; rx += blurStep) {
|
||||
for (float ry = -blurRadius; ry <= blurRadius; ry += blurStep) {
|
||||
vec2 target = pos + vec2(rx / blurSize[0], ry / blurSize[1]);
|
||||
float weight = (blurRadius - abs(rx)) * (blurRadius - abs(ry));
|
||||
target.x = clamp(target.x, 0.0, 1.0);
|
||||
target.y = clamp(target.y, 0.0, 1.0);
|
||||
color += texture(cc_spriteTexture, target) * weight;
|
||||
sum += weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color /= sum;
|
||||
return color;
|
||||
}
|
||||
|
||||
vec4 frag () {
|
||||
// 获取纹理像素颜色
|
||||
vec4 o = vec4(1, 1, 1, 1);
|
||||
o *= texture(cc_spriteTexture, v_texCoord);
|
||||
|
||||
// 执行模糊逻辑
|
||||
vec4 color = blur(v_texCoord);
|
||||
color.a = o.a;
|
||||
o = o + (color-o) * blurriness;
|
||||
|
||||
return o;
|
||||
}
|
||||
}%
|
||||
11
extensions/app/assets/manager/ui/effect/blur.effect.meta
Normal file
11
extensions/app/assets/manager/ui/effect/blur.effect.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.7.1",
|
||||
"importer": "effect",
|
||||
"imported": true,
|
||||
"uuid": "b5376e0b-9e5d-4c91-b0a4-19448fd39179",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
36
extensions/app/assets/manager/ui/effect/blur.mtl
Normal file
36
extensions/app/assets/manager/ui/effect/blur.mtl
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"__type__": "cc.Material",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"_effectAsset": {
|
||||
"__uuid__": "b5376e0b-9e5d-4c91-b0a4-19448fd39179",
|
||||
"__expectedType__": "cc.EffectAsset"
|
||||
},
|
||||
"_techIdx": 0,
|
||||
"_defines": [
|
||||
{}
|
||||
],
|
||||
"_states": [
|
||||
{
|
||||
"rasterizerState": {},
|
||||
"depthStencilState": {},
|
||||
"blendState": {
|
||||
"targets": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"_props": [
|
||||
{
|
||||
"textureSize": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 750,
|
||||
"y": 1334
|
||||
},
|
||||
"blurDegree": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
11
extensions/app/assets/manager/ui/effect/blur.mtl.meta
Normal file
11
extensions/app/assets/manager/ui/effect/blur.mtl.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.21",
|
||||
"importer": "material",
|
||||
"imported": true,
|
||||
"uuid": "a313b5eb-b939-4c44-affc-32c713440cea",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
extensions/app/assets/manager/ui/prefab.meta
Normal file
12
extensions/app/assets/manager/ui/prefab.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "a32ee073-dc9a-4d81-b3c1-54283a151627",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
330
extensions/app/assets/manager/ui/prefab/UIMgrLoading.prefab
Normal file
330
extensions/app/assets/manager/ui/prefab/UIMgrLoading.prefab
Normal file
@@ -0,0 +1,330 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "UIMgrLoading",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "UIMgrLoading",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "loading",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "93a3D7kcNLmKSzPl3DUiom"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Graphics",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_lineWidth": 8,
|
||||
"_strokeColor": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 247,
|
||||
"g": 155,
|
||||
"b": 17,
|
||||
"a": 255
|
||||
},
|
||||
"_lineJoin": 2,
|
||||
"_lineCap": 1,
|
||||
"_fillColor": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 247,
|
||||
"g": 155,
|
||||
"b": 17,
|
||||
"a": 255
|
||||
},
|
||||
"_miterLimit": 10,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "8cV7EpeTlFy50kiDgQAuVw"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "f1BL1+S9ZHKLm/dYTzeaLU",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 1080,
|
||||
"height": 1920
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "3brXLn6dBA1Zn+gXeG0T+V"
|
||||
},
|
||||
{
|
||||
"__type__": "4a8e5aXrnhKSo0IF6zGgjon",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"loading": {
|
||||
"__id__": 2
|
||||
},
|
||||
"size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 60,
|
||||
"height": 60
|
||||
},
|
||||
"delay": 1,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "07sEXIwyZEKI/ruuFHnBcu"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 100,
|
||||
"_originalHeight": 100,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "1en2H6LWVAnbHn1Id9zrSK"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BlockInputEvents",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "23+7We+IdLxIZlOVikvEPE"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "daRB56CWxIRa37BwtucqYI",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "fe542035-b018-493e-bea8-084fe4e01905",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "UIMgrLoading"
|
||||
}
|
||||
}
|
||||
262
extensions/app/assets/manager/ui/prefab/UIMgrShade.prefab
Normal file
262
extensions/app/assets/manager/ui/prefab/UIMgrShade.prefab
Normal file
@@ -0,0 +1,262 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "UIMgrShade",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "UIMgrShade",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 4
|
||||
},
|
||||
{
|
||||
"__id__": 6
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 14
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 3
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 750,
|
||||
"height": 1334
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "7dX6ImdfBJcqlTYmg63cOq"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UIOpacity",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 5
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "79YFX8QOxIqrfZHGmtwiec"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "22F/XyC25NNbnQRqf69Fet"
|
||||
},
|
||||
{
|
||||
"__type__": "d02952bsB1JPJ4xXteObDOr",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"blurMaterial": {
|
||||
"__uuid__": "a313b5eb-b939-4c44-affc-32c713440cea",
|
||||
"__expectedType__": "cc.Material"
|
||||
},
|
||||
"shadeFrame": {
|
||||
"__uuid__": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_delay": 0,
|
||||
"_begin": 60,
|
||||
"_end": 180,
|
||||
"_speed": 100,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "cfGNW3HSFJZ5C0B0FM1PtW"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_alignFlags": 45,
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 750,
|
||||
"_originalHeight": 1334,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "229/N15SBGH4HGma+cYqM5"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BlockInputEvents",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "82DtXS4ChDkLThlpVA53IU"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "61DZmvnnRICYRzOyDnyCeu",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "000cee21-922c-4fcd-bd39-6f80ac2436a4",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "UIMgrShade"
|
||||
}
|
||||
}
|
||||
93
extensions/app/assets/manager/ui/prefab/UIMgrToast.prefab
Normal file
93
extensions/app/assets/manager/ui/prefab/UIMgrToast.prefab
Normal file
@@ -0,0 +1,93 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "UIMgrToast",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "UIMgrToast",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cde15KM9mxA9L3SJ78TjOHf",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 3
|
||||
},
|
||||
"cell": {
|
||||
"__uuid__": "5aa9450d-6710-4fac-a82c-ee2939cf9411",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "3aBOvgZTJM7o51sRqaqstL"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7cYDN4HdROmJQ7qqaDYftE",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "b2a00c44-d199-4031-8fa7-ea681618b9d4",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "UIMgrToast"
|
||||
}
|
||||
}
|
||||
438
extensions/app/assets/manager/ui/prefab/UIMgrToastCell.prefab
Normal file
438
extensions/app/assets/manager/ui/prefab/UIMgrToastCell.prefab
Normal file
@@ -0,0 +1,438 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "UIMgrToastCell",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "UIMgrToastCell",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 20
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "title",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 3.552713678800501e-15,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 0,
|
||||
"height": 50.4
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "18U2eEmv1MSrJ3Kp8ChYCB"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 30,
|
||||
"_fontSize": 30,
|
||||
"_fontFamily": "Arial",
|
||||
"_lineHeight": 40,
|
||||
"_overflow": 0,
|
||||
"_enableWrapText": true,
|
||||
"_font": null,
|
||||
"_isSystemFontUsed": true,
|
||||
"_spacingX": 0,
|
||||
"_isItalic": false,
|
||||
"_isBold": false,
|
||||
"_isUnderline": false,
|
||||
"_underlineHeight": 2,
|
||||
"_cacheMode": 0,
|
||||
"_enableOutline": false,
|
||||
"_outlineColor": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 0,
|
||||
"g": 0,
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_outlineWidth": 2,
|
||||
"_enableShadow": false,
|
||||
"_shadowColor": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 0,
|
||||
"g": 0,
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_shadowOffset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"_shadowBlur": 2,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "fcBV+kyJJKoLa0miLOwB0D"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "17FiiUdlpA7INUb+CSPtXV",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 70.4
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "7bhW+VfdhFIZBU1YlNH87w"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UIOpacity",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "85IfdKUvlDVobXX10lMYgh"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "7922bee9-7eb5-449b-884e-14ac57ae515c@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "d5KZg62HRMhqP9FpXXBvrN"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Layout",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
},
|
||||
"_resizeMode": 1,
|
||||
"_layoutType": 1,
|
||||
"_cellSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 40,
|
||||
"height": 40
|
||||
},
|
||||
"_startAxis": 0,
|
||||
"_paddingLeft": 40,
|
||||
"_paddingRight": 40,
|
||||
"_paddingTop": 10,
|
||||
"_paddingBottom": 10,
|
||||
"_spacingX": 0,
|
||||
"_spacingY": 0,
|
||||
"_verticalDirection": 1,
|
||||
"_horizontalDirection": 0,
|
||||
"_constraint": 0,
|
||||
"_constraintNum": 1,
|
||||
"_affectedByScale": false,
|
||||
"_isAlign": false,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e0RO5Tg+lAWq8B14qLuRXc"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Layout",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"_resizeMode": 1,
|
||||
"_layoutType": 2,
|
||||
"_cellSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 40,
|
||||
"height": 40
|
||||
},
|
||||
"_startAxis": 0,
|
||||
"_paddingLeft": 0,
|
||||
"_paddingRight": 0,
|
||||
"_paddingTop": 10,
|
||||
"_paddingBottom": 10,
|
||||
"_spacingX": 0,
|
||||
"_spacingY": 0,
|
||||
"_verticalDirection": 1,
|
||||
"_horizontalDirection": 0,
|
||||
"_constraint": 0,
|
||||
"_constraintNum": 2,
|
||||
"_affectedByScale": false,
|
||||
"_isAlign": false,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4w/hORDRDYLZbEx1j4ybh"
|
||||
},
|
||||
{
|
||||
"__type__": "6cc63HWsI5O44ve4wfEKIc0",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 19
|
||||
},
|
||||
"title": {
|
||||
"__id__": 5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "a82bayEVpB1YYG3zm38T3l"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "5aa9450d-6710-4fac-a82c-ee2939cf9411",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "UIMgrToastCell"
|
||||
}
|
||||
}
|
||||
12
extensions/app/assets/manager/ui/texture.meta
Normal file
12
extensions/app/assets/manager/ui/texture.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "f5f10a35-ca33-4eb2-81f1-52459832001b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
BIN
extensions/app/assets/manager/ui/texture/singleColor.png
Normal file
BIN
extensions/app/assets/manager/ui/texture/singleColor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 B |
134
extensions/app/assets/manager/ui/texture/singleColor.png.meta
Normal file
134
extensions/app/assets/manager/ui/texture/singleColor.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "5512993f-89ea-46fe-b788-0ecc0c2cd51c",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@6c48a",
|
||||
"displayName": "singleColor",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "5512993f-89ea-46fe-b788-0ecc0c2cd51c",
|
||||
"isUuid": true,
|
||||
"visible": false,
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@f9941",
|
||||
"displayName": "singleColor",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 2,
|
||||
"height": 2,
|
||||
"rawWidth": 2,
|
||||
"rawHeight": 2,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-1,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
0,
|
||||
-1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-1,
|
||||
-1,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
1,
|
||||
1,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@6c48a",
|
||||
"atlasUuid": ""
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"fixAlphaTransparencyArtifacts": true,
|
||||
"hasAlpha": false,
|
||||
"redirect": "5512993f-89ea-46fe-b788-0ecc0c2cd51c@6c48a"
|
||||
}
|
||||
}
|
||||
BIN
extensions/app/assets/manager/ui/texture/toastBox.png
Normal file
BIN
extensions/app/assets/manager/ui/texture/toastBox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
134
extensions/app/assets/manager/ui/texture/toastBox.png.meta
Normal file
134
extensions/app/assets/manager/ui/texture/toastBox.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "b250e49c-5d79-4d07-a85f-a980fca36170",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "b250e49c-5d79-4d07-a85f-a980fca36170@6c48a",
|
||||
"displayName": "toastBox",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "b250e49c-5d79-4d07-a85f-a980fca36170",
|
||||
"isUuid": true,
|
||||
"visible": false,
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "b250e49c-5d79-4d07-a85f-a980fca36170@f9941",
|
||||
"displayName": "toastBox",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 288,
|
||||
"height": 78,
|
||||
"rawWidth": 288,
|
||||
"rawHeight": 78,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 40,
|
||||
"borderRight": 40,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-144,
|
||||
-39,
|
||||
0,
|
||||
144,
|
||||
-39,
|
||||
0,
|
||||
-144,
|
||||
39,
|
||||
0,
|
||||
144,
|
||||
39,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
78,
|
||||
288,
|
||||
78,
|
||||
0,
|
||||
0,
|
||||
288,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-144,
|
||||
-39,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
144,
|
||||
39,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "b250e49c-5d79-4d07-a85f-a980fca36170@6c48a",
|
||||
"atlasUuid": ""
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"fixAlphaTransparencyArtifacts": true,
|
||||
"hasAlpha": true,
|
||||
"redirect": "b250e49c-5d79-4d07-a85f-a980fca36170@6c48a"
|
||||
}
|
||||
}
|
||||
BIN
extensions/app/assets/manager/ui/texture/toastCell.png
Normal file
BIN
extensions/app/assets/manager/ui/texture/toastCell.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 629 B |
134
extensions/app/assets/manager/ui/texture/toastCell.png.meta
Normal file
134
extensions/app/assets/manager/ui/texture/toastCell.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "7922bee9-7eb5-449b-884e-14ac57ae515c",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "7922bee9-7eb5-449b-884e-14ac57ae515c@6c48a",
|
||||
"displayName": "toastCell",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "7922bee9-7eb5-449b-884e-14ac57ae515c",
|
||||
"isUuid": true,
|
||||
"visible": false,
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "7922bee9-7eb5-449b-884e-14ac57ae515c@f9941",
|
||||
"displayName": "toastCell",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 100,
|
||||
"height": 100,
|
||||
"rawWidth": 100,
|
||||
"rawHeight": 100,
|
||||
"borderTop": 15,
|
||||
"borderBottom": 15,
|
||||
"borderLeft": 15,
|
||||
"borderRight": 15,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-50,
|
||||
-50,
|
||||
0,
|
||||
50,
|
||||
-50,
|
||||
0,
|
||||
-50,
|
||||
50,
|
||||
0,
|
||||
50,
|
||||
50,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-50,
|
||||
-50,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
50,
|
||||
50,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "7922bee9-7eb5-449b-884e-14ac57ae515c@6c48a",
|
||||
"atlasUuid": ""
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"hasAlpha": true,
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"redirect": "7922bee9-7eb5-449b-884e-14ac57ae515c@6c48a"
|
||||
}
|
||||
}
|
||||
4
extensions/app/engine/.gitignore
vendored
Normal file
4
extensions/app/engine/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
/node_modules
|
||||
1227
extensions/app/engine/@types/editor.d.ts
vendored
Normal file
1227
extensions/app/engine/@types/editor.d.ts
vendored
Normal file
@@ -0,0 +1,1227 @@
|
||||
/// <reference path='./electron.d.ts'/>
|
||||
|
||||
/// <reference types='node' />
|
||||
/// <reference path='./extension.d.ts'/>
|
||||
|
||||
import * as NodeJSPath from 'path';
|
||||
import { EventEmitter } from 'events';
|
||||
import { FileFilter, BrowserWindow, OpenDialogReturnValue, SaveDialogReturnValue, MessageBoxReturnValue } from 'electron';
|
||||
|
||||
declare global {
|
||||
export namespace Editor {
|
||||
export namespace App {
|
||||
export const userAgent: string;
|
||||
/**
|
||||
* 是否是开发模式
|
||||
* Development mode
|
||||
*/
|
||||
export const dev: boolean;
|
||||
/**
|
||||
* 编辑器版本号
|
||||
* Editor version
|
||||
*/
|
||||
export const version: string;
|
||||
/**
|
||||
* 主目录
|
||||
* Home directory
|
||||
*/
|
||||
export const home: string;
|
||||
/**
|
||||
* 编辑器程序文件夹
|
||||
* Program folder
|
||||
*/
|
||||
export const path: string;
|
||||
/**
|
||||
* 获取当前编辑器的临时缓存目录
|
||||
* Temporary cache directory
|
||||
*/
|
||||
export const temp: string;
|
||||
/**
|
||||
* 获取当前编辑器 icon 地址
|
||||
* Gets the icon address of the current editor
|
||||
*/
|
||||
export const icon: string;
|
||||
/**
|
||||
* 获取当前编辑器使用的 url 地址
|
||||
* Gets the URL used by the current editor
|
||||
*/
|
||||
export const urls: {
|
||||
manual: string;
|
||||
api: string;
|
||||
forum: string;
|
||||
};
|
||||
/**
|
||||
* 退出程序
|
||||
* Exit the program
|
||||
*/
|
||||
export function quit(): void;
|
||||
}
|
||||
export namespace Clipboard {
|
||||
export type ICopyType = 'image' | 'text' | 'files' | string;
|
||||
/**
|
||||
* 获取剪贴板内容
|
||||
* @param type
|
||||
*/
|
||||
export function read(type: ICopyType): any;
|
||||
/**
|
||||
* 写入剪贴板内容
|
||||
* @param type
|
||||
* @param value
|
||||
*/
|
||||
export function write(type: 'image', value: string): boolean;
|
||||
export function write(type: 'text', value: string): boolean;
|
||||
export function write(type: 'files', value: FileList): boolean;
|
||||
export function write(type: string, value: any): boolean;
|
||||
|
||||
/**
|
||||
* 判断当前剪贴板内是否是指定类型
|
||||
* @param type
|
||||
*/
|
||||
export function has(type: ICopyType): boolean;
|
||||
/**
|
||||
* 清空剪贴板
|
||||
*/
|
||||
export function clear(): void;
|
||||
}
|
||||
export namespace Dialog {
|
||||
|
||||
export interface SaveDialogOptions {
|
||||
title?: string;
|
||||
path?: string;
|
||||
button?: string;
|
||||
filters?: FileFilter[];
|
||||
}
|
||||
export interface SelectDialogOptions {
|
||||
title?: string;
|
||||
path?: string;
|
||||
type?: 'directory' | 'file';
|
||||
button?: string;
|
||||
multi?: boolean;
|
||||
filters?: FileFilter[];
|
||||
extensions?: string;
|
||||
}
|
||||
export interface MessageDialogOptions {
|
||||
title?: string;
|
||||
detail?: string;
|
||||
default?: number;
|
||||
cancel?: number;
|
||||
checkboxLabel?: string;
|
||||
checkboxChecked?: boolean;
|
||||
buttons?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择文件弹窗
|
||||
* Select the file popover
|
||||
*
|
||||
* @param options 选择弹窗参数 Select popover parameters
|
||||
* @param window 依附于哪个窗口(插件主进程才可使用) Which window it is attached to (only available to the plugin's main process)
|
||||
*/
|
||||
export function select(options?: SelectDialogOptions, window?: BrowserWindow): Promise<OpenDialogReturnValue>;
|
||||
/**
|
||||
* 保存文件弹窗
|
||||
* Save the file popup
|
||||
*
|
||||
* @param options 保存文件窗口参数 Save the file window parameters
|
||||
* @param window 依附于哪个窗口(插件主进程才可使用) Which window it is attached to (only available to the plugin's main process)
|
||||
*/
|
||||
export function save(options?: SaveDialogOptions, window?: BrowserWindow): Promise<SaveDialogReturnValue>;
|
||||
/**
|
||||
* 信息弹窗
|
||||
* Information popup window
|
||||
*
|
||||
* @param message 显示的消息 Displayed message
|
||||
* @param options 信息弹窗可选参数 Information popup optional parameter
|
||||
* @param window 依附于哪个窗口(插件主进程才可使用) Which window it is attached to (only available to the plugin's main process)
|
||||
*/
|
||||
export function info(message: string, options?: MessageDialogOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue>;
|
||||
/**
|
||||
* 警告弹窗
|
||||
* Warning popup
|
||||
*
|
||||
* @param message 警告信息 Warning message
|
||||
* @param options 警告弹窗可选参数 Warning popover optional parameter
|
||||
* @param window 依附于哪个窗口(插件主进程才可使用) Which window it is attached to (only available to the plugin's main process)
|
||||
*/
|
||||
export function warn(message: string, options?: MessageDialogOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue>;
|
||||
/**
|
||||
* 错误弹窗
|
||||
* Error popup window
|
||||
*
|
||||
* @param message 错误信息 The error message
|
||||
* @param options 错误弹窗可选参数 Error popover optional parameter
|
||||
* @param window 依附于哪个窗口(插件主进程才可使用) Which window it is attached to (only available to the plugin's main process)
|
||||
*/
|
||||
export function error(message: string, options?: MessageDialogOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue>;
|
||||
}
|
||||
export namespace EditMode {
|
||||
/**
|
||||
* 标记编辑器进入了一种编辑模式
|
||||
* The tag editor goes into an edit mode
|
||||
*
|
||||
* @param mode 编辑模式的名字 The name of the edit mode
|
||||
*/
|
||||
export function enter(mode: string);
|
||||
/**
|
||||
* 当前所处的编辑模式
|
||||
* The current editing mode
|
||||
*
|
||||
*/
|
||||
export function getMode(): string;
|
||||
}
|
||||
export namespace I18n {
|
||||
export type I18nMap = {
|
||||
[key: string]: I18nMap | string;
|
||||
};
|
||||
/**
|
||||
* 获取当前的语言 zh | en
|
||||
* Get the current language
|
||||
*/
|
||||
export function getLanguage(): string;
|
||||
/**
|
||||
* 传入 key,翻译成当前语言
|
||||
* Passing in the key translates into the current language
|
||||
* 允许翻译变量 {a},传入的第二个参数 obj 内定义 a
|
||||
* The translation variable {a} is allowed, and a is defined in the second argument passed in obj
|
||||
*
|
||||
* @param key 用于翻译的 key 值 The key value for translation
|
||||
* @param obj 翻译字段内如果有 {key} 等可以在这里传入替换字段 If you have {key} in the translation field, you can pass in the replacement field here
|
||||
*/
|
||||
export function t(
|
||||
key: string,
|
||||
obj?: {
|
||||
[key: string]: string;
|
||||
},
|
||||
): string;
|
||||
|
||||
/**
|
||||
* 选择一种翻译语言
|
||||
* Choose a translation language
|
||||
*
|
||||
* @param language 选择当前使用的语言 Select the language currently in use
|
||||
*/
|
||||
export function select(language: string): void;
|
||||
}
|
||||
export namespace Layout {
|
||||
/**
|
||||
* 应用布局信息
|
||||
* Application layout information
|
||||
*
|
||||
* @param json 布局文件内容 Layout file content
|
||||
*/
|
||||
export function apply(json: any);
|
||||
/**
|
||||
* 初始化布局系统
|
||||
* Initialize the layout system
|
||||
*/
|
||||
export function init();
|
||||
}
|
||||
export namespace Logger {
|
||||
/**
|
||||
* 清空所有的日志
|
||||
* Clear all logs
|
||||
*/
|
||||
export function clear(regexp?: string | RegExp): any;
|
||||
/**
|
||||
* 查询所有日志
|
||||
* Query all logs
|
||||
*/
|
||||
export function query(): any;
|
||||
}
|
||||
export namespace Menu {
|
||||
export interface BaseMenuItem {
|
||||
template?: string;
|
||||
type?: string;
|
||||
label?: string;
|
||||
sublabel?: string;
|
||||
checked?: boolean;
|
||||
enabled?: boolean;
|
||||
icon?: string;
|
||||
accelerator?: string;
|
||||
order?: number;
|
||||
group?: string;
|
||||
message?: string;
|
||||
target?: string;
|
||||
params?: any[];
|
||||
click?: Function | null;
|
||||
role?: string;
|
||||
submenu?: MenuTemplateItem[];
|
||||
}
|
||||
export interface MainMenuItem extends BaseMenuItem {
|
||||
path: string;
|
||||
}
|
||||
export interface ContextMenuItem extends BaseMenuItem {
|
||||
accelerator?: string;
|
||||
}
|
||||
export type MenuTemplateItem = BaseMenuItem;
|
||||
export interface PopupOptions {
|
||||
x?: number;
|
||||
y?: number;
|
||||
menu: ContextMenuItem[];
|
||||
}
|
||||
/**
|
||||
* 右键弹窗
|
||||
* Right-click pop-up
|
||||
* 只有面板进程可以使用
|
||||
* Only panel processes can be used
|
||||
*
|
||||
* @param json
|
||||
*/
|
||||
export function popup(json: PopupOptions): any;
|
||||
}
|
||||
export namespace Message {
|
||||
export interface MessageInfo {
|
||||
methods: string[];
|
||||
public?: boolean;
|
||||
description?: string;
|
||||
doc?: string;
|
||||
sync?: boolean;
|
||||
}
|
||||
|
||||
export interface TableBase {
|
||||
[x: string]: any;
|
||||
params: any[];
|
||||
}
|
||||
/**
|
||||
* 发送一个消息,并等待返回
|
||||
* Send a message and wait for it to return
|
||||
*
|
||||
* @param name 目标插件的名字 The name of the target plug-in
|
||||
* @param message 触发消息的名字 The name of the trigger message
|
||||
* @param args 消息需要的参数 The parameters required for the message
|
||||
*/
|
||||
export function request<J extends string, K extends keyof EditorMessageMaps[J]>(
|
||||
name: J,
|
||||
message: K,
|
||||
...args: EditorMessageMaps[J][K]['params']
|
||||
): Promise<EditorMessageMaps[J][K]['result']>;
|
||||
/**
|
||||
* 发送一个消息,没有返回
|
||||
* Send a message, no return
|
||||
*
|
||||
* @param name 目标插件的名字 The name of the target plug-in
|
||||
* @param message 触发消息的名字 The name of the trigger message
|
||||
* @param args 消息需要的参数 The parameters required for the message
|
||||
*/
|
||||
export function send<M extends string, N extends keyof EditorMessageMaps[M]>(
|
||||
name: M,
|
||||
message: N,
|
||||
...args: EditorMessageMaps[M][N]['params']
|
||||
): void;
|
||||
/**
|
||||
* 广播一个消息
|
||||
* Broadcast a message
|
||||
*
|
||||
* @param message 消息的名字 Name of message
|
||||
* @param args 消息附加的参数 Parameter attached to the message
|
||||
*/
|
||||
export function broadcast(message: string, ...args: any[]): void;
|
||||
/**
|
||||
* 新增一个广播消息监听器
|
||||
* Add a new broadcast message listener
|
||||
* 不监听的时候,需要主动取消监听
|
||||
* When not listening, you need to take the initiative to cancel listening
|
||||
*
|
||||
* @param message 消息名 Message name
|
||||
* @param func 处理函数 The processing function
|
||||
*/
|
||||
export function addBroadcastListener(message: string, func: Function): any;
|
||||
/**
|
||||
* 新增一个广播消息监听器
|
||||
* Removes a broadcast message listener
|
||||
*
|
||||
* @param message 消息名 Message name
|
||||
* @param func 处理函数 The processing function
|
||||
*/
|
||||
export function removeBroadcastListener(message: string, func: Function): any;
|
||||
}
|
||||
export namespace Network {
|
||||
/**
|
||||
* 查询当前电脑的 ip 列表
|
||||
* Query the IP list of the current computer
|
||||
*/
|
||||
export function queryIPList(): string[];
|
||||
/**
|
||||
* 测试是否可以联通 passport.cocos.com 服务器
|
||||
* Test whether you can connect to the passport.cocos.com server
|
||||
*/
|
||||
export function testConnectServer(): Promise<boolean>;
|
||||
/**
|
||||
* 检查一个端口是否被占用
|
||||
* Checks if a port is used
|
||||
*
|
||||
* @param port
|
||||
*/
|
||||
export function portIsOccupied(port: number): Promise<boolean>;
|
||||
/**
|
||||
* 测试是否可以联通某一台主机
|
||||
* Test whether a host can be connected
|
||||
*
|
||||
* @param ip
|
||||
*/
|
||||
export function testHost(ip: string): Promise<boolean>;
|
||||
/**
|
||||
* Get 方式请求某个服务器数据
|
||||
* GET requests data from a server
|
||||
*
|
||||
* @param url
|
||||
* @param data
|
||||
*/
|
||||
export function get(
|
||||
url: string,
|
||||
data?: {
|
||||
[index: string]: string | string[];
|
||||
},
|
||||
): Promise<Buffer>;
|
||||
/**
|
||||
* Post 方式请求某个服务器数据
|
||||
* POST requests data from a server
|
||||
*
|
||||
* @param url
|
||||
* @param data
|
||||
*/
|
||||
export function post(
|
||||
url: string,
|
||||
data?: {
|
||||
[index: string]: string | number | string[];
|
||||
},
|
||||
): Promise<Buffer>;
|
||||
/**
|
||||
* 获取某个可用的端口号
|
||||
* get the port that is free
|
||||
*
|
||||
* @param port
|
||||
*/
|
||||
export function getFreePort(port: number): Promise<number>;
|
||||
}
|
||||
export namespace Package {
|
||||
// export module VERSION: string;
|
||||
export interface GetPackageOptions {
|
||||
name?: string;
|
||||
debug?: boolean;
|
||||
path?: string;
|
||||
enable?: boolean;
|
||||
invalid?: boolean;
|
||||
}
|
||||
export interface PackageJson {
|
||||
author?: string;
|
||||
debug?: boolean;
|
||||
description?: string;
|
||||
main?: string;
|
||||
menu?: any;
|
||||
name: string;
|
||||
version: string;
|
||||
windows: string;
|
||||
editor?: string;
|
||||
panel?: any;
|
||||
}
|
||||
export type PathType = 'home' | 'data' | 'temp';
|
||||
/**
|
||||
* 查询插件列表
|
||||
* Query Plug-in List
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
export function getPackages(options?: GetPackageOptions): Editor.Interface.PackageInfo[];
|
||||
/**
|
||||
* 注册一个插件
|
||||
* Register a plug-in
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function register(path: string): any;
|
||||
/**
|
||||
* 反注册一个插件
|
||||
* Unregister a plug-in
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function unregister(path: string): any;
|
||||
/**
|
||||
* 启动一个插件
|
||||
* Enable a plug-in
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function enable(path: string): any;
|
||||
/**
|
||||
* 关闭一个插件
|
||||
* Disable a plug-in
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function disable(path: string, options: any): any;
|
||||
/**
|
||||
* 获取一个插件的几个预制目录地址
|
||||
* Gets several prefab directory addresses for a plug-in
|
||||
*
|
||||
* @param extensionName 扩展的名字 Name of the extension
|
||||
* @param type 地址类型(temp 临时目录,data 需要同步的数据目录,不传则返回现在打开的插件路径) Address type (temp temporary directory, data need to synchronize data directory, do not pass to return the current open plug-in path)
|
||||
*/
|
||||
export function getPath(extensionName: string, type?: PathType): any;
|
||||
}
|
||||
export namespace Panel {
|
||||
/**
|
||||
* 打开一个面板
|
||||
* Open up a panel
|
||||
*
|
||||
* @param name
|
||||
* @param args
|
||||
*/
|
||||
export function open(name: string, ...args: any[]): any;
|
||||
/**
|
||||
* 关闭一个面板
|
||||
* Close a panel
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
export function close(name: string): any;
|
||||
/**
|
||||
* 将焦点传递给一个面板
|
||||
* Pass focus to a panel
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
export function focus(name: string): any;
|
||||
/**
|
||||
* 检查面板是否已经打开
|
||||
* Check that the panel is open
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
export function has(name: string): Promise<boolean>;
|
||||
/**
|
||||
* 查询当前窗口里某个面板里的元素列表
|
||||
* @param name
|
||||
* @param selector
|
||||
*/
|
||||
export function querySelector(name: string, selector: string): Promise<any>;
|
||||
|
||||
export type Selector<$> = { $: Record<keyof $, HTMLElement | null> };
|
||||
|
||||
export type Options<S, M, U extends (...args: any[]) => void> = {
|
||||
/**
|
||||
* @en Listening to panel events
|
||||
* @zh 监听面板事件
|
||||
*/
|
||||
listeners?: {
|
||||
/**
|
||||
* @en Hooks triggered when the panel is displayed
|
||||
* @zh 面板显示的时候触发的钩子
|
||||
*/
|
||||
show?: () => any;
|
||||
/**
|
||||
* @en Hooks triggered when the panel is hidden
|
||||
* @zh 面板隐藏的时候触发的钩子
|
||||
*/
|
||||
hide?: () => any;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Template of the panel
|
||||
* @zh 面板的内容
|
||||
*/
|
||||
template: string;
|
||||
/**
|
||||
* @en Style of the panel
|
||||
* @zh 面板上的样式
|
||||
* */
|
||||
style?: string;
|
||||
/**
|
||||
* @en Selector of the panel
|
||||
* @zh 快捷选择器
|
||||
*/
|
||||
$?: S;
|
||||
/**
|
||||
* @en Panel built-in function methods that can be called in Messages, Listeners, lifecycle functions
|
||||
* @zh panel 内置的函数方法,可以在 messages、listeners、生命周期函数内调用
|
||||
*/
|
||||
methods?: M;
|
||||
/**
|
||||
* @en Hooks triggered when the panel is update
|
||||
* @zh 面板数据更新后触发的钩子函数
|
||||
*/
|
||||
update?: (...args: Parameters<U>) => void;
|
||||
/**
|
||||
* @en Hooks triggered when the panel is ready
|
||||
* @zh 面板启动后触发的钩子函数
|
||||
*/
|
||||
ready?: () => void;
|
||||
/**
|
||||
* @en The function that will be triggered when the panel is ready to close, and will terminate the closing of the panel if it
|
||||
* returns false
|
||||
* @zh 面板准备关闭的时候会触发的函数,return false 的话,会终止关闭面板
|
||||
* 生命周期函数,在 panel 准备关闭的时候触发
|
||||
* 如果 return false,则会中断关闭流程,请谨慎使用,错误的判断会导致编辑器无法关闭。
|
||||
*/
|
||||
beforeClose?: () => Promise<boolean | void> | boolean | void;
|
||||
/**
|
||||
* @en Hook functions after panel closure
|
||||
* @zh 面板关闭后的钩子函数
|
||||
*/
|
||||
close?: () => void;
|
||||
} & ThisType<Selector<S> & M>; // merge them together
|
||||
|
||||
export function define<U extends (...args: any[]) => void, Selector = Record<string, string>, M = Record<string, Function>>(
|
||||
options: Options<Selector, M, U>,
|
||||
): any;
|
||||
}
|
||||
export namespace Profile {
|
||||
export type preferencesProtocol = 'default' | 'global' | 'local';
|
||||
export type projectProtocol = 'default' | 'project';
|
||||
export type tempProtocol = 'temp';
|
||||
export interface ProfileGetOptions {
|
||||
type: 'deep' | 'current' | 'inherit';
|
||||
}
|
||||
export interface ProfileObj {
|
||||
get: (key?: string, options?: ProfileGetOptions) => any;
|
||||
set: (key?: string, value?: any) => any;
|
||||
remove: (key: string) => void;
|
||||
save: () => void;
|
||||
clear: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
/**
|
||||
* 读取插件配置
|
||||
* Read the plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(global,local,default)
|
||||
*/
|
||||
export function getConfig(name: string, key?: string, type?: preferencesProtocol): Promise<any>;
|
||||
/**
|
||||
* 设置插件配置
|
||||
* Set the plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param value 配置的值 The value of the configuration
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(global,local,default)
|
||||
*/
|
||||
export function setConfig(name: string, key: string, value: any, type?: preferencesProtocol): Promise<void>;
|
||||
/**
|
||||
* 删除某个插件配置
|
||||
* Delete a plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(global,local,default)
|
||||
*/
|
||||
export function removeConfig(name: string, key: string, type?: preferencesProtocol): Promise<void>;
|
||||
/**
|
||||
* 读取插件内的项目配置
|
||||
* Read the project configuration within the plug-in
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(project,default)
|
||||
*/
|
||||
export function getProject(name: string, key?: string, type?: projectProtocol): Promise<any>;
|
||||
/**
|
||||
* 设置插件内的项目配置
|
||||
* Set the project configuration within the plug-in
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param value 配置的值 The value of the configuration
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(project,default)
|
||||
*/
|
||||
export function setProject(name: string, key: string, value: any, type?: projectProtocol): Promise<void>;
|
||||
/**
|
||||
* 删除插件内的项目配置
|
||||
* Delete the project configuration within the plug-in
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param type 配置的类型,选填 Type of configuration, optional(project,default)
|
||||
*/
|
||||
export function removeProject(name: string, key: string, type?: projectProtocol): Promise<void>;
|
||||
/**
|
||||
* 读取插件配置
|
||||
* Read the plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
*/
|
||||
export function getTemp(name: string, key?: string): Promise<any>;
|
||||
/**
|
||||
* 设置插件配置
|
||||
* Set the plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
* @param value 配置的值 The value of the configuration
|
||||
*/
|
||||
export function setTemp(name: string, key: string, value: any): Promise<void>;
|
||||
/**
|
||||
* 删除某个插件配置
|
||||
* Delete a plug-in configuration
|
||||
*
|
||||
* @param name 插件名 The plugin name
|
||||
* @param key 配置路径 Configure path
|
||||
*/
|
||||
export function removeTemp(name: string, key: string): Promise<void>;
|
||||
/**
|
||||
* 迁移插件某个版本的本地配置数据到编辑器最新版本
|
||||
* Migrate the local configuration data of a certain version of the plugin to the latest version of the editor
|
||||
*
|
||||
* @param pkgName
|
||||
* @param profileVersion
|
||||
* @param profileData
|
||||
*/
|
||||
export function migrateLocal(pkgName: string, profileVersion: string, profileData: any): any;
|
||||
/**
|
||||
* 迁移插件某个版本的全局配置数据到编辑器最新版本
|
||||
* Migrate the global configuration data of a certain version of the plugin to the latest version of the editor
|
||||
*
|
||||
* @param pkgName
|
||||
* @param profileVersion
|
||||
* @param profileData
|
||||
*/
|
||||
export function migrateGlobal(pkgName: string, profileVersion: string, profileData: any): any;
|
||||
/**
|
||||
* 迁移插件某个版本的项目配置数据到编辑器最新版本
|
||||
* Migrate the project configuration data of a certain version of the plugin to the latest version of the editor
|
||||
*
|
||||
* @param pkgName
|
||||
* @param profileVersion
|
||||
* @param profileData
|
||||
*/
|
||||
export function migrateProject(pkgName: string, profileVersion: string, profileData: any): any;
|
||||
}
|
||||
export namespace Project {
|
||||
/**
|
||||
* 创建一个项目
|
||||
* Creating a project
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export function create(): any;
|
||||
/**
|
||||
* 打开一个项目
|
||||
* Open a project
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function open(path?: string): Promise<any>;
|
||||
/**
|
||||
* 添加一个项目
|
||||
* Add a project
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function add(path: string): any;
|
||||
/**
|
||||
* 当前项目路径
|
||||
* Current project path
|
||||
*/
|
||||
export const path: string;
|
||||
/**
|
||||
* 当前项目 uuid
|
||||
* The current project UUID
|
||||
*/
|
||||
export const uuid: string;
|
||||
/**
|
||||
* 当前项目名称(取自 package.json)
|
||||
* The current project name
|
||||
*/
|
||||
export const name: string;
|
||||
/**
|
||||
* 当前项目临时文件夹
|
||||
* Temporary folder for current project
|
||||
*/
|
||||
export const tmpDir: string;
|
||||
/**
|
||||
* 当前项目类型
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export const type: '2d' | '3d';
|
||||
}
|
||||
export namespace Selection {
|
||||
/**
|
||||
* 选中一个或者一组元素
|
||||
* Select one or a group of elements
|
||||
*
|
||||
* @param type
|
||||
* @param uuid
|
||||
*/
|
||||
export function select(type: string, uuid: string | string[]): any;
|
||||
/**
|
||||
* 取消一个或者一组元素的选中状态
|
||||
* To deselect one or a group of elements
|
||||
*
|
||||
* @param type
|
||||
* @param uuid
|
||||
*/
|
||||
export function unselect(type: string, uuid: string | string[]): any;
|
||||
/**
|
||||
* 清空一个类型的所有选中元素
|
||||
* Clears all selected elements of a type
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
export function clear(type: string): any;
|
||||
/**
|
||||
* 更新当前选中的类型数据
|
||||
* Updates the currently selected type data
|
||||
*
|
||||
* @param type
|
||||
* @param uuids
|
||||
*/
|
||||
export function update(type: string, uuids: string[]): any;
|
||||
/**
|
||||
* 悬停触碰了某个元素
|
||||
* Hover touches an element
|
||||
* 会发出 selection:hover 的广播消息
|
||||
* A broadcast message for selection:hover is issued
|
||||
*
|
||||
* @param type
|
||||
* @param uuid
|
||||
*/
|
||||
export function hover(type: string, uuid?: string): any;
|
||||
/**
|
||||
* 获取最后选中的元素的类型
|
||||
* Gets the type of the last selected element
|
||||
*/
|
||||
export function getLastSelectedType(): string;
|
||||
/**
|
||||
* 获取某个类型内,最后选中的元素
|
||||
* Gets the last selected element of a type
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
export function getLastSelected(type: string): string;
|
||||
/**
|
||||
* 获取一个类型选中的所有元素数组
|
||||
* Gets an array of all elements selected for a type
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
export function getSelected(type: string): string[];
|
||||
}
|
||||
export namespace Task {
|
||||
export interface NoticeOptions {
|
||||
title: string;
|
||||
message?: string;
|
||||
type?: 'error' | 'warn' | 'log' | 'success';
|
||||
source?: string;
|
||||
timeout?: number;
|
||||
}
|
||||
/**
|
||||
* 添加一个同步任务
|
||||
* Add a synchronous task
|
||||
* 会在主窗口显示一个遮罩层
|
||||
* A mask layer is displayed in the main window
|
||||
*
|
||||
* @param title 任务名字 The task name
|
||||
* @param describe 任务描述 Task description
|
||||
* @param message 任务内容 Content of the task
|
||||
*/
|
||||
export function addSyncTask(title: string, describe?: string, message?: string): any;
|
||||
/**
|
||||
* 更新某一个同步任务显示的数据
|
||||
* Update the data displayed by a synchronous task
|
||||
*
|
||||
* @param title 任务名字 The task name
|
||||
* @param describe 任务描述 Task description
|
||||
* @param message 任务内容 Content of the task
|
||||
*/
|
||||
export function updateSyncTask(title: string, describe?: string, message?: string): any;
|
||||
/**
|
||||
* 删除一个同步任务
|
||||
* Delete a synchronous task
|
||||
*
|
||||
* @param title 任务的名字 The name of the task
|
||||
*/
|
||||
export function removeSyncTask(title: string): any;
|
||||
/**
|
||||
* 添加一个通知
|
||||
* Add a notification
|
||||
*
|
||||
* @param options 消息配置 Message configuration
|
||||
*/
|
||||
export function addNotice(options: NoticeOptions): any;
|
||||
/**
|
||||
* 删除一个通知
|
||||
* Delete a notification
|
||||
*
|
||||
* @param id 通知 id Notification ID
|
||||
*/
|
||||
export function removeNotice(id: number): any;
|
||||
/**
|
||||
* 修改 notice 自动移除的时间
|
||||
* Modify notice automatic removal time
|
||||
*
|
||||
* @param id 通知 id Notification ID
|
||||
* @param time 超时时间 timeout
|
||||
*/
|
||||
export function changeNoticeTimeout(id: number, time: number): any;
|
||||
/**
|
||||
* 查询所有通知
|
||||
* Query all notifications
|
||||
*/
|
||||
export function queryNotices(): any;
|
||||
/**
|
||||
* 页面进程立即同步一次主进程数据
|
||||
* The page process synchronizes the master process data immediately
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export function sync(): any;
|
||||
}
|
||||
export namespace Theme {
|
||||
/**
|
||||
* 获取所有主题的名字
|
||||
* Gets the names of all topics
|
||||
*/
|
||||
export function getList(): any;
|
||||
/**
|
||||
* 使用某个皮肤
|
||||
* Use a certain skin
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
export function use(name?: string): any;
|
||||
}
|
||||
export namespace UI {
|
||||
/**
|
||||
* 在当前页面上注册一个自定义节点
|
||||
* Registers a custom node on the current page
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*
|
||||
* @param tagName 元素名字
|
||||
* @param element 元素的定义函数
|
||||
*/
|
||||
export function register(tagName: string, element: any): void;
|
||||
export const Base: any;
|
||||
export const Button: any;
|
||||
export const Input: any;
|
||||
export const NumInput: any;
|
||||
export const Loading: any;
|
||||
export const Checkbox: any;
|
||||
export const Section: any;
|
||||
export const Select: any;
|
||||
export const Bit: any;
|
||||
export const Slider: any;
|
||||
export const ColorPicker: any;
|
||||
export const Color: any;
|
||||
export const DragItem: any;
|
||||
export const DragArea: any;
|
||||
export const DragObject: any;
|
||||
export const Prop: any;
|
||||
export const Tooltip: any;
|
||||
export const TextArea: any;
|
||||
export const Progress: any;
|
||||
export const Label: any;
|
||||
export const Code: any;
|
||||
export const Tab: any;
|
||||
export const Gradient: any;
|
||||
export const GradientPicker: any;
|
||||
export const Icon: any;
|
||||
export const File: any;
|
||||
export const Link: any;
|
||||
export const Image: any;
|
||||
export const QRCode: any;
|
||||
export const Markdown: any;
|
||||
export const Curve: any;
|
||||
export const CurveEditor: any;
|
||||
export const NodeGraph: any;
|
||||
}
|
||||
export namespace User {
|
||||
export interface UserData {
|
||||
session_id: string;
|
||||
session_key: string;
|
||||
cocos_uid: string;
|
||||
email: string;
|
||||
nickname: string;
|
||||
}
|
||||
/**
|
||||
* 跳过 User
|
||||
* Skip the User
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export function skip(): any;
|
||||
/**
|
||||
* 获取 user 数据
|
||||
* Get user data
|
||||
*/
|
||||
export function getData(): Promise<UserData>;
|
||||
/**
|
||||
* 检查用户是否登陆
|
||||
* Check if the user is logged in
|
||||
*/
|
||||
export function isLoggedIn(): Promise<boolean>;
|
||||
/**
|
||||
* 用户登陆
|
||||
* The user login
|
||||
* 失败会抛出异常
|
||||
* Failure throws an exception
|
||||
*
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
export function login(username: string, password: string): Promise<UserData>;
|
||||
/**
|
||||
* 退出登陆
|
||||
* Logged out
|
||||
* 失败会抛出异常
|
||||
* Failure throws an exception
|
||||
*/
|
||||
export function logout(): void;
|
||||
/**
|
||||
* 获取用户 token
|
||||
* Get user token
|
||||
* 失败会抛出异常
|
||||
* Failure throws an exception
|
||||
*/
|
||||
export function getUserToken(): Promise<string>;
|
||||
/**
|
||||
* 根据插件 id 返回 session code
|
||||
* Returns the session code based on the plug-in ID
|
||||
*
|
||||
* @param extensionId
|
||||
*/
|
||||
export function getSessionCode(extensionId: number): Promise<string>;
|
||||
/**
|
||||
* 显示用户登陆遮罩层
|
||||
* Shows user login mask layer
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export function showMask(): void;
|
||||
/**
|
||||
* 隐藏用户登陆遮罩层
|
||||
* Hide user login mask layer
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
*/
|
||||
export function hideMask(): void;
|
||||
/**
|
||||
* 监听事件
|
||||
* Listen for an event
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
* @param action
|
||||
* @param handle
|
||||
*/
|
||||
export function on(action: string, handle: Function): any;
|
||||
/**
|
||||
* 监听一次事件
|
||||
* Listening for one event
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
* @param action
|
||||
* @param handle
|
||||
*/
|
||||
export function once(action: string, handle: Function): any;
|
||||
/**
|
||||
* 取消已经监听的事件
|
||||
* Cancels the event you are listening for
|
||||
* 谨慎使用,之后会被移除
|
||||
* Use with caution and it will be removed later
|
||||
* @param action
|
||||
* @param handle
|
||||
*/
|
||||
export function removeListener(action: string, handle: Function): any;
|
||||
}
|
||||
export namespace Utils {
|
||||
export namespace File {
|
||||
/**
|
||||
* 初始化一个可用的文件名
|
||||
* Initializes a available filename
|
||||
* 返回可用名称的文件路径
|
||||
* Returns the file path with the available name
|
||||
*
|
||||
* @param file 初始文件路径 Initial file path
|
||||
*/
|
||||
export function getName(file: string): string;
|
||||
interface UnzipOptions {
|
||||
peel?: boolean;
|
||||
}
|
||||
/**
|
||||
* 解压文件夹
|
||||
* Unzip folder
|
||||
*
|
||||
* @param zip
|
||||
* @param target
|
||||
* @param options
|
||||
*/
|
||||
export function unzip(zip: string, target: string, options?: UnzipOptions): Promise<void>;
|
||||
/**
|
||||
* 复制一个文件到另一个位置
|
||||
* Copy a file to another location
|
||||
*
|
||||
* @param source
|
||||
* @param target
|
||||
*/
|
||||
export function copy(source: string, target: string): void;
|
||||
}
|
||||
export namespace Path {
|
||||
/**
|
||||
* 返回一个不含扩展名的文件名
|
||||
* @param path
|
||||
*/
|
||||
export function basenameNoExt(path: string): string;
|
||||
/**
|
||||
* 将 \ 统一换成 /
|
||||
* @param path
|
||||
*/
|
||||
export function slash(path: string): string;
|
||||
/**
|
||||
* 去除路径最后的斜杆,返回一个不带斜杆的路径
|
||||
* @param path
|
||||
*/
|
||||
export function stripSep(path: string): string;
|
||||
/**
|
||||
* 删除一个路径的扩展名
|
||||
* @param path
|
||||
*/
|
||||
export function stripExt(path: string): string;
|
||||
/**
|
||||
* 判断路径 pathA 是否包含 pathB
|
||||
* pathA = foo/bar, pathB = foo/bar/foobar, return true
|
||||
* pathA = foo/bar, pathB = foo/bar, return true
|
||||
* pathA = foo/bar/foobar, pathB = foo/bar, return false
|
||||
* pathA = foo/bar/foobar, pathB = foobar/bar/foo, return false
|
||||
* @param pathA
|
||||
* @param pathB
|
||||
*/
|
||||
export function contains(pathA: string, pathB: string): boolean;
|
||||
/**
|
||||
* 格式化路径
|
||||
* 如果是 Windows 平台,需要将盘符转成小写进行判断
|
||||
* @param path
|
||||
*/
|
||||
export function normalize(path: string): string;
|
||||
export const join: typeof NodeJSPath.join;
|
||||
export const resolve: typeof NodeJSPath.resolve;
|
||||
export const isAbsolute: typeof NodeJSPath.isAbsolute;
|
||||
export const relative: typeof NodeJSPath.relative;
|
||||
export const dirname: typeof NodeJSPath.dirname;
|
||||
export const basename: typeof NodeJSPath.basename;
|
||||
export const extname: typeof NodeJSPath.extname;
|
||||
export const sep: '\\' | '/';
|
||||
export const delimiter: ';' | ':';
|
||||
export const parse: typeof NodeJSPath.parse;
|
||||
export const format: typeof NodeJSPath.format;
|
||||
}
|
||||
export namespace Math {
|
||||
/**
|
||||
* 取给定边界范围的值
|
||||
* Take the value of the given boundary range
|
||||
* @param {number} val
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
*/
|
||||
export function clamp(val: number, min: number, max: number): number;
|
||||
/**
|
||||
* @function clamp01
|
||||
* @param {number} val
|
||||
* @returns {number}
|
||||
*
|
||||
* Clamps a value between 0 and 1.
|
||||
*/
|
||||
export function clamp01(val: number): number;
|
||||
/**
|
||||
* 加法函数
|
||||
* 入参:函数内部转化时会先转字符串再转数值,因而传入字符串或 number 均可
|
||||
* 返回值:arg1 加上 arg2 的精确结果
|
||||
* @param {number|string} arg1
|
||||
* @param {number|string} arg2
|
||||
*/
|
||||
export function add(arg1: number | string, arg2: number | string): number;
|
||||
/**
|
||||
* 减法函数
|
||||
* 入参:函数内部转化时会先转字符串再转数值,因而传入字符串或number均可
|
||||
* 返回值:arg1 减 arg2的精确结果
|
||||
* @param {number|string} arg1
|
||||
* @param {number|string} arg2
|
||||
*/
|
||||
export function sub(arg1: number | string, arg2: number | string): number;
|
||||
/**
|
||||
* 保留小数点
|
||||
* @param val
|
||||
* @param num
|
||||
*/
|
||||
export function toFixed(val: number, num: number): number;
|
||||
}
|
||||
export namespace Parse {
|
||||
interface WhenParam {
|
||||
PanelName?: string;
|
||||
EditMode?: string;
|
||||
ProjectType?: string;
|
||||
}
|
||||
/**
|
||||
* 解析 when 参数
|
||||
* when 的格式:
|
||||
* PanelName === '' && EditMode === ''
|
||||
* 整理后的数据格式:
|
||||
* {
|
||||
* PanelName: '',
|
||||
* EditMode: '',
|
||||
* }
|
||||
*/
|
||||
export function when(when: string): WhenParam;
|
||||
/**
|
||||
* 判断一个 when 数据是否符合当前条件
|
||||
* @param when
|
||||
*/
|
||||
export function checkWhen(when: string): boolean;
|
||||
}
|
||||
export namespace Url {
|
||||
/**
|
||||
* 快捷获取文档路径
|
||||
* @param relativeUrl
|
||||
* @param type
|
||||
*/
|
||||
export function getDocUrl(relativeUrl: string, type?: 'manual' | 'api'): string;
|
||||
}
|
||||
|
||||
export namespace UUID {
|
||||
/**
|
||||
* 压缩 UUID
|
||||
* compress UUID
|
||||
* @param uuid
|
||||
* @param min
|
||||
*/
|
||||
export function compressUUID(uuid: string, min: boolean): string;
|
||||
/**
|
||||
* 解压 UUID
|
||||
* decompress the UUID
|
||||
* @param str
|
||||
*/
|
||||
export function decompressUUID(str: string): string;
|
||||
/**
|
||||
* 检查输入字符串是否是 UUID
|
||||
* Check whether the input string is a UUID
|
||||
* @param str
|
||||
*/
|
||||
export function isUUID(str: string): string;
|
||||
/**
|
||||
* 生成一个新的 uuid
|
||||
*/
|
||||
export function generate(): string;
|
||||
}
|
||||
}
|
||||
export namespace Module {
|
||||
/**
|
||||
* 导入一个项目模块。
|
||||
* @param url 项目模块的 Database URL。
|
||||
* @experimental 实验性质。
|
||||
*/
|
||||
export function importProjectModule(url: string): Promise<unknown>;
|
||||
}
|
||||
}
|
||||
}
|
||||
16090
extensions/app/engine/@types/electron.d.ts
vendored
Normal file
16090
extensions/app/engine/@types/electron.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
61
extensions/app/engine/@types/extension.d.ts
vendored
Normal file
61
extensions/app/engine/@types/extension.d.ts
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
declare namespace Editor {
|
||||
|
||||
namespace Interface {
|
||||
// ---- Package ---- start
|
||||
interface PackageInfo {
|
||||
debug: boolean;
|
||||
enable: boolean;
|
||||
// TODO 更名为 packageJSON 更合适
|
||||
info: PackageJson;
|
||||
invalid: boolean;
|
||||
name: string;
|
||||
path: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name: string;
|
||||
version: string;
|
||||
|
||||
title?: string;
|
||||
author?: string;
|
||||
debug?: boolean;
|
||||
description?: string;
|
||||
main?: string;
|
||||
editor?: string;
|
||||
panel?: any;
|
||||
contributions?: {
|
||||
[key: string]: any;
|
||||
builder?: string; // 构建插件注册脚本
|
||||
};
|
||||
}
|
||||
// ---- Package ---- end
|
||||
|
||||
// ---- UI ---- start
|
||||
interface PanelInfo {
|
||||
template?: string;
|
||||
style?: string;
|
||||
listeners?: { [key: string]: () => {} };
|
||||
methods?: { [key: string]: Function };
|
||||
$?: { [key: string]: string };
|
||||
ready?(): void;
|
||||
update?(...args: any[]): void;
|
||||
beforeClose?(): void;
|
||||
close?(): void;
|
||||
}
|
||||
|
||||
namespace UIKit {
|
||||
interface UIPanelInfo extends PanelInfo {
|
||||
// 向上触发事件
|
||||
dispath(eventName: string, ...arg: any): void;
|
||||
}
|
||||
|
||||
interface EditorElementBase extends HTMLElement {
|
||||
value: any;
|
||||
dispath: (name: string, event: any) => void;
|
||||
}
|
||||
|
||||
}
|
||||
// ---- UI ---- end
|
||||
}
|
||||
}
|
||||
2
extensions/app/engine/@types/index.d.ts
vendored
Normal file
2
extensions/app/engine/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference path="./editor.d.ts"/>
|
||||
/// <reference path="./message.d.ts"/>
|
||||
27
extensions/app/engine/@types/message.d.ts
vendored
Normal file
27
extensions/app/engine/@types/message.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as AssetDB from './packages/asset-db/@types/message';
|
||||
import * as Scene from './packages/scene/@types/message';
|
||||
import * as Engine from './packages/engine/@types/message';
|
||||
import * as Builder from './packages/builder/@types/public/message';
|
||||
import * as Programming from './packages/programming/@types/message';
|
||||
// import * as Extension from './packages/extension/@types/message';
|
||||
|
||||
declare global {
|
||||
interface EditorMessageContent {
|
||||
params: any[],
|
||||
result: any;
|
||||
}
|
||||
|
||||
interface EditorMessageMap {
|
||||
[x: string]: EditorMessageContent;
|
||||
}
|
||||
|
||||
interface EditorMessageMaps {
|
||||
[x: string]: EditorMessageMap;
|
||||
'asset-db': AssetDB.message;
|
||||
'scene': Scene.message;
|
||||
'engine': Engine.message;
|
||||
'builder': Builder.message;
|
||||
'programming': Programming.message,
|
||||
// 'extension': Extension.message;
|
||||
}
|
||||
}
|
||||
14
extensions/app/engine/@types/packages/alipay-mini-game/@types/index.d.ts
vendored
Normal file
14
extensions/app/engine/@types/packages/alipay-mini-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions, IPolyFills, ISettings } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'alipay-mini-game': {
|
||||
deviceOrientation: IOrientation;
|
||||
};
|
||||
};
|
||||
}
|
||||
72
extensions/app/engine/@types/packages/android/@types/index.d.ts
vendored
Normal file
72
extensions/app/engine/@types/packages/android/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IOptions as INativeOption } from '@editor/library-type/packages/native';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'android': IOptions;
|
||||
native: INativeOption;
|
||||
}
|
||||
}
|
||||
|
||||
export type IAppABI = 'armeabi-v7a' | 'arm64-v8a' | 'x86' | 'x86_64';
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
orientation: {
|
||||
landscapeRight: boolean;
|
||||
landscapeLeft: boolean;
|
||||
portrait: boolean;
|
||||
upsideDown: boolean;
|
||||
},
|
||||
|
||||
apiLevel: number;
|
||||
appABIs: IAppABI[];
|
||||
|
||||
useDebugKeystore: boolean;
|
||||
keystorePath: string;
|
||||
keystorePassword: string;
|
||||
keystoreAlias: string;
|
||||
keystoreAliasPassword: string;
|
||||
|
||||
appBundle: boolean;
|
||||
androidInstant: boolean;
|
||||
remoteUrl: string;
|
||||
sdkPath: string;
|
||||
ndkPath: string;
|
||||
|
||||
swappy: boolean;
|
||||
|
||||
renderBackEnd: {
|
||||
vulkan: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
|
||||
export interface ICertificateSetting {
|
||||
country: string;
|
||||
state: string;
|
||||
locality: string;
|
||||
organizationalUnit: string;
|
||||
organization: string;
|
||||
email: string;
|
||||
certificatePath: string;
|
||||
|
||||
password: string; // 密钥密码
|
||||
confirmPassword: string; // 确认密钥密码
|
||||
|
||||
alias: string; // 密钥别名
|
||||
aliasPassword: string;
|
||||
confirmAliasPassword: string;
|
||||
|
||||
validity: number; // 有效期
|
||||
}
|
||||
179
extensions/app/engine/@types/packages/asset-db/@types/message.d.ts
vendored
Normal file
179
extensions/app/engine/@types/packages/asset-db/@types/message.d.ts
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import { AssetInfo, QueryAssetsOption, AssetOperationOption, AssetDBOptions, IAssetMeta } from './public';
|
||||
|
||||
export interface message extends EditorMessageMap {
|
||||
'query-ready': {
|
||||
params: [],
|
||||
result: boolean,
|
||||
},
|
||||
'create-asset': {
|
||||
params: [
|
||||
string,
|
||||
string | Buffer | null,
|
||||
] | [
|
||||
string,
|
||||
string | Buffer | null,
|
||||
AssetOperationOption,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'import-asset': {
|
||||
params: [
|
||||
string,
|
||||
string,
|
||||
] | [
|
||||
string,
|
||||
string,
|
||||
AssetOperationOption,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'copy-asset': {
|
||||
params: [
|
||||
string,
|
||||
string,
|
||||
] | [
|
||||
string,
|
||||
string,
|
||||
AssetOperationOption,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'move-asset': {
|
||||
params: [
|
||||
string,
|
||||
string,
|
||||
] | [
|
||||
string,
|
||||
string,
|
||||
AssetOperationOption,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'delete-asset': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'open-asset': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: void,
|
||||
},
|
||||
'save-asset': {
|
||||
params: [
|
||||
string,
|
||||
string | Buffer,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'save-asset-meta': {
|
||||
params: [
|
||||
string,
|
||||
string,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'reimport-asset': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'refresh-asset': {
|
||||
params: [
|
||||
string
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'query-asset-info': {
|
||||
params: [
|
||||
string, // uuid | url | path
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'query-asset-meta': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: IAssetMeta | null,
|
||||
},
|
||||
'query-path': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: string | null,
|
||||
},
|
||||
'query-url': {
|
||||
params: [
|
||||
string
|
||||
],
|
||||
result: string | null,
|
||||
},
|
||||
'query-uuid': {
|
||||
params: [
|
||||
string
|
||||
],
|
||||
result: string | null,
|
||||
},
|
||||
'query-assets': {
|
||||
params: [] | [
|
||||
QueryAssetsOption,
|
||||
],
|
||||
result: AssetInfo[],
|
||||
},
|
||||
'generate-available-url': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: string,
|
||||
},
|
||||
|
||||
// private
|
||||
|
||||
'query-asset-mtime': {
|
||||
params: [
|
||||
string
|
||||
],
|
||||
result: string | null,
|
||||
},
|
||||
'refresh': {
|
||||
params: [],
|
||||
result: void,
|
||||
},
|
||||
'open-devtools': {
|
||||
params: [],
|
||||
result: void,
|
||||
},
|
||||
'query-db-info': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: AssetDBOptions,
|
||||
},
|
||||
'create-asset-dialog': {
|
||||
params: [
|
||||
string,
|
||||
] | [
|
||||
string,
|
||||
string,
|
||||
],
|
||||
result: string | null,
|
||||
},
|
||||
'init-asset': {
|
||||
params: [
|
||||
string,
|
||||
string,
|
||||
],
|
||||
result: AssetInfo | null,
|
||||
},
|
||||
'query-all-importer': {
|
||||
params: [],
|
||||
result: string[],
|
||||
},
|
||||
'query-all-asset-types': {
|
||||
params: [],
|
||||
result: string[],
|
||||
},
|
||||
}
|
||||
117
extensions/app/engine/@types/packages/asset-db/@types/public.d.ts
vendored
Normal file
117
extensions/app/engine/@types/packages/asset-db/@types/public.d.ts
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// Basic information about the resource
|
||||
// 资源的基础信息
|
||||
export interface AssetInfo {
|
||||
// Asset name
|
||||
// 资源名字
|
||||
name: string;
|
||||
// Asset display name
|
||||
// 资源用于显示的名字
|
||||
displayName: string;
|
||||
// URL
|
||||
source: string;
|
||||
// loader 加载的层级地址
|
||||
path: string;
|
||||
// loader 加载地址会去掉扩展名,这个参数不去掉
|
||||
url: string;
|
||||
// 绝对路径
|
||||
file: string;
|
||||
// 资源的唯一 ID
|
||||
uuid: string;
|
||||
// 使用的导入器名字
|
||||
importer: string;
|
||||
// 类型
|
||||
type: string;
|
||||
// 是否是文件夹
|
||||
isDirectory: boolean;
|
||||
// 导入资源的 map
|
||||
library: { [key: string]: string };
|
||||
// 子资源 map
|
||||
subAssets: { [key: string]: AssetInfo };
|
||||
// 是否显示
|
||||
visible: boolean;
|
||||
// 是否只读
|
||||
readonly: boolean;
|
||||
|
||||
// 虚拟资源可以实例化成实体的话,会带上这个扩展名
|
||||
instantiation?: string;
|
||||
// 跳转指向资源
|
||||
redirect?: IRedirectInfo;
|
||||
// 继承类型
|
||||
extends?: string[];
|
||||
// 是否导入完成
|
||||
imported: boolean;
|
||||
// 是否导入失败
|
||||
invalid: boolean;
|
||||
}
|
||||
|
||||
export interface IRedirectInfo {
|
||||
// 跳转资源的类型
|
||||
type: string;
|
||||
// 跳转资源的 uuid
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export interface QueryAssetsOption {
|
||||
type?: string;
|
||||
pattern?: string;
|
||||
ccType?: string;
|
||||
extname?: string;
|
||||
importer?: string;
|
||||
isBundle?: boolean;
|
||||
}
|
||||
|
||||
export interface AssetOperationOption {
|
||||
// 是否强制覆盖已经存在的文件,默认 false
|
||||
overwrite?: boolean;
|
||||
// 是否自动重命名冲突文件,默认 false
|
||||
rename?: boolean;
|
||||
}
|
||||
|
||||
export interface AssetDBOptions {
|
||||
name: string;
|
||||
target: string;
|
||||
library: string;
|
||||
temp: string;
|
||||
/**
|
||||
* 0: 忽略错误
|
||||
* 1: 仅仅打印错误
|
||||
* 2: 打印错误、警告
|
||||
* 3: 打印错误、警告、日志
|
||||
* 4: 打印错误、警告、日志、调试信息
|
||||
*/
|
||||
level: number;
|
||||
ignoreFiles: string[];
|
||||
readonly: boolean;
|
||||
}
|
||||
|
||||
export interface ContributionInfo {
|
||||
mount?: {
|
||||
path: string;
|
||||
readonly?: boolean;
|
||||
visible?: boolean;
|
||||
enable?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ExecuteAssetDBScriptMethodOptions {
|
||||
name: string;
|
||||
method: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export interface IAssetMeta {
|
||||
ver: string;
|
||||
importer: string;
|
||||
imported: boolean;
|
||||
uuid: string;
|
||||
files: string[];
|
||||
subMetas: {
|
||||
[index: string]: IAssetMeta;
|
||||
};
|
||||
userData: {
|
||||
[index: string]: any;
|
||||
};
|
||||
displayName: string;
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
25
extensions/app/engine/@types/packages/assets/@types/public.d.ts
vendored
Normal file
25
extensions/app/engine/@types/packages/assets/@types/public.d.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 外部插件注册搜索方式指定返回的接口
|
||||
*
|
||||
* @export
|
||||
* @interface SearchMenuItem
|
||||
*/
|
||||
export interface SearchMenuItem {
|
||||
label: string;
|
||||
key: string;
|
||||
// handler 方法是外部扩展的搜索方法,返回 true 表示匹配搜索成功
|
||||
// searchValue 表示 assets 面板输入的搜索内容,asset 表示匹配搜索时的节点信息
|
||||
handler: (searchVale: string, asset: any) => boolean | Promise<boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部插件注册扩展的入口
|
||||
* 可以是搜索方式或限定搜索类型
|
||||
*
|
||||
* @export
|
||||
* @interface SearchExtension
|
||||
*/
|
||||
export interface SearchExtension {
|
||||
typeMenu?: Function; // 限定的搜索类型
|
||||
searchMenu: Function; // 搜索方式
|
||||
}
|
||||
18
extensions/app/engine/@types/packages/baidu-mini-game/@types/index.d.ts
vendored
Normal file
18
extensions/app/engine/@types/packages/baidu-mini-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'auto' | 'landscape' | 'portrait';
|
||||
|
||||
export interface IOptions {
|
||||
appid: string;
|
||||
buildOpenDataContextTemplate: boolean;
|
||||
orientation: IOrientation;
|
||||
}
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'baidu-mini-game': IOptions;
|
||||
};
|
||||
}
|
||||
2
extensions/app/engine/@types/packages/builder/@types/index.d.ts
vendored
Normal file
2
extensions/app/engine/@types/packages/builder/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
export * from './public';
|
||||
101
extensions/app/engine/@types/packages/builder/@types/public/build-plugin.d.ts
vendored
Normal file
101
extensions/app/engine/@types/packages/builder/@types/public/build-plugin.d.ts
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import { ITextureCompressType, IPVRQuality, IASTCQuality, IETCQuality, ITextureFormatInfo } from './texture-compress';
|
||||
import { IBuildTaskOption, IConsoleType } from './options';
|
||||
import { IBuildResult } from './build-result';
|
||||
|
||||
export interface IBuildPluginConfig {
|
||||
doc?: string; // 文档地址,支持 HTTP 地址,支持相对于编辑器官方 URL 的地址
|
||||
hooks?: string; // relate url about IHook
|
||||
options?: IDisplayOptions; // config of options
|
||||
verifyRuleMap?: IVerificationRuleMap;
|
||||
}
|
||||
|
||||
export type IVerificationFunc = (val: any, ...arg: any[]) => boolean | Promise<boolean>;
|
||||
export type IInternalVerificationFunc = (val: any, ...arg: any[]) => boolean;
|
||||
|
||||
export type IVerificationRuleMap = Record<string, IVerificationRule>;
|
||||
|
||||
export interface IVerificationRule {
|
||||
func: IVerificationFunc;
|
||||
message: string;
|
||||
}
|
||||
export interface IInternalVerificationRule {
|
||||
func: IInternalVerificationFunc;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ITextureFormatConfig {
|
||||
displayName: string;
|
||||
options: IDisplayOptions;
|
||||
formats: ITextureFormatInfo[]; // 未指定 formats 则当前格式 key 作为存储的格式 value
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
export type IDisplayOptions = Record<string, IConfigItem>;
|
||||
|
||||
export type ArrayItem = {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export interface IConfigItem {
|
||||
key?: string; // 唯一标识符
|
||||
// 配置显示的名字,如果需要翻译,则传入 i18n:${key}
|
||||
label?: string;
|
||||
// 设置的简单说明
|
||||
description?: string;
|
||||
|
||||
experiment?: boolean; // 是否为实验性属性
|
||||
// 默认值
|
||||
default?: any;
|
||||
// 配置的类型
|
||||
type?: 'array' | 'object';
|
||||
itemConfigs?: IConfigItem[] | Record<string, IConfigItem>;
|
||||
verifyRules?: string[];
|
||||
verifyLevel?: IConsoleType, // 不赋值是默认为 error,等级为 error 时校验不通过将会无法点击构建,其他则仅做界面提示
|
||||
hidden?: boolean; // 是否隐藏
|
||||
render?: {
|
||||
ui: string;
|
||||
attributes?: Record<string, string | boolean | number>;
|
||||
items?: ArrayItem[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IBuildPlugin {
|
||||
configs?: BuildPlugin.Configs;
|
||||
assetHandlers?: BuildPlugin.AssetHandlers;
|
||||
load?: BuildPlugin.load;
|
||||
unload?: BuildPlugin.Unload;
|
||||
}
|
||||
export type IBaseHooks = (options: IBuildTaskOption, result: IBuildResult) => Promise<void> | void;
|
||||
export type IBuildStageHooks = (root: string, options: IBuildTaskOption) => Promise<void> | void;
|
||||
|
||||
export namespace BuildPlugin {
|
||||
export type Configs = Record<string, IBuildPluginConfig>;
|
||||
export type AssetHandlers = string;
|
||||
export type load = () => Promise<void> | void;
|
||||
export type Unload = () => Promise<void> | void;
|
||||
}
|
||||
|
||||
export namespace BuildHook {
|
||||
export type throwError = boolean; // 插件注入的钩子函数,在执行失败时是否直接退出构建流程
|
||||
export type title = string; // 插件任务整体 title,支持 i18n 写法
|
||||
|
||||
export type onError = IBaseHooks; // 构建发生中断错误时的回调,仅作为事件通知,并不能劫持错误
|
||||
|
||||
export type onBeforeBuild = IBaseHooks;
|
||||
export type onBeforeCompressSettings = IBaseHooks;
|
||||
export type onAfterCompressSettings = IBaseHooks;
|
||||
export type onAfterBuild = IBaseHooks;
|
||||
|
||||
export type onAfterMake = IBuildStageHooks;
|
||||
export type onBeforeMake = IBuildStageHooks;
|
||||
|
||||
export type load = () => Promise<void> | void;
|
||||
export type unload = () => Promise<void> | void;
|
||||
}
|
||||
|
||||
export namespace AssetHandlers {
|
||||
export type compressTextures = (
|
||||
tasks: { src: string; dest: string; quality: number | IPVRQuality | IASTCQuality | IETCQuality; format: ITextureCompressType }[],
|
||||
) => Promise<void>;
|
||||
}
|
||||
243
extensions/app/engine/@types/packages/builder/@types/public/build-result.d.ts
vendored
Normal file
243
extensions/app/engine/@types/packages/builder/@types/public/build-result.d.ts
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* settings.js 里定义的数据
|
||||
*/
|
||||
|
||||
import { ISplashSetting, ICustomJointTextureLayout, UUID, IOrientation } from './options';
|
||||
|
||||
// ****************************** settings ************************************************
|
||||
|
||||
// debug: true
|
||||
// designResolution: {width: "960", height: "640", policy: 4}
|
||||
// jsList: ["assets/resources/b.js", "assets/resources/a.js"]
|
||||
// launchScene: "db://assets/New Scene-001.scene"
|
||||
// platform: "web-desktop"
|
||||
// rawAssets: {
|
||||
// assets: {
|
||||
// "0e95a9f8-d4e7-4849-875a-7a11dd692b34": ["mesh/env/gltf/textures/birch_yellow_mat_baseColor.png", "cc.ImageAsset"]
|
||||
// }
|
||||
// internal: {
|
||||
// "1baf0fc9-befa-459c-8bdd-af1a450a0319": ["effects/builtin-standard.effect", "cc.EffectAsset"]
|
||||
// }
|
||||
// }
|
||||
// scenes: [{url: "db://assets/New Scene-001.scene", uuid: "69dc4a42-cc6c-49fb-9a57-7de0c212f83d"},…]
|
||||
// startScene: "current_scene"
|
||||
export interface ISettings {
|
||||
CocosEngine: string;
|
||||
debug: boolean;
|
||||
designResolution: ISettingsDesignResolution;
|
||||
jsList: string[];
|
||||
launchScene: string;
|
||||
preloadAssets: string[],
|
||||
moduleIds: string[];
|
||||
platform: string;
|
||||
renderPipeline: string;
|
||||
physics?: IPhysicsConfig;
|
||||
exactFitScreen: boolean;
|
||||
|
||||
bundleVers: Record<string, string>;
|
||||
subpackages: string[];
|
||||
remoteBundles: string[];
|
||||
server: string;
|
||||
hasResourcesBundle: boolean;
|
||||
hasStartSceneBundle: boolean;
|
||||
|
||||
scriptPackages?: string[];
|
||||
splashScreen?: ISplashSetting;
|
||||
|
||||
customJointTextureLayouts?: ICustomJointTextureLayout[];
|
||||
|
||||
importMaps?: Array<{
|
||||
url: string;
|
||||
map: any;
|
||||
}>;
|
||||
|
||||
macros?: Record<string, any>;
|
||||
collisionMatrix?: any;
|
||||
groupList?: any;
|
||||
// preview
|
||||
engineModules: string[];
|
||||
customLayers: {name: string, bit: number}[];
|
||||
orientation?: IOrientation;
|
||||
}
|
||||
|
||||
export interface IOutputSettings {
|
||||
CocosEngine: string;
|
||||
engine: {
|
||||
debug: boolean;
|
||||
macros: Record<string, any>;
|
||||
customLayers: {name: string, bit: number}[];
|
||||
platform: string;
|
||||
engineModules?: string[];
|
||||
builtinAssets: string[];
|
||||
};
|
||||
physics?: IPhysicsConfig;
|
||||
rendering: {
|
||||
renderPipeline: string;
|
||||
renderMode?: number;
|
||||
};
|
||||
assets: {
|
||||
server: string;
|
||||
remoteBundles: string[];
|
||||
bundleVers: Record<string, string>;
|
||||
preloadBundles: { bundle: string, version?: string }[];
|
||||
importBase?: string;
|
||||
nativeBase?: string;
|
||||
subpackages: string[];
|
||||
preloadAssets: string[];
|
||||
jsbDownloaderMaxTasks?: number;
|
||||
jsbDownloaderTimeout?: number;
|
||||
projectBundles: string[];
|
||||
};
|
||||
plugins: {
|
||||
jsList: string[];
|
||||
};
|
||||
scripting: {
|
||||
scriptPackages?: string[];
|
||||
};
|
||||
launch: {
|
||||
launchScene: string;
|
||||
};
|
||||
screen: {
|
||||
frameRate?: number;
|
||||
exactFitScreen: boolean;
|
||||
orientation?: IOrientation;
|
||||
designResolution: ISettingsDesignResolution;
|
||||
};
|
||||
splashScreen?: ISplashSetting;
|
||||
animation: {
|
||||
customJointTextureLayouts?: ICustomJointTextureLayout[];
|
||||
};
|
||||
profiling?: {
|
||||
showFPS: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// 物理配置
|
||||
export interface IVec3Like {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
|
||||
export interface ICollisionMatrix {
|
||||
[x: string]: number;
|
||||
}
|
||||
|
||||
export interface IPhysicsMaterial {
|
||||
friction: number; // 0.5
|
||||
rollingFriction: number; // 0.1
|
||||
spinningFriction: number; // 0.1
|
||||
restitution: number; // 0.1
|
||||
}
|
||||
|
||||
export interface IPhysicsConfig {
|
||||
gravity: IVec3Like; // (0,-10, 0)
|
||||
allowSleep: boolean; // true
|
||||
sleepThreshold: number; // 0.1,最小 0
|
||||
autoSimulation: boolean; // true
|
||||
fixedTimeStep: number; // 1 / 60 ,最小 0
|
||||
maxSubSteps: number; // 1,最小 0
|
||||
defaultMaterial: IPhysicsMaterial;
|
||||
useNodeChains: boolean; // true
|
||||
collisionMatrix: ICollisionMatrix;
|
||||
physicsEngine: string;
|
||||
}
|
||||
|
||||
export interface IPackageInfo {
|
||||
name: string;
|
||||
path: string;
|
||||
uuids: UUID[];
|
||||
}
|
||||
|
||||
export interface ISettingsDesignResolution {
|
||||
width: number;
|
||||
height: number;
|
||||
policy: number;
|
||||
}
|
||||
|
||||
interface IAssetPathBase {
|
||||
bundleName?: string;
|
||||
redirect?: string; // 重定向的 bundle 包名
|
||||
}
|
||||
|
||||
export interface IRawAssetPathInfo extends IAssetPathBase {
|
||||
raw: string[];
|
||||
}
|
||||
export declare interface IAssetPathInfo extends IAssetPathBase {
|
||||
raw?: string[];
|
||||
json?: string;
|
||||
groupIndex?: number;
|
||||
}
|
||||
|
||||
export interface IJsonPathInfo extends IAssetPathBase {
|
||||
json?: string;
|
||||
groupIndex?: number;
|
||||
}
|
||||
|
||||
export interface IBuildPaths {
|
||||
dir: string; // 构建资源输出地址( assets 所在的目录,并不一定与构建目录对应)
|
||||
settings: string; // settings.json 输出地址
|
||||
systemJs?: string; // system.js 生成地址
|
||||
engineDir?: string; // 引擎生成地址
|
||||
polyfillsJs?: string; // polyfill.js 生成地址
|
||||
assets: string; // assets 目录
|
||||
subpackages: string; // subpackages 目录
|
||||
remote: string; // remote 目录
|
||||
bundleScripts: string // bundle 的脚本,某些平台无法下载脚本,则将远程包中的脚本移到本地
|
||||
applicationJS: string; // application.js 的生成地址
|
||||
compileConfig?: string; // cocos.compile.config.json
|
||||
importMap: string; // import-map 文件地址
|
||||
}
|
||||
|
||||
export declare class IBuildResult {
|
||||
dest: string; // options 指定的构建目录
|
||||
|
||||
paths: IBuildPaths; // 构建后资源相关地址集合
|
||||
|
||||
settings?: ISettings;
|
||||
|
||||
/**
|
||||
* 指定的 uuid 资源是否包含在构建资源中
|
||||
*/
|
||||
containsAsset: (uuid: string) => boolean;
|
||||
|
||||
/**
|
||||
* 获取指定 uuid 原始资源的存放路径(不包括序列化 json)
|
||||
* 自动图集的小图 uuid 和自动图集的 uuid 都将会查询到合图大图的生成路径
|
||||
* 实际返回多个路径的情况:查询 uuid 为自动图集资源,且对应图集生成多张大图,纹理压缩会有多个图片格式路径
|
||||
*/
|
||||
getRawAssetPaths: (uuid: string) => IRawAssetPathInfo[];
|
||||
|
||||
/**
|
||||
* 获取指定 uuid 资源的序列化 json 路径
|
||||
*/
|
||||
getJsonPathInfo: (uuid: string) => IJsonPathInfo[];
|
||||
|
||||
/**
|
||||
* 获取指定 uuid 资源的路径相关信息
|
||||
* @return {raw?: string[]; json?: string; groupIndex?: number;}
|
||||
* @return.raw: 该资源源文件的实际存储位置
|
||||
* @return.json: 该资源序列化 json 的实际存储位置,不存在为空
|
||||
* @return.groupIndex: 若该资源的序列化 json 在某个 json 分组内,这里标识在分组内的 index,不存在为空
|
||||
*/
|
||||
getAssetPathInfo: (uuid: string) => IAssetPathInfo[];
|
||||
}
|
||||
|
||||
export interface IBundleConfig {
|
||||
importBase: string; // bundle 中 import 目录的名称,通常是 'import'
|
||||
nativeBase: string; // native 中 native 目录的名称,通常是 'native'
|
||||
name: string; // bundle 的名称,可以通过 bundle 名称加载 bundle
|
||||
deps: string[]; // 该 bundle 依赖的其他 bundle 名称
|
||||
uuids: UUID[]; // 该 bundle 中的所有资源的 uuid
|
||||
paths: Record<string, any[]>; // 该 bundle 中可以通过路径加载的资源,参考以前 settings 中 rawAssets 的定义
|
||||
scenes: Record<string, UUID|number>; // 该 bundle 中所有场景,场景名为 key, uuid 为 value
|
||||
packs: Record<UUID, UUID[]>; // 该 bundle 中所有合并的 json, 参考以前 settings 中 packedAssets 的定义
|
||||
versions: { import: Array<string|number>, native: Array<string|number> }; // 该 bundle 中所有资源的版本号,参考以前 settings 中 md5AssetsMap 的定义
|
||||
redirect: Array<string|number>; // 该 bundle 中重定向到其他 bundle 的资源
|
||||
debug: boolean; // 是否是 debug 模式,debug 模式会对 config.json 的数据进行压缩,所以运行时得解压
|
||||
types?: string[]; // paths 中的类型数组,参考以前 settings 中 assetTypes 的定义
|
||||
encrypted?: boolean; // 原生上使用,标记该 bundle 中的脚本是否加密
|
||||
isZip?: boolean; // 是否是 zip 模式
|
||||
zipVersion?: string;
|
||||
extensionMap: Record<string, UUID[]>
|
||||
}
|
||||
7
extensions/app/engine/@types/packages/builder/@types/public/global.d.ts
vendored
Normal file
7
extensions/app/engine/@types/packages/builder/@types/public/global.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { IBuild } from '.';
|
||||
|
||||
// 定义 builder 进程内的全局变量
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
const Build: IBuild;
|
||||
}
|
||||
101
extensions/app/engine/@types/packages/builder/@types/public/index.d.ts
vendored
Normal file
101
extensions/app/engine/@types/packages/builder/@types/public/index.d.ts
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import { ITransformOptions } from './options';
|
||||
|
||||
export * from './build-result';
|
||||
export * from './build-plugin';
|
||||
export * from './texture-compress';
|
||||
export * from './options';
|
||||
|
||||
interface IAppendRes {
|
||||
hash: string;
|
||||
paths: string[];
|
||||
}
|
||||
|
||||
interface ICreateBundleOptions {
|
||||
excludes?: string[];
|
||||
debug?: boolean;
|
||||
sourceMap?: boolean;
|
||||
targets?: string;
|
||||
}
|
||||
export interface IBuildUtils {
|
||||
/**
|
||||
* 压缩 uuid
|
||||
* 'fc991dd7-0033-4b80-9d41-c8a86a702e59' -> 'fc9913XADNLgJ1ByKhqcC5Z'
|
||||
*/
|
||||
compressUuid: (uuid: string, min: boolean) => string;
|
||||
|
||||
/**
|
||||
* 解压缩 uuid
|
||||
* 'fc9913XADNLgJ1ByKhqcC5Z' -> 'fc991dd7-0033-4b80-9d41-c8a86a702e59'
|
||||
*/
|
||||
decompressUuid: (uuid: string) => string;
|
||||
|
||||
/**
|
||||
* 翻译带有 i18n 开头的名称(i18n:test)(待定)
|
||||
* 'i18n:test' -> '测试'
|
||||
*/
|
||||
transI18nName: (name: string) => string;
|
||||
|
||||
/**
|
||||
* 移除 db 前缀
|
||||
* 'db://assets/test.jpg' -> 'assets/test.jpg'
|
||||
*/
|
||||
removeDbHeader: (url: string) => string;
|
||||
|
||||
/**
|
||||
* 将 db 开头的 url 转为项目里的实际 url
|
||||
* 'db://assets/test.jpg' -> 'c:/project/assets/test.jpg'
|
||||
*/
|
||||
dbUrlToRawPath: (url: string) => string;
|
||||
|
||||
/**
|
||||
* 从路径里获取存在的 uuid
|
||||
* 'E:\test3d\library\oc\0c0c1f5742-89b0-4a1e-b5eb-914d84f48c1c.json' -> '0c0c1f5742-89b0-4a1e-b5eb-914d84f48c1c'
|
||||
*/
|
||||
getUuidFromPath: (path: string) => string;
|
||||
|
||||
/**
|
||||
* 检查是否全局安装了 nodejs
|
||||
*/
|
||||
isInstallNodeJs: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 逐文件拷贝
|
||||
*/
|
||||
copyDirSync: (src: string, dest: string) => void;
|
||||
|
||||
/**
|
||||
* 获取相对路径接口
|
||||
* 返回 / 拼接的相对路径
|
||||
*/
|
||||
relativeUrl: (from: string, to: string) => string;
|
||||
|
||||
transformCode: (code: string, options: ITransformOptions) => Promise<string>;
|
||||
|
||||
/**
|
||||
* 给指定路径添加 md5
|
||||
*/
|
||||
appendMd5ToPaths: (paths: string[]) => Promise<IAppendRes | null>;
|
||||
|
||||
calcMd5: (data: Buffer | string) => string;
|
||||
|
||||
copyPaths: (paths: { src: string; dest: string }[]) => Promise<void[]>;
|
||||
|
||||
createBundle: (src: string, dest: string, options?: ICreateBundleOptions) => Promise<unknown>;
|
||||
}
|
||||
export interface IBuild {
|
||||
Utils: IBuildUtils;
|
||||
|
||||
LIBRARY_NAME: string;
|
||||
IMPORT_HEADER: string;
|
||||
NATIVE_HEADER: string;
|
||||
ASSETS_HEADER: string;
|
||||
SUBPACKAGES_HEADER: string;
|
||||
REMOTE_HEADER: string;
|
||||
BUNDLE_SCRIPTS_HEADER: string;
|
||||
SCRIPT_NAME: string;
|
||||
CONFIG_NAME: string;
|
||||
BUNDLE_ZIP_NAME: string;
|
||||
projectTempDir: string;
|
||||
globalTempDir: string;
|
||||
buildTemplateDir: string; // 构建模板地址 build-templates
|
||||
}
|
||||
40
extensions/app/engine/@types/packages/builder/@types/public/message.d.ts
vendored
Normal file
40
extensions/app/engine/@types/packages/builder/@types/public/message.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import { IBundleConfig, ISettings, IOutputSettings } from './build-result';
|
||||
import { IBuildTaskItemJSON } from './options';
|
||||
export interface message extends EditorMessageMap {
|
||||
'open-devtools': {
|
||||
params: [],
|
||||
result: void,
|
||||
},
|
||||
open: {
|
||||
params: [],
|
||||
result: void,
|
||||
},
|
||||
'generate-preview-setting': {
|
||||
params: any[],
|
||||
result: Promise<{
|
||||
settings: IOutputSettings;
|
||||
script2library: Record<string, string>;
|
||||
bundleConfigs: IBundleConfig[];
|
||||
}>,
|
||||
},
|
||||
'query-tasks-info': {
|
||||
params: [],
|
||||
result: {
|
||||
queue: Record<string, IBuildTaskItemJSON>,
|
||||
free: Promise<boolean>,
|
||||
},
|
||||
},
|
||||
'query-task': {
|
||||
params: string[],
|
||||
result: Promise<IBuildTaskItemJSON>,
|
||||
},
|
||||
/**
|
||||
* 预览合图
|
||||
* @param {object} pacUuid
|
||||
*/
|
||||
'preview-pac': {
|
||||
params: string[],
|
||||
result: Promise<IBuildTaskItemJSON>,
|
||||
},
|
||||
|
||||
}
|
||||
187
extensions/app/engine/@types/packages/builder/@types/public/options.d.ts
vendored
Normal file
187
extensions/app/engine/@types/packages/builder/@types/public/options.d.ts
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
import * as babel from '@babel/core';
|
||||
|
||||
export type IConsoleType = 'log' | 'warn' | 'error' | 'debug';
|
||||
|
||||
/**
|
||||
* 构建所需的完整参数
|
||||
*/
|
||||
export interface IBuildTaskOption {
|
||||
// 构建后的游戏文件夹生成的路径
|
||||
buildPath: string;
|
||||
debug: boolean;
|
||||
inlineSpriteFrames: boolean;
|
||||
md5Cache: boolean;
|
||||
|
||||
// bundle 设置
|
||||
mainBundleCompressionType: BundleCompressionType;
|
||||
mainBundleIsRemote: boolean;
|
||||
useBuiltinServer: boolean; // 使用内置的服务器地址,实验性功能
|
||||
server?: string; // 服务器地址
|
||||
// 小游戏平台将会自动勾选
|
||||
moveRemoteBundleScript: boolean;
|
||||
|
||||
mergeJson: boolean;
|
||||
name: string;
|
||||
// packAutoAtlas: boolean;
|
||||
platform: Platform;
|
||||
scenes: IBuildSceneItem[];
|
||||
skipCompressTexture: boolean;
|
||||
sourceMaps: boolean;
|
||||
startScene: string;
|
||||
outputName: string;
|
||||
experimentalEraseModules: boolean;
|
||||
polyfills?: IPolyFills;
|
||||
nextStages?: string[];
|
||||
|
||||
// 构建阶段性任务绑定分组
|
||||
buildStageGroup?: Record<string, string[]>;
|
||||
|
||||
/**
|
||||
* 是否是预览进程发送的构建请求。
|
||||
* @default false
|
||||
*/
|
||||
preview?: boolean;
|
||||
|
||||
// 项目设置
|
||||
includeModules?: string[];
|
||||
renderPipeline?: string;
|
||||
designResolution?: IBuildDesignResolution;
|
||||
physicsConfig?: any;
|
||||
flags?: Record<string, boolean>;
|
||||
customLayers: {name: string, value: number}[];
|
||||
|
||||
// 是否使用自定义插屏选项
|
||||
replaceSplashScreen?: boolean;
|
||||
splashScreen: ISplashSetting;
|
||||
|
||||
packages?: Record<string, any>;
|
||||
id?: string; // 手动配置构建任务 id
|
||||
// recompileConfig?: IRecompileConfig;
|
||||
|
||||
// 一些偏好设置选项
|
||||
useBuildAssetCache?: boolean;
|
||||
useBuildEngineCache?: boolean;
|
||||
useBuildTextureCompressCache?: boolean;
|
||||
useBuildAutoAtlasCache?: boolean;
|
||||
__version__?: string;
|
||||
}
|
||||
|
||||
export type UUID = string;
|
||||
|
||||
export interface ISplashSetting {
|
||||
enabled: boolean;
|
||||
base64src: string;
|
||||
displayRatio: number;
|
||||
totalTime: number;
|
||||
effect: string;
|
||||
clearColor: { x: number; y: number; z: number; w: number };
|
||||
displayWatermark: boolean;
|
||||
}
|
||||
|
||||
export interface ICustomJointTextureLayout {
|
||||
textureLength: number;
|
||||
contents: IChunkContent[];
|
||||
}
|
||||
|
||||
export interface IChunkContent {
|
||||
skeleton: null | string;
|
||||
clips: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建使用的设计分辨率数据
|
||||
*/
|
||||
export interface IBuildDesignResolution {
|
||||
height: number;
|
||||
width: number;
|
||||
fitWidth?: boolean;
|
||||
fitHeight?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建使用的场景的数据
|
||||
*/
|
||||
export interface IBuildSceneItem {
|
||||
url: string;
|
||||
uuid: string;
|
||||
inBundle?: boolean;
|
||||
}
|
||||
|
||||
export interface IPolyFills {
|
||||
/**
|
||||
* True if async functions polyfills(i.e. regeneratorRuntime) needs to be included.
|
||||
* You need to turn on this field if you want to use async functions in language.
|
||||
*/
|
||||
asyncFunctions?: boolean;
|
||||
|
||||
/**
|
||||
* If true, [core-js](https://github.com/zloirock/core-js) polyfills are included.
|
||||
* The default options of [core-js-builder](https://github.com/zloirock/core-js/tree/master/packages/core-js-builder)
|
||||
* will be used to build the core-js.
|
||||
*/
|
||||
coreJs?: boolean;
|
||||
|
||||
targets?: string;
|
||||
}
|
||||
|
||||
// **************************** options *******************************************
|
||||
export type Platform =
|
||||
| 'web-desktop'
|
||||
| 'web-mobile'
|
||||
| 'wechatgame'
|
||||
| 'oppo-mini-game'
|
||||
| 'vivo-mini-game'
|
||||
| 'huawei-quick-game'
|
||||
| 'alipay-mini-game'
|
||||
| 'mac'
|
||||
| 'ios'
|
||||
| 'linux'
|
||||
// | 'ios-app-clip'
|
||||
| 'android'
|
||||
| 'ohos'
|
||||
| 'open-harmonyos'
|
||||
| 'windows'
|
||||
| 'xiaomi-quick-game'
|
||||
| 'baidu-mini-game'
|
||||
| 'bytedance-mini-game'
|
||||
| 'cocos-play'
|
||||
| 'huawei-agc'
|
||||
| 'link-sure'
|
||||
| 'qtt'
|
||||
| 'cocos-runtime'
|
||||
| 'xr-meta'
|
||||
| 'xr-huaweivr'
|
||||
| 'xr-pico'
|
||||
| 'xr-rokid'
|
||||
| 'xr-monado'
|
||||
| 'ar-android'
|
||||
| 'ar-ios'
|
||||
;
|
||||
|
||||
export type BundleCompressionType = 'none' | 'merge_dep' | 'merge_all_json' | 'subpackage' | 'zip';
|
||||
export type IModules = 'esm' | 'commonjs' | 'systemjs';
|
||||
|
||||
export interface ITransformOptions {
|
||||
importMapFormat: IModules;
|
||||
plugins?: babel.PluginItem[];
|
||||
}
|
||||
|
||||
export type ITaskState = 'waiting' | 'success' | 'failure' | 'cancel' | 'processing';
|
||||
|
||||
export interface ITaskItemJSON{
|
||||
id: string;
|
||||
progress: number;
|
||||
state: ITaskState;
|
||||
message: string;
|
||||
time: string;
|
||||
}
|
||||
|
||||
export interface IBuildTaskItemJSON extends ITaskItemJSON {
|
||||
stage: 'build' | string;
|
||||
options: IBuildTaskOption;
|
||||
dirty: boolean;
|
||||
rawOptions?: IBuildTaskOption;
|
||||
type: 'build',
|
||||
}
|
||||
|
||||
export type IOrientation = 'auto' | 'landscape' | 'portrait';
|
||||
70
extensions/app/engine/@types/packages/builder/@types/public/texture-compress.d.ts
vendored
Normal file
70
extensions/app/engine/@types/packages/builder/@types/public/texture-compress.d.ts
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
export type ITextureCompressType =
|
||||
| 'jpg'
|
||||
| 'png'
|
||||
| 'webp'
|
||||
| 'pvrtc_4bits_rgb'
|
||||
| 'pvrtc_4bits_rgba'
|
||||
| 'pvrtc_4bits_rgb_a'
|
||||
| 'pvrtc_2bits_rgb'
|
||||
| 'pvrtc_2bits_rgba'
|
||||
| 'pvrtc_2bits_rgb_a'
|
||||
| 'etc1_rgb'
|
||||
| 'etc1_rgb_a'
|
||||
| 'etc2_rgb'
|
||||
| 'etc2_rgba'
|
||||
| 'astc_4x4'
|
||||
| 'astc_5x5'
|
||||
| 'astc_6x6'
|
||||
| 'astc_8x8'
|
||||
| 'astc_10x5'
|
||||
| 'astc_10x10'
|
||||
| 'astc_12x12'
|
||||
| string;
|
||||
export type ITextureCompressPlatform = 'miniGame' | 'web' | 'ios' | 'android';
|
||||
|
||||
export interface IHandlerInfo {
|
||||
type: 'program' | 'npm' | 'function';
|
||||
info: ICommandInfo | Function;
|
||||
func?: Function;
|
||||
}
|
||||
|
||||
export interface ICustomConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
path: string;
|
||||
command: string;
|
||||
format: string;
|
||||
overwrite?: boolean;
|
||||
}
|
||||
|
||||
export interface ICommandInfo {
|
||||
command: string;
|
||||
params?: string[];
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface ITextureFormatInfo {
|
||||
displayName: string;
|
||||
value: ITextureCompressType | string;
|
||||
formatSuffix?: string;
|
||||
alpha?: boolean;
|
||||
formatType?: string;
|
||||
handler?: IHandlerInfo;
|
||||
custom?: boolean;
|
||||
params?: string[];
|
||||
}
|
||||
export interface ISupportFormat {
|
||||
rgb: ITextureCompressType[];
|
||||
rgba: ITextureCompressType[];
|
||||
}
|
||||
export interface IConfigGroupsInfo {
|
||||
defaultSupport?: ISupportFormat,
|
||||
support: ISupportFormat,
|
||||
displayName: string;
|
||||
icon: string;
|
||||
}
|
||||
export type IConfigGroups = Record<ITextureCompressPlatform, IConfigGroupsInfo>;
|
||||
|
||||
export type IPVRQuality = 'fastest' | 'fast' | 'normal' | 'high' | 'best';
|
||||
export type IETCQuality = 'slow' | 'fast';
|
||||
export type IASTCQuality = 'veryfast' | 'fast' | 'medium' | 'thorough' | 'exhaustive';
|
||||
26
extensions/app/engine/@types/packages/bytedance-mini-game/@types/index.d.ts
vendored
Normal file
26
extensions/app/engine/@types/packages/bytedance-mini-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'auto' | 'landscape' | 'portrait';
|
||||
|
||||
export interface IOptions {
|
||||
appid: string;
|
||||
buildOpenDataContextTemplate: boolean;
|
||||
orientation: IOrientation;
|
||||
physX: {
|
||||
use: 'physX' | 'project';
|
||||
notPackPhysXLibs: boolean;
|
||||
mutiThread: boolean;
|
||||
subThreadCount: number;
|
||||
epsilon: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'bytedance-mini-game': IOptions;
|
||||
};
|
||||
}
|
||||
1
extensions/app/engine/@types/packages/certificate/@types/index.d.ts
vendored
Normal file
1
extensions/app/engine/@types/packages/certificate/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
1
extensions/app/engine/@types/packages/channel-upload-tools/@types/index.d.ts
vendored
Normal file
1
extensions/app/engine/@types/packages/channel-upload-tools/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
28
extensions/app/engine/@types/packages/cocos-play/@types/index.d.ts
vendored
Normal file
28
extensions/app/engine/@types/packages/cocos-play/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface PlatformSettings {
|
||||
runtimeVersion: string,
|
||||
deviceOrientation: IOrientation,
|
||||
statusbarDisplay: boolean,
|
||||
startSceneAssetBundle: false,
|
||||
workerPath: string,
|
||||
XHRTimeout: number,
|
||||
WSTimeout: number,
|
||||
uploadFileTimeout: number,
|
||||
downloadFileTimeout: number,
|
||||
cameraPermissionHint: string,
|
||||
userInfoPermissionHint: string,
|
||||
locationPermissionHint: string,
|
||||
albumPermissionHint: string
|
||||
}
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'cocos-play': PlatformSettings
|
||||
}
|
||||
}
|
||||
33
extensions/app/engine/@types/packages/console/@types/pritate.d.ts
vendored
Normal file
33
extensions/app/engine/@types/packages/console/@types/pritate.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
export type logType = 'log' | 'warn' | 'error';
|
||||
export interface IMessageItem {
|
||||
rows: number; // 内部有几行 包括 details & stacks
|
||||
translateY: number;
|
||||
show: boolean;
|
||||
title: string;
|
||||
content: string[]; // details
|
||||
count: number; // 重复的个数
|
||||
fold: boolean; // 折叠
|
||||
type: logType;
|
||||
message: any;
|
||||
texture: string; // 纹理 light or dark
|
||||
date?: number; // 格式化的时间
|
||||
time?: number; // 时间戳
|
||||
process?: string;
|
||||
stack: string[];
|
||||
}
|
||||
|
||||
export interface INewItem {
|
||||
type: logType
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
export type ILogCounter = Record<logType, number>;
|
||||
|
||||
export type IConsoleExtension = {
|
||||
name: string,
|
||||
key: string,
|
||||
label: string,
|
||||
value?: boolean,
|
||||
show: boolean
|
||||
}
|
||||
684
extensions/app/engine/@types/packages/engine-extends/@types/glTF.d.ts
vendored
Normal file
684
extensions/app/engine/@types/packages/engine-extends/@types/glTF.d.ts
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
export type GlTfId = number;
|
||||
/**
|
||||
* Indices of those attributes that deviate from their initialization value.
|
||||
*/
|
||||
export interface AccessorSparseIndices {
|
||||
/**
|
||||
* The index of the bufferView with sparse indices. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
||||
*/
|
||||
'bufferView': GlTfId;
|
||||
/**
|
||||
* The offset relative to the start of the bufferView in bytes. Must be aligned.
|
||||
*/
|
||||
'byteOffset'?: number;
|
||||
/**
|
||||
* The indices data type.
|
||||
*/
|
||||
'componentType': 5121 | 5123 | 5125 | number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Array of size `accessor.sparse.count` times number of components storing the displaced accessor attributes pointed by `accessor.sparse.indices`.
|
||||
*/
|
||||
export interface AccessorSparseValues {
|
||||
/**
|
||||
* The index of the bufferView with sparse values. Referenced bufferView can't have ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target.
|
||||
*/
|
||||
'bufferView': GlTfId;
|
||||
/**
|
||||
* The offset relative to the start of the bufferView in bytes. Must be aligned.
|
||||
*/
|
||||
'byteOffset'?: number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Sparse storage of attributes that deviate from their initialization value.
|
||||
*/
|
||||
export interface AccessorSparse {
|
||||
/**
|
||||
* Number of entries stored in the sparse array.
|
||||
*/
|
||||
'count': number;
|
||||
/**
|
||||
* Index array of size `count` that points to those accessor attributes that deviate from their initialization value. Indices must strictly increase.
|
||||
*/
|
||||
'indices': AccessorSparseIndices;
|
||||
/**
|
||||
* Array of size `count` times number of components, storing the displaced accessor attributes pointed by `indices`. Substituted values must have the same `componentType` and number of components as the base accessor.
|
||||
*/
|
||||
'values': AccessorSparseValues;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A typed view into a bufferView. A bufferView contains raw binary data. An accessor provides a typed view into a bufferView or a subset of a bufferView similar to how WebGL's `vertexAttribPointer()` defines an attribute in a buffer.
|
||||
*/
|
||||
export interface Accessor {
|
||||
/**
|
||||
* The index of the bufferView.
|
||||
*/
|
||||
'bufferView'?: GlTfId;
|
||||
/**
|
||||
* The offset relative to the start of the bufferView in bytes.
|
||||
*/
|
||||
'byteOffset'?: number;
|
||||
/**
|
||||
* The datatype of components in the attribute.
|
||||
*/
|
||||
'componentType': 5120 | 5121 | 5122 | 5123 | 5125 | 5126 | number;
|
||||
/**
|
||||
* Specifies whether integer data values should be normalized.
|
||||
*/
|
||||
'normalized'?: boolean;
|
||||
/**
|
||||
* The number of attributes referenced by this accessor.
|
||||
*/
|
||||
'count': number;
|
||||
/**
|
||||
* Specifies if the attribute is a scalar, vector, or matrix.
|
||||
*/
|
||||
'type': 'SCALAR' | 'VEC2' | 'VEC3' | 'VEC4' | 'MAT2' | 'MAT3' | 'MAT4' | string;
|
||||
/**
|
||||
* Maximum value of each component in this attribute.
|
||||
*/
|
||||
'max'?: number[];
|
||||
/**
|
||||
* Minimum value of each component in this attribute.
|
||||
*/
|
||||
'min'?: number[];
|
||||
/**
|
||||
* Sparse storage of attributes that deviate from their initialization value.
|
||||
*/
|
||||
'sparse'?: AccessorSparse;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* The index of the node and TRS property that an animation channel targets.
|
||||
*/
|
||||
export interface AnimationChannelTarget {
|
||||
/**
|
||||
* The index of the node to target.
|
||||
*/
|
||||
'node'?: GlTfId;
|
||||
/**
|
||||
* The name of the node's TRS property to modify, or the "weights" of the Morph Targets it instantiates. For the "translation" property, the values that are provided by the sampler are the translation along the x, y, and z axes. For the "rotation" property, the values are a quaternion in the order (x, y, z, w), where w is the scalar. For the "scale" property, the values are the scaling factors along the x, y, and z axes.
|
||||
*/
|
||||
'path': 'translation' | 'rotation' | 'scale' | 'weights' | string;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Targets an animation's sampler at a node's property.
|
||||
*/
|
||||
export interface AnimationChannel {
|
||||
/**
|
||||
* The index of a sampler in this animation used to compute the value for the target.
|
||||
*/
|
||||
'sampler': GlTfId;
|
||||
/**
|
||||
* The index of the node and TRS property to target.
|
||||
*/
|
||||
'target': AnimationChannelTarget;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
||||
*/
|
||||
export interface AnimationSampler {
|
||||
/**
|
||||
* The index of an accessor containing keyframe input values, e.g., time.
|
||||
*/
|
||||
'input': GlTfId;
|
||||
/**
|
||||
* Interpolation algorithm.
|
||||
*/
|
||||
'interpolation'?: 'LINEAR' | 'STEP' | 'CUBICSPLINE' | string;
|
||||
/**
|
||||
* The index of an accessor, containing keyframe output values.
|
||||
*/
|
||||
'output': GlTfId;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A keyframe animation.
|
||||
*/
|
||||
export interface Animation {
|
||||
/**
|
||||
* An array of channels, each of which targets an animation's sampler at a node's property. Different channels of the same animation can't have equal targets.
|
||||
*/
|
||||
'channels': AnimationChannel[];
|
||||
/**
|
||||
* An array of samplers that combines input and output accessors with an interpolation algorithm to define a keyframe graph (but not its target).
|
||||
*/
|
||||
'samplers': AnimationSampler[];
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Metadata about the glTF asset.
|
||||
*/
|
||||
export interface Asset {
|
||||
/**
|
||||
* A copyright message suitable for display to credit the content creator.
|
||||
*/
|
||||
'copyright'?: string;
|
||||
/**
|
||||
* Tool that generated this glTF model. Useful for debugging.
|
||||
*/
|
||||
'generator'?: string;
|
||||
/**
|
||||
* The glTF version that this asset targets.
|
||||
*/
|
||||
'version': string;
|
||||
/**
|
||||
* The minimum glTF version that this asset targets.
|
||||
*/
|
||||
'minVersion'?: string;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A buffer points to binary geometry, animation, or skins.
|
||||
*/
|
||||
export interface Buffer {
|
||||
/**
|
||||
* The uri of the buffer.
|
||||
*/
|
||||
'uri'?: string;
|
||||
/**
|
||||
* The length of the buffer in bytes.
|
||||
*/
|
||||
'byteLength': number;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A view into a buffer generally representing a subset of the buffer.
|
||||
*/
|
||||
export interface BufferView {
|
||||
/**
|
||||
* The index of the buffer.
|
||||
*/
|
||||
'buffer': GlTfId;
|
||||
/**
|
||||
* The offset into the buffer in bytes.
|
||||
*/
|
||||
'byteOffset'?: number;
|
||||
/**
|
||||
* The length of the bufferView in bytes.
|
||||
*/
|
||||
'byteLength': number;
|
||||
/**
|
||||
* The stride, in bytes.
|
||||
*/
|
||||
'byteStride'?: number;
|
||||
/**
|
||||
* The target that the GPU buffer should be bound to.
|
||||
*/
|
||||
'target'?: 34962 | 34963 | number;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* An orthographic camera containing properties to create an orthographic projection matrix.
|
||||
*/
|
||||
export interface CameraOrthographic {
|
||||
/**
|
||||
* The floating-point horizontal magnification of the view. Must not be zero.
|
||||
*/
|
||||
'xmag': number;
|
||||
/**
|
||||
* The floating-point vertical magnification of the view. Must not be zero.
|
||||
*/
|
||||
'ymag': number;
|
||||
/**
|
||||
* The floating-point distance to the far clipping plane. `zfar` must be greater than `znear`.
|
||||
*/
|
||||
'zfar': number;
|
||||
/**
|
||||
* The floating-point distance to the near clipping plane.
|
||||
*/
|
||||
'znear': number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A perspective camera containing properties to create a perspective projection matrix.
|
||||
*/
|
||||
export interface CameraPerspective {
|
||||
/**
|
||||
* The floating-point aspect ratio of the field of view.
|
||||
*/
|
||||
'aspectRatio'?: number;
|
||||
/**
|
||||
* The floating-point vertical field of view in radians.
|
||||
*/
|
||||
'yfov': number;
|
||||
/**
|
||||
* The floating-point distance to the far clipping plane.
|
||||
*/
|
||||
'zfar'?: number;
|
||||
/**
|
||||
* The floating-point distance to the near clipping plane.
|
||||
*/
|
||||
'znear': number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A camera's projection. A node can reference a camera to apply a transform to place the camera in the scene.
|
||||
*/
|
||||
export interface Camera {
|
||||
/**
|
||||
* An orthographic camera containing properties to create an orthographic projection matrix.
|
||||
*/
|
||||
'orthographic'?: CameraOrthographic;
|
||||
/**
|
||||
* A perspective camera containing properties to create a perspective projection matrix.
|
||||
*/
|
||||
'perspective'?: CameraPerspective;
|
||||
/**
|
||||
* Specifies if the camera uses a perspective or orthographic projection.
|
||||
*/
|
||||
'type': 'perspective' | 'orthographic' | string;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Image data used to create a texture. Image can be referenced by URI or `bufferView` index. `mimeType` is required in the latter case.
|
||||
*/
|
||||
export interface Image {
|
||||
/**
|
||||
* The uri of the image.
|
||||
*/
|
||||
'uri'?: string;
|
||||
/**
|
||||
* The image's MIME type. Required if `bufferView` is defined.
|
||||
*/
|
||||
'mimeType'?: 'image/jpeg' | 'image/png' | string;
|
||||
/**
|
||||
* The index of the bufferView that contains the image. Use this instead of the image's uri property.
|
||||
*/
|
||||
'bufferView'?: GlTfId;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Reference to a texture.
|
||||
*/
|
||||
export interface TextureInfo {
|
||||
/**
|
||||
* The index of the texture.
|
||||
*/
|
||||
'index': GlTfId;
|
||||
/**
|
||||
* The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
|
||||
*/
|
||||
'texCoord'?: number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology.
|
||||
*/
|
||||
export interface MaterialPbrMetallicRoughness {
|
||||
/**
|
||||
* The material's base color factor.
|
||||
*/
|
||||
'baseColorFactor'?: number[];
|
||||
/**
|
||||
* The base color texture.
|
||||
*/
|
||||
'baseColorTexture'?: TextureInfo;
|
||||
/**
|
||||
* The metalness of the material.
|
||||
*/
|
||||
'metallicFactor'?: number;
|
||||
/**
|
||||
* The roughness of the material.
|
||||
*/
|
||||
'roughnessFactor'?: number;
|
||||
/**
|
||||
* The metallic-roughness texture.
|
||||
*/
|
||||
'metallicRoughnessTexture'?: TextureInfo;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
export interface MaterialNormalTextureInfo {
|
||||
'index'?: any;
|
||||
'texCoord'?: any;
|
||||
/**
|
||||
* The scalar multiplier applied to each normal vector of the normal texture.
|
||||
*/
|
||||
'scale'?: number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
export interface MaterialOcclusionTextureInfo {
|
||||
'index'?: any;
|
||||
'texCoord'?: any;
|
||||
/**
|
||||
* A scalar multiplier controlling the amount of occlusion applied.
|
||||
*/
|
||||
'strength'?: number;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* The material appearance of a primitive.
|
||||
*/
|
||||
export interface Material {
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
/**
|
||||
* A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology. When not specified, all the default values of `pbrMetallicRoughness` apply.
|
||||
*/
|
||||
'pbrMetallicRoughness'?: MaterialPbrMetallicRoughness;
|
||||
/**
|
||||
* The normal map texture.
|
||||
*/
|
||||
'normalTexture'?: MaterialNormalTextureInfo;
|
||||
/**
|
||||
* The occlusion map texture.
|
||||
*/
|
||||
'occlusionTexture'?: MaterialOcclusionTextureInfo;
|
||||
/**
|
||||
* The emissive map texture.
|
||||
*/
|
||||
'emissiveTexture'?: TextureInfo;
|
||||
/**
|
||||
* The emissive color of the material.
|
||||
*/
|
||||
'emissiveFactor'?: number[];
|
||||
/**
|
||||
* The alpha rendering mode of the material.
|
||||
*/
|
||||
'alphaMode'?: 'OPAQUE' | 'MASK' | 'BLEND' | string;
|
||||
/**
|
||||
* The alpha cutoff value of the material.
|
||||
*/
|
||||
'alphaCutoff'?: number;
|
||||
/**
|
||||
* Specifies whether the material is double sided.
|
||||
*/
|
||||
'doubleSided'?: boolean;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Geometry to be rendered with the given material.
|
||||
*/
|
||||
export interface MeshPrimitive {
|
||||
/**
|
||||
* A dictionary object, where each key corresponds to mesh attribute semantic and each value is the index of the accessor containing attribute's data.
|
||||
*/
|
||||
'attributes': {
|
||||
[k: string]: GlTfId;
|
||||
};
|
||||
/**
|
||||
* The index of the accessor that contains the indices.
|
||||
*/
|
||||
'indices'?: GlTfId;
|
||||
/**
|
||||
* The index of the material to apply to this primitive when rendering.
|
||||
*/
|
||||
'material'?: GlTfId;
|
||||
/**
|
||||
* The type of primitives to render.
|
||||
*/
|
||||
'mode'?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | number;
|
||||
/**
|
||||
* An array of Morph Targets, each Morph Target is a dictionary mapping attributes (only `POSITION`, `NORMAL`, and `TANGENT` supported) to their deviations in the Morph Target.
|
||||
*/
|
||||
'targets'?: {
|
||||
[k: string]: GlTfId;
|
||||
}[];
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A set of primitives to be rendered. A node can contain one mesh. A node's transform places the mesh in the scene.
|
||||
*/
|
||||
export interface Mesh {
|
||||
/**
|
||||
* An array of primitives, each defining geometry to be rendered with a material.
|
||||
*/
|
||||
'primitives': MeshPrimitive[];
|
||||
/**
|
||||
* Array of weights to be applied to the Morph Targets.
|
||||
*/
|
||||
'weights'?: number[];
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A node in the node hierarchy. When the node contains `skin`, all `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes. A node can have either a `matrix` or any combination of `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted to matrices and postmultiplied in the `T * R * S` order to compose the transformation matrix; first the scale is applied to the vertices, then the rotation, and then the translation. If none are provided, the transform is the identity. When a node is targeted for animation (referenced by an animation.channel.target), only TRS properties may be present; `matrix` will not be present.
|
||||
*/
|
||||
export interface Node {
|
||||
/**
|
||||
* The index of the camera referenced by this node.
|
||||
*/
|
||||
'camera'?: GlTfId;
|
||||
/**
|
||||
* The indices of this node's children.
|
||||
*/
|
||||
'children'?: GlTfId[];
|
||||
/**
|
||||
* The index of the skin referenced by this node.
|
||||
*/
|
||||
'skin'?: GlTfId;
|
||||
/**
|
||||
* A floating-point 4x4 transformation matrix stored in column-major order.
|
||||
*/
|
||||
'matrix'?: number[];
|
||||
/**
|
||||
* The index of the mesh in this node.
|
||||
*/
|
||||
'mesh'?: GlTfId;
|
||||
/**
|
||||
* The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
|
||||
*/
|
||||
'rotation'?: number[];
|
||||
/**
|
||||
* The node's non-uniform scale, given as the scaling factors along the x, y, and z axes.
|
||||
*/
|
||||
'scale'?: number[];
|
||||
/**
|
||||
* The node's translation along the x, y, and z axes.
|
||||
*/
|
||||
'translation'?: number[];
|
||||
/**
|
||||
* The weights of the instantiated Morph Target. Number of elements must match number of Morph Targets of used mesh.
|
||||
*/
|
||||
'weights'?: number[];
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Texture sampler properties for filtering and wrapping modes.
|
||||
*/
|
||||
export interface Sampler {
|
||||
/**
|
||||
* Magnification filter.
|
||||
*/
|
||||
'magFilter'?: 9728 | 9729 | number;
|
||||
/**
|
||||
* Minification filter.
|
||||
*/
|
||||
'minFilter'?: 9728 | 9729 | 9984 | 9985 | 9986 | 9987 | number;
|
||||
/**
|
||||
* s wrapping mode.
|
||||
*/
|
||||
'wrapS'?: 33071 | 33648 | 10497 | number;
|
||||
/**
|
||||
* t wrapping mode.
|
||||
*/
|
||||
'wrapT'?: 33071 | 33648 | 10497 | number;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* The root nodes of a scene.
|
||||
*/
|
||||
export interface Scene {
|
||||
/**
|
||||
* The indices of each root node.
|
||||
*/
|
||||
'nodes'?: GlTfId[];
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* Joints and matrices defining a skin.
|
||||
*/
|
||||
export interface Skin {
|
||||
/**
|
||||
* The index of the accessor containing the floating-point 4x4 inverse-bind matrices. The default is that each matrix is a 4x4 identity matrix, which implies that inverse-bind matrices were pre-applied.
|
||||
*/
|
||||
'inverseBindMatrices'?: GlTfId;
|
||||
/**
|
||||
* The index of the node used as a skeleton root. When undefined, joints transforms resolve to scene root.
|
||||
*/
|
||||
'skeleton'?: GlTfId;
|
||||
/**
|
||||
* Indices of skeleton nodes, used as joints in this skin.
|
||||
*/
|
||||
'joints': GlTfId[];
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* A texture and its sampler.
|
||||
*/
|
||||
export interface Texture {
|
||||
/**
|
||||
* The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used.
|
||||
*/
|
||||
'sampler'?: GlTfId;
|
||||
/**
|
||||
* The index of the image used by this texture.
|
||||
*/
|
||||
'source'?: GlTfId;
|
||||
'name'?: any;
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
/**
|
||||
* The root object for a glTF asset.
|
||||
*/
|
||||
export interface GlTf {
|
||||
/**
|
||||
* Names of glTF extensions used somewhere in this asset.
|
||||
*/
|
||||
'extensionsUsed'?: string[];
|
||||
/**
|
||||
* Names of glTF extensions required to properly load this asset.
|
||||
*/
|
||||
'extensionsRequired'?: string[];
|
||||
/**
|
||||
* An array of accessors.
|
||||
*/
|
||||
'accessors'?: Accessor[];
|
||||
/**
|
||||
* An array of keyframe animations.
|
||||
*/
|
||||
'animations'?: Animation[];
|
||||
/**
|
||||
* Metadata about the glTF asset.
|
||||
*/
|
||||
'asset': Asset;
|
||||
/**
|
||||
* An array of buffers.
|
||||
*/
|
||||
'buffers'?: Buffer[];
|
||||
/**
|
||||
* An array of bufferViews.
|
||||
*/
|
||||
'bufferViews'?: BufferView[];
|
||||
/**
|
||||
* An array of cameras.
|
||||
*/
|
||||
'cameras'?: Camera[];
|
||||
/**
|
||||
* An array of images.
|
||||
*/
|
||||
'images'?: Image[];
|
||||
/**
|
||||
* An array of materials.
|
||||
*/
|
||||
'materials'?: Material[];
|
||||
/**
|
||||
* An array of meshes.
|
||||
*/
|
||||
'meshes'?: Mesh[];
|
||||
/**
|
||||
* An array of nodes.
|
||||
*/
|
||||
'nodes'?: Node[];
|
||||
/**
|
||||
* An array of samplers.
|
||||
*/
|
||||
'samplers'?: Sampler[];
|
||||
/**
|
||||
* The index of the default scene.
|
||||
*/
|
||||
'scene'?: GlTfId;
|
||||
/**
|
||||
* An array of scenes.
|
||||
*/
|
||||
'scenes'?: Scene[];
|
||||
/**
|
||||
* An array of skins.
|
||||
*/
|
||||
'skins'?: Skin[];
|
||||
/**
|
||||
* An array of textures.
|
||||
*/
|
||||
'textures'?: Texture[];
|
||||
'extensions'?: any;
|
||||
'extras'?: any;
|
||||
[k: string]: any;
|
||||
}
|
||||
109
extensions/app/engine/@types/packages/engine-extends/@types/gltf-validator.d.ts
vendored
Normal file
109
extensions/app/engine/@types/packages/engine-extends/@types/gltf-validator.d.ts
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
declare module 'gltf-validator' {
|
||||
/**
|
||||
* Returns a version string.
|
||||
*/
|
||||
export const version: string;
|
||||
|
||||
/**
|
||||
* Returns an array of supported extensions names.
|
||||
*/
|
||||
export const supportedExtensions: string[];
|
||||
|
||||
/**
|
||||
* @param uri Relative URI of the external resource.
|
||||
* @returns Promise with Uint8Array data.
|
||||
*/
|
||||
export type ExternalResourceFunction = (uri: string) => Promise<Uint8Array>;
|
||||
|
||||
export interface ValidationOptions {
|
||||
/**
|
||||
* Absolute or relative asset URI that will be copied to validation report.
|
||||
*/
|
||||
uri?: string;
|
||||
|
||||
/**
|
||||
* Max number of reported issues. Use 0 for unlimited output.
|
||||
*/
|
||||
maxIssues?: number;
|
||||
|
||||
/**
|
||||
* Array of ignored issue codes.
|
||||
*/
|
||||
ignoredIssues?: string[];
|
||||
|
||||
/**
|
||||
* Object with overridden severities for issue codes.
|
||||
*/
|
||||
severityOverrides?: {
|
||||
[x: string]: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function for loading external resources. If omitted, external resources are not validated.
|
||||
*/
|
||||
externalResourceFunction?: ExternalResourceFunction;
|
||||
|
||||
/**
|
||||
* Set to false to skip reading of accessor data.
|
||||
*/
|
||||
validateAccessorData?: boolean;
|
||||
}
|
||||
|
||||
export interface Resource {
|
||||
pointer: string;
|
||||
mimeType: string;
|
||||
storage: string;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface Report {
|
||||
uri: string;
|
||||
mimeType: string;
|
||||
validatorVersion: string;
|
||||
validatedAt: string;
|
||||
issues: {
|
||||
numErrors: number;
|
||||
numWarnings: number;
|
||||
numInfos: number;
|
||||
numHints: number;
|
||||
messages: Array<{
|
||||
code: string;
|
||||
message: string;
|
||||
pointer: string;
|
||||
severity: number;
|
||||
}>;
|
||||
truncated: boolean;
|
||||
};
|
||||
info: {
|
||||
version: string;
|
||||
generator: string;
|
||||
resources: Array<{
|
||||
pointer: string;
|
||||
mimeType: string;
|
||||
storage: string;
|
||||
uri: string;
|
||||
}>;
|
||||
hasAnimations: boolean;
|
||||
hasMaterials: boolean;
|
||||
hasMorphTargets: boolean;
|
||||
hasSkins: boolean;
|
||||
hasTextures: boolean;
|
||||
hasDefaultScene: boolean;
|
||||
primitivesCount: number;
|
||||
maxAttributesUsed: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function validateBytes(data: Uint8Array, options?: ValidationOptions): Promise<Report>;
|
||||
|
||||
export function validateString(json: string, options?: ValidationOptions): Promise<Report>;
|
||||
|
||||
export const enum Severity {
|
||||
Error = 0,
|
||||
|
||||
Warning = 1,
|
||||
|
||||
Information = 2,
|
||||
}
|
||||
}
|
||||
811
extensions/app/engine/@types/packages/engine-extends/@types/i18n-well-defined.d.ts
vendored
Normal file
811
extensions/app/engine/@types/packages/engine-extends/@types/i18n-well-defined.d.ts
vendored
Normal file
@@ -0,0 +1,811 @@
|
||||
declare module '@base/electron-i18n' {
|
||||
export function translation(key: string, language?: any): string;
|
||||
}
|
||||
|
||||
declare interface I18NWellDefinedDictionary {
|
||||
['about.title']: [];
|
||||
['about.editor']: [];
|
||||
['about.engine']: [];
|
||||
['about.version']: [];
|
||||
['animator.title']: [];
|
||||
['animator.loading.wait_scene_ready']: [];
|
||||
['animator.loading.init_animation_data']: [];
|
||||
['animator.mask.need_select_node']: [];
|
||||
['animator.mask.need_animation_component']: [];
|
||||
['animator.mask.need_animation_clip']: [];
|
||||
['animator.mask.enter_animation_mode']: [];
|
||||
['animator.mask.add_animation_component']: [];
|
||||
['animator.mask.add_animation_clip']: [];
|
||||
['animator.toolbar.exit']: [];
|
||||
['animator.toolbar.setting']: [];
|
||||
['animator.toolbar.order']: [];
|
||||
['animator.toolbar.jump_first_frame']: [];
|
||||
['animator.toolbar.jump_prev_frame']: [];
|
||||
['animator.toolbar.play_animation']: [];
|
||||
['animator.toolbar.stop_animation']: [];
|
||||
['animator.toolbar.pause_animation']: [];
|
||||
['animator.toolbar.jump_next_frame']: [];
|
||||
['animator.toolbar.jump_last_frame']: [];
|
||||
['animator.toolbar.insert_event']: [];
|
||||
['animator.toolbar.save_clip']: [];
|
||||
['animator.property.title']: [];
|
||||
['animator.property.create_prop']: [];
|
||||
['animator.property.remove_prop']: [];
|
||||
['animator.property.clear_keys']: [];
|
||||
['animator.property.create_key']: [];
|
||||
['animator.property.remove_key']: [];
|
||||
['animator.property.copy_key']: [];
|
||||
['animator.property.paste_key']: [];
|
||||
['animator.property.spacing_key']: [];
|
||||
['animator.property.spacing_frame']: [];
|
||||
['animator.event.title']: [];
|
||||
['animator.event.add_func']: [];
|
||||
['animator.event.del_func']: [];
|
||||
['animator.event.add_params']: [];
|
||||
['animator.event.del_params']: [];
|
||||
['animator.event.clear_params']: [];
|
||||
['animator.event.create']: [];
|
||||
['animator.event.paste']: [];
|
||||
['animator.bezier.title']: [];
|
||||
['animator.bezier.click_to_apply']: [];
|
||||
['animator.node.title']: [];
|
||||
['animator.node.move_data']: [];
|
||||
['animator.node.move_data_to']: [];
|
||||
['animator.node.clear_data']: [];
|
||||
['animator.preview_row.line_tips']: [];
|
||||
['animator.preview_row.open_curve_editor']: [];
|
||||
['animator.preview_row.asset_type_should_be']: [];
|
||||
['animator.preview_row.asset_position_tips']: [];
|
||||
['animator.is_save']: [];
|
||||
['animator.is_save_message']: [];
|
||||
['animator.is_paste_overwrite']: [];
|
||||
['animator.is_paste_overwrite_message']: [];
|
||||
['animator.overwrite']: [];
|
||||
['animator.is_clear']: [];
|
||||
['animator.is_clear_message']: [];
|
||||
['animator.is_move_data']: [];
|
||||
['animator.is_move_data_message']: [];
|
||||
['animator.is_remove_prop.title']: [];
|
||||
['animator.is_remove_prop.message']: [];
|
||||
['animator.is_remove_prop.remove']: [];
|
||||
['animator.is_clear_prop.title']: [];
|
||||
['animator.is_clear_prop.message']: [];
|
||||
['animator.is_clear_prop.remove']: [];
|
||||
['animator.move']: [];
|
||||
['animator.clear']: [];
|
||||
['animator.copy']: [];
|
||||
['animator.paste']: [];
|
||||
['animator.save']: [];
|
||||
['animator.abort']: [];
|
||||
['animator.cancel']: [];
|
||||
['animator.edit']: [];
|
||||
['animator.delete']: [];
|
||||
['animator.toolbar.spacing_frame']: [];
|
||||
['asset-db.mask.startup']: [];
|
||||
['asset-db.mask.loading']: [];
|
||||
['asset-db.debug-mode']: [];
|
||||
['asset-db.operate.dialogError']: [];
|
||||
['asset-db.operate.dialogWarning']: [];
|
||||
['asset-db.operate.dialogQuestion']: [];
|
||||
['asset-db.operate.dialogInfo']: [];
|
||||
['asset-db.fail.readonly']: [];
|
||||
['asset-db.createAsset.fail.unknown']: [];
|
||||
['asset-db.createAsset.fail.url']: [];
|
||||
['asset-db.createAsset.fail.exist']: [];
|
||||
['asset-db.createAsset.fail.drop']: [];
|
||||
['asset-db.createAsset.fail.toUrl']: [];
|
||||
['asset-db.createAsset.fail.uuid']: [];
|
||||
['asset-db.createAsset.fail.content']: [];
|
||||
['asset-db.createAsset.fail.readonly']: [];
|
||||
['asset-db.createAsset.warn.overwrite']: [];
|
||||
['asset-db.dropAsset.overwrite']: [];
|
||||
['asset-db.dropAsset.reserve']: [];
|
||||
['asset-db.dropAsset.fail.unknown']: [];
|
||||
['asset-db.dropAsset.fail.url']: [];
|
||||
['asset-db.dropAsset.fail.filepaths']: [];
|
||||
['asset-db.dropAsset.fail.readonly']: [];
|
||||
['asset-db.dropAsset.warn.overwrite']: [];
|
||||
['asset-db.dropAsset.warn.sameway']: [];
|
||||
['asset-db.saveAsset.fail.unknown']: [];
|
||||
['asset-db.saveAsset.fail.uuid']: [];
|
||||
['asset-db.saveAsset.fail.content']: [];
|
||||
['asset-db.saveAsset.fail.readonly']: [];
|
||||
['asset-db.saveAssetMeta.fail.unknown']: [];
|
||||
['asset-db.saveAssetMeta.fail.uuid']: [];
|
||||
['asset-db.saveAssetMeta.fail.content']: [];
|
||||
['asset-db.saveAssetMeta.fail.readonly']: [];
|
||||
['asset-db.copyAsset.fail.unknown']: [];
|
||||
['asset-db.copyAsset.fail.url']: [];
|
||||
['asset-db.copyAsset.fail.source']: [];
|
||||
['asset-db.copyAsset.fail.target']: [];
|
||||
['asset-db.copyAsset.fail.include']: [];
|
||||
['asset-db.copyAsset.fail.parent']: [];
|
||||
['asset-db.copyAsset.fail.readonly']: [];
|
||||
['asset-db.copyAsset.fail.metauuid']: [];
|
||||
['asset-db.moveAsset.fail.unknown']: [];
|
||||
['asset-db.moveAsset.fail.url']: [];
|
||||
['asset-db.moveAsset.fail.source']: [];
|
||||
['asset-db.moveAsset.fail.target']: [];
|
||||
['asset-db.moveAsset.fail.exist']: [];
|
||||
['asset-db.moveAsset.fail.include']: [];
|
||||
['asset-db.moveAsset.fail.parent']: [];
|
||||
['asset-db.moveAsset.fail.readonly_source']: [];
|
||||
['asset-db.moveAsset.fail.readonly']: [];
|
||||
['asset-db.moveAsset.warn.overwrite']: [];
|
||||
['asset-db.deleteAsset.fail.unknown']: [];
|
||||
['asset-db.deleteAsset.fail.url']: [];
|
||||
['asset-db.deleteAsset.fail.unexist']: [];
|
||||
['asset-db.deleteAsset.fail.readonly']: [];
|
||||
['asset-db.preferences.log_level']: [];
|
||||
['asset-db.preferences.log_level_debug']: [];
|
||||
['asset-db.preferences.log_level_log']: [];
|
||||
['asset-db.preferences.log_level_warn']: [];
|
||||
['asset-db.preferences.log_level_error']: [];
|
||||
['asset-db.importers.glTF.glTF_asset_group_mesh']: [];
|
||||
['asset-db.importers.glTF.glTF_asset_group_animation']: [];
|
||||
['asset-db.importers.glTF.glTF_asset_group_node']: [];
|
||||
['asset-db.importers.glTF.glTF_asset_group_skin']: [];
|
||||
['asset-db.importers.glTF.glTF_asset_group_sampler']: [];
|
||||
['asset-db.importers.glTF.glTF_asset']: [{
|
||||
group: any;
|
||||
index: any;
|
||||
name: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.glTF_asset_no_name']: [{
|
||||
group: any;
|
||||
index: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.unsupported_alpha_mode']: [{
|
||||
material: any;
|
||||
mode: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.unsupported_texture_parameter']: [{
|
||||
texture: any;
|
||||
sampler: any;
|
||||
type: any;
|
||||
value: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.texture_parameter_min_filter']: [];
|
||||
['asset-db.importers.glTF.texture_parameter_mag_filter']: [];
|
||||
['asset-db.importers.glTF.unsupported_channel_path']: [{
|
||||
animation: any;
|
||||
channel: any;
|
||||
path: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.reference_skin_in_different_scene']: [{
|
||||
node: any;
|
||||
skin: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.disallow_cubic_spline_channel_split']: [{
|
||||
animation: any;
|
||||
channel: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.failed_to_calculate_tangents_due_to_lack_of_normals']: [{
|
||||
mesh: any;
|
||||
primitive: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.failed_to_calculate_tangents_due_to_lack_of_uvs']: [{
|
||||
mesh: any;
|
||||
primitive: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.failed_to_load_image']: [{
|
||||
url: any;
|
||||
reason: any;
|
||||
}];
|
||||
['asset-db.importers.glTF.image_uri_should_be_file_url']: [];
|
||||
['asset-db.importers.glTF.failed_to_convert_tga']: [];
|
||||
['asset-db.importers.fbx.failed_to_convert_fbx_file']: [{
|
||||
path: any;
|
||||
}];
|
||||
['asset-db.importers.fbx.no_available_fbx_temp_dir']: [];
|
||||
['asset-db.importers.fbx.fbx2glTF_exists_with_non_zero_code']: [{
|
||||
code: any;
|
||||
output: any;
|
||||
}];
|
||||
['asset-db.importers.javascript.transform_failure']: [{
|
||||
path: any;
|
||||
reason: any;
|
||||
}];
|
||||
['assets.title']: [];
|
||||
['assets.previewTitle']: [];
|
||||
['assets.menu.createMenu']: [];
|
||||
['assets.menu.searchPlaceholder_name']: [];
|
||||
['assets.menu.searchPlaceholder_uuid']: [];
|
||||
['assets.menu.searchPlaceholder_type']: [];
|
||||
['assets.menu.searchTip']: [];
|
||||
['assets.menu.search']: [];
|
||||
['assets.menu.searchName']: [];
|
||||
['assets.menu.searchUuid']: [];
|
||||
['assets.menu.searchType']: [];
|
||||
['assets.menu.sort']: [];
|
||||
['assets.menu.sortName']: [];
|
||||
['assets.menu.sortType']: [];
|
||||
['assets.menu.refresh']: [];
|
||||
['assets.menu.allExpand']: [];
|
||||
['assets.menu.allCollapse']: [];
|
||||
['assets.menu.new']: [];
|
||||
['assets.menu.newFolder']: [];
|
||||
['assets.menu.newJavaScript']: [];
|
||||
['assets.menu.newTypeScript']: [];
|
||||
['assets.menu.newCubeMap']: [];
|
||||
['assets.menu.newScene']: [];
|
||||
['assets.menu.newMaterial']: [];
|
||||
['assets.menu.newPhysicsMaterial']: [];
|
||||
['assets.menu.newEffect']: [];
|
||||
['assets.menu.newChunk']: [];
|
||||
['assets.menu.newAnimation']: [];
|
||||
['assets.menu.renderPipeline']: [];
|
||||
['assets.menu.forwardPipeline']: [];
|
||||
['assets.menu.renderPipelineTS']: [];
|
||||
['assets.menu.RenderFlowTS']: [];
|
||||
['assets.menu.RenderStageTS']: [];
|
||||
['assets.menu.newPac']: [];
|
||||
['assets.menu.newTerrain']: [];
|
||||
['assets.menu.copy']: [];
|
||||
['assets.menu.cut']: [];
|
||||
['assets.menu.paste']: [];
|
||||
['assets.menu.delete']: [];
|
||||
['assets.menu.rename']: [];
|
||||
['assets.menu.selectall']: [];
|
||||
['assets.menu.readonly']: [];
|
||||
['assets.menu.revealInlibrary']: [];
|
||||
['assets.menu.reimport']: [];
|
||||
['assets.menu.revealInExplorer']: [];
|
||||
['assets.menu.showUuid']: [];
|
||||
['assets.menu.recommendTS']: [];
|
||||
['assets.operate.cutReady']: [];
|
||||
['assets.operate.cutDone']: [];
|
||||
['assets.operate.copyReady']: [];
|
||||
['assets.operate.copyDone']: [];
|
||||
['assets.operate.dialogError']: [];
|
||||
['assets.operate.dialogWarning']: [];
|
||||
['assets.operate.dialogQuestion']: [];
|
||||
['assets.operate.dialogInfo']: [];
|
||||
['assets.operate.refreshing']: [];
|
||||
['assets.operate.assetDataError']: [];
|
||||
['assets.operate.sureDelete']: [{
|
||||
length: any;
|
||||
filelist: any;
|
||||
}];
|
||||
['assets.operate.renameFail']: [];
|
||||
['assets.operate.pasteFail_parent_into_child']: [];
|
||||
['assets.operate.refreshFail']: [];
|
||||
['assets.operate.readDefaultFileFail']: [];
|
||||
['assets.operate.errorNewnameDuplicate']: [];
|
||||
['assets.operate.errorNewnameUnlegal']: [];
|
||||
['assets.operate.errorNewnameEmpty']: [];
|
||||
['assets.operate.errorScriptName']: [];
|
||||
['assets.operate.errorScriptClassName']: [];
|
||||
['assets.deprecate.fire']: [];
|
||||
['builder.title']: [];
|
||||
['builder.create_user_template']: [];
|
||||
['builder.build_config']: [];
|
||||
['builder.build']: [];
|
||||
['builder.compile']: [];
|
||||
['builder.select_all']: [];
|
||||
['builder.open_compile_file']: [];
|
||||
['builder.source_map']: [];
|
||||
['builder.recompile_engine']: [];
|
||||
['builder.debug_mode']: [];
|
||||
['builder.web_debugger']: [];
|
||||
['builder.require']: [];
|
||||
['builder.new_build_task']: [];
|
||||
['builder.empty_task_holder']: [];
|
||||
['builder.empty_scene']: [];
|
||||
['builder.reveal_in_explorer']: [];
|
||||
['builder.view_build_config']: [];
|
||||
['builder.recompile']: [];
|
||||
['builder.compress_texture']: [];
|
||||
['builder.pack_autoAtlas']: [];
|
||||
['builder.replace_splash_screen']: [];
|
||||
['builder.run']: [];
|
||||
['builder.open']: [];
|
||||
['builder.export']: [];
|
||||
['builder.import']: [];
|
||||
['builder.export_build_config']: [];
|
||||
['builder.import_build_config']: [];
|
||||
['builder.include_project_setting']: [];
|
||||
['builder.only_build_panel']: [];
|
||||
['builder.options.taskName']: [];
|
||||
['builder.options.name']: [];
|
||||
['builder.options.platform']: [];
|
||||
['builder.options.build_path']: [];
|
||||
['builder.options.start_scene']: [];
|
||||
['builder.options.inline_SpriteFrames']: [];
|
||||
['builder.options.merge_json_by_scene']: [];
|
||||
['builder.options.merge_start_scene']: [];
|
||||
['builder.options.orientation']: [];
|
||||
['builder.options.scenes']: [];
|
||||
['builder.options.debug']: [];
|
||||
['builder.options.resolution']: [];
|
||||
['builder.options.preview_url']: [];
|
||||
['builder.options.source_map']: [];
|
||||
['builder.options.force_combile_engine']: [];
|
||||
['builder.options.web_debugger']: [];
|
||||
['builder.options.compress_texture']: [];
|
||||
['builder.options.pack_autoAtlas']: [];
|
||||
['builder.package']: [];
|
||||
['builder.package_hint']: [];
|
||||
['builder.desktop_icon']: [];
|
||||
['builder.desktop_icon_hint']: [];
|
||||
['builder.version_name']: [];
|
||||
['builder.version_name_hint']: [];
|
||||
['builder.version_number']: [];
|
||||
['builder.version_number_hint']: [];
|
||||
['builder.support_min_platform']: [];
|
||||
['builder.support_min_platform_hint']: [];
|
||||
['builder.full_screen']: [];
|
||||
['builder.screen_orientation']: [];
|
||||
['builder.landscape']: [];
|
||||
['builder.portrait']: [];
|
||||
['builder.tiny_packet_mode']: [];
|
||||
['builder.tiny_packet_path']: [];
|
||||
['builder.tiny_packet_path_hint']: [];
|
||||
['builder.keystore']: [];
|
||||
['builder.use_debug_keystore']: [];
|
||||
['builder.private_pem_path']: [];
|
||||
['builder.private_pem_path_hint']: [];
|
||||
['builder.certificate_pem_path']: [];
|
||||
['builder.certificate_pem_path_hint']: [];
|
||||
['builder.print_finger']: [];
|
||||
['builder.pack_res_to_first_pack']: [];
|
||||
['builder.custom_npm_path']: [];
|
||||
['builder.custom_npm_path_hint']: [];
|
||||
['builder.custom_manifest_data']: [];
|
||||
['builder.custom_manifest_data_error']: [];
|
||||
['builder.remote_url']: [];
|
||||
['builder.not_install_nodejs_windows_error']: [];
|
||||
['builder.not_install_nodejs_mac_error']: [];
|
||||
['builder.rpk_installing']: [];
|
||||
['builder.rpk_install_fail']: [];
|
||||
['builder.rpk_install_success']: [];
|
||||
['builder.not_mainfest_data']: [];
|
||||
['builder.npm_installed_success']: [];
|
||||
['builder.npm_install_fail']: [];
|
||||
['builder.oppo.new']: [];
|
||||
['builder.oppo.not_empty']: [];
|
||||
['builder.oppo.icon_not_exist']: [];
|
||||
['builder.oppo.signature_not_exist']: [];
|
||||
['builder.oppo.private_pem_path_error']: [];
|
||||
['builder.oppo.certificate_pem_path_error']: [];
|
||||
['builder.certificate.country']: [];
|
||||
['builder.certificate.state']: [];
|
||||
['builder.certificate.locality']: [];
|
||||
['builder.certificate.organization']: [];
|
||||
['builder.certificate.organizationalUnit']: [];
|
||||
['builder.certificate.commonName']: [];
|
||||
['builder.certificate.email']: [];
|
||||
['builder.certificate.certificatePath']: [];
|
||||
['builder.certificate.generate']: [];
|
||||
['builder.certificate.build_certificate_complete']: [];
|
||||
['builder.certificate.build_certificate_fail']: [];
|
||||
['builder.huawei.select_certificate_path']: [];
|
||||
['builder.huawei.install_nodejs_before_view_certificate']: [];
|
||||
['builder.huawei.select_certificate_path_after_view_certificate']: [];
|
||||
['builder.huawei.certificate_fingerprint']: [];
|
||||
['builder.huawei.certificate_fingerprint_error']: [];
|
||||
['builder.huawei.use_native_renderer']: [];
|
||||
['builder.wechat_game.separate_engine']: [];
|
||||
['builder.wechat_game.separate_engine_tips']: [];
|
||||
['builder.wechat_game.client_path_error']: [{
|
||||
path: any;
|
||||
}];
|
||||
['builder.wechat_game.client_info_path_err']: [{
|
||||
path: any;
|
||||
}];
|
||||
['builder.wechat_game.client_version_low']: [];
|
||||
['builder.wechat_game.remote_server_address']: [];
|
||||
['builder.wechat_game.remote_server_address_tips']: [];
|
||||
['builder.wechat_game.sub_context']: [];
|
||||
['builder.wechat_game.sub_context_tips']: [];
|
||||
['builder.wechat_game.build_sub']: [];
|
||||
['builder.wechat_game.build_sub_tips']: [];
|
||||
['builder.wechat_game.wechatgame_app_path_empty']: [];
|
||||
['builder.error.build_error']: [];
|
||||
['builder.error.dirty_info']: [];
|
||||
['builder.error.build_dir_not_exists']: [{
|
||||
buildDir: any;
|
||||
}];
|
||||
['builder.error.build_path_contains_space']: [];
|
||||
['builder.error.build_path_contains_chinese']: [];
|
||||
['builder.error.can_not_empty']: [];
|
||||
['builder.error.project_name_not_legal']: [];
|
||||
['builder.error.package_name_not_legal']: [];
|
||||
['builder.error.package_name_start_with_number']: [];
|
||||
['builder.error.select_scenes_to_build']: [];
|
||||
['builder.error.binary_api_level']: [];
|
||||
['builder.error.path_too_long_title']: [];
|
||||
['builder.error.path_too_long_desc']: [{
|
||||
max_length: any;
|
||||
}];
|
||||
['builder.error.keep_raw_texture_of_atlas']: [{
|
||||
texturePath: any;
|
||||
pacPath: any;
|
||||
assetPath: any;
|
||||
}];
|
||||
['builder.error.arm64_not_support']: [{
|
||||
current_api: any;
|
||||
min_version: any;
|
||||
}];
|
||||
['builder.warn.same_url']: [];
|
||||
['builder.tasks.build_asset']: [];
|
||||
['builder.tasks.build_engine']: [];
|
||||
['builder.tasks.build_img']: [];
|
||||
['builder.tasks.build_json']: [];
|
||||
['builder.tasks.build_atlas']: [];
|
||||
['builder.tasks.build_script']: [];
|
||||
['builder.tasks.build_suffix']: [];
|
||||
['builder.tasks.build_template']: [];
|
||||
['builder.tasks.load_script']: [];
|
||||
['builder.tasks.sort_asset']: [];
|
||||
['builder.tasks.sort_image']: [];
|
||||
['builder.tasks.sort_script']: [];
|
||||
['builder.tasks.sort_sprite_frame']: [];
|
||||
['builder.tasks.sort_texture']: [];
|
||||
['builder.tasks.sort_json']: [];
|
||||
['builder.tasks.settings.compress']: [];
|
||||
['builder.tasks.settings.design_resolution']: [];
|
||||
['builder.tasks.settings.group']: [];
|
||||
['builder.tasks.settings.md5']: [];
|
||||
['builder.tasks.settings.scene']: [];
|
||||
['builder.tasks.settings.script']: [];
|
||||
['builder.tips.enter_name']: [];
|
||||
['builder.tips.taskName']: [];
|
||||
['builder.tips.build_path']: [];
|
||||
['builder.tips.build_scenes']: [];
|
||||
['builder.tips.inline_SpriteFrames']: [];
|
||||
['builder.tips.md5Cache']: [];
|
||||
['builder.tips.merge_start_scene']: [];
|
||||
['builder.tips.debug']: [];
|
||||
['builder.tips.resolution']: [];
|
||||
['builder.tips.web_debugger']: [];
|
||||
['builder.tips.creat_template_success']: [];
|
||||
['builder.tips.set_start_scene']: [];
|
||||
['builder.splash_setting.title']: [];
|
||||
['builder.splash_setting.drag_img_here']: [];
|
||||
['builder.splash_setting.img_loading']: [];
|
||||
['builder.splash_setting.confirm']: [];
|
||||
['builder.splash_setting.settings.total_time']: [];
|
||||
['builder.splash_setting.settings.display_ratio']: [];
|
||||
['builder.splash_setting.settings.clear_color']: [];
|
||||
['builder.splash_setting.settings.effect']: [];
|
||||
['builder.splash_setting.settings.display_watermark']: [];
|
||||
['builder.splash_setting.is_save_dialog.title']: [];
|
||||
['builder.splash_setting.is_save_dialog.save']: [];
|
||||
['builder.splash_setting.is_save_dialog.cancel']: [];
|
||||
['builder.splash_setting.is_save_dialog.abort']: [];
|
||||
['builder.is_remove_task.title']: [];
|
||||
['builder.is_remove_task.has_building_task']: [];
|
||||
['builder.is_remove_task.message']: [];
|
||||
['builder.is_remove_task.remove']: [];
|
||||
['builder.is_remove_task.deep_remove']: [];
|
||||
['builder.is_remove_task.cancel']: [];
|
||||
['builder.is_stop_build.title']: [];
|
||||
['builder.is_stop_build.message']: [];
|
||||
['builder.is_stop_build.stop']: [];
|
||||
['builder.is_stop_build.cancel']: [];
|
||||
['builder.is_close_win.title']: [];
|
||||
['builder.is_close_win.message']: [];
|
||||
['builder.is_close_win.force_close']: [];
|
||||
['builder.is_close_win.cancel']: [];
|
||||
['builder.is_save_scene.title']: [];
|
||||
['builder.is_save_scene.message']: [];
|
||||
['builder.is_save_scene.save']: [];
|
||||
['builder.is_save_scene.ignore']: [];
|
||||
['builder.is_save_scene.cancel']: [];
|
||||
['builder.merge_json_by_scene']: [];
|
||||
['builder.not_require']: [];
|
||||
['builder.options.open_compile_file']: [];
|
||||
['builder.custom_manifest_file_path']: [];
|
||||
['builder.custom_manifest_file_path_hint']: [];
|
||||
['builder.install_nodejs_before_view_certificate']: [];
|
||||
['builder.window_default_npm_path_error']: [];
|
||||
['builder.mac_default_npm_path_error']: [];
|
||||
['builder.oppo.package_name_error']: [];
|
||||
['builder.huawei.certificate_fingerprint_window_error']: [];
|
||||
['builder.huawei.certificate_fingerprint_mac_error']: [];
|
||||
['console.title']: [];
|
||||
['console.editorLog']: [];
|
||||
['console.cocosLog']: [];
|
||||
['console.tabbar.regex']: [];
|
||||
['console.preferences.display_date']: [];
|
||||
['console.preferences.font_size']: [];
|
||||
['console.preferences.line_height']: [];
|
||||
['engine.title']: [];
|
||||
['engine.compile_engine']: [];
|
||||
['engine.wait_quick_compile']: [];
|
||||
['engine.confirm']: [];
|
||||
['engine.browse']: [];
|
||||
['engine.open']: [];
|
||||
['engine.engine_directory_illegal']: [];
|
||||
['engine.engine_compile_failed']: [];
|
||||
['engine.engine_compile_crash']: [];
|
||||
['engine.javascript_engine']: [];
|
||||
['engine.use_builtin_engine']: [];
|
||||
['engine.custom_engine_path']: [];
|
||||
['engine.QUICK_COMPILER.engine_modified_info']: [];
|
||||
['engine.resources_docs_1']: [];
|
||||
['engine.resources_docs_2']: [];
|
||||
['engine.resources_docs_3']: [];
|
||||
['engine.resources_docs_4']: [];
|
||||
['hierarchy.title']: [];
|
||||
['hierarchy.menu.createMenu']: [];
|
||||
['hierarchy.menu.searchPlaceholder']: [];
|
||||
['hierarchy.menu.searchPlaceholder_name']: [];
|
||||
['hierarchy.menu.searchPlaceholder_uuid']: [];
|
||||
['hierarchy.menu.searchPlaceholder_component']: [];
|
||||
['hierarchy.menu.searchTip']: [];
|
||||
['hierarchy.menu.search']: [];
|
||||
['hierarchy.menu.searchName']: [];
|
||||
['hierarchy.menu.searchUuid']: [];
|
||||
['hierarchy.menu.searchComponent']: [];
|
||||
['hierarchy.menu.refresh']: [];
|
||||
['hierarchy.menu.allExpand']: [];
|
||||
['hierarchy.menu.allCollapse']: [];
|
||||
['hierarchy.menu.newNode']: [];
|
||||
['hierarchy.menu.newNodeEmpty']: [];
|
||||
['hierarchy.menu.new3dObject']: [];
|
||||
['hierarchy.menu.new3dCube']: [];
|
||||
['hierarchy.menu.new3dCylinder']: [];
|
||||
['hierarchy.menu.new3dSphere']: [];
|
||||
['hierarchy.menu.new3dCapsule']: [];
|
||||
['hierarchy.menu.new3dCone']: [];
|
||||
['hierarchy.menu.new3dTorus']: [];
|
||||
['hierarchy.menu.new3dPlane']: [];
|
||||
['hierarchy.menu.new3dQuad']: [];
|
||||
['hierarchy.menu.newLightObject']: [];
|
||||
['hierarchy.menu.newLightDirectional']: [];
|
||||
['hierarchy.menu.newLightSphere']: [];
|
||||
['hierarchy.menu.newLightSpot']: [];
|
||||
['hierarchy.menu.newCameraObject']: [];
|
||||
['hierarchy.menu.newTerrain']: [];
|
||||
['hierarchy.menu.newEffects']: [];
|
||||
['hierarchy.menu.newEffectsParticle']: [];
|
||||
['hierarchy.menu.newUI']: [];
|
||||
['hierarchy.menu.newUICanvas']: [];
|
||||
['hierarchy.menu.newUISprite']: [];
|
||||
['hierarchy.menu.newUILabel']: [];
|
||||
['hierarchy.menu.newUIButton']: [];
|
||||
['hierarchy.menu.newUIToggle']: [];
|
||||
['hierarchy.menu.newUIToggleGroup']: [];
|
||||
['hierarchy.menu.newUISlider']: [];
|
||||
['hierarchy.menu.newUIProgressBar']: [];
|
||||
['hierarchy.menu.newUIWidget']: [];
|
||||
['hierarchy.menu.newUIEditBox']: [];
|
||||
['hierarchy.menu.newUILayout']: [];
|
||||
['hierarchy.menu.newUIScrollView']: [];
|
||||
['hierarchy.menu.newUIMask']: [];
|
||||
['hierarchy.menu.copy']: [];
|
||||
['hierarchy.menu.cut']: [];
|
||||
['hierarchy.menu.paste']: [];
|
||||
['hierarchy.menu.delete']: [];
|
||||
['hierarchy.menu.rename']: [];
|
||||
['hierarchy.menu.duplicate']: [];
|
||||
['hierarchy.menu.showUuid']: [];
|
||||
['hierarchy.menu.link_prefab']: [];
|
||||
['hierarchy.menu.link_prefab_error_node_empty']: [];
|
||||
['hierarchy.menu.link_prefab_error_node_isScene']: [];
|
||||
['hierarchy.menu.link_prefab_error_asset_empty']: [];
|
||||
['hierarchy.menu.link_prefab_error_asset_invalid']: [];
|
||||
['hierarchy.menu.link_prefab_make_sure']: [];
|
||||
['hierarchy.menu.unlink_prefab']: [];
|
||||
['hierarchy.menu.unlink_prefab_error_prefab_empty']: [];
|
||||
['hierarchy.menu.errorNewnameEmpty']: [];
|
||||
['hierarchy.operate.cutReady']: [];
|
||||
['hierarchy.operate.cutDone']: [];
|
||||
['hierarchy.operate.copyReady']: [];
|
||||
['hierarchy.operate.copyDone']: [];
|
||||
['hierarchy.operate.duplicateDone']: [];
|
||||
['hierarchy.operate.dialogError']: [];
|
||||
['hierarchy.operate.dialogWarning']: [];
|
||||
['hierarchy.operate.dialogQuestion']: [];
|
||||
['hierarchy.operate.dialogInfo']: [];
|
||||
['hierarchy.operate.renameFail']: [];
|
||||
['inspector.title']: [];
|
||||
['inspector.add_component']: [];
|
||||
['inspector.lock_unlock']: [];
|
||||
['inspector.backward_selection']: [];
|
||||
['inspector.forward_selection']: [];
|
||||
['inspector.menu.remove_component']: [];
|
||||
['inspector.menu.move_up_component']: [];
|
||||
['inspector.menu.move_down_component']: [];
|
||||
['inspector.menu.copy_node_value']: [];
|
||||
['inspector.menu.paste_node_value']: [];
|
||||
['inspector.menu.copy_component']: [];
|
||||
['inspector.menu.paste_component']: [];
|
||||
['inspector.menu.paste_component_values']: [];
|
||||
['inspector.asset.directory.is_subpackage']: [];
|
||||
['inspector.asset.directory.subpackage_name']: [];
|
||||
['inspector.asset.javascript.plugin']: [];
|
||||
['inspector.asset.javascript.loadPluginInWeb']: [];
|
||||
['inspector.asset.javascript.loadPluginInEditor']: [];
|
||||
['inspector.asset.javascript.loadPluginInNative']: [];
|
||||
['inspector.asset.fbx.browse']: [];
|
||||
['inspector.asset.spriteFrame.edit']: [];
|
||||
['inspector.asset.texture.modeWarn']: [];
|
||||
['inspector.node.layer.confirm_message']: [];
|
||||
['inspector.node.layer.change_children']: [];
|
||||
['inspector.node.layer.change_self']: [];
|
||||
['inspector.gradient.title']: [];
|
||||
['inspector.curve_editor.title']: [];
|
||||
['inspector.sprite_editor.title']: [];
|
||||
['inspector.sprite_editor.scale']: [];
|
||||
['inspector.sprite_editor.reset']: [];
|
||||
['inspector.sprite_editor.save']: [];
|
||||
['inspector.sprite_editor.saveError']: [];
|
||||
['inspector.sprite_editor.border']: [];
|
||||
['inspector.sprite_editor.left']: [];
|
||||
['inspector.sprite_editor.right']: [];
|
||||
['inspector.sprite_editor.top']: [];
|
||||
['inspector.sprite_editor.bottom']: [];
|
||||
['inspector.check_is_saved.message']: [];
|
||||
['inspector.check_is_saved.save']: [];
|
||||
['inspector.check_is_saved.abort']: [];
|
||||
['inspector.prefab.local']: [];
|
||||
['inspector.prefab.reset']: [];
|
||||
['inspector.prefab.save']: [];
|
||||
['inspector.prefab.link']: [];
|
||||
['inspector.prefab.unlink']: [];
|
||||
['inspector.prefab.lost']: [];
|
||||
['inspector.prefab.exist']: [];
|
||||
['packager.title']: [];
|
||||
['packager.menu.internal']: [];
|
||||
['packager.menu.project']: [];
|
||||
['packager.menu.global']: [];
|
||||
['packager.menu.add']: [];
|
||||
['packager.menu.addProject']: [];
|
||||
['packager.menu.addGlobal']: [];
|
||||
['packager.menu.addLabel']: [];
|
||||
['packager.menu.addSuccess']: [];
|
||||
['packager.menu.import']: [];
|
||||
['packager.menu.importProject']: [];
|
||||
['packager.menu.importGlobal']: [];
|
||||
['packager.menu.importSuccess']: [];
|
||||
['packager.menu.install']: [];
|
||||
['packager.menu.installProject']: [];
|
||||
['packager.menu.installGlobal']: [];
|
||||
['packager.menu.installSuccess']: [];
|
||||
['packager.menu.selectDirectory']: [];
|
||||
['packager.menu.search']: [];
|
||||
['packager.menu.openFolder']: [];
|
||||
['packager.menu.author']: [];
|
||||
['packager.menu.state']: [];
|
||||
['packager.menu.remove']: [];
|
||||
['packager.menu.removeSuccess']: [];
|
||||
['packager.menu.removeConfirm']: [];
|
||||
['packager.menu.enable']: [];
|
||||
['packager.menu.disable']: [];
|
||||
['packager.menu.enabled']: [];
|
||||
['packager.menu.disabled']: [];
|
||||
['packager.menu.invalid']: [];
|
||||
['packager.menu.confirm']: [];
|
||||
['packager.menu.addError']: [];
|
||||
['packager.menu.importError']: [];
|
||||
['preferences.title']: [];
|
||||
['preferences.nav.general']: [];
|
||||
['preferences.nav.edit']: [];
|
||||
['preferences.nav.extension']: [];
|
||||
['preferences.nav.native']: [];
|
||||
['preferences.nav.laboratory']: [];
|
||||
['preferences.general.language']: [];
|
||||
['preferences.general.step']: [];
|
||||
['preferences.general.preci']: [];
|
||||
['preferences.general.theme']: [];
|
||||
['preferences.general.themeColor']: [];
|
||||
['preferences.general.preview_ip']: [];
|
||||
['preferences.edit.script_editor']: [];
|
||||
['preferences.edit.picture_editor']: [];
|
||||
['preferences.edit.browse']: [];
|
||||
['preferences.edit.remove']: [];
|
||||
['preferences.edit.internal']: [];
|
||||
['preferences.native.wechatgame_app_path']: [];
|
||||
['preferences.extension.package']: [];
|
||||
['preferences.laboratory.about']: [];
|
||||
['preferences.laboratory.new_add_component']: [];
|
||||
['preferences.browse']: [];
|
||||
['preferences.open']: [];
|
||||
['preview.title']: [];
|
||||
['preview.automatic']: [];
|
||||
['preview.automatic_tooltip']: [];
|
||||
['preview.scene_is_empty']: [];
|
||||
['preview.play']: [];
|
||||
['preview.refresh_device']: [];
|
||||
['preview.scan']: [];
|
||||
['preview.create_template']: [];
|
||||
['preview.load_current_scene_error']: [];
|
||||
['preview.creat_template_success']: [];
|
||||
['project-setting.title']: [];
|
||||
['project-setting.nav.preview']: [];
|
||||
['project-setting.nav.groupList']: [];
|
||||
['project-setting.nav.modules']: [];
|
||||
['project-setting.nav.engine']: [];
|
||||
['project-setting.nav.layer']: [];
|
||||
['project-setting.nav.graphics']: [];
|
||||
['project-setting.nav.general']: [];
|
||||
['project-setting.nav.projectPath']: [];
|
||||
['project-setting.nav.wizardPath']: [];
|
||||
['project-setting.preview.start_scene']: [];
|
||||
['project-setting.preview.auto_refresh']: [];
|
||||
['project-setting.preview.current_scene']: [];
|
||||
['project-setting.preview.simulator_setting_type']: [];
|
||||
['project-setting.preview.global']: [];
|
||||
['project-setting.preview.project']: [];
|
||||
['project-setting.preview.simulator_device_orientation']: [];
|
||||
['project-setting.preview.simulator_resolution']: [];
|
||||
['project-setting.preview.customize_resolution']: [];
|
||||
['project-setting.preview.vertical']: [];
|
||||
['project-setting.preview.horizontal']: [];
|
||||
['project-setting.modules.title']: [];
|
||||
['project-setting.modules.info']: [];
|
||||
['project-setting.modules.warn']: [];
|
||||
['project-setting.modules.module']: [];
|
||||
['project-setting.modules.inquiry']: [];
|
||||
['project-setting.modules.submodule']: [];
|
||||
['project-setting.modules.inquiry_all']: [];
|
||||
['project-setting.engine.cocos_default']: [];
|
||||
['project-setting.engine.user_customize']: [];
|
||||
['project-setting.engine.renderPipeline']: [];
|
||||
['project-setting.engine.physics']: [];
|
||||
['project-setting.engine.builtin']: [];
|
||||
['project-setting.engine.cannon']: [];
|
||||
['project-setting.engine.ammo']: [];
|
||||
['project-setting.general.browse']: [];
|
||||
['project-setting.general.ts_compiler']: [];
|
||||
['project-setting.general.tslint.title']: [];
|
||||
['project-setting.general.tslint.default']: [];
|
||||
['project-setting.general.tslint.path']: [];
|
||||
['project-setting.general.section_canvas']: [];
|
||||
['project-setting.general.design_resolution']: [];
|
||||
['project-setting.general.width']: [];
|
||||
['project-setting.general.height']: [];
|
||||
['project-setting.general.fit_width']: [];
|
||||
['project-setting.general.fit_height']: [];
|
||||
['project-setting.general.type_check_level']: [];
|
||||
['project-setting.general.type_check_tips.disable']: [];
|
||||
['project-setting.general.type_check_tips.checkOnly']: [];
|
||||
['project-setting.general.type_check_tips.fatalOnError']: [];
|
||||
['scene.title']: [];
|
||||
['scene.new']: [];
|
||||
['scene.save']: [];
|
||||
['scene.save_as']: [];
|
||||
['scene.develop']: [];
|
||||
['scene.terrain.is_create_message']: [];
|
||||
['scene.terrain.is_create']: [];
|
||||
['scene.terrain.cancel']: [];
|
||||
['scene.terrain.edit']: [];
|
||||
['scene.terrain.save']: [];
|
||||
['scene.terrain.delete']: [];
|
||||
['scene.terrain.abort']: [];
|
||||
['scene.messages.warning']: [];
|
||||
['scene.messages.scenario_modified']: [];
|
||||
['scene.messages.want_to_save']: [];
|
||||
['scene.messages.save']: [];
|
||||
['scene.messages.dont_save']: [];
|
||||
['scene.messages.cancel']: [];
|
||||
['scene.messages.save_as_fail']: [];
|
||||
['scene.save_prefab']: [];
|
||||
['scene.close_prefab']: [];
|
||||
['scene.save_clip']: [];
|
||||
['scene.close_clip']: [];
|
||||
['scene.gizmos.icon3d']: [];
|
||||
['scene.gizmos.showGrid']: [];
|
||||
['scene.ui_tools.zoom_up']: [];
|
||||
['scene.ui_tools.zoom_down']: [];
|
||||
['scene.ui_tools.zoom_reset']: [];
|
||||
['scene.ui_tools.align_top']: [];
|
||||
['scene.ui_tools.align_v_center']: [];
|
||||
['scene.ui_tools.align_bottom']: [];
|
||||
['scene.ui_tools.align_left']: [];
|
||||
['scene.ui_tools.align_h_center']: [];
|
||||
['scene.ui_tools.align_right']: [];
|
||||
['scene.ui_tools.distribute_top']: [];
|
||||
['scene.ui_tools.distribute_v_center']: [];
|
||||
['scene.ui_tools.distribute_bottom']: [];
|
||||
['scene.ui_tools.distribute_left']: [];
|
||||
['scene.ui_tools.distribute_h_center']: [];
|
||||
['scene.ui_tools.distribute_right']: [];
|
||||
['tester.auto_tooltip']: [];
|
||||
['tester.play_tooltip']: [];
|
||||
['tester.pause_tooltip']: [];
|
||||
['ui-kit.title']: [];
|
||||
}
|
||||
160
extensions/app/engine/@types/packages/engine-extends/@types/third-parts.d.ts
vendored
Normal file
160
extensions/app/engine/@types/packages/engine-extends/@types/third-parts.d.ts
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
declare module 'tga-js' {
|
||||
export default class TGA {
|
||||
width: number;
|
||||
height: number;
|
||||
getImageData(imageData?: ImageData): ImageData | {width: number, height: number, data: Uint8ClampedArray};
|
||||
constructor();
|
||||
load(data: Buffer): null;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'psd.js' {
|
||||
import PNG from 'pngjs';
|
||||
export default class PSD {
|
||||
constructor (data: Buffer);
|
||||
|
||||
parse();
|
||||
|
||||
image: {
|
||||
toPng(): PNG;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'draco3dgltf' {
|
||||
export function createDecoderModule(options: DecoderModuleOptions): typeof DecoderModule;
|
||||
|
||||
// eslint-disable-next-line
|
||||
export interface DecoderModuleOptions {
|
||||
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
interface DecoderModule {
|
||||
|
||||
}
|
||||
|
||||
namespace DecoderModule {
|
||||
function destroy(decoder: Decoder): void;
|
||||
|
||||
function destroy(buffer: DecoderBuffer): void;
|
||||
|
||||
function destroy(int32Array: DracoInt32Array): void;
|
||||
|
||||
function destroy(mesh: Geometry): void;
|
||||
|
||||
export class DecoderBuffer {
|
||||
public Init(buffer: Int8Array, size: number): void;
|
||||
}
|
||||
|
||||
export class Decoder {
|
||||
public GetEncodedGeometryType(buffer: DecoderBuffer): GeometryType;
|
||||
|
||||
public DecodeBufferToMesh(buffer: DecoderBuffer, mesh: Mesh): Status;
|
||||
|
||||
public DecodeBufferToPointCloud(buffer: DecoderBuffer, pointCloud: PointCloud): Status;
|
||||
|
||||
public GetFaceFromMesh(geometry: Geometry, index: number, out: DracoInt32Array): void;
|
||||
|
||||
public GetAttributeId(geometry: Geometry, attributeType: AttributeType): number;
|
||||
|
||||
public GetAttributeByUniqueId(geometry: Geometry, uniqueId: number): Attribute;
|
||||
|
||||
public GetAttribute(geometry: Geometry, attributeId: number): Attribute;
|
||||
|
||||
public GetAttributeInt8ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoInt8Array): void;
|
||||
|
||||
public GetAttributeInt16ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoInt16Array): void;
|
||||
|
||||
public GetAttributeInt32ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoInt32Array): void;
|
||||
|
||||
public GetAttributeUInt8ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoUInt8Array): void;
|
||||
|
||||
public GetAttributeUInt16ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoUInt16Array): void;
|
||||
|
||||
public GetAttributeUInt32ForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoUInt32Array): void;
|
||||
|
||||
public GetAttributeFloatForAllPoints(geometry: Geometry, attribute: Attribute, attributeData: DracoFloat32Array): void;
|
||||
}
|
||||
|
||||
class Status {
|
||||
public ok(): boolean;
|
||||
public error_msg(): string;
|
||||
}
|
||||
|
||||
enum GeometryType {
|
||||
// See below
|
||||
}
|
||||
|
||||
export const TRIANGULAR_MESH: GeometryType;
|
||||
|
||||
export const POINT_CLOUD: GeometryType;
|
||||
|
||||
export class Mesh {
|
||||
public ptr: number;
|
||||
|
||||
public num_faces(): number;
|
||||
|
||||
public num_points(): number;
|
||||
}
|
||||
|
||||
export class PointCloud {
|
||||
public ptr: number;
|
||||
|
||||
public num_points(): number;
|
||||
}
|
||||
|
||||
export type Geometry = Mesh | PointCloud;
|
||||
|
||||
enum AttributeType {
|
||||
// See below
|
||||
}
|
||||
|
||||
export const POSITION: AttributeType;
|
||||
export const NORMAL: AttributeType;
|
||||
export const COLOR: AttributeType;
|
||||
export const TEX_COORD: AttributeType;
|
||||
|
||||
class Attribute {
|
||||
private constructor();
|
||||
public num_components(): number;
|
||||
}
|
||||
|
||||
export class DracoInt8Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoInt16Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoInt32Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoUInt8Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoUInt16Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoUInt32Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
|
||||
export class DracoFloat32Array {
|
||||
public size(): number;
|
||||
public GetValue(index: number): number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare const EditorExtends: any;
|
||||
15
extensions/app/engine/@types/packages/engine/@types/index.d.ts
vendored
Normal file
15
extensions/app/engine/@types/packages/engine/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export * from './module';
|
||||
export interface EngineInfo {
|
||||
typescript: {
|
||||
type: 'builtin' | 'custom'; // 当前使用的引擎类型(内置或自定义)
|
||||
custom: string; // 自定义引擎地址
|
||||
builtin: string, // 内置引擎地址
|
||||
path: string; // 当前使用的引擎路径,为空也表示编译失败
|
||||
},
|
||||
native: {
|
||||
type: 'builtin' | 'custom'; // 当前使用的引擎类型(内置或自定义)
|
||||
custom: string; // 自定义引擎地址
|
||||
builtin: string; // 内置引擎地址
|
||||
path: string; // 当前使用的引擎路径,为空也表示编译失败
|
||||
},
|
||||
}
|
||||
22
extensions/app/engine/@types/packages/engine/@types/message.d.ts
vendored
Normal file
22
extensions/app/engine/@types/packages/engine/@types/message.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { EngineInfo } from './index';
|
||||
export interface message extends EditorMessageMap {
|
||||
'query-info': {
|
||||
params: [] | [
|
||||
string,
|
||||
],
|
||||
result: {
|
||||
version: string;
|
||||
path: string;
|
||||
nativeVersion: string; // 原生引擎类型 'custom' 'builtin'
|
||||
nativePath: string;
|
||||
editor: string;
|
||||
},
|
||||
},
|
||||
'query-engine-info': {
|
||||
params: [] | [
|
||||
string,
|
||||
],
|
||||
result: EngineInfo,
|
||||
},
|
||||
}
|
||||
|
||||
78
extensions/app/engine/@types/packages/engine/@types/module.d.ts
vendored
Normal file
78
extensions/app/engine/@types/packages/engine/@types/module.d.ts
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
export type IModules = Record<string, IModuleItem>;
|
||||
|
||||
export interface IFlagBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
native?: string;
|
||||
|
||||
wechatPlugin?: boolean;
|
||||
|
||||
default?: string[];
|
||||
}
|
||||
|
||||
export interface IBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
required?: boolean;
|
||||
|
||||
native?: string;
|
||||
|
||||
wechatPlugin?: boolean;
|
||||
}
|
||||
|
||||
export interface IModuleItem extends IBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Whether if the feature of options allow multiple selection.
|
||||
*/
|
||||
multi?: boolean;
|
||||
|
||||
/**
|
||||
* If have default it will checked
|
||||
*/
|
||||
default?: string[];
|
||||
|
||||
options?: Record<string, IBaseItem>;
|
||||
|
||||
category?: string;
|
||||
|
||||
flags?: Record<string, IFlagBaseItem>;
|
||||
}
|
||||
|
||||
export interface IDisplayModuleItem extends IModuleItem {
|
||||
_value: boolean;
|
||||
_option?: string;
|
||||
options?: Record<string, IDisplayModuleItem>;
|
||||
}
|
||||
|
||||
export interface IDisplayModuleCache {
|
||||
_value: boolean;
|
||||
_option?: string;
|
||||
flags?: Record<string, boolean>;
|
||||
}
|
||||
50
extensions/app/engine/@types/packages/huawei-agc/@types/index.d.ts
vendored
Normal file
50
extensions/app/engine/@types/packages/huawei-agc/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'android': IOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export type IAppABI = 'armeabi-v7a' | 'arm64-v8a' | 'x86' | 'x86_64';
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
orientation: {
|
||||
landscapeRight: boolean;
|
||||
landscapeLeft: boolean;
|
||||
portrait: boolean;
|
||||
upsideDown: boolean;
|
||||
},
|
||||
|
||||
apiLevel: number;
|
||||
appABIs: IAppABI[];
|
||||
|
||||
useDebugKeystore: boolean;
|
||||
keystorePath: string;
|
||||
keystorePassword: string;
|
||||
keystoreAlias: string;
|
||||
keystoreAliasPassword: string;
|
||||
|
||||
appBundle: boolean;
|
||||
androidInstant: boolean;
|
||||
remoteUrl: string;
|
||||
sdkPath: string;
|
||||
ndkPath: string;
|
||||
|
||||
renderBackEnd: {
|
||||
vulkan: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
32
extensions/app/engine/@types/packages/huawei-quick-game/@types/index.d.ts
vendored
Normal file
32
extensions/app/engine/@types/packages/huawei-quick-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'huawei-quick-game': IOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
package: string;
|
||||
icon: string;
|
||||
versionName: string;
|
||||
versionCode: string;
|
||||
minPlatformVersion: string;
|
||||
deviceOrientation: IOrientation;
|
||||
useDebugKey: boolean;
|
||||
privatePemPath: string;
|
||||
certificatePemPath: string;
|
||||
|
||||
fullScreen: boolean;
|
||||
logLevel: string;
|
||||
manifestPath?: string;
|
||||
separateEngine: boolean;
|
||||
}
|
||||
|
||||
export interface ICompileOptions {
|
||||
name: string;
|
||||
}
|
||||
41
extensions/app/engine/@types/packages/ios/@types/index.d.ts
vendored
Normal file
41
extensions/app/engine/@types/packages/ios/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'ios': IOptions;
|
||||
native: {
|
||||
JobSystem: 'none' | 'tbb' | 'taskFlow';
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
orientation: {
|
||||
landscapeRight: boolean;
|
||||
landscapeLeft: boolean;
|
||||
portrait: boolean;
|
||||
upsideDown: boolean;
|
||||
},
|
||||
skipUpdateXcodeProject: boolean;
|
||||
renderBackEnd: {
|
||||
metal: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
},
|
||||
osTarget: {
|
||||
iphoneos: boolean,
|
||||
simulator: boolean,
|
||||
},
|
||||
developerTeam?: string,
|
||||
targetVersion: string,
|
||||
}
|
||||
18
extensions/app/engine/@types/packages/linux/@types/index.d.ts
vendored
Normal file
18
extensions/app/engine/@types/packages/linux/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'linux': IOptions;
|
||||
native: any;
|
||||
}
|
||||
}
|
||||
|
||||
interface IOptions {
|
||||
renderBackEnd: {
|
||||
metal: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
},
|
||||
}
|
||||
42
extensions/app/engine/@types/packages/localization-editor/@types/gettext-parser/index.d.ts
vendored
Normal file
42
extensions/app/engine/@types/packages/localization-editor/@types/gettext-parser/index.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Type definitions for gettext-parser 4.0
|
||||
// Project: https://github.com/smhg/gettext-parser
|
||||
// Definitions by: Lorent Lempereur <https://github.com/looorent>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
declare module 'gettext-parser' {
|
||||
export interface GetTextComment {
|
||||
translator?: string;
|
||||
reference?: string;
|
||||
extracted?: string;
|
||||
flag?: string;
|
||||
previous?: string;
|
||||
}
|
||||
|
||||
export interface GetTextTranslation {
|
||||
msgctxt?: string | undefined;
|
||||
msgid: string;
|
||||
msgid_plural?: string;
|
||||
msgstr: string[];
|
||||
comments: GetTextComment;
|
||||
}
|
||||
|
||||
export interface GetTextTranslations {
|
||||
charset: string;
|
||||
headers: { [headerName: string]: string };
|
||||
translations: { [msgctxt: string]: { [msgId: string]: GetTextTranslation } };
|
||||
}
|
||||
|
||||
export interface PoParser {
|
||||
parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations;
|
||||
compile: (table: GetTextTranslations, options?: any) => Buffer;
|
||||
createParseStream: (buffer: any, defaultCharset?: string) => any;
|
||||
}
|
||||
|
||||
export interface MoParser {
|
||||
parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations;
|
||||
compile: (table: GetTextTranslations, options?: any) => Buffer;
|
||||
}
|
||||
|
||||
export const po: PoParser;
|
||||
export const mo: MoParser;
|
||||
}
|
||||
104
extensions/app/engine/@types/packages/localization-editor/@types/globals.d.ts
vendored
Normal file
104
extensions/app/engine/@types/packages/localization-editor/@types/globals.d.ts
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
declare const gfx: any;
|
||||
declare const global: any;
|
||||
|
||||
interface Window {
|
||||
|
||||
[x: string]: any;
|
||||
|
||||
WebGL2RenderingContext: any;
|
||||
|
||||
sharedCanvas: any;
|
||||
__canvas: any;
|
||||
canvas: any;
|
||||
|
||||
XMLHttpRequest: any;
|
||||
mozRequestAnimationFrame(callback: any, element?: any): any;
|
||||
oRequestAnimationFrame(callback: any, element?: any): any;
|
||||
msRequestAnimationFrame(callback: any, element?: any): any;
|
||||
cancelRequestAnimationFrame(callback: any, element?: any): any;
|
||||
msCancelRequestAnimationFrame(callback: any, element?: any): any;
|
||||
mozCancelRequestAnimationFrame(callback: any, element?: any): any;
|
||||
oCancelRequestAnimationFrame(callback: any, element?: any): any;
|
||||
webkitCancelRequestAnimationFrame(callback: any, element?: any): any;
|
||||
msCancelAnimationFrame(callback: any, element?: any): any;
|
||||
mozCancelAnimationFrame(callback: any, element?: any): any;
|
||||
ocancelAnimationFrame(callback: any, element?: any): any;
|
||||
}
|
||||
|
||||
interface Document {
|
||||
mozHidden: any;
|
||||
msHidden: any;
|
||||
webkitHidden: any;
|
||||
}
|
||||
|
||||
interface HTMLElement {
|
||||
content: any;
|
||||
name: any;
|
||||
}
|
||||
|
||||
declare type CompareFunction<T> = (a: T, b: T) => number;
|
||||
|
||||
declare type RecursivePartial<T> = {
|
||||
[P in keyof T]?:
|
||||
T[P] extends Array<infer U> ? Array<RecursivePartial<U>> :
|
||||
T[P] extends ReadonlyArray<infer V> ? ReadonlyArray<RecursivePartial<V>> : RecursivePartial<T[P]>;
|
||||
};
|
||||
|
||||
declare type TypedArray = Uint8Array | Uint8ClampedArray | Int8Array | Uint16Array |
|
||||
Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array;
|
||||
|
||||
declare type TypedArrayConstructor = Uint8ArrayConstructor | Uint8ClampedArrayConstructor |
|
||||
Int8ArrayConstructor | Uint16ArrayConstructor | Int16ArrayConstructor | Uint32ArrayConstructor |
|
||||
Int32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor;
|
||||
|
||||
declare interface IWritableArrayLike<T> {
|
||||
readonly length: number;
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
declare type Constructor<T = unknown> = new (...args: any[]) => T;
|
||||
|
||||
declare type AbstractedConstructor<T = unknown> = abstract new (...args: any[]) => T;
|
||||
|
||||
/**
|
||||
* Alias of `Function` but suppress eslint warning.
|
||||
* Please avoid using it and explicitly specify function signatures as possible.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
declare type AnyFunction = Function;
|
||||
|
||||
declare type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
||||
|
||||
declare type Getter = () => any;
|
||||
|
||||
declare type Setter = (value: any) => void;
|
||||
|
||||
declare const Buffer: any;
|
||||
|
||||
declare type EnumAlias<EnumT> = EnumT[keyof EnumT];
|
||||
37
extensions/app/engine/@types/packages/localization-editor/@types/index.d.ts
vendored
Normal file
37
extensions/app/engine/@types/packages/localization-editor/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
interface CCENodeEventMap {
|
||||
added (node: import('cc').Node): void
|
||||
change (node: import('cc').Node): void
|
||||
removed (node: import('cc').Node): void
|
||||
}
|
||||
|
||||
interface CCEComponentEventMap {
|
||||
added (component: import('cc').Component): void,
|
||||
removed (component: import('cc').Component): void,
|
||||
}
|
||||
|
||||
declare class CCENodeManager extends EventEmitter {
|
||||
on<T extends keyof CCENodeEventMap> (message: T, callback: CCENodeEventMap[T]): this;
|
||||
off<T extends keyof CCENodeEventMap> (message: T, callback: CCENodeEventMap[T]): this;
|
||||
}
|
||||
declare class CCEComponentManager extends EventEmitter {
|
||||
on<T extends keyof CCEComponentEventMap> (message: T, callback: CCEComponentEventMap[T]): this;
|
||||
off<T extends keyof CCEComponentEventMap> (message: T, callback: CCEComponentEventMap[T]): this;
|
||||
}
|
||||
|
||||
type CCE = {
|
||||
Node: CCENodeManager,
|
||||
Component: CCEComponentManager,
|
||||
Prefab: {
|
||||
generatePrefabDataFromNode(nodeUUID: string| cc.Node): string | null
|
||||
}
|
||||
};
|
||||
|
||||
declare const cce: CCE;
|
||||
declare type UnPromise<T> = T extends Promise<infer R> ? R : T;
|
||||
declare type UUID = string;
|
||||
declare type Dump = { value: Record<string, { value: Dump | any, values?: any | Dump[], visible: boolean, readonly: boolean }> };
|
||||
declare module 'cc/env' {
|
||||
export const EDITOR: boolean;
|
||||
export const BUILD: boolean;
|
||||
}
|
||||
declare const EditorExtends: any;
|
||||
111
extensions/app/engine/@types/packages/localization-editor/@types/intl/index.d.ts
vendored
Normal file
111
extensions/app/engine/@types/packages/localization-editor/@types/intl/index.d.ts
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
declare namespace Intl {
|
||||
type BCP47LanguageTag = string;
|
||||
/**
|
||||
* The locale matching algorithm to use.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters).
|
||||
*/
|
||||
type ListFormatLocaleMatcher = 'lookup' | 'best fit';
|
||||
|
||||
/**
|
||||
* The format of output message.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters).
|
||||
*/
|
||||
type ListFormatType = 'conjunction' | 'disjunction' | 'unit';
|
||||
|
||||
/**
|
||||
* The length of the formatted message.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters).
|
||||
*/
|
||||
type ListFormatStyle = 'long' | 'short' | 'narrow';
|
||||
|
||||
/**
|
||||
* An object with some or all properties of the `Intl.ListFormat` constructor `options` parameter.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters).
|
||||
*/
|
||||
interface ListFormatOptions {
|
||||
/** The locale matching algorithm to use. For information about this option, see [Intl page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation). */
|
||||
localeMatcher?: ListFormatLocaleMatcher | undefined;
|
||||
/** The format of output message. */
|
||||
type?: ListFormatType | undefined;
|
||||
/** The length of the internationalized message. */
|
||||
style?: ListFormatStyle | undefined;
|
||||
}
|
||||
|
||||
interface ListFormat {
|
||||
/**
|
||||
* Returns a string with a language-specific representation of the list.
|
||||
*
|
||||
* @param list - An iterable object, such as an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
|
||||
*
|
||||
* @throws `TypeError` if `list` includes something other than the possible values.
|
||||
*
|
||||
* @returns {string} A language-specific formatted string representing the elements of the list.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/format).
|
||||
*/
|
||||
format(list: Iterable<string>): string;
|
||||
|
||||
/**
|
||||
* Returns an Array of objects representing the different components that can be used to format a list of values in a locale-aware fashion.
|
||||
*
|
||||
* @param list - An iterable object, such as an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), to be formatted according to a locale.
|
||||
*
|
||||
* @throws `TypeError` if `list` includes something other than the possible values.
|
||||
*
|
||||
* @returns {{ type: "element" | "literal", value: string; }[]} An Array of components which contains the formatted parts from the list.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/formatToParts).
|
||||
*/
|
||||
formatToParts(list: Iterable<string>): { type: 'element' | 'literal', value: string; }[];
|
||||
}
|
||||
|
||||
const ListFormat: {
|
||||
prototype: ListFormat;
|
||||
|
||||
/**
|
||||
* Creates [Intl.ListFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) objects that
|
||||
* enable language-sensitive list formatting.
|
||||
*
|
||||
* @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings.
|
||||
* For the general form and interpretation of the `locales` argument,
|
||||
* see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation).
|
||||
*
|
||||
* @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters)
|
||||
* with some or all options of `ListFormatOptions`.
|
||||
*
|
||||
* @returns [Intl.ListFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) object.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat).
|
||||
*/
|
||||
new(locales?: BCP47LanguageTag | BCP47LanguageTag[], options?: ListFormatOptions): ListFormat;
|
||||
|
||||
/**
|
||||
* Returns an array containing those of the provided locales that are
|
||||
* supported in list formatting without having to fall back to the runtime's default locale.
|
||||
*
|
||||
* @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings.
|
||||
* For the general form and interpretation of the `locales` argument,
|
||||
* see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation).
|
||||
*
|
||||
* @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf#parameters).
|
||||
* with some or all possible options.
|
||||
*
|
||||
* @returns An array of strings representing a subset of the given locale tags that are supported in list
|
||||
* formatting without having to fall back to the runtime's default locale.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf).
|
||||
*/
|
||||
supportedLocalesOf(locales: BCP47LanguageTag | BCP47LanguageTag[], options?: Pick<ListFormatOptions, 'localeMatcher'>): BCP47LanguageTag[];
|
||||
};
|
||||
|
||||
type TextInfo = { direction: 'ltr' | 'rtl' }
|
||||
|
||||
interface Locale {
|
||||
prototype: Locale
|
||||
textInfo(): TextInfo
|
||||
}
|
||||
}
|
||||
25
extensions/app/engine/@types/packages/localization-editor/@types/po.d.ts
vendored
Normal file
25
extensions/app/engine/@types/packages/localization-editor/@types/po.d.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
export type PoHeader = {
|
||||
/** This is the name and version of the package. */
|
||||
'Project-Id-Version'?: string
|
||||
/** (非必须) po 创建日期 */
|
||||
'POT-Creation-Date'?: string
|
||||
/** (非必须) po 修改日期*/
|
||||
'PO-Revision-Date'?: string
|
||||
/** 上一个翻译人员 */
|
||||
'Last-Translator'?: string
|
||||
/** 翻译团队的名称或者邮箱 */
|
||||
'Language-Team'?: string
|
||||
/** (非必须)要使 MIME 文档符合 RFC 2045,需要此字段在顶级头中值为 1.0 */
|
||||
'MIME-Version'?: '1.0'
|
||||
/** 译文的语言 */
|
||||
Language: string
|
||||
/** Content-Type 定义了正文的类型,我们实际上是通过这个标识来知道正文内是什么类型的文件。比如:text/plain 表示的是无格式的文本正文,text/html 表示的 Html 文档,image/gif 表示的是 gif 格式的图片等等 */
|
||||
'Content-Type'?: 'text/plain; charset=UTF-8'
|
||||
/** 它表示了这个部分文档的编码方式。只有识别了这个说明,才能用正确的解码方式实现对其解码。 */
|
||||
'Content-Transfer-Encoding'?: '8bit'
|
||||
/** (非必须)复数的规则,*/
|
||||
'Plural-Forms'?: string
|
||||
}
|
||||
|
||||
export type IPluralRulesJson = Record<Intl.BCP47LanguageTag, [Intl.LDMLPluralRule]>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference types="../../../@types/cc" />
|
||||
import { Component, Label } from 'cc';
|
||||
export default abstract class L10nComponent extends Component {
|
||||
protected constructor();
|
||||
get string(): string;
|
||||
label?: Label | null;
|
||||
protected onLoad(): void;
|
||||
protected start(): void;
|
||||
render(): void;
|
||||
preview(value: string): void;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import L10nComponent from './l10n-component';
|
||||
export default class L10nLabel extends L10nComponent {
|
||||
_key: string;
|
||||
set key(value: string);
|
||||
get key(): string;
|
||||
_count: number;
|
||||
set count(value: number);
|
||||
get count(): number;
|
||||
onLoad(): void;
|
||||
render(): void;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { AssetManager } from 'cc';
|
||||
import type { L10nManager } from './l10n-manager';
|
||||
export default class AMPipeLineManager {
|
||||
initialized: boolean;
|
||||
l10n?: L10nManager;
|
||||
_redirectTask: this['redirectTask'];
|
||||
initAssetManager(l10n: L10nManager): void;
|
||||
uninstall(): void;
|
||||
redirectTask: (task: {
|
||||
output: AssetManager.RequestItem[];
|
||||
input: AssetManager.RequestItem[];
|
||||
}) => void;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
51
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/icu-options.d.ts
vendored
Normal file
51
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/icu-options.d.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import { FallbackLanguage, L10nValue } from './l10n-options';
|
||||
export declare type FormattedValue = string;
|
||||
export declare type TextInfoDirection = 'ltr' | 'rtl';
|
||||
export interface StandardOption {
|
||||
count?: number;
|
||||
defaultValue?: L10nValue;
|
||||
language?: Intl.BCP47LanguageTag;
|
||||
fallbackLanguage?: FallbackLanguage;
|
||||
}
|
||||
export interface Template {
|
||||
[key: string]: string | {
|
||||
[key: string]: StandardOption;
|
||||
};
|
||||
}
|
||||
export interface NumberFormatOptions extends Intl.NumberFormatOptions {
|
||||
style?: 'decimal' | 'percent' | 'currency' | string;
|
||||
/**
|
||||
* 货币代码,采用ISO 4217标准
|
||||
* @see ISO4217Tag
|
||||
*/
|
||||
currency?: string;
|
||||
currencySign?: 'standard' | 'accounting' | string;
|
||||
currencyDisplay?: 'symbol' | 'code' | 'name' | string;
|
||||
useGrouping?: boolean;
|
||||
minimumIntegerDigits?: number;
|
||||
minimumFractionDigits?: number;
|
||||
maximumFractionDigits?: number;
|
||||
minimumSignificantDigits?: number;
|
||||
maximumSignificantDigits?: number;
|
||||
}
|
||||
export interface DateTimeFormatOptions {
|
||||
localeMatcher?: 'best fit' | 'lookup' | undefined | string;
|
||||
weekday?: 'long' | 'short' | 'narrow' | undefined | string;
|
||||
era?: 'long' | 'short' | 'narrow' | undefined | string;
|
||||
year?: 'numeric' | '2-digit' | undefined | string;
|
||||
month?: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow' | undefined | string;
|
||||
day?: 'numeric' | '2-digit' | undefined | string;
|
||||
hour?: 'numeric' | '2-digit' | undefined | string;
|
||||
minute?: 'numeric' | '2-digit' | undefined | string;
|
||||
second?: 'numeric' | '2-digit' | undefined | string;
|
||||
timeZoneName?: 'long' | 'short' | undefined | string;
|
||||
formatMatcher?: 'best fit' | 'basic' | undefined | string;
|
||||
hour12?: boolean | undefined;
|
||||
timeZone?: string | undefined;
|
||||
}
|
||||
export declare type RelativeTimeFormatUnit = 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year' | string;
|
||||
export interface RelativeTimeFormatOptions {
|
||||
localeMatcher?: 'lookup' | 'best fit' | string;
|
||||
style?: 'narrow' | 'short' | 'long' | string;
|
||||
numeric?: 'auto' | 'always' | string;
|
||||
}
|
||||
10
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/icu-type.d.ts
vendored
Normal file
10
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/icu-type.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Intl formatting
|
||||
*/
|
||||
declare enum ICUType {
|
||||
DateTime = 0,
|
||||
Number = 1,
|
||||
List = 2,
|
||||
RelativeTime = 3,
|
||||
}
|
||||
export default ICUType;
|
||||
@@ -0,0 +1,5 @@
|
||||
declare enum L10nListenEvent {
|
||||
languageChanged = 'languageChanged',
|
||||
onMissingKey = 'missingKey',
|
||||
}
|
||||
export default L10nListenEvent;
|
||||
60
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/l10n-manager.d.ts
vendored
Normal file
60
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/l10n-manager.d.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { L10nOptions, ResourceData, L10nKey, L10nValue } from './l10n-options';
|
||||
import { StandardOption, Template, TextInfoDirection } from './icu-options';
|
||||
import L10nListenEvent from './l10n-listen-event';
|
||||
import ResourceDataManager from './resource-data-manager';
|
||||
import AMPipeLineManager from './asset-manager-initer';
|
||||
export declare class L10nManager {
|
||||
static LOCAL_STORAGE_LANGUAGE_KEY: string;
|
||||
static DEFAULT_NAMESPACE: string;
|
||||
static l10n: L10nManager;
|
||||
/**
|
||||
* @zh
|
||||
* i18n 实例
|
||||
* @en
|
||||
* i18next instance
|
||||
*/
|
||||
private _intl?;
|
||||
private _options;
|
||||
private resourceList?;
|
||||
private resourceBundle;
|
||||
resourceDataManager: ResourceDataManager;
|
||||
amPipeLineManager: AMPipeLineManager;
|
||||
private constructor();
|
||||
isInitialized(): boolean;
|
||||
createIntl(options: L10nOptions): Promise<void>;
|
||||
cloneIntl(options: L10nOptions): void;
|
||||
reloadResourceData(): Promise<boolean>;
|
||||
/** 初始化 i18next */
|
||||
config(options: L10nOptions): void;
|
||||
changeLanguage(language: Intl.BCP47LanguageTag): Promise<void>;
|
||||
t(key: L10nKey, options?: StandardOption | Template): L10nValue;
|
||||
/**
|
||||
* 实验性功能暂不开放
|
||||
* 数字类ICU
|
||||
*/
|
||||
private tn;
|
||||
/**
|
||||
* 实验性功能暂不开放
|
||||
* 日期/时刻类ICU
|
||||
*/
|
||||
private td;
|
||||
/**
|
||||
* 实验性功能暂不开放
|
||||
* 时长类ICU
|
||||
*/
|
||||
private tt;
|
||||
/**
|
||||
* 实验性功能暂不开放
|
||||
* 数组类ICU
|
||||
*/
|
||||
private tl;
|
||||
exists(key: L10nKey): boolean;
|
||||
get currentLanguage(): Intl.BCP47LanguageTag;
|
||||
get languages(): readonly Intl.BCP47LanguageTag[];
|
||||
direction(language?: Intl.BCP47LanguageTag): TextInfoDirection;
|
||||
on(event: L10nListenEvent, callback: (...args: any[]) => void): void;
|
||||
off(event: L10nListenEvent, callback: (...args: any[]) => void): void;
|
||||
getResourceBundle(language: string): ResourceData | undefined;
|
||||
}
|
||||
declare const l10n: L10nManager;
|
||||
export default l10n;
|
||||
78
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/l10n-options.d.ts
vendored
Normal file
78
extensions/app/engine/@types/packages/localization-editor/@types/runtime/core/l10n-options.d.ts
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
export declare type L10nKey = string;
|
||||
export declare type L10nValue = string;
|
||||
export interface ResourceList {
|
||||
defaultLanguage?: Intl.BCP47LanguageTag;
|
||||
fallbackLanguage?: Intl.BCP47LanguageTag;
|
||||
languages: Intl.BCP47LanguageTag[];
|
||||
}
|
||||
export interface ResourceBundle {
|
||||
[language: Intl.BCP47LanguageTag]: ResourceData;
|
||||
}
|
||||
export interface ResourceData {
|
||||
[namespace: string]: ResourceItem;
|
||||
}
|
||||
export interface ResourceItem {
|
||||
[key: string]: any;
|
||||
}
|
||||
export interface FallbackLanguageObjectList {
|
||||
[language: string]: readonly string[];
|
||||
}
|
||||
export declare type FallbackLanguage = string | readonly string[] | FallbackLanguageObjectList | ((language: Intl.BCP47LanguageTag) => string | readonly string[] | FallbackLanguageObjectList);
|
||||
export interface L10nOptions {
|
||||
/**
|
||||
* Logs info level to console output. Helps finding issues with loading not working.
|
||||
* @default false
|
||||
*/
|
||||
/**
|
||||
* Resources to initialize with (if not using loading or not appending using addResourceBundle)
|
||||
* @default undefined
|
||||
*/
|
||||
resources?: ResourceBundle;
|
||||
/**
|
||||
* Language to use (overrides language detection)
|
||||
*/
|
||||
language?: Intl.BCP47LanguageTag;
|
||||
/**
|
||||
* Language to use if translations in user language are not available.
|
||||
* @default same as language
|
||||
*/
|
||||
fallbackLanguage?: false | FallbackLanguage;
|
||||
/**
|
||||
* @default IntlManager.LOCAL_STORAGE_LANGUAGE_KEY
|
||||
*/
|
||||
localStorageLanguageKey?: string;
|
||||
/**
|
||||
* @zh
|
||||
* 可以对key进行前置处理,返回值应该是处理后的key
|
||||
*
|
||||
* @en
|
||||
* Preprocess the key
|
||||
*
|
||||
* @param key
|
||||
* @return string
|
||||
* onBeforeProcessHandler
|
||||
*/
|
||||
beforeTranslate?: (key: L10nKey) => L10nValue;
|
||||
/**
|
||||
* @zh
|
||||
* 对value进行后置处理,返回值应该是处理后的value
|
||||
*
|
||||
* @en
|
||||
* Postprocess the value, return the processed value
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @return string
|
||||
*/
|
||||
afterTranslate?: (key: string, value: string) => string;
|
||||
/**
|
||||
* Allows null values as valid translation
|
||||
* @default true
|
||||
*/
|
||||
returnNull?: boolean;
|
||||
/**
|
||||
* Allows empty string as valid translation
|
||||
* @default true
|
||||
*/
|
||||
returnEmptyString?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export declare const pluginName = 'Localization Editor';
|
||||
export declare const mainName = 'localization-editor';
|
||||
export declare const runtimeBundleName = 'l10n';
|
||||
export declare const resourceListPath = 'resource-list';
|
||||
export declare const resourceBundlePath = 'resource-bundle';
|
||||
@@ -0,0 +1,25 @@
|
||||
/// <reference types="../../../@types/cc" />
|
||||
import { AssetManager, JsonAsset } from 'cc';
|
||||
import { ResourceBundle, ResourceList } from './l10n-options';
|
||||
export default class ResourceDataManager {
|
||||
readResourceList(): Promise<ResourceList>;
|
||||
readResourceBundle(tags: Intl.BCP47LanguageTag[]): Promise<ResourceBundle>;
|
||||
/**
|
||||
* 编辑器模式下使用
|
||||
* @param locales
|
||||
*/
|
||||
editorLoad(locales: Intl.BCP47LanguageTag[]): Promise<ResourceBundle | undefined>;
|
||||
/**
|
||||
* 构建后运行时使用
|
||||
* @param fileName
|
||||
*/
|
||||
runtimeLoad<T>(fileName: string): Promise<T | undefined>;
|
||||
/**
|
||||
* 浏览器预览使用
|
||||
* @param urlPath
|
||||
*/
|
||||
previewLoad<T>(urlPath: string): Promise<T | undefined>;
|
||||
checkBundle(bundleName: string): Promise<boolean>;
|
||||
getBundle(bundleName: string): Promise<AssetManager.Bundle | undefined>;
|
||||
getResource(bundle: AssetManager.Bundle, resourceName: string): Promise<JsonAsset | undefined>;
|
||||
}
|
||||
5
extensions/app/engine/@types/packages/localization-editor/@types/runtime/l10n.d.ts
vendored
Normal file
5
extensions/app/engine/@types/packages/localization-editor/@types/runtime/l10n.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import l10n, { L10nManager } from './core/l10n-manager';
|
||||
import L10nListenEvent from './core/l10n-listen-event';
|
||||
import L10nLabel from './components/l10n-label';
|
||||
export type { L10nKey, L10nValue, ResourceList, ResourceBundle, ResourceData, ResourceItem, FallbackLanguageObjectList, FallbackLanguage, L10nOptions } from './core/l10n-options';
|
||||
export { l10n, L10nManager, L10nLabel, L10nListenEvent };
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-datetimeformat';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-displaynames';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-listformat';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-locale';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-numberformat';
|
||||
@@ -0,0 +1 @@
|
||||
import 'intl-pluralrules';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-relativetimeformat';
|
||||
@@ -0,0 +1 @@
|
||||
import '@formatjs/intl-getcanonicallocales';
|
||||
29
extensions/app/engine/@types/packages/mac/@types/index.d.ts
vendored
Normal file
29
extensions/app/engine/@types/packages/mac/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'mac': IOptions;
|
||||
native: any;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
renderBackEnd: {
|
||||
metal: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
},
|
||||
supportM1: boolean;
|
||||
skipUpdateXcodeProject: boolean;
|
||||
targetVersion: string;
|
||||
}
|
||||
|
||||
export interface IBuildCache extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
39
extensions/app/engine/@types/packages/native/@types/index.d.ts
vendored
Normal file
39
extensions/app/engine/@types/packages/native/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions, InternalBuildResult, IPolyFills, IBuildScriptParam } from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { CocosParams } from 'native-pack-tool';
|
||||
|
||||
declare enum NetMode {
|
||||
client = 0,
|
||||
hostServer = 1,
|
||||
listenServer = 2,
|
||||
}
|
||||
export interface ITaskOptionPackages {
|
||||
native: IOptions;
|
||||
}
|
||||
|
||||
interface ICustomBuildScriptParam extends IBuildScriptParam {
|
||||
experimentalHotReload: boolean;
|
||||
}
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: ITaskOptionPackages;
|
||||
buildScriptParam: ICustomBuildScriptParam;
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
template: string;
|
||||
engine?: string;
|
||||
runAfterMake: boolean;
|
||||
encrypted: boolean;// 是否加密脚本
|
||||
compressZip: boolean;// 是否压缩脚本
|
||||
xxteaKey?: string;// xxtea 加密的 key 值
|
||||
params?: CocosParams; // console 需要的参数
|
||||
JobSystem: 'none' | 'tbb' | 'taskFlow';
|
||||
serverMode: boolean;
|
||||
netMode: NetMode;
|
||||
}
|
||||
|
||||
export interface IBuildCache extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
36
extensions/app/engine/@types/packages/ohos/@types/index.d.ts
vendored
Normal file
36
extensions/app/engine/@types/packages/ohos/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'ohos': IOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
orientation: {
|
||||
landscapeRight: boolean;
|
||||
landscapeLeft: boolean;
|
||||
portrait: boolean;
|
||||
upsideDown: boolean;
|
||||
},
|
||||
|
||||
apiLevel: number;
|
||||
sdkPath: string;
|
||||
ndkPath: string;
|
||||
|
||||
renderBackEnd: {
|
||||
// vulkan: boolean;
|
||||
gles3: boolean;
|
||||
// gles2: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
37
extensions/app/engine/@types/packages/open-harmonyos/@types/index.d.ts
vendored
Normal file
37
extensions/app/engine/@types/packages/open-harmonyos/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
/// <reference path="../../../@types/index.d.ts"/>
|
||||
/// <reference path="@editor/library-type/packages/builder/@types/protect/global.d.ts"/>
|
||||
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'open-harmonyos': IOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
packageName: string;
|
||||
orientation: {
|
||||
landscapeRight: boolean;
|
||||
landscapeLeft: boolean;
|
||||
portrait: boolean;
|
||||
upsideDown: boolean;
|
||||
},
|
||||
|
||||
apiLevel: string;
|
||||
sdkPath: string;
|
||||
ndkPath: string;
|
||||
|
||||
renderBackEnd: {
|
||||
// vulkan: boolean;
|
||||
gles3: boolean;
|
||||
// gles2: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
30
extensions/app/engine/@types/packages/oppo-mini-game/@types/index.d.ts
vendored
Normal file
30
extensions/app/engine/@types/packages/oppo-mini-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'oppo-mini-game': IOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
package: string;
|
||||
icon: string;
|
||||
versionName: string;
|
||||
versionCode: string;
|
||||
minPlatformVersion: string;
|
||||
deviceOrientation: IOrientation;
|
||||
useDebugKey: boolean;
|
||||
privatePemPath: string;
|
||||
certificatePemPath: string;
|
||||
hasSubPackage?: boolean;
|
||||
separateEngine: boolean;
|
||||
}
|
||||
|
||||
export interface ICompileOptions {
|
||||
name: string;
|
||||
useDebugKey: boolean;
|
||||
hasSubPackage: boolean;
|
||||
}
|
||||
60
extensions/app/engine/@types/packages/package-asset/@types/public.d.ts
vendored
Normal file
60
extensions/app/engine/@types/packages/package-asset/@types/public.d.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
export interface MenuAssetInfo {
|
||||
// 资源名字
|
||||
name: string;
|
||||
// 资源用于显示的名字
|
||||
displayName: string;
|
||||
// loader 加载的层级地址
|
||||
url: string;
|
||||
// 绝对路径
|
||||
file: string;
|
||||
// 资源的唯一 ID
|
||||
uuid: string;
|
||||
// 使用的导入器名字
|
||||
importer: string;
|
||||
// 类型
|
||||
type: string;
|
||||
// 是否是文件夹
|
||||
isDirectory: boolean;
|
||||
// 是否只读
|
||||
readonly: boolean;
|
||||
// 虚拟资源可以实例化成实体的话,会带上这个扩展名
|
||||
instantiation?: string;
|
||||
// 跳转指向资源
|
||||
redirect?: IRedirectInfo;
|
||||
// 继承类型
|
||||
extends?: string[];
|
||||
// 是否导入完成
|
||||
imported: boolean;
|
||||
// 是否导入失败
|
||||
invalid: boolean;
|
||||
}
|
||||
|
||||
export interface IRedirectInfo {
|
||||
// 跳转资源的类型
|
||||
type: string;
|
||||
// 跳转资源的 uuid
|
||||
uuid: string;
|
||||
}
|
||||
export interface IAssetInfo {
|
||||
name: string; // 资源名字
|
||||
displayName: string; // 资源用于显示的名字
|
||||
source: string; // url 地址
|
||||
path: string; // loader 加载的层级地址
|
||||
url: string; // loader 加载地址会去掉扩展名,这个参数不去掉
|
||||
file: string; // 绝对路径
|
||||
uuid: string; // 资源的唯一 ID
|
||||
importer: string; // 使用的导入器名字
|
||||
imported: boolean; // 是否结束导入过程
|
||||
invalid: boolean; // 是否导入成功
|
||||
type: string; // 类型
|
||||
isDirectory: boolean; // 是否是文件夹
|
||||
library: { [key: string]: string }; // 导入资源的 map
|
||||
subAssets: { [key: string]: IAssetInfo }; // 子资源 map
|
||||
visible: boolean; // 是否显示
|
||||
readonly: boolean; // 是否只读
|
||||
|
||||
instantiation?: string; // 虚拟资源可以实例化成实体的话,会带上这个扩展名
|
||||
redirect?: IRedirectInfo; // 跳转指向资源
|
||||
meta?: any,
|
||||
fatherInfo?: any;
|
||||
}
|
||||
1
extensions/app/engine/@types/packages/preview/@types/index.d.ts
vendored
Normal file
1
extensions/app/engine/@types/packages/preview/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './protect';
|
||||
19
extensions/app/engine/@types/packages/programming/@types/message.d.ts
vendored
Normal file
19
extensions/app/engine/@types/packages/programming/@types/message.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export interface message extends EditorMessageMap {
|
||||
'query-shared-settings': {
|
||||
params: [],
|
||||
result: {
|
||||
useDefineForClassFields: boolean;
|
||||
allowDeclareFields: boolean;
|
||||
loose: boolean;
|
||||
guessCommonJsExports: boolean;
|
||||
exportsConditions: string[];
|
||||
importMap?: {
|
||||
json: {
|
||||
imports?: Record<string, string>;
|
||||
scopes?: Record<string, Record<string, string>>;
|
||||
};
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
2
extensions/app/engine/@types/packages/runtime-dev-tools/@types/index.d.ts
vendored
Normal file
2
extensions/app/engine/@types/packages/runtime-dev-tools/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '../../../@types/editor';
|
||||
72
extensions/app/engine/@types/packages/scene/@types/engine-view.d.ts
vendored
Normal file
72
extensions/app/engine/@types/packages/scene/@types/engine-view.d.ts
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { WebviewTag } from 'electron';
|
||||
import ISceneFacade from './scene-facade-interface';
|
||||
/**
|
||||
* 这个是 engine-view 标签的接口
|
||||
*/
|
||||
export interface EngineView {
|
||||
dirty: boolean;
|
||||
managerReady: boolean;
|
||||
|
||||
$scene: WebviewTag;
|
||||
depend: any;
|
||||
$floatWindow: any;
|
||||
|
||||
// 封装的 webview 通讯模块
|
||||
ipc: any;
|
||||
|
||||
info: any;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 调用场景进程里的方法
|
||||
* @param methodName
|
||||
* @param params
|
||||
* @param forced
|
||||
* @param timeout
|
||||
*/
|
||||
|
||||
callSceneMethod<T extends keyof ISceneFacade>(methodName: T, params: Parameters<ISceneFacade[T]>, forced?: boolean, timeout?: boolean): Promise<ReturnType<typeof ISceneFacade[T]>>
|
||||
|
||||
/**
|
||||
* 执行组件方法
|
||||
* @param options
|
||||
*/
|
||||
executeComponentMethod(options: { uuid: string, index: number, methodNames: string[] });
|
||||
|
||||
//////////////
|
||||
|
||||
attachFloatWindow(name: string, options: FloatWindowOptions)
|
||||
|
||||
detachFloatWindow(name: string)
|
||||
|
||||
attachToolbar(name: string, options: any)
|
||||
|
||||
detachToolbar(name: string)
|
||||
|
||||
attachInfobar(name: string, options: any)
|
||||
|
||||
detachInfobar(name: string)
|
||||
}
|
||||
export interface FloatWindowOptions {
|
||||
type: string;
|
||||
width: number;
|
||||
height: number;
|
||||
top?: number;
|
||||
bottom?: number;
|
||||
left?: number;
|
||||
right?: number;
|
||||
|
||||
dock?: boolean;
|
||||
|
||||
mode?: 'dock' | 'simple';
|
||||
|
||||
template: string;
|
||||
ready?: ($window: HTMLDivElement, info: ScenePluginInfo, componentMap: { [type: string]: ScenePluginComponentInfo[] }) => void;
|
||||
close?: Function;
|
||||
update?: Function;
|
||||
send?: Function;
|
||||
}
|
||||
68
extensions/app/engine/@types/packages/scene/@types/message.d.ts
vendored
Normal file
68
extensions/app/engine/@types/packages/scene/@types/message.d.ts
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
SetPropertyOptions,
|
||||
} from './public';
|
||||
|
||||
export interface message extends EditorMessageMap {
|
||||
'update-create-node-template': {
|
||||
params: [],
|
||||
result: any,
|
||||
},
|
||||
'open': {
|
||||
params: [],
|
||||
result: any,
|
||||
},
|
||||
'open-devtools': {
|
||||
params: [],
|
||||
result: any,
|
||||
},
|
||||
'graphical-tools': {
|
||||
params: [
|
||||
boolean,
|
||||
],
|
||||
result: void,
|
||||
},
|
||||
'open-scene': {
|
||||
params: [
|
||||
string,
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'save-scene': {
|
||||
params: [] | [
|
||||
boolean,
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'save-as-scene': {
|
||||
params: [
|
||||
boolean,
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'close-scene': {
|
||||
params: [],
|
||||
result: boolean,
|
||||
},
|
||||
'set-property': {
|
||||
params: [
|
||||
SetPropertyOptions,
|
||||
],
|
||||
result: boolean,
|
||||
},
|
||||
'query-node-tree': {
|
||||
params: [] | [
|
||||
string,
|
||||
],
|
||||
result: any,
|
||||
},
|
||||
'execute-scene-script': {
|
||||
params: [] | [
|
||||
{
|
||||
name: string;
|
||||
method: string;
|
||||
args: any[];
|
||||
}
|
||||
],
|
||||
result: any,
|
||||
},
|
||||
}
|
||||
469
extensions/app/engine/@types/packages/scene/@types/public.d.ts
vendored
Normal file
469
extensions/app/engine/@types/packages/scene/@types/public.d.ts
vendored
Normal file
@@ -0,0 +1,469 @@
|
||||
import { EmbeddedPlayerGroup } from 'cc';
|
||||
// ---- 一些 engine 基础数据 ---- start
|
||||
interface Vec2 {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface Vec3 {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
|
||||
interface Vec4 {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
w: number;
|
||||
}
|
||||
|
||||
interface Quat {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
w: number;
|
||||
}
|
||||
|
||||
interface Color3 {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
}
|
||||
|
||||
interface Color4 {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a: number;
|
||||
}
|
||||
|
||||
interface Mat3 {
|
||||
m00: number;
|
||||
m01: number;
|
||||
m02: number;
|
||||
|
||||
m03: number;
|
||||
m04: number;
|
||||
m05: number;
|
||||
|
||||
m06: number;
|
||||
m07: number;
|
||||
m08: number;
|
||||
}
|
||||
|
||||
interface Mat4 {
|
||||
m00: number;
|
||||
m01: number;
|
||||
m02: number;
|
||||
m03: number;
|
||||
|
||||
m04: number;
|
||||
m05: number;
|
||||
m06: number;
|
||||
m07: number;
|
||||
|
||||
m08: number;
|
||||
m09: number;
|
||||
m10: number;
|
||||
m11: number;
|
||||
|
||||
m12: number;
|
||||
m13: number;
|
||||
m14: number;
|
||||
m15: number;
|
||||
}
|
||||
// ---- 一些 engine 基础数据 ---- end
|
||||
|
||||
// ---- 操作消息的参数定义 --- strart
|
||||
|
||||
// set-property 消息的 options 定义
|
||||
export interface SetPropertyOptions {
|
||||
uuid: string; // 修改属性的对象的 uuid
|
||||
path: string; // 属性挂载对象的搜索路径
|
||||
// key: string; // 属性的 key
|
||||
dump: IProperty; // 属性 dump 出来的数据
|
||||
record?: boolean;// 是否记录undo
|
||||
}
|
||||
|
||||
// move-array-element 消息的 options 定义
|
||||
export interface MoveArrayOptions {
|
||||
uuid: string;
|
||||
path: string;
|
||||
target: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
// remove-array-element 消息的 options 定义
|
||||
export interface RemoveArrayOptions {
|
||||
uuid: string;
|
||||
path: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface PasteNodeOptions {
|
||||
target: string; // 目标节点
|
||||
uuids: string | string[]; // 被复制的节点 uuids
|
||||
keepWorldTransform?: boolean; // 是否保持新节点的世界坐标不变
|
||||
pasteAsChild?: boolean; // 是否粘贴成为子节点
|
||||
}
|
||||
|
||||
export interface CutNodeOptions {
|
||||
parent: string; // 父节点
|
||||
uuids: string | string[]; // 被移入的节点 uuids
|
||||
keepWorldTransform?: boolean; // 是否保持新节点的世界坐标不变
|
||||
}
|
||||
|
||||
// create-node 消息的 options 定义
|
||||
export interface CreateNodeOptions {
|
||||
parent?: string;
|
||||
components?: string[];
|
||||
|
||||
name?: string;
|
||||
dump?: INode | IScene; // node 初始化应用的数据
|
||||
keepWorldTransform?: boolean; // 是否保持新节点的世界坐标不变
|
||||
type?: string; // 资源类型
|
||||
assetUuid?: string; // asset uuid , type value 格式保持兼容拖动的数据格式,有资源 id,则从资源内创建对应的节点
|
||||
canvasRequired?: boolean; // 是否需要有 Canvas
|
||||
unlinkPrefab?: boolean; // 创建后取消 prefab 状态
|
||||
position?: Vec3; // 指定生成的位置
|
||||
nameIncrease?: boolean; // 名称自增 xxx001 -> xxx002
|
||||
snapshot?: boolean;
|
||||
}
|
||||
|
||||
export interface ResetNodeOptions {
|
||||
uuid: string | string[];
|
||||
}
|
||||
|
||||
export interface RemoveNodeOptions {
|
||||
uuid: string | string[];
|
||||
keepWorldTransform?: boolean;
|
||||
}
|
||||
|
||||
export interface CreateComponentOptions {
|
||||
uuid: string;
|
||||
component: string;
|
||||
}
|
||||
|
||||
export interface ResetComponentOptions {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export interface RemoveComponentOptions {
|
||||
uuid: string;
|
||||
component: string;
|
||||
}
|
||||
|
||||
export interface ExecuteComponentMethodOptions {
|
||||
uuid: string;
|
||||
name: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export interface IAnimOperation {
|
||||
funcName: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export interface ExecuteSceneScriptMethodOptions {
|
||||
name: string;
|
||||
method: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export type IPropertyValueType = IProperty | IProperty[] | null | undefined | number | boolean | string | Vec3 | Vec2;
|
||||
|
||||
export interface IPropertyGroupOptions {
|
||||
id: string // 默认 'default'
|
||||
name: string,
|
||||
displayOrder: number, // 默认 Infinity, 排在最后面
|
||||
style: string // 默认为 'tab'
|
||||
}
|
||||
|
||||
export interface IProperty {
|
||||
value: { [key: string]: IPropertyValueType } | IPropertyValueType;
|
||||
default?: any; // 默认值
|
||||
|
||||
// 多选节点之后,这里存储多个数据,用于自行判断多选后的显示效果,无需更新该数据
|
||||
values?: ({ [key: string]: IPropertyValueType } | IPropertyValueType)[];
|
||||
|
||||
cid?: string;
|
||||
type?: string;
|
||||
ui?: { name: string, data?: any }; // 是否用指定的 UI 组件,name 是组件的名称
|
||||
readonly?: boolean;
|
||||
visible?: boolean;
|
||||
name?: string;
|
||||
|
||||
elementTypeData?: IProperty; // 数组里的数据的默认值 dump
|
||||
|
||||
path?: string; // 数据的搜索路径,这个是由使用方填充的
|
||||
|
||||
isArray?: boolean;
|
||||
invalid?: boolean;
|
||||
extends?: string[]; // 继承链
|
||||
displayName?: string; // 显示到界面上的名字
|
||||
displayOrder?: number; // 显示排序
|
||||
help?: string; // 帮助文档的 url 地址
|
||||
group?: IPropertyGroupOptions; // tab
|
||||
tooltip?: string; // 提示文本
|
||||
editor?: any; // 组件上定义的编辑器数据
|
||||
animatable?: boolean; // 是否可以在动画中编辑
|
||||
|
||||
// Enum
|
||||
enumList?: any[]; // enum 类型的 list 选项数组
|
||||
|
||||
bitmaskList?: any[];
|
||||
|
||||
// Number
|
||||
min?: number; // 数值类型的最小值
|
||||
max?: number; // 数值类型的最大值
|
||||
step?: number; // 数值类型的步进值
|
||||
slide?: boolean; // 数组是否显示为滑块
|
||||
unit?: string; // 显示的单位
|
||||
radian?: boolean; // 标识是否为角度
|
||||
|
||||
// Label
|
||||
multiline?: boolean; // 字符串是否允许换行
|
||||
// nullable?: boolean; 属性是否允许为空
|
||||
|
||||
optionalTypes?: string[]; // 对属性是 object 且是可变类型的数据的支持,比如 render-pipeline
|
||||
}
|
||||
|
||||
export interface IRemovedComponentInfo {
|
||||
name: string;
|
||||
fileID: string;
|
||||
}
|
||||
|
||||
export interface INode {
|
||||
active: IProperty;
|
||||
locked: IProperty;
|
||||
name: IProperty;
|
||||
position: IProperty;
|
||||
|
||||
/**
|
||||
* 此为 dump 数据,非 node.rotation
|
||||
* 实际指向 node.eulerAngles
|
||||
* rotation 为了给用户更友好的文案
|
||||
*/
|
||||
rotation: IProperty;
|
||||
|
||||
scale: IProperty;
|
||||
layer: IProperty;
|
||||
uuid: IProperty;
|
||||
|
||||
children: any[];
|
||||
parent: any;
|
||||
|
||||
__comps__: IProperty[];
|
||||
__type__: string;
|
||||
__prefab__?: any;
|
||||
_prefabInstance?: any;
|
||||
removedComponents?: IRemovedComponentInfo[];
|
||||
mountedRoot?: string;
|
||||
}
|
||||
|
||||
export interface IComponent extends IProperty {
|
||||
value: {
|
||||
enabled: IPropertyValueType;
|
||||
uuid: IPropertyValueType;
|
||||
name: IPropertyValueType;
|
||||
} & Record<string, IPropertyValueType>;
|
||||
mountedRoot?: string;
|
||||
}
|
||||
|
||||
export interface IScene {
|
||||
name: IProperty;
|
||||
active: IProperty;
|
||||
locked: IProperty;
|
||||
_globals: any;
|
||||
isScene: boolean;
|
||||
autoReleaseAssets: IProperty;
|
||||
|
||||
uuid: IProperty;
|
||||
children: any[];
|
||||
parent: any;
|
||||
__type__: string;
|
||||
targetOverrides?: any;
|
||||
}
|
||||
|
||||
export interface ITargetOverrideInfo {
|
||||
source: string;
|
||||
sourceInfo?: string[];
|
||||
propertyPath: string[];
|
||||
target: string;
|
||||
targetInfo?: string[];
|
||||
}
|
||||
// ---- 操作消息的参数定义 --- end
|
||||
|
||||
// ---- 场景插件返回的 info 信息 ---- start
|
||||
interface ScenePluginNodeInfo {
|
||||
uuid: string;
|
||||
components: ScenePluginComponentInfo[];
|
||||
}
|
||||
|
||||
// 场景插件传回的场景信息
|
||||
export interface ScenePluginInfo {
|
||||
// 选中节点列表
|
||||
nodes: ScenePluginNodeInfo[];
|
||||
|
||||
// gizmo 的一些信息
|
||||
gizmo: {
|
||||
is2D: boolean;
|
||||
};
|
||||
// 当前编辑模式数组
|
||||
modes: string[];
|
||||
}
|
||||
|
||||
// 场景插件传回的组件信息
|
||||
export interface ScenePluginComponentInfo {
|
||||
uuid: string;
|
||||
enabled: boolean;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface QueryClassesOptions {
|
||||
extends?: string | string[];
|
||||
excludeSelf?: boolean;
|
||||
}
|
||||
|
||||
// ---- 场景插件返回的 info 信息 ---- end
|
||||
|
||||
// ---- 动画数据 ---- start
|
||||
|
||||
export interface IKeyDumpData {
|
||||
frame: number;
|
||||
dump: any; // value的dump数据
|
||||
inTangent?: number;
|
||||
inTangentWeight?: number;
|
||||
outTangent?: number;
|
||||
outTangentWeight?: number;
|
||||
interpMode?: number;
|
||||
broken?: boolean;
|
||||
tangentWeightMode?: number;
|
||||
imgUrl?: string;
|
||||
easingMethod?: number;
|
||||
}
|
||||
|
||||
export interface IDumpType {
|
||||
value: string;
|
||||
extends?: string[];
|
||||
}
|
||||
|
||||
export interface IPropCurveDumpData {
|
||||
nodePath: string;
|
||||
// 原始的 keyframe 数据
|
||||
keyframes: IKeyDumpData[];
|
||||
displayName: string;
|
||||
key: string;
|
||||
type?: IDumpType;
|
||||
preExtrap: number;
|
||||
postExtrap: number;
|
||||
isCurveSupport: boolean; // 是否支持贝塞尔曲线编辑
|
||||
}
|
||||
|
||||
export interface IAnimCopyKeySrcInfo {
|
||||
curvesDump: IPropCurveDumpData[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyNodeSrcInfo {
|
||||
curvesDump: IPropCurveDumpData[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyNodeDstInfo {
|
||||
nodePath: string;
|
||||
}
|
||||
|
||||
interface IEventDump {
|
||||
frame: number;
|
||||
func: string;
|
||||
params: string[];
|
||||
}
|
||||
|
||||
interface IEventDump {
|
||||
frame: number;
|
||||
func: string;
|
||||
params: string[];
|
||||
}
|
||||
|
||||
export interface IPlayableInfo {
|
||||
type: 'animation-clip' | 'particle-system';
|
||||
clip?: string;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export interface IEmbeddedPlayers {
|
||||
begin: number;
|
||||
end: number;
|
||||
reconciledSpeed: boolean;
|
||||
playable?: IPlayableInfo;
|
||||
group: string;
|
||||
}
|
||||
|
||||
export interface AnimationClipPlayerInfo extends IPlayableInfo {
|
||||
clip: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface ParticleSystemPlayerInfo extends IPlayableInfo {
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface EditorAnimationClipDump {
|
||||
name: string;
|
||||
duration: number;
|
||||
sample: number;
|
||||
speed: number;
|
||||
wrapMode: number;
|
||||
|
||||
curves: ICurveDumpData[];
|
||||
events: IEventDump[];
|
||||
embeddedPlayers: IEmbeddedPlayers[];
|
||||
time: number;
|
||||
isLock: boolean;
|
||||
embeddedPlayerGroups: EmbeddedPlayerGroup[];
|
||||
}
|
||||
|
||||
export interface EditorEmbeddedPlayer extends IEmbeddedPlayers {
|
||||
_embeddedPlayer: any;
|
||||
}
|
||||
|
||||
export interface IAnimCopyEmbeddedPlayersSrcInfo {
|
||||
embeddedPlayersDump: IEmbeddedPlayers[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyEventSrcInfo {
|
||||
eventsDump: IEventDump[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyPropSrcInfo {
|
||||
curvesDump: IPropCurveDumpData[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyPropDstInfo {
|
||||
nodePath: string;
|
||||
propKeys?: string[];
|
||||
}
|
||||
|
||||
export interface IAnimCopyKeyDstInfo {
|
||||
nodePath: string;
|
||||
propKeys?: string[];
|
||||
startFrame: number;
|
||||
}
|
||||
|
||||
export interface IAnimCopyEventDstInfo {
|
||||
startFrame: number;
|
||||
}
|
||||
// ---- 动画数据 ---- end
|
||||
|
||||
// ---- Contributions ---- start
|
||||
|
||||
export interface ContributionDropItem {
|
||||
type: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// ---- Contributions ---- end
|
||||
|
||||
export interface UnitTestInfo {
|
||||
name: string;
|
||||
}
|
||||
761
extensions/app/engine/@types/packages/scene/@types/scene-facade-interface.d.ts
vendored
Normal file
761
extensions/app/engine/@types/packages/scene/@types/scene-facade-interface.d.ts
vendored
Normal file
@@ -0,0 +1,761 @@
|
||||
import {
|
||||
SetPropertyOptions,
|
||||
MoveArrayOptions,
|
||||
RemoveArrayOptions,
|
||||
CutNodeOptions,
|
||||
PasteNodeOptions,
|
||||
CreateNodeOptions,
|
||||
RemoveNodeOptions,
|
||||
CreateComponentOptions,
|
||||
RemoveComponentOptions,
|
||||
ExecuteComponentMethodOptions,
|
||||
IAnimOperation,
|
||||
ExecuteSceneScriptMethodOptions,
|
||||
QueryClassesOptions,
|
||||
} from './public';
|
||||
|
||||
import { Node, Vec3, Quat } from 'cc';
|
||||
import type ParticleManager from '../source/script/3d/manager/particle';
|
||||
import { ISceneEvents } from '../source/script/3d/manager/scene-events-interface';
|
||||
|
||||
interface ISceneFacade extends ISceneEvents {
|
||||
init(): void;
|
||||
|
||||
//////////
|
||||
// node //
|
||||
//////////
|
||||
|
||||
/**
|
||||
* 打开某个场景
|
||||
* @param uuid 场景uuid
|
||||
*/
|
||||
openScene(uuid: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 保存当前场景
|
||||
*/
|
||||
saveScene(asNew: boolean): Promise<boolean>;
|
||||
|
||||
closeScene(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 软刷新场景
|
||||
*/
|
||||
softReloadScene(json: any): Promise<boolean>;
|
||||
|
||||
reloadScene(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 查询当前场景的节点树信息
|
||||
* @param uuid 节点的唯一标识符
|
||||
*/
|
||||
queryNodeTree(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询使用了资源 UUID 的节点
|
||||
* @param uuid 资源 asset uuid
|
||||
*/
|
||||
queryNodesByAssetUuid(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询当前场景的序列化数据
|
||||
*/
|
||||
querySceneSerializedData(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询当前场景是否被修改
|
||||
*/
|
||||
querySceneDirty(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询引擎内所有的类
|
||||
*/
|
||||
queryClasses(options?: QueryClassesOptions): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询引擎内所有的组件列表
|
||||
*/
|
||||
queryComponents(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询引擎组件列表是否含有指定类名的脚本
|
||||
* @param name 查询脚本的名字
|
||||
*/
|
||||
queryComponentHasScript(name: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 查询引擎内 Layer 的内置项
|
||||
*/
|
||||
queryLayerBuiltin(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询当前场景的编辑模式
|
||||
*/
|
||||
queryMode(): string;
|
||||
|
||||
/**
|
||||
* 查询当前场景资源的 uuid
|
||||
*/
|
||||
queryCurrentSceneUuid(): string;
|
||||
|
||||
//////////
|
||||
// node //
|
||||
//////////
|
||||
|
||||
/**
|
||||
* 查询一个节点的 dump 数据
|
||||
* @param uuid 节点的唯一标识符
|
||||
*/
|
||||
queryNodeDump(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询一个节点内挂载的所有组件以及对应的函数
|
||||
* @param uuid 节点的唯一标识符
|
||||
*/
|
||||
queryComponentFunctionOfNode(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 设置某个元素内的属性
|
||||
* @param options
|
||||
*/
|
||||
setNodeProperty(options: SetPropertyOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 设置某个元素内的某个属性的默认值
|
||||
* @param options
|
||||
*/
|
||||
resetNodeProperty(options: SetPropertyOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 预览设置某个元素内的属性(不会进undo)
|
||||
* @param options
|
||||
*/
|
||||
previewSetNodeProperty(options: SetPropertyOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 取消预览设置某个元素内的属性(不会进undo)
|
||||
* @param options
|
||||
*/
|
||||
cancelPreviewSetNodeProperty(options: SetPropertyOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 将一个属性从 null 值变为可编辑的值
|
||||
* @param options
|
||||
*/
|
||||
updateNodePropertyFromNull(options: SetPropertyOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 设置某个节点连同它的子集的 layer 属性值
|
||||
* @param options
|
||||
*/
|
||||
setNodeAndChildrenLayer(options: SetPropertyOptions): void;
|
||||
|
||||
/**
|
||||
* 移动数组类型 property 内的某个 item 的位置
|
||||
* @param options
|
||||
*/
|
||||
moveNodeArrayElement(options: MoveArrayOptions): void;
|
||||
|
||||
/**
|
||||
* 删除数组类型 property 内的某个 item 的位置
|
||||
* @param options
|
||||
*/
|
||||
removeNodeArrayElement(options: RemoveArrayOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 实时获取新节点在一个父节点下的有效名称
|
||||
* 规则是 Node 同名时为 Node-001
|
||||
* @param name 名称
|
||||
* @param parentUuid 父节点 uuid
|
||||
*/
|
||||
generateNodeAvailableName(name: string, parentUuid: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* 暂存一个节点的实例化对象
|
||||
* 一般用在复制节点的动作,给下一步粘贴(创建)节点准备数据
|
||||
* @param uuids 节点uuid
|
||||
*/
|
||||
copyNode(uuids: string | string[]): string[];
|
||||
|
||||
/**
|
||||
* 复制节点自身
|
||||
* ctrl + d
|
||||
* @param uuids 节点uuid
|
||||
*/
|
||||
duplicateNode(uuids: string | string[]): string[];
|
||||
|
||||
/**
|
||||
* 粘贴节点
|
||||
* @param options 参数
|
||||
*/
|
||||
pasteNode(options: PasteNodeOptions): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* 挂载节点
|
||||
* @param options 参数
|
||||
*/
|
||||
setNodeParent(options: CutNodeOptions): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* 创建一个新的节点
|
||||
* @param options 参数
|
||||
*/
|
||||
createNode(options: CreateNodeOptions): Promise<any>;
|
||||
|
||||
/**
|
||||
* 重置节点属性 position rotation scale
|
||||
* @param options 参数
|
||||
*/
|
||||
resetNode(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 删除一个节点
|
||||
* @param options 参数
|
||||
*/
|
||||
removeNode(options: RemoveNodeOptions): void;
|
||||
|
||||
/**
|
||||
* 锁定一个节点不让其在场景中被选中
|
||||
* @param uuids 节点uuid
|
||||
* @param locked true | false
|
||||
* @param loop true | false 是否循环子孙级节点设置
|
||||
*/
|
||||
changeNodeLock(uuids: string | string[], locked: Boolean, loop: Boolean): void;
|
||||
|
||||
/**
|
||||
* 从资源数据还原一个 prefab 节点
|
||||
* @param uuid 节点uuid
|
||||
* @param assetUuid 资源uuid
|
||||
*/
|
||||
restorePrefab(uuid: string, assetUuid: string): Promise<boolean>;
|
||||
|
||||
///////////////
|
||||
// component //
|
||||
///////////////
|
||||
|
||||
/**
|
||||
* 查询一个组件的 dump 数据
|
||||
* @param uuid 节点的唯一标识符
|
||||
*/
|
||||
queryComponent(uuid: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 在某个节点上创建一个组件
|
||||
* @param options 参数
|
||||
*/
|
||||
createComponent(options: CreateComponentOptions): void;
|
||||
|
||||
/**
|
||||
* 重置组件
|
||||
* @param uuid 组件
|
||||
*/
|
||||
resetComponent(uuid: string): void;
|
||||
|
||||
/**
|
||||
* 删除某个节点上的某个组件
|
||||
* @param options 参数
|
||||
*/
|
||||
removeComponent(options: RemoveComponentOptions): void;
|
||||
|
||||
/**
|
||||
* 执行 entity 上指定组件的方法
|
||||
* @param options 参数
|
||||
*/
|
||||
executeComponentMethod(options: ExecuteComponentMethodOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 执行插件注册的场景脚本方法
|
||||
* @param name 插件名字
|
||||
* @param method 方法名字
|
||||
* @param args 传入的参数
|
||||
*/
|
||||
executeSceneScriptMethod(options: ExecuteSceneScriptMethodOptions): Promise<any>;
|
||||
|
||||
///////////////
|
||||
// undo/redo //
|
||||
///////////////
|
||||
|
||||
/**
|
||||
* 保存一次操作记录
|
||||
*/
|
||||
snapshot(command?: any): void;
|
||||
|
||||
/**
|
||||
* 放弃当前步骤的所有变动记录
|
||||
*/
|
||||
abortSnapshot(): void;
|
||||
|
||||
/**
|
||||
* 撤销一次操作记录
|
||||
*/
|
||||
undo(): void;
|
||||
|
||||
/**
|
||||
* 重做一次操作记录
|
||||
*/
|
||||
redo(): void;
|
||||
|
||||
/**
|
||||
* 记录变动的节点
|
||||
* @param node
|
||||
* @param enable enable = false 是内部 undo redo 产生的变化, 不参与重新记录
|
||||
*/
|
||||
recordNode(node: Node, enable: boolean): void;
|
||||
|
||||
///////////
|
||||
// asset //
|
||||
///////////
|
||||
|
||||
/**
|
||||
* 查询所有内置 Effects
|
||||
*/
|
||||
queryAllEffects(): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询一个 material 的 dump 数据
|
||||
* @param uuid material 的唯一标识符
|
||||
*/
|
||||
queryMaterial(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 根据 effecName 构建指定 Effect 的 props 和 defines 属性
|
||||
* @param effectName effect 的名字
|
||||
*/
|
||||
queryEffect(effectName: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 查询当个 RenderPipeline
|
||||
* @param uuid 查询的资源的唯一标识符
|
||||
*/
|
||||
queryRenderPipeline(uuid: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* 材质,实时预览 material 数据
|
||||
* @param uuid 材质uuid
|
||||
* @param material 材质数据
|
||||
*/
|
||||
previewMaterial(uuid: string, material: any, opts?: {emit?: boolean}): void;
|
||||
|
||||
/**
|
||||
* 应用材质
|
||||
* @param uuid 材质uuid
|
||||
* @param materialDump 材质dump数据
|
||||
*/
|
||||
applyMaterial(uuid: string, materialDump: any): void;
|
||||
|
||||
/**
|
||||
* 修改 physics-material
|
||||
* @param dump dump数据
|
||||
*/
|
||||
changePhysicsMaterial(dump: any): Promise<any>;
|
||||
|
||||
/**
|
||||
* 保存 physics-material
|
||||
* @param uuid uuid
|
||||
*/
|
||||
applyPhysicsMaterial(uuid: string): void;
|
||||
|
||||
/**
|
||||
* 修改 animation-mask
|
||||
* @param dump dump数据
|
||||
*/
|
||||
changeAnimationMask(dump: any): Promise<any>;
|
||||
|
||||
/**
|
||||
* 保存 animation-mask
|
||||
* @param uuid uuid
|
||||
*/
|
||||
applyAnimationMask(uuid: string): void;
|
||||
|
||||
/**
|
||||
* 保存 render-texture
|
||||
* @param uuid uuid
|
||||
* @param dump dump数据
|
||||
*/
|
||||
applyRenderTexture(uuid: string, dump: any): void;
|
||||
|
||||
/**
|
||||
* 修改了 RenderPipeline 数据
|
||||
* @param dump 数据
|
||||
*/
|
||||
changeRenderPipeline(dump: any): Promise<any>;
|
||||
|
||||
/**
|
||||
* 应用 RenderPipeline 数据
|
||||
* @param uuid pipeline uuid
|
||||
* @param renderPipelineDump RenderPipeline的dump数据
|
||||
*/
|
||||
applyRenderPipeline(uuid: string, renderPipelineDump: any): void;
|
||||
|
||||
/**
|
||||
* 查询一个 physics-material 的 dump 数据
|
||||
* @param uuid 资源的唯一标识符
|
||||
*/
|
||||
queryPhysicsMaterial(uuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询一个 animation-mask 的 dump 数据
|
||||
* @param uuid 资源的唯一标识符
|
||||
*/
|
||||
queryAnimationMask(uuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询可以被创建为节点的所有资源类型
|
||||
*/
|
||||
queryCreatableAssetTypes(): any;
|
||||
|
||||
assetChange(uuid: string, info?: any, meta?: any): Promise<void>;
|
||||
|
||||
assetDelete(uuid: string, info?: any): void;
|
||||
|
||||
/**
|
||||
* 一个资源更新到场景的引用中后发出此消息
|
||||
* @param uuid 资源uuid
|
||||
*/
|
||||
assetRefresh(uuid: string): void;
|
||||
|
||||
///////////
|
||||
// gizmo //
|
||||
///////////
|
||||
|
||||
/**
|
||||
* 查询当前 gizmo 工具的名字
|
||||
*/
|
||||
queryGizmoToolName(): Promise<string>;
|
||||
|
||||
/**
|
||||
* 查询 gizmo 中心点类型
|
||||
*/
|
||||
queryGizmoPivot(): Promise<string>;
|
||||
|
||||
/**
|
||||
* 查询 gizmo 坐标类型
|
||||
*/
|
||||
queryGizmoCoordinate(): Promise<string>;
|
||||
|
||||
/**
|
||||
* 查询 是否处于2D编辑模式
|
||||
*/
|
||||
queryIs2D(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 查询icon gizmo是否为3D
|
||||
*/
|
||||
queryIsIconGizmo3D(): boolean;
|
||||
|
||||
/**
|
||||
* 获取icon gizmo的大小
|
||||
*/
|
||||
queryIconGizmoSize(): number;
|
||||
|
||||
/**
|
||||
* 改变Gizmo的操作工具
|
||||
* @param name 变换工具名字
|
||||
*/
|
||||
setTransformToolName(name: string): void;
|
||||
|
||||
/**
|
||||
* 改变基准中心
|
||||
* @param name 中心位置名
|
||||
*/
|
||||
setPivot(name: string): void;
|
||||
|
||||
/**
|
||||
* 设置使用全局或局部坐标系
|
||||
* @param type 坐标系类型
|
||||
*/
|
||||
setCoordinate(type: string): void;
|
||||
|
||||
/**
|
||||
* 是否进入2D编辑模式
|
||||
* @param value 是否使用2D
|
||||
*/
|
||||
setIs2D(value: boolean): void;
|
||||
|
||||
/**
|
||||
* 设置icon gizmo是否为3D
|
||||
* @param is3D 是否为3D icon
|
||||
*/
|
||||
setIconGizmo3D(is3D: boolean): void;
|
||||
|
||||
/**
|
||||
* 设置icon gizmo的大小
|
||||
*
|
||||
* @param size icon大小
|
||||
*/
|
||||
setIconGizmoSize(size: number): void;
|
||||
|
||||
////////////
|
||||
// camera //
|
||||
////////////
|
||||
/**
|
||||
* 聚焦于某个节点
|
||||
* @param uuid 节点uuid
|
||||
*/
|
||||
focus(uuid: string[] | null, position?: Vec3, rotation?: Quat, viewCenter?: Vec3, immediate?: boolean): void;
|
||||
|
||||
/**
|
||||
* 将编辑相机数据拷贝到节点上
|
||||
* @param uuids 节点数组
|
||||
*/
|
||||
alignNodeToSceneView(uuids: string[]): void;
|
||||
|
||||
/**
|
||||
* 查询grid是否可见
|
||||
*/
|
||||
queryIsGridVisible(): boolean;
|
||||
/**
|
||||
* 设置grid是否可见
|
||||
* @param visible 是否可见
|
||||
*/
|
||||
setGridVisible(visible: boolean): void;
|
||||
|
||||
/**
|
||||
* 将选中的节点与场景相机对齐
|
||||
*/
|
||||
alignWithView(): void;
|
||||
|
||||
/**
|
||||
* 将场景相机与选中的节点对齐
|
||||
*/
|
||||
alignViewWithNode(): void;
|
||||
/**
|
||||
* 设置网格线的颜色
|
||||
* @param color 网格线的颜色[255,255,255,255]
|
||||
*/
|
||||
setGridLineColor(color: number[]): void;
|
||||
|
||||
getCameraProperty(): any;
|
||||
setCameraProperty(opts: any): void;
|
||||
getCameraWheelSpeed(): number;
|
||||
setCameraWheelSpeed(speed: number): void;
|
||||
getCameraWanderSpeed(): number;
|
||||
setCameraWanderSpeed(speed: number): void;
|
||||
zoomSceneViewUp(): void;
|
||||
zoomSceneViewDown(): void;
|
||||
resetSceneViewZoom(): void;
|
||||
|
||||
///////////////
|
||||
// animation //
|
||||
///////////////
|
||||
|
||||
/**
|
||||
* 查询当前动画的播放状态
|
||||
*/
|
||||
queryCurrentAnimationState(): any;
|
||||
|
||||
/**
|
||||
* 查询当前动画的播放状态
|
||||
*/
|
||||
queryCurrentAnimationInfo(): any;
|
||||
|
||||
/**
|
||||
* 传入一个节点,查询这个节点所在的动画节点的 uuid
|
||||
* @param uuid 查询的节点的 uuid
|
||||
*/
|
||||
queryAnimationRootNode(uuid: string): string;
|
||||
|
||||
/**
|
||||
* 查询动画根节点的动画数据信息
|
||||
* @param uuid 查询的节点的 uuid
|
||||
*/
|
||||
queryAnimationRootInfo(uuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询一个 clip 的 dump 数据
|
||||
* @param nodeUuid 节点的唯一标识符
|
||||
* @param clipUuid 动画的唯一标识符
|
||||
*/
|
||||
queryAnimationClip(nodeUuid: string, clipUuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询一个节点上,可以编辑的动画属性数组
|
||||
* @param uuid 动画的 uuid
|
||||
*/
|
||||
queryAnimationProperties(uuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询一个节点上,可以编辑的嵌入播放器数组
|
||||
* @param uuid 节点的 uuid
|
||||
*/
|
||||
queryEmbeddedPlayerMenu(uuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询一个节点上的所有动画 clips 信息
|
||||
* @param nodeUuid 节点的唯一标识符
|
||||
*/
|
||||
queryAnimationClipsInfo(nodeUuid: string): any;
|
||||
|
||||
/**
|
||||
* 查询动画当前的播放时间信息
|
||||
* @param clipUuid 动画资源的唯一标识符
|
||||
*/
|
||||
queryAnimationClipCurrentTime(clipUuid: string): number;
|
||||
|
||||
/**
|
||||
* 查询动画当前轨道的某一帧的数值
|
||||
* @param clipUuid 动画 uuid
|
||||
* @param nodePath 查询数据所在的节点搜索路径
|
||||
* @param propKey 属性名字
|
||||
* @param frame 关键帧数
|
||||
*/
|
||||
queryAnimationPropValueAtFrame(clipUuid: string, nodePath: string, propKey: string, frame: number): any;
|
||||
|
||||
/**
|
||||
* 更改当前动画编辑模式
|
||||
* @param uuid uuid
|
||||
* @param active 激活或关闭
|
||||
*/
|
||||
recordAnimation(uuid: string, active: boolean): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 切换动画根节点
|
||||
* @param uuid uuid
|
||||
* @param clipUuid uuid of clip
|
||||
*/
|
||||
changeAnimationRootNode(uuid: string, clipUuid: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 更改当前当前关键帧
|
||||
* @param time 时间
|
||||
*/
|
||||
setCurEditTime(time: number): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 更改当前正在编辑的动画的播放状态
|
||||
* @param operate 操作
|
||||
* @param clipUuid uuid of clip
|
||||
*/
|
||||
changeClipState(operate: string, clipUuid: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 更改当前正在编辑的动画 uuid
|
||||
* @param clipUuid uuid of clip
|
||||
*/
|
||||
setEditClip(clipUuid: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 保存动画数据
|
||||
*/
|
||||
saveClip(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 动画操作
|
||||
*
|
||||
* @param operationList 操作方法数组
|
||||
*/
|
||||
applyAnimationOperation(operationList: IAnimOperation[]): Promise<boolean>;
|
||||
|
||||
/////////////
|
||||
// preview //
|
||||
/////////////
|
||||
queryPreviewWindowList(): any;
|
||||
|
||||
////////////
|
||||
// script //
|
||||
////////////
|
||||
queryScriptName(uuid: string): Promise<any>;
|
||||
queryScriptCid(uuid: string): Promise<any>;
|
||||
loadScript(uuid: string): Promise<void>;
|
||||
removeScript(info: any): Promise<void>;
|
||||
scriptChange(info: any): Promise<void>;
|
||||
|
||||
///////////////
|
||||
// selection //
|
||||
///////////////
|
||||
_selectNode(uuid: string): void;
|
||||
_unselectNode(uuid: string): void;
|
||||
querySelection(): string[];
|
||||
isSelectNode(uuid: string): boolean;
|
||||
selectNode(uuid: string): void;
|
||||
unselectNode(uuid: string): void;
|
||||
clearSelection(): void;
|
||||
|
||||
////////////
|
||||
// effect //
|
||||
////////////
|
||||
registerEffects(uuids: string[]): void;
|
||||
removeEffects(uuids: string[]): void;
|
||||
updateEffect(uuid: string): void;
|
||||
|
||||
/////////////
|
||||
// terrain //
|
||||
/////////////
|
||||
onRemoveTerrain(uuid: string, info: any): void;
|
||||
|
||||
/////////////
|
||||
// prefab //
|
||||
/////////////
|
||||
createPrefab(uuid: string, url: string): any;
|
||||
getPrefabData(uuid: string): any;
|
||||
linkPrefab(nodeUuid: string, assetUuid: string): any;
|
||||
unlinkPrefab(nodeUuid: string, removeNested: boolean): any;
|
||||
applyPrefab(nodeUuid: string): any;
|
||||
|
||||
//////////
|
||||
// UI //
|
||||
//////////
|
||||
distributeSelectionUI(type: string): void;
|
||||
alignSelectionUI(type: string): void;
|
||||
|
||||
////////////////
|
||||
// particle //
|
||||
////////////////
|
||||
/**
|
||||
* 查询粒子播放的信息
|
||||
* @param uuid 粒子组件的 uuid
|
||||
*/
|
||||
queryParticlePlayInfo(uuid: string): any;
|
||||
/**
|
||||
* 设置粒子播放速度
|
||||
* @param uuid 粒子组件的 uuid
|
||||
* @param speed
|
||||
*/
|
||||
setParticlePlaySpeed(uuid: string, speed: number): void;
|
||||
/**
|
||||
* 播放选中的粒子
|
||||
* @param uuid 粒子组件的 uuid
|
||||
*/
|
||||
playParticle();
|
||||
/**
|
||||
* 重新开始播放选中的粒子
|
||||
* @param uuid 粒子组件的 uuid
|
||||
*/
|
||||
restartParticle();
|
||||
/**
|
||||
* 暂停选中的粒子
|
||||
* @param uuid 粒子组件的 uuid
|
||||
*/
|
||||
pauseParticle();
|
||||
/**
|
||||
* 停止播放选中的粒子
|
||||
* @param uuid 粒子组件的 uuid
|
||||
*/
|
||||
stopParticle();
|
||||
/////////////////
|
||||
// wireframe //
|
||||
/////////////////
|
||||
// applyWireframeStorage(mode: any, color: any): void;
|
||||
// setWireframeMode(mode: any): void;
|
||||
// setWireframeColor(color: any): void;
|
||||
|
||||
///////////////////
|
||||
// physics //
|
||||
///////////////////
|
||||
updatePhysicsGroup(): void;
|
||||
|
||||
// others
|
||||
onEngineUpdate(): void;
|
||||
|
||||
///////////////////
|
||||
// physics 2D //
|
||||
///////////////////
|
||||
regeneratePolygon2DPoints(uuid: string): void;
|
||||
|
||||
///////////////////
|
||||
// particle 2D //
|
||||
///////////////////
|
||||
exportParticlePlist(uuid: string): Promise<any>;
|
||||
}
|
||||
|
||||
export default ISceneFacade;
|
||||
27
extensions/app/engine/@types/packages/server/@types/package.d.ts
vendored
Normal file
27
extensions/app/engine/@types/packages/server/@types/package.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// 消息定义
|
||||
interface MessageInterface {
|
||||
params: any[],
|
||||
result: any;
|
||||
}
|
||||
|
||||
// host
|
||||
export interface HostInfo {
|
||||
host: string;
|
||||
ip: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
// 消息定义
|
||||
export interface main {
|
||||
scene: {
|
||||
[x: string]: MessageInterface;
|
||||
'query-port': {
|
||||
params: [],
|
||||
result: number,
|
||||
};
|
||||
'scan-lan': {
|
||||
params: [],
|
||||
result: HostInfo[],
|
||||
};
|
||||
}
|
||||
}
|
||||
20
extensions/app/engine/@types/packages/shortcuts/@types/shortcut.d.ts
vendored
Normal file
20
extensions/app/engine/@types/packages/shortcuts/@types/shortcut.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
export interface ShortcutItem {
|
||||
when: string;
|
||||
message: string;
|
||||
shortcut: string;
|
||||
pkgName: string;
|
||||
params?: Array<string | number | boolean>;
|
||||
rawShortcut?: string;
|
||||
key: string;
|
||||
missing?: boolean;
|
||||
}
|
||||
|
||||
export type IShortcutItemMap = Record<string, ShortcutItem>;
|
||||
|
||||
export interface IShortcutEditInfo {
|
||||
key: string;
|
||||
shortcut: string;
|
||||
searches: ShortcutItem[];
|
||||
conflict: boolean;
|
||||
when: string;
|
||||
}
|
||||
30
extensions/app/engine/@types/packages/vivo-mini-game/@types/index.d.ts
vendored
Normal file
30
extensions/app/engine/@types/packages/vivo-mini-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'vivo-mini-game': IOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
package: string;
|
||||
icon: string;
|
||||
versionName: string;
|
||||
versionCode: string;
|
||||
minPlatformVersion: string;
|
||||
deviceOrientation: IOrientation;
|
||||
useDebugKey: boolean;
|
||||
privatePemPath: string;
|
||||
certificatePemPath: string;
|
||||
logLevel: string;
|
||||
separateEngine: boolean;
|
||||
}
|
||||
|
||||
export interface ICompileOptions {
|
||||
name: string;
|
||||
useDebugKey: boolean;
|
||||
}
|
||||
17
extensions/app/engine/@types/packages/web-desktop/@types/index.d.ts
vendored
Normal file
17
extensions/app/engine/@types/packages/web-desktop/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { appTemplateData, IInternalBuildOptions, IPolyFills } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export interface IOptions {
|
||||
resolution: {
|
||||
designHeight: number;
|
||||
designWidth: number;
|
||||
},
|
||||
}
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'web-desktop': IOptions;
|
||||
};
|
||||
appTemplateData: appTemplateData;
|
||||
}
|
||||
15
extensions/app/engine/@types/packages/web-mobile/@types/index.d.ts
vendored
Normal file
15
extensions/app/engine/@types/packages/web-mobile/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, IPolyFills, ISettings } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'auto' | 'landscape' | 'portrait';
|
||||
export interface IOptions {
|
||||
orientation: IOrientation;
|
||||
embedWebDebugger: boolean;
|
||||
}
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'web-mobile': IOptions;
|
||||
}
|
||||
}
|
||||
100
extensions/app/engine/@types/packages/wechatgame/@types/index.d.ts
vendored
Normal file
100
extensions/app/engine/@types/packages/wechatgame/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
export * from '../../../@types/editor';
|
||||
|
||||
import { IInternalBuildOptions } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'auto' | 'landscape' | 'portrait';
|
||||
|
||||
export interface IOptions {
|
||||
appid: string;
|
||||
buildOpenDataContextTemplate: boolean;
|
||||
orientation: IOrientation;
|
||||
separateEngine: boolean;
|
||||
wasm: 'js' | 'wasm' | boolean;
|
||||
enabelWebGL2: 'off' | 'sameAsProjectSetting';
|
||||
}
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
wechatgame: IOptions;
|
||||
};
|
||||
}
|
||||
|
||||
// TODO 需要更新 editor 接口定义
|
||||
export type IModules = Record<string, IModuleItem>;
|
||||
|
||||
export interface IFlagBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
native?: string;
|
||||
|
||||
wechatPlugin?: boolean;
|
||||
|
||||
default?: string[];
|
||||
}
|
||||
export interface IBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
required?: boolean;
|
||||
|
||||
native?: string;
|
||||
|
||||
wechatPlugin?: boolean;
|
||||
}
|
||||
|
||||
export interface IModuleItem extends IBaseItem {
|
||||
/**
|
||||
* Display text.
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Whether if the feature of options allow multiple selection.
|
||||
*/
|
||||
multi?: boolean;
|
||||
|
||||
/**
|
||||
* If have default it will checked
|
||||
*/
|
||||
default?: string[];
|
||||
|
||||
options?: Record<string, IBaseItem>;
|
||||
|
||||
category?: string;
|
||||
|
||||
flags?: Record<string, IFlagBaseItem>;
|
||||
}
|
||||
|
||||
export interface IDisplayModuleItem extends IModuleItem {
|
||||
_value: boolean;
|
||||
_option?: string;
|
||||
options?: Record<string, IDisplayModuleItem>;
|
||||
}
|
||||
|
||||
export interface IDisplayModuleCache {
|
||||
_value: boolean;
|
||||
_option?: string;
|
||||
flags?: Record<string, boolean>;
|
||||
}
|
||||
29
extensions/app/engine/@types/packages/windows/@types/index.d.ts
vendored
Normal file
29
extensions/app/engine/@types/packages/windows/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/// <reference path='../../../@types/index'/>
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
import { IInternalBuildOptions, InternalBuildResult } from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IOptions as INativeOption } from '@editor/library-type/packages/native';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'windows': IOptions;
|
||||
native: INativeOption;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
renderBackEnd: {
|
||||
vulkan: boolean;
|
||||
gles3: boolean;
|
||||
gles2: boolean;
|
||||
};
|
||||
targetPlatform: 'win32' | 'x64';
|
||||
serverMode: boolean;
|
||||
targetPlatform: 'x64';
|
||||
}
|
||||
|
||||
export interface IBuildResult extends InternalBuildResult {
|
||||
userFrameWorks: boolean; // 是否使用用户的配置数据
|
||||
}
|
||||
33
extensions/app/engine/@types/packages/xiaomi-quick-game/@types/index.d.ts
vendored
Normal file
33
extensions/app/engine/@types/packages/xiaomi-quick-game/@types/index.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
export * from '@editor/library-type/packages/builder/@types/protect';
|
||||
import { IInternalBuildOptions, ISettings } from '@editor/library-type/packages/builder/@types/protect';
|
||||
|
||||
export type IOrientation = 'landscape' | 'portrait';
|
||||
|
||||
export interface ITaskOption extends IInternalBuildOptions {
|
||||
packages: {
|
||||
'xiaomi-quick-game': IOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
package: string;
|
||||
icon: string;
|
||||
versionName: string;
|
||||
versionCode: string;
|
||||
minPlatformVersion: string;
|
||||
deviceOrientation: IOrientation;
|
||||
useDebugKey: boolean;
|
||||
privatePemPath: string;
|
||||
certificatePemPath: string;
|
||||
logLevel: string;
|
||||
|
||||
encapsulation: boolean;
|
||||
}
|
||||
|
||||
export interface ICompileOption {
|
||||
name: string;
|
||||
useDebugKey: boolean;
|
||||
tinyPackageServer: string;
|
||||
}
|
||||
|
||||
18
extensions/app/engine/dist/builder/hooks.js
vendored
Normal file
18
extensions/app/engine/dist/builder/hooks.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.onAfterBuild = void 0;
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const file_1 = require("./utils/file");
|
||||
const onAfterBuild = async function (options, result) {
|
||||
if (options.platform !== 'web-mobile' && options.platform !== 'web-desktop') {
|
||||
return;
|
||||
}
|
||||
if (!options.md5Cache) {
|
||||
return;
|
||||
}
|
||||
file_1.adaptFileMD5(path_1.default.join(result.dest, 'index.html'));
|
||||
};
|
||||
exports.onAfterBuild = onAfterBuild;
|
||||
8
extensions/app/engine/dist/builder/index.js
vendored
Normal file
8
extensions/app/engine/dist/builder/index.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.configs = void 0;
|
||||
exports.configs = {
|
||||
'*': {
|
||||
hooks: './hooks',
|
||||
}
|
||||
};
|
||||
248
extensions/app/engine/dist/builder/utils/file.js
vendored
Normal file
248
extensions/app/engine/dist/builder/utils/file.js
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.queryFile = exports.getFilePathRemoveMD5 = exports.getFileNameRemoveMD5 = exports.getFilesBySameNameDiffMD5 = exports.renameFileByMD5 = exports.isFileNameHasMD5 = exports.adaptFilename = exports.adaptFileMD5 = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const md5_1 = __importDefault(require("./md5"));
|
||||
const includeExts = ['.html', '.css', '.js', '.json'];
|
||||
const regExp = new RegExp('(?<=(\'|"|url\\(|URL\\())(?!//)[a-zA-Z0-9_\./-]+\\.(js|css|json|png|apng|jpg|jpeg|gif|svg)(?=(\'|"|\\)))', 'g');
|
||||
/**
|
||||
* 获取文件夹内的文件
|
||||
*/
|
||||
function getFiles(dir) {
|
||||
const result = [];
|
||||
// 判断文件是否存在
|
||||
if (!fs_1.default.existsSync(dir))
|
||||
return result;
|
||||
// 如果不是文件夹则返回
|
||||
if (!fs_1.default.statSync(dir).isDirectory())
|
||||
return result;
|
||||
// 遍历文件夹
|
||||
fs_1.default.readdirSync(dir).forEach(item => {
|
||||
const item_path = path_1.default.join(dir, item);
|
||||
const isDir = fs_1.default.statSync(item_path).isDirectory();
|
||||
if (!isDir)
|
||||
result.push(item_path);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 以某个文件为起点,对其引用的文件树进行md5
|
||||
* @param filepath 文件路径
|
||||
* @param exclude 排除的文件路径(不带md5,不支持相对路径),排除的文件不会遍历子文件树,默认其本身会进行md5
|
||||
*/
|
||||
function adaptFileMD5(filepath, exclude = []) {
|
||||
// 参数不合法
|
||||
if (!filepath)
|
||||
return false;
|
||||
// 修正文件路径
|
||||
filepath = fs_1.default.existsSync(filepath) ? filepath : queryFile(filepath);
|
||||
if (!filepath)
|
||||
return false;
|
||||
// 排除的文件
|
||||
const fileExt = path_1.default.extname(filepath);
|
||||
const filepathNoMD5 = getFilePathRemoveMD5(filepath);
|
||||
const excludeItem = exclude.find(item => {
|
||||
if (item.path instanceof RegExp)
|
||||
return item.path.test(filepath);
|
||||
else
|
||||
return item.path === filepathNoMD5;
|
||||
});
|
||||
const isExcluded = !!excludeItem || includeExts.indexOf(fileExt) === -1;
|
||||
// 文件扩展名
|
||||
if (!isExcluded) {
|
||||
// 文件目录
|
||||
const fileDir = path_1.default.dirname(filepath);
|
||||
// 文件内容
|
||||
let fileText = fs_1.default.readFileSync(filepath, 'utf-8');
|
||||
// 文件内所有引用的相对路径(排重)
|
||||
const subRelativePaths = Array.from(new Set(fileText.match(regExp)));
|
||||
for (let index = 0; index < subRelativePaths.length; index++) {
|
||||
// 子文件相对路径(读取到的)
|
||||
const subRelativePath = subRelativePaths[index];
|
||||
// 子文件路径(读取到的)
|
||||
const subFilePath = path_1.default.join(fileDir, subRelativePath);
|
||||
// 如果当前引用的文件的路径带有md5戳,并且文件存在,则跳过
|
||||
if (isFileNameHasMD5(subFilePath) && fs_1.default.existsSync(subFilePath))
|
||||
continue;
|
||||
{
|
||||
// 实际的子文件路径(不确定有没有md5)
|
||||
const subFilePathReal = queryFile(subFilePath);
|
||||
// 实际的子文件不存在
|
||||
if (!subFilePathReal) {
|
||||
// console.warn('[跳过] [文件不存在]', filepath, subRelativePath);
|
||||
continue;
|
||||
}
|
||||
// 如果引用的文件路径不带md5,但是实际文件有md5,则
|
||||
if (!isFileNameHasMD5(subFilePath) && isFileNameHasMD5(subFilePathReal)) {
|
||||
// 原始的子文件名
|
||||
const subFileBasename = path_1.default.basename(subRelativePath);
|
||||
// 实际的子文件名(带md5)
|
||||
const subFileBasenameReal = path_1.default.basename(subFilePathReal);
|
||||
// 替换
|
||||
fileText = fileText.replace(new RegExp(subRelativePath, 'g'), subRelativePath.replace(subFileBasename, subFileBasenameReal));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
// 对它进行md5处理
|
||||
const result = adaptFileMD5(subFilePath, exclude);
|
||||
// 文件不存在
|
||||
if (!result) {
|
||||
// console.warn('[跳过] [文件不存在]', filepath, subRelativePath);
|
||||
continue;
|
||||
}
|
||||
// 实际的子文件路径(已经带上md5了)
|
||||
const subFilepathReal = queryFile(subFilePath);
|
||||
// 原始的子文件名
|
||||
const subFileBasename = path_1.default.basename(subRelativePath);
|
||||
// 实际的子文件名(带md5)
|
||||
const subFileBasenameReal = path_1.default.basename(subFilepathReal);
|
||||
// 替换
|
||||
fileText = fileText.replace(new RegExp(subRelativePath, 'g'), subRelativePath.replace(subFileBasename, subFileBasenameReal));
|
||||
}
|
||||
}
|
||||
// 重新写入文件内容
|
||||
fs_1.default.writeFileSync(filepath, fileText, 'utf-8');
|
||||
}
|
||||
// 将文件md5重命名
|
||||
if (fileExt !== '.html' && (excludeItem === null || excludeItem === void 0 ? void 0 : excludeItem.md5) !== false) {
|
||||
renameFileByMD5(filepath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.adaptFileMD5 = adaptFileMD5;
|
||||
/**
|
||||
* 替换某个文件里引用的的文件名
|
||||
* @param {string} filepath 被替换的文件路径
|
||||
* @param {string} adaptDir adaptFile所在的文件夹
|
||||
* @param {string} adaptFile 文件名.后缀,不能包含其他东西
|
||||
*/
|
||||
function adaptFilename(filepath, adaptDir, adaptFile) {
|
||||
if (!fs_1.default.existsSync(filepath))
|
||||
return false;
|
||||
const adaptName = adaptFile.split('.')[0];
|
||||
const adaptExtname = path_1.default.extname(adaptFile) || '';
|
||||
let text = fs_1.default.readFileSync(filepath, 'utf-8');
|
||||
const filePaths = getFiles(adaptDir);
|
||||
for (let index = 0; index < filePaths.length; index++) {
|
||||
const filePath = filePaths[index];
|
||||
const basename = path_1.default.basename(filePath);
|
||||
const name = basename.split('.')[0];
|
||||
const extname = path_1.default.extname(basename) || '';
|
||||
if (basename !== adaptFile && name === adaptName && extname === adaptExtname) {
|
||||
const regExp = new RegExp(`(?<=('|"|\/))${name}[\.a-zA-Z0-9]*\\${extname}(?=('|"))`, 'g');
|
||||
text = text.replace(regExp, basename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fs_1.default.writeFileSync(filepath, text, 'utf-8');
|
||||
return true;
|
||||
}
|
||||
exports.adaptFilename = adaptFilename;
|
||||
/**
|
||||
* 判断一个文件是否有md5戳
|
||||
* @param {string} filename
|
||||
*/
|
||||
function isFileNameHasMD5(filename) {
|
||||
filename = path_1.default.basename(filename);
|
||||
return filename !== getFileNameRemoveMD5(filename);
|
||||
}
|
||||
exports.isFileNameHasMD5 = isFileNameHasMD5;
|
||||
/**
|
||||
* md5重命名文件名字
|
||||
* @param {string} filePath
|
||||
* @returns
|
||||
*/
|
||||
function renameFileByMD5(filePath) {
|
||||
const basename = getFileNameRemoveMD5(filePath);
|
||||
const extname = path_1.default.extname(basename);
|
||||
if (!extname)
|
||||
return filePath;
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
if (!filename)
|
||||
return filePath;
|
||||
const dirname = path_1.default.dirname(filePath);
|
||||
const txt = fs_1.default.readFileSync(filePath, 'utf-8');
|
||||
const renamePath = path_1.default.join(dirname, `${filename}.${md5_1.default(txt)}${extname}`);
|
||||
fs_1.default.renameSync(filePath, renamePath);
|
||||
return renamePath;
|
||||
}
|
||||
exports.renameFileByMD5 = renameFileByMD5;
|
||||
/**
|
||||
* 获取相同名字相同后缀, 但md5戳不一样的文件数组
|
||||
* @param {string} dir
|
||||
*/
|
||||
function getFilesBySameNameDiffMD5(dir) {
|
||||
// [ [ {name:'index',ext:'.js',files:['/test/index.js','/test/index.c67d.js']} ]
|
||||
const result = [];
|
||||
const files = getFiles(dir);
|
||||
files.forEach(filepath => {
|
||||
const basename = getFileNameRemoveMD5(filepath);
|
||||
if (!basename)
|
||||
return;
|
||||
const extname = path_1.default.extname(basename);
|
||||
if (!extname)
|
||||
return;
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
if (!filename)
|
||||
return;
|
||||
const res = result.find(data => data.name === filename && data.ext === extname);
|
||||
if (res)
|
||||
return res.files.push(filepath);
|
||||
result.push({
|
||||
name: filename,
|
||||
ext: extname,
|
||||
files: [filepath]
|
||||
});
|
||||
});
|
||||
return result.filter((data) => data.files.length >= 2);
|
||||
}
|
||||
exports.getFilesBySameNameDiffMD5 = getFilesBySameNameDiffMD5;
|
||||
/**
|
||||
* 将文件名中的md5字段去除
|
||||
* @param {string} filename
|
||||
* @returns
|
||||
*/
|
||||
function getFileNameRemoveMD5(filename) {
|
||||
const basename = path_1.default.basename(filename)
|
||||
// a-jqw89a.js => a.js
|
||||
// a-jqw89a.min.js => a.min.js
|
||||
.replace(/-[a-z0-9]+\./, '.');
|
||||
return basename.split('.').filter((str, index, array) => {
|
||||
if (index === 0 || index === array.length - 1)
|
||||
return true;
|
||||
return index == 1 && str === 'min';
|
||||
}).join('.');
|
||||
}
|
||||
exports.getFileNameRemoveMD5 = getFileNameRemoveMD5;
|
||||
/**
|
||||
* 删除文件路径中的md5字段
|
||||
* @param {string} filepath
|
||||
* @returns
|
||||
*/
|
||||
function getFilePathRemoveMD5(filepath) {
|
||||
const dirname = path_1.default.dirname(filepath);
|
||||
return path_1.default.join(dirname, getFileNameRemoveMD5(filepath));
|
||||
}
|
||||
exports.getFilePathRemoveMD5 = getFilePathRemoveMD5;
|
||||
/**
|
||||
* 输入文件路径,可以索引到对应的带有md5的文件路径
|
||||
* @param {string} filepath 文件路径(带后缀)
|
||||
* @returns
|
||||
*/
|
||||
function queryFile(filepath) {
|
||||
// 将文件名中的md5字段去除
|
||||
const filename = getFileNameRemoveMD5(filepath);
|
||||
const fileDir = path_1.default.dirname(filepath);
|
||||
const filesList = getFiles(fileDir);
|
||||
return filesList.find(filepath => {
|
||||
return path_1.default.basename(filepath) === filename;
|
||||
}) || filesList.find(filepath => {
|
||||
return getFileNameRemoveMD5(filepath) === filename;
|
||||
});
|
||||
}
|
||||
exports.queryFile = queryFile;
|
||||
370
extensions/app/engine/dist/builder/utils/md5.js
vendored
Normal file
370
extensions/app/engine/dist/builder/utils/md5.js
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
"use strict";
|
||||
/*
|
||||
* JavaScript MD5
|
||||
* https://github.com/blueimp/JavaScript-MD5
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
* Based on
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
* Distributed under the BSD License
|
||||
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/* global define */
|
||||
/* eslint-disable strict */
|
||||
/**
|
||||
* Add integers, wrapping at 2^32.
|
||||
* This uses 16-bit operations internally to work around bugs in interpreters.
|
||||
*
|
||||
* @param {number} x First integer
|
||||
* @param {number} y Second integer
|
||||
* @returns {number} Sum
|
||||
*/
|
||||
function safeAdd(x, y) {
|
||||
let lsw = (x & 0xffff) + (y & 0xffff);
|
||||
let msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xffff);
|
||||
}
|
||||
/**
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*
|
||||
* @param {number} num 32-bit number
|
||||
* @param {number} cnt Rotation count
|
||||
* @returns {number} Rotated number
|
||||
*/
|
||||
function bitRotateLeft(num, cnt) {
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} q q
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5cmn(q, a, b, x, s, t) {
|
||||
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5ff(a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5gg(a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5hh(a, b, c, d, x, s, t) {
|
||||
return md5cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5ii(a, b, c, d, x, s, t) {
|
||||
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Calculate the MD5 of an array of little-endian words, and a bit length.
|
||||
*
|
||||
* @param {Array} x Array of little-endian words
|
||||
* @param {number} len Bit length
|
||||
* @returns {Array<number>} MD5 Array
|
||||
*/
|
||||
function binlMD5(x, len) {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << len % 32;
|
||||
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||
let i;
|
||||
let olda;
|
||||
let oldb;
|
||||
let oldc;
|
||||
let oldd;
|
||||
let a = 1732584193;
|
||||
let b = -271733879;
|
||||
let c = -1732584194;
|
||||
let d = 271733878;
|
||||
for (i = 0; i < x.length; i += 16) {
|
||||
olda = a;
|
||||
oldb = b;
|
||||
oldc = c;
|
||||
oldd = d;
|
||||
a = md5ff(a, b, c, d, x[i], 7, -680876936);
|
||||
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||||
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||||
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||||
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||||
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||||
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||||
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||||
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||||
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||||
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
|
||||
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||||
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||||
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||||
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||||
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||||
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||||
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||||
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||||
b = md5gg(b, c, d, a, x[i], 20, -373897302);
|
||||
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||||
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||||
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||||
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||||
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||||
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||||
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||||
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||||
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||||
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||||
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||||
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||||
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
|
||||
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||||
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||||
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||||
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||||
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||||
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||||
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||||
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||||
d = md5hh(d, a, b, c, x[i], 11, -358537222);
|
||||
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||||
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||||
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||||
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||||
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||||
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||||
a = md5ii(a, b, c, d, x[i], 6, -198630844);
|
||||
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||||
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||||
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||||
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||||
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||||
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||||
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||||
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||||
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||||
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||||
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||||
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||||
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||||
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||||
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||||
a = safeAdd(a, olda);
|
||||
b = safeAdd(b, oldb);
|
||||
c = safeAdd(c, oldc);
|
||||
d = safeAdd(d, oldd);
|
||||
}
|
||||
return [a, b, c, d];
|
||||
}
|
||||
/**
|
||||
* Convert an array of little-endian words to a string
|
||||
*
|
||||
* @param {Array<number>} input MD5 Array
|
||||
* @returns {string} MD5 string
|
||||
*/
|
||||
function binl2rstr(input) {
|
||||
let i;
|
||||
let output = '';
|
||||
let length32 = input.length * 32;
|
||||
for (i = 0; i < length32; i += 8) {
|
||||
output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
/**
|
||||
* Convert a raw string to an array of little-endian words
|
||||
* Characters >255 have their high-byte silently ignored.
|
||||
*
|
||||
* @param {string} input Raw input string
|
||||
* @returns {Array<number>} Array of little-endian words
|
||||
*/
|
||||
function rstr2binl(input) {
|
||||
let i;
|
||||
let output = [];
|
||||
output[(input.length >> 2) - 1] = undefined;
|
||||
for (i = 0; i < output.length; i += 1) {
|
||||
output[i] = 0;
|
||||
}
|
||||
let length8 = input.length * 8;
|
||||
for (i = 0; i < length8; i += 8) {
|
||||
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
/**
|
||||
* Calculate the MD5 of a raw string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rstrMD5(s) {
|
||||
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8));
|
||||
}
|
||||
/**
|
||||
* Calculates the HMAC-MD5 of a key and some data (raw strings)
|
||||
*
|
||||
* @param {string} key HMAC key
|
||||
* @param {string} data Raw input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rstrHMACMD5(key, data) {
|
||||
let i;
|
||||
let bkey = rstr2binl(key);
|
||||
let ipad = [];
|
||||
let opad = [];
|
||||
let hash;
|
||||
ipad[15] = opad[15] = undefined;
|
||||
if (bkey.length > 16) {
|
||||
bkey = binlMD5(bkey, key.length * 8);
|
||||
}
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
ipad[i] = bkey[i] ^ 0x36363636;
|
||||
opad[i] = bkey[i] ^ 0x5c5c5c5c;
|
||||
}
|
||||
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
|
||||
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128));
|
||||
}
|
||||
/**
|
||||
* Convert a raw string to a hex string
|
||||
*
|
||||
* @param {string} input Raw input string
|
||||
* @returns {string} Hex encoded string
|
||||
*/
|
||||
function rstr2hex(input) {
|
||||
let hexTab = '0123456789abcdef';
|
||||
let output = '';
|
||||
let x;
|
||||
let i;
|
||||
for (i = 0; i < input.length; i += 1) {
|
||||
x = input.charCodeAt(i);
|
||||
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
/**
|
||||
* Encode a string as UTF-8
|
||||
*
|
||||
* @param {string} input Input string
|
||||
* @returns {string} UTF8 string
|
||||
*/
|
||||
function str2rstrUTF8(input) {
|
||||
return unescape(encodeURIComponent(input));
|
||||
}
|
||||
/**
|
||||
* Encodes input string as raw MD5 string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rawMD5(s) {
|
||||
return rstrMD5(str2rstrUTF8(s));
|
||||
}
|
||||
/**
|
||||
* Encodes input string as Hex encoded string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Hex encoded string
|
||||
*/
|
||||
function hexMD5(s) {
|
||||
return rstr2hex(rawMD5(s));
|
||||
}
|
||||
/**
|
||||
* Calculates the raw HMAC-MD5 for the given key and data
|
||||
*
|
||||
* @param {string} k HMAC key
|
||||
* @param {string} d Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rawHMACMD5(k, d) {
|
||||
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d));
|
||||
}
|
||||
/**
|
||||
* Calculates the Hex encoded HMAC-MD5 for the given key and data
|
||||
*
|
||||
* @param {string} k HMAC key
|
||||
* @param {string} d Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function hexHMACMD5(k, d) {
|
||||
return rstr2hex(rawHMACMD5(k, d));
|
||||
}
|
||||
/**
|
||||
* Calculates MD5 value for a given string.
|
||||
* If a key is provided, calculates the HMAC-MD5 value.
|
||||
* Returns a Hex encoded string unless the raw argument is given.
|
||||
*
|
||||
* @param {string} string Input string
|
||||
* @param {string} [key] HMAC key
|
||||
* @param {boolean} [raw] Raw output switch
|
||||
* @returns {string} MD5 output
|
||||
*/
|
||||
function md5(string, key, raw) {
|
||||
if (!key) {
|
||||
if (!raw) {
|
||||
return hexMD5(string);
|
||||
}
|
||||
return rawMD5(string);
|
||||
}
|
||||
if (!raw) {
|
||||
return hexHMACMD5(key, string);
|
||||
}
|
||||
return rawHMACMD5(key, string);
|
||||
}
|
||||
exports.default = md5;
|
||||
49
extensions/app/engine/dist/inspector/asset-directory.js
vendored
Normal file
49
extensions/app/engine/dist/inspector/asset-directory.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.close = exports.ready = exports.update = exports.template = exports.$ = void 0;
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
exports.$ = {
|
||||
'code': '#code',
|
||||
'section': '#section',
|
||||
};
|
||||
exports.template = `
|
||||
<ui-section id="section" header="文件夹说明" expand>
|
||||
<ui-code id="code"></ui-code>
|
||||
</ui-section>
|
||||
`;
|
||||
function update(assetList, metaList) {
|
||||
this.assetList = assetList;
|
||||
this.metaList = metaList;
|
||||
if (assetList.length === 0) {
|
||||
this.$.code.innerHTML = '';
|
||||
}
|
||||
else {
|
||||
this.$.code.innerHTML = assetList
|
||||
.filter((asset) => {
|
||||
const mdFile = path_1.join(asset.file, `.${asset.name}.md`);
|
||||
return fs_1.existsSync(mdFile);
|
||||
})
|
||||
.map((asset) => {
|
||||
const mdFile = path_1.join(asset.file, `.${asset.name}.md`);
|
||||
const mdStr = fs_1.readFileSync(mdFile, 'utf-8');
|
||||
return assetList.length > 1 ? `${asset.url}:\n ${mdStr}` : mdStr;
|
||||
})
|
||||
.join('\n') || '';
|
||||
}
|
||||
if (this.$.code.innerHTML === '') {
|
||||
this.$.section.hidden = true;
|
||||
}
|
||||
else {
|
||||
this.$.section.hidden = false;
|
||||
}
|
||||
}
|
||||
exports.update = update;
|
||||
function ready() {
|
||||
// TODO something
|
||||
}
|
||||
exports.ready = ready;
|
||||
function close() {
|
||||
// TODO something
|
||||
}
|
||||
exports.close = close;
|
||||
549
extensions/app/engine/dist/main.js
vendored
Normal file
549
extensions/app/engine/dist/main.js
vendored
Normal file
@@ -0,0 +1,549 @@
|
||||
"use strict";
|
||||
/**
|
||||
* @en Registration method for the main process of Extension
|
||||
* @zh 为扩展的主进程的注册方法
|
||||
*/
|
||||
/**
|
||||
* // 打开panel
|
||||
* Editor.Panel.open(`${插件名}.${panel名}`);
|
||||
* // 调用普通事件
|
||||
* Editor.Message.request(插件名, 消息名, ...args);
|
||||
* // 调用场景方法
|
||||
* Editor.Message.request('scene', 'execute-scene-script', {
|
||||
* //插件名
|
||||
* name: string,
|
||||
* //方法名
|
||||
* method: string,
|
||||
* //参数列表
|
||||
* args: any[]
|
||||
* });
|
||||
*
|
||||
*/
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.unload = exports.load = exports.methods = void 0;
|
||||
// path.join不能正确处理'db://'结构,会把'//'变成'/'
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const utils_1 = require("./utils");
|
||||
const electron = require('electron');
|
||||
const adminFolderName = 'app-admin';
|
||||
const controllerFolderName = 'app-controller';
|
||||
const managerFolderName = 'app-manager';
|
||||
const modelFolderName = 'app-model';
|
||||
const soundFolderName = 'app-sound';
|
||||
const viewFolderName = 'app-view';
|
||||
const builtinFolderName = 'app-builtin';
|
||||
const bundleFolderName = 'app-bundle';
|
||||
const pkgFolderUrl = 'db://pkg/';
|
||||
const pkgFolderPath = utils_1.convertUrlToPath(pkgFolderUrl);
|
||||
const builtinFolderUrl = 'db://assets/' + builtinFolderName;
|
||||
const builtinFolderPath = utils_1.convertUrlToPath(builtinFolderUrl);
|
||||
const bundleFolderUrl = 'db://assets/' + bundleFolderName;
|
||||
const bundleFolderPath = utils_1.convertUrlToPath(bundleFolderUrl);
|
||||
const adminFolderUrl = builtinFolderUrl + '/' + adminFolderName;
|
||||
const adminFolderPath = builtinFolderPath + '/' + adminFolderName;
|
||||
const controllerFolderUrl = builtinFolderUrl + '/' + controllerFolderName;
|
||||
const controllerFolderPath = builtinFolderPath + '/' + controllerFolderName;
|
||||
const managerFolderUrl = builtinFolderUrl + '/' + managerFolderName;
|
||||
const managerFolderPath = builtinFolderPath + '/' + managerFolderName;
|
||||
const modelFolderUrl = builtinFolderUrl + '/' + modelFolderName;
|
||||
const modelFolderPath = builtinFolderPath + '/' + modelFolderName;
|
||||
const soundFolderUrl = bundleFolderUrl + '/' + soundFolderName;
|
||||
const soundFolderPath = bundleFolderPath + '/' + soundFolderName;
|
||||
const viewFolderUrl = bundleFolderUrl + '/' + viewFolderName;
|
||||
const viewFolderPath = bundleFolderPath + '/' + viewFolderName;
|
||||
const executorFileUrl = adminFolderUrl + '/executor.ts';
|
||||
const executorFilePath = adminFolderPath + '/executor.ts';
|
||||
function isExecutor(info, strict = true) {
|
||||
if (!strict) {
|
||||
if (info.path.endsWith('Controller') && info.type === 'cc.Script')
|
||||
return true;
|
||||
if (info.path.endsWith('Manager') && (info.type === 'cc.Script' || info.type === 'cc.Prefab'))
|
||||
return true;
|
||||
if ((info.name.startsWith('data.') || info.name.startsWith('config.') || info.name.startsWith('store.')) && info.type === 'cc.Script')
|
||||
return true;
|
||||
if ((info.name.startsWith('Page') || info.name.startsWith('Paper') || info.name.startsWith('Pop') || info.name.startsWith('Top'))
|
||||
&& (info.type === 'cc.Script' || info.type === 'cc.Prefab' || info.type === 'cc.Scene' || info.type === 'cc.SceneAsset'))
|
||||
return true;
|
||||
if (info.type === 'cc.AudioClip')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (info.path === builtinFolderUrl)
|
||||
return true;
|
||||
if (info.path === bundleFolderUrl)
|
||||
return true;
|
||||
if (info.path === managerFolderUrl)
|
||||
return true;
|
||||
if (info.path === controllerFolderUrl)
|
||||
return true;
|
||||
if (info.path === modelFolderUrl)
|
||||
return true;
|
||||
if (info.path === soundFolderUrl)
|
||||
return true;
|
||||
if (info.path === viewFolderUrl)
|
||||
return true;
|
||||
if (info.path.startsWith(controllerFolderUrl)) {
|
||||
return info.path.endsWith('Controller') && info.type === 'cc.Script';
|
||||
}
|
||||
if (info.path.startsWith(managerFolderUrl)) {
|
||||
return info.path.endsWith('Manager') && (info.type === 'cc.Script' || info.type === 'cc.Prefab');
|
||||
}
|
||||
if (info.path.startsWith(modelFolderUrl)) {
|
||||
return (info.name.startsWith('data.') || info.name.startsWith('config.') || info.name.startsWith('store.')) && info.type === 'cc.Script';
|
||||
}
|
||||
if (info.path.startsWith(viewFolderUrl)) {
|
||||
return (info.name.startsWith('Page') || info.name.startsWith('Paper') || info.name.startsWith('Pop') || info.name.startsWith('Top'))
|
||||
&& (info.type === 'cc.Script' || info.type === 'cc.Prefab' || info.type === 'cc.Scene' || info.type === 'cc.SceneAsset');
|
||||
}
|
||||
if (info.path.startsWith(soundFolderUrl)) {
|
||||
return info.type === 'cc.AudioClip';
|
||||
}
|
||||
}
|
||||
function compareStr(str1, str2) {
|
||||
if (str1 === str2) {
|
||||
return 0;
|
||||
}
|
||||
const len = Math.max(str1.length, str2.length);
|
||||
for (let i = 0, code1 = 0, code2 = 0; i < len; i++) {
|
||||
if (str1.length <= i) {
|
||||
return -1;
|
||||
}
|
||||
else if (str2.length <= i) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
code1 = str1.charCodeAt(i);
|
||||
code2 = str2.charCodeAt(i);
|
||||
if (code1 > code2) {
|
||||
return 1;
|
||||
}
|
||||
else if (code1 < code2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const viewSelect = ['Page', 'Paper', 'Pop', 'Top'];
|
||||
const viewRegExp = RegExp(`^(${viewSelect.join('|')})`);
|
||||
function readFileSyncByPath(url) {
|
||||
const filepath = utils_1.convertUrlToPath(url);
|
||||
return fs_1.existsSync(filepath) ? fs_1.readFileSync(filepath, 'utf8') : '';
|
||||
}
|
||||
function isTSDefault(value) {
|
||||
// const varname = value[0];
|
||||
const filename = value[1];
|
||||
const dirname = value[2];
|
||||
const extname = value[3];
|
||||
if (extname.endsWith('js')) {
|
||||
return false;
|
||||
}
|
||||
const filepath = path_1.default.join(utils_1.convertUrlToPath(dirname), filename + '.ts');
|
||||
const js = fs_1.readFileSync(filepath, 'utf8');
|
||||
return js.search(/export\s+default/) >= 0;
|
||||
}
|
||||
const keyWords = [
|
||||
'lib', 'manager', 'Manager', 'controller', 'Controller', 'data', 'config', 'store',
|
||||
'IViewName', 'IViewNames', 'IMiniViewName', 'IMiniViewNames', 'IMusicName', 'IMusicNames', 'IEffectName', 'IEffectNames',
|
||||
'ViewName', 'MiniViewName', 'MusicName', 'EffectName'
|
||||
];
|
||||
async function clearExecutor() {
|
||||
if (!fs_1.existsSync(executorFilePath))
|
||||
return;
|
||||
let result = '/* eslint-disable */\n' +
|
||||
'import { Component } from \'cc\';\n' +
|
||||
'import { app } from \'../../app/app\';\n' +
|
||||
'import { EDITOR,EDITOR_NOT_IN_PREVIEW } from \'cc/env\';\n\n';
|
||||
result += 'export type IReadOnly<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : (T[P] extends Object ? IReadOnly<T[P]> : T[P]); };\n\n';
|
||||
result += 'export type IViewName = "never"\n';
|
||||
result += 'export type IViewNames = IViewName[]\n';
|
||||
result += 'export type IMiniViewName = "never"\n';
|
||||
result += 'export type IMiniViewNames = IMiniViewName[]\n';
|
||||
result += 'export type IMusicName = "never"\n';
|
||||
result += 'export type IMusicNames = IMusicName[]\n';
|
||||
result += 'export type IEffectName = "never"\n';
|
||||
result += 'export type IEffectNames = IEffectName[]\n\n';
|
||||
result += 'export type IApp = {\n';
|
||||
result += ' Controller: {},\n';
|
||||
result += ' controller: {},\n';
|
||||
result += ' Manager: {},\n';
|
||||
result += ' manager: {},\n';
|
||||
result += ' data: {},\n';
|
||||
result += ' config: {}\n';
|
||||
result += ' store: {}\n';
|
||||
result += '}\n';
|
||||
// config
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.config, {})\n';
|
||||
// data
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.data, {})\n';
|
||||
// store
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.store, {})\n\n';
|
||||
// controller
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.Controller, {})\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.controller, {})\n\n';
|
||||
// 修正windows系统中的\为/
|
||||
result = result.replace(/\\/g, '/');
|
||||
// save
|
||||
if (readFileSyncByPath(executorFileUrl) !== result) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', executorFileUrl, result, {
|
||||
overwrite: true
|
||||
});
|
||||
}
|
||||
}
|
||||
async function updateExecutor() {
|
||||
// app-builtin文件夹不存在, 创建
|
||||
if (!fs_1.existsSync(builtinFolderPath))
|
||||
await utils_1.createFolderByUrl(builtinFolderUrl, { readme: utils_1.getResReadme(builtinFolderName) });
|
||||
// app-admin文件夹不存在, 创建
|
||||
if (!fs_1.existsSync(adminFolderPath))
|
||||
await utils_1.createFolderByUrl(adminFolderUrl, { meta: utils_1.getResMeta(adminFolderName), readme: utils_1.getResReadme(adminFolderName) });
|
||||
const mgrList = [];
|
||||
const ctrList = [];
|
||||
const dataList = [];
|
||||
const confList = [];
|
||||
const storeList = [];
|
||||
const viewScene = {};
|
||||
const miniViewKeys = {};
|
||||
const musicKeys = {};
|
||||
const effectKeys = {};
|
||||
// app-controller app-manager app-model
|
||||
const result1 = await Editor.Message.request('asset-db', 'query-assets', { pattern: builtinFolderUrl + '/{app-controller,app-manager/*,app-model}/*.ts' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// app-sound
|
||||
const result2 = await Editor.Message.request('asset-db', 'query-assets', { pattern: soundFolderUrl + '/{music,effect}/**/*.*' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// app-view
|
||||
const result3 = await Editor.Message.request('asset-db', 'query-assets', { pattern: viewFolderUrl + '/{page,pop,top,paper/*}/*/native/*.{prefab,scene}' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// manager
|
||||
const result4 = await Editor.Message.request('asset-db', 'query-assets', { pattern: 'db://app/manager/**/*.ts' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// 集合
|
||||
const results = result1.slice().concat(result2).concat(result3).concat(result4);
|
||||
for (let index = 0; index < results.length; index++) {
|
||||
const result = results[index];
|
||||
const fileUrl = result.url;
|
||||
// 文件名.扩展名
|
||||
const basename = path_1.default.basename(result.url || '') || '';
|
||||
// 扩展名
|
||||
const extname = path_1.default.extname(result.url || '') || '';
|
||||
// 文件名
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
// 文件目录名
|
||||
const dirname = path_1.default.dirname(result.url || '') || '';
|
||||
if (!basename)
|
||||
continue;
|
||||
if (!extname)
|
||||
continue;
|
||||
if (!filename)
|
||||
continue;
|
||||
if (!dirname)
|
||||
continue;
|
||||
if (extname === '.ts') {
|
||||
// 变量名
|
||||
const varname = filename.replace(/[.-]/g, '_');
|
||||
if (keyWords.indexOf(varname) >= 0) {
|
||||
console.log(`[跳过此文件] [${filename}] 原因: ${varname}与关键字中(${JSON.stringify(keyWords)})的一个重复`);
|
||||
}
|
||||
else if (fileUrl.startsWith(controllerFolderUrl)) {
|
||||
// 用户controller
|
||||
if (filename.endsWith('Controller')) {
|
||||
ctrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith(managerFolderUrl)) {
|
||||
// 用户manager
|
||||
if (filename.endsWith('Manager') && dirname.endsWith(utils_1.stringCaseNegate(filename.slice(0, -7)))) {
|
||||
mgrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith('db://app/manager/')) {
|
||||
// 系统manager(系统Mgr的文件夹命名为了美观没有那么规范,所以和用户Mgr的逻辑有区别)
|
||||
if (filename.endsWith('Manager') && dirname.endsWith(filename.slice(0, -7).toLowerCase())) {
|
||||
mgrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith(modelFolderUrl)) {
|
||||
// model
|
||||
if (filename.startsWith('data.')) {
|
||||
dataList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
else if (filename.startsWith('config.')) {
|
||||
confList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
else if (filename.startsWith('store.')) {
|
||||
storeList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (extname === '.prefab' || extname === '.scene') {
|
||||
if (fileUrl.startsWith(viewFolderUrl) && viewRegExp.test(filename)) {
|
||||
const dirArray = dirname.split('/');
|
||||
const index = dirArray.indexOf(viewFolderName);
|
||||
const viewDirArray = dirArray.slice(index + 1);
|
||||
if (['page', 'paper', 'pop', 'top'].indexOf(viewDirArray[0].toLowerCase()) >= 0) {
|
||||
// 主界面
|
||||
if (filename === `${utils_1.stringCase(viewDirArray[0], false)}${utils_1.stringCase(viewDirArray[1], false)}`) {
|
||||
viewScene[filename] = extname === '.scene';
|
||||
}
|
||||
// 子界面
|
||||
else if (filename === `${utils_1.stringCase(viewDirArray[0], false)}${utils_1.stringCase(viewDirArray[1], false)}${utils_1.stringCase(viewDirArray[2], false)}`) {
|
||||
miniViewKeys[filename] = `${utils_1.stringCase(viewDirArray[0], false)}${utils_1.stringCase(viewDirArray[1], false)}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 主界面
|
||||
if (filename === `${utils_1.stringCase(viewDirArray[1], false)}${utils_1.stringCase(viewDirArray[2], false)}`) {
|
||||
viewScene[filename] = extname === '.scene';
|
||||
}
|
||||
// 子界面
|
||||
else if (filename === `${utils_1.stringCase(viewDirArray[1], false)}${utils_1.stringCase(viewDirArray[2], false)}${utils_1.stringCase(viewDirArray[3], false)}`) {
|
||||
miniViewKeys[filename] = `${utils_1.stringCase(viewDirArray[0], false)}${utils_1.stringCase(viewDirArray[1], false)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith(soundFolderUrl)) {
|
||||
const dir = path_1.default.join(dirname.split(soundFolderName + '/').pop(), filename);
|
||||
if (dir.startsWith('music')) {
|
||||
// musicKeys
|
||||
musicKeys[dir] = dir;
|
||||
}
|
||||
else {
|
||||
// effectKeys
|
||||
effectKeys[dir] = dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
// const pkgNames: string[] = [];
|
||||
// if (existsSync(pkgFolderPath)) {
|
||||
// readdirSync(pkgFolderPath).forEach(function (item) {
|
||||
// const item_path = path.join(pkgFolderPath, item);
|
||||
// const item_stat = statSync(item_path);
|
||||
// if (!item_stat.isDirectory()) return;
|
||||
// const item_name = path.basename(item_path);
|
||||
// if (item_name.startsWith('@')) {
|
||||
// readdirSync(item_path).forEach(function (sub) {
|
||||
// const sub_path = path.join(item_path, sub);
|
||||
// const sub_stat = statSync(sub_path);
|
||||
// if (!sub_stat.isDirectory()) return;
|
||||
// const sub_name = path.basename(sub_path);
|
||||
// pkgNames.push(item_name + '/' + sub_name);
|
||||
// });
|
||||
// } else {
|
||||
// pkgNames.push(item_name);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
let result = '/* eslint-disable */\n' +
|
||||
'import { Component,director,Director } from \'cc\';\n' +
|
||||
'import { app } from \'../../app/app\';\n' +
|
||||
'import { EDITOR,EDITOR_NOT_IN_PREVIEW } from \'cc/env\';\n\n';
|
||||
result += 'export type IReadOnly<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : (T[P] extends Object ? IReadOnly<T[P]> : T[P]); };\n\n';
|
||||
result += `export type IViewName = ${Object.keys(viewScene).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IViewNames = IViewName[]\n';
|
||||
result += `export type IMiniViewName = ${Object.keys(miniViewKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IMiniViewNames = IMiniViewName[]\n';
|
||||
result += `export type IMusicName = ${Object.keys(musicKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IMusicNames = IMusicName[]\n';
|
||||
result += `export type IEffectName = ${Object.keys(effectKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IEffectNames = IEffectName[]\n\n';
|
||||
// pkgNames.forEach(name => result += `import 'db://pkg/${name}'\n`);
|
||||
const writeImport = function writeImport(arr, module) {
|
||||
return arr.forEach(function (value) {
|
||||
const varname = value[0];
|
||||
const filename = value[1];
|
||||
const dirname = value[2];
|
||||
if (isTSDefault(value)) {
|
||||
result += `import ${varname} from '${path_1.default.join(path_1.default.relative(adminFolderPath, utils_1.convertUrlToPath(dirname)), filename)}'\n`;
|
||||
}
|
||||
else if (module) {
|
||||
result += `import {${varname}} from '${path_1.default.join(path_1.default.relative(adminFolderPath, utils_1.convertUrlToPath(dirname)), filename)}'\n`;
|
||||
}
|
||||
else {
|
||||
result += `import * as ${varname} from '${path_1.default.join(path_1.default.relative(adminFolderPath, utils_1.convertUrlToPath(dirname)), filename)}'\n`;
|
||||
}
|
||||
});
|
||||
};
|
||||
writeImport(confList, false);
|
||||
writeImport(dataList, false);
|
||||
writeImport(storeList, false);
|
||||
writeImport(ctrList, true);
|
||||
writeImport(mgrList, true);
|
||||
// controller
|
||||
let ctrStr = '';
|
||||
let CtrStr = '';
|
||||
ctrList.forEach(function ([varname], index, array) {
|
||||
CtrStr += `${varname.slice(0, -10)}:typeof ${varname}`;
|
||||
ctrStr += `${varname.slice(0, -10).toLowerCase()}:IReadOnly<${varname}>`;
|
||||
if (index < array.length - 1) {
|
||||
CtrStr += ',';
|
||||
ctrStr += ',';
|
||||
}
|
||||
});
|
||||
// manager
|
||||
let mgrStr = '';
|
||||
let MgrStr = '';
|
||||
mgrList.forEach(function ([varname], index, array) {
|
||||
MgrStr += `${varname.slice(0, -7)}:Omit<typeof ${varname},keyof Component>`;
|
||||
if (varname === 'UIManager') {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname}<IViewName,IMiniViewName>,keyof Component>`;
|
||||
}
|
||||
else if (varname === 'SoundManager') {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname}<IEffectName,IMusicName>,keyof Component>`;
|
||||
}
|
||||
else {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname},keyof Component>`;
|
||||
}
|
||||
if (index < array.length - 1) {
|
||||
MgrStr += ',';
|
||||
mgrStr += ',';
|
||||
}
|
||||
});
|
||||
result += 'export type IApp = {\n';
|
||||
result += ` Controller: {${CtrStr}},\n`;
|
||||
result += ` controller: {${ctrStr}},\n`;
|
||||
result += ` Manager: {${MgrStr}},\n`;
|
||||
result += ` manager: {${mgrStr}},\n`;
|
||||
result += ` data: {${dataList.map(([varname]) => `${varname.slice(5)}:${varname}`).join(',')}},\n`;
|
||||
result += ` config: {${confList.map(([varname]) => `${varname.slice(7)}:IReadOnly<${varname}>`).join(',')}}\n`;
|
||||
result += ` store: {${storeList.map(([varname]) => `${varname.slice(6)}:IReadOnly<${varname}>`).join(',')}}\n`;
|
||||
result += '}\n\n';
|
||||
result += 'function init(){\n';
|
||||
// config
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.config, {${confList.map(([varname]) => `${varname.slice(7)}:new ${varname}()`).join(',')}})\n`;
|
||||
// data
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.data, {${dataList.map(([varname]) => `${varname.slice(5)}:new ${varname}()`).join(',')}})\n`;
|
||||
// store
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.store, {${storeList.map(([varname]) => `${varname.slice(6)}:new ${varname}()`).join(',')}})\n\n`;
|
||||
// controller
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.Controller, {${ctrList.map(([varname]) => `${varname.slice(0, -10)}:${varname}`).join(',')}})\n`;
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.controller, {${ctrList.map(([varname]) => `${varname.slice(0, -10).toLowerCase()}:new ${varname}()`).join(',')}})\n`;
|
||||
result += '}\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) director.on(Director.EVENT_RESET,init)\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) init()\n';
|
||||
// 修正windows系统中的\为/
|
||||
result = result.replace(/\\/g, '/');
|
||||
// save
|
||||
if (readFileSyncByPath(executorFileUrl) !== result) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', executorFileUrl, result, {
|
||||
overwrite: true
|
||||
});
|
||||
}
|
||||
}
|
||||
let timer = null;
|
||||
function callUpdateExecutor(clear = false) {
|
||||
if (timer)
|
||||
return;
|
||||
if (clear) {
|
||||
clearExecutor();
|
||||
callUpdateExecutor(false);
|
||||
}
|
||||
else {
|
||||
timer = setTimeout(() => {
|
||||
updateExecutor().finally(() => {
|
||||
timer = null;
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
// 获得Creator主窗口
|
||||
function getMainWebContents() {
|
||||
const windows = electron.BrowserWindow.getAllWindows();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
const win = windows[i];
|
||||
if (win.webContents.getURL().includes('windows/main.html') || (win.title && win.title.includes('Cocos Creator'))) {
|
||||
return win.webContents;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
function updateMark() {
|
||||
const webContents = getMainWebContents();
|
||||
if (webContents) {
|
||||
const hackCode = fs_1.readFileSync(path_1.default.join(__dirname, '../res/mark.js'), 'utf-8');
|
||||
webContents.executeJavaScript(hackCode);
|
||||
}
|
||||
}
|
||||
exports.methods = {
|
||||
['open-panel']() {
|
||||
Editor.Panel.open('app.open-panel');
|
||||
},
|
||||
['open-wiki']() {
|
||||
const url = 'https://gitee.com/cocos2d-zp/xforge/wikis/pages';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-issues']() {
|
||||
const url = 'https://gitee.com/cocos2d-zp/xforge/issues';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-github']() {
|
||||
const url = 'https://github.com/a1076559139/XForge';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-store']() {
|
||||
const url = 'https://store.cocos.com/app/search?name=xforge';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['refresh-executor']() {
|
||||
// 点击更新
|
||||
callUpdateExecutor();
|
||||
console.log('[executor.ts] 刷新成功');
|
||||
},
|
||||
['scene:ready']() {
|
||||
//
|
||||
},
|
||||
['asset-db:ready']() {
|
||||
updateExecutor();
|
||||
updateMark();
|
||||
},
|
||||
['asset-db:asset-add'](uuid, info) {
|
||||
if (!isExecutor(info))
|
||||
return;
|
||||
callUpdateExecutor();
|
||||
},
|
||||
['asset-db:asset-change'](uuid, info) {
|
||||
if (!isExecutor(info, false))
|
||||
return;
|
||||
callUpdateExecutor();
|
||||
},
|
||||
['asset-db:asset-delete'](uuid, info) {
|
||||
if (!isExecutor(info))
|
||||
return;
|
||||
callUpdateExecutor(true);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @en Hooks triggered after extension loading is complete
|
||||
* @zh 扩展加载完成后触发的钩子
|
||||
*/
|
||||
function load() {
|
||||
Editor.Message.request('asset-db', 'query-ready').then(ready => {
|
||||
if (!ready)
|
||||
return;
|
||||
updateExecutor();
|
||||
});
|
||||
}
|
||||
exports.load = load;
|
||||
/**
|
||||
* @en Hooks triggered after extension uninstallation is complete
|
||||
* @zh 扩展卸载完成后触发的钩子
|
||||
*/
|
||||
function unload() { }
|
||||
exports.unload = unload;
|
||||
38
extensions/app/engine/dist/menu/index.js
vendored
Normal file
38
extensions/app/engine/dist/menu/index.js
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.onAssetMenu = exports.onPanelMenu = exports.onDBMenu = exports.onCreateMenu = void 0;
|
||||
const tinyPNG_1 = __importDefault(require("./tinyPNG"));
|
||||
function getMenu(assetInfo) {
|
||||
return [
|
||||
{
|
||||
label: 'i18n:app.app',
|
||||
submenu: [
|
||||
{
|
||||
label: 'i18n:app.tiny',
|
||||
click() {
|
||||
tinyPNG_1.default(assetInfo.file);
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
function onCreateMenu(assetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
exports.onCreateMenu = onCreateMenu;
|
||||
function onDBMenu(assetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
exports.onDBMenu = onDBMenu;
|
||||
function onPanelMenu(assetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
exports.onPanelMenu = onPanelMenu;
|
||||
function onAssetMenu(assetInfo) {
|
||||
return getMenu(assetInfo);
|
||||
}
|
||||
exports.onAssetMenu = onAssetMenu;
|
||||
164
extensions/app/engine/dist/menu/tinyPNG.js
vendored
Normal file
164
extensions/app/engine/dist/menu/tinyPNG.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
"use strict";
|
||||
/**
|
||||
*
|
||||
* 参考: https://segmentfault.com/a/1190000015467084
|
||||
* 优化:通过 X-Forwarded-For 添加了动态随机伪IP,绕过 tinypng 的上传数量限制
|
||||
*
|
||||
*/
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const https_1 = __importDefault(require("https"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const url_1 = require("url");
|
||||
const exts = ['.png', '.jpg', '.jpeg'];
|
||||
const max = 5200000; // 5MB == 5242848.754299136
|
||||
const options = {
|
||||
method: 'POST',
|
||||
hostname: 'tinypng.com',
|
||||
path: '/backend/opt/shrink',
|
||||
headers: {
|
||||
'rejectUnauthorized': 'false',
|
||||
'Postman-Token': Date.now(),
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
|
||||
}
|
||||
};
|
||||
// 生成随机IP, 赋值给 X-Forwarded-For
|
||||
function getRandomIP() {
|
||||
return Array.from(Array(4)).map(() => Math.floor(Math.random() * 255)).join('.');
|
||||
}
|
||||
// 遍历文件列表
|
||||
function fileEach(folder, callback) {
|
||||
fs_1.default.readdir(folder, (err, files) => {
|
||||
if (err)
|
||||
console.error(err);
|
||||
files.forEach(file => {
|
||||
const filePath = path_1.default.join(folder, file);
|
||||
fs_1.default.stat(filePath, (err, stats) => {
|
||||
if (err)
|
||||
return console.error(err);
|
||||
if (stats.isDirectory()) {
|
||||
fileEach(filePath, callback);
|
||||
}
|
||||
else if (
|
||||
// 必须是文件,小于5MB,后缀 jpg||png
|
||||
stats.size <= max &&
|
||||
stats.isFile() &&
|
||||
exts.includes(path_1.default.extname(file))) {
|
||||
callback(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
// 压缩图片
|
||||
async function fileUpload(img_path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 通过 X-Forwarded-For 头部伪造客户端IP
|
||||
options.headers['X-Forwarded-For'] = getRandomIP();
|
||||
const req = https_1.default.request(options, function (res) {
|
||||
res.on('data', buf => {
|
||||
const data = JSON.parse(buf.toString());
|
||||
if (data.error) {
|
||||
reject(data.message);
|
||||
}
|
||||
else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.write(fs_1.default.readFileSync(img_path), 'binary');
|
||||
req.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
// 该方法被循环调用,请求图片数据
|
||||
function fileUpdate(img_path, obj) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = new url_1.URL(obj.output.url);
|
||||
const req = https_1.default.request(options, res => {
|
||||
let body = '';
|
||||
res.setEncoding('binary');
|
||||
res.on('data', function (data) {
|
||||
body += data;
|
||||
});
|
||||
res.on('end', function () {
|
||||
fs_1.default.writeFile(img_path, body, 'binary', err => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(obj);
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
// 根据字节大小转成B、KB、MB
|
||||
function toSize(b) {
|
||||
if (b < 1024) {
|
||||
return b + 'B';
|
||||
}
|
||||
else if (b < 1024 * 1024) {
|
||||
return (b / 1024).toFixed(2) + 'KB';
|
||||
}
|
||||
else {
|
||||
return (b / 1024 / 1024).toFixed(2) + 'MB';
|
||||
}
|
||||
}
|
||||
// 根据小数转成百分比字符串
|
||||
function toPercent(num) {
|
||||
return (num * 100).toFixed(2) + '%';
|
||||
}
|
||||
async function fileTiny(filePath) {
|
||||
return fileUpload(filePath)
|
||||
.then(obj => fileUpdate(filePath, obj));
|
||||
}
|
||||
function default_1(folder) {
|
||||
// 路径是否存在
|
||||
if (!fs_1.default.existsSync(folder)) {
|
||||
console.log(`路径不存在:${folder}`);
|
||||
return;
|
||||
}
|
||||
const basename = path_1.default.basename(folder);
|
||||
console.log(`[${basename}] 压缩中...`);
|
||||
// 是文件
|
||||
if (!fs_1.default.statSync(folder).isDirectory()) {
|
||||
if (!exts.includes(path_1.default.extname(folder))) {
|
||||
console.log(`[${basename}] 压缩失败!报错:只支持png、jpg与jpeg格式`);
|
||||
return;
|
||||
}
|
||||
fileTiny(folder)
|
||||
.then(obj => {
|
||||
console.log('[1/1]', `[${basename}]`, `压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('[1/1]', `[${basename}]`, `压缩失败!报错:${err}`);
|
||||
});
|
||||
return;
|
||||
}
|
||||
let total = 0;
|
||||
let finished = 0;
|
||||
// 是文件夹
|
||||
fileEach(folder, (filePath => {
|
||||
total++;
|
||||
const relativePath = path_1.default.relative(folder, filePath);
|
||||
fileTiny(filePath)
|
||||
.then(obj => {
|
||||
console.log(`[${++finished}/${total}]`, `[${relativePath}]`, `压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(`[${++finished}/${total}]`, `[${relativePath}]`, `压缩失败!报错:${err}`);
|
||||
});
|
||||
}));
|
||||
}
|
||||
exports.default = default_1;
|
||||
31
extensions/app/engine/dist/panel/components/app-create.js
vendored
Normal file
31
extensions/app/engine/dist/panel/components/app-create.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const create_controller_1 = __importDefault(require("./create-controller"));
|
||||
const create_manager_1 = __importDefault(require("./create-manager"));
|
||||
const create_model_1 = __importDefault(require("./create-model"));
|
||||
const create_res_1 = __importDefault(require("./create-res"));
|
||||
const create_sound_1 = __importDefault(require("./create-sound"));
|
||||
const create_view_1 = __importDefault(require("./create-view"));
|
||||
const Assets = path_1.join(__dirname, '../../../res/panel');
|
||||
const Menus = ['ViewComponent', 'ManagerComponent', 'ControllerComponent', 'ModelComponent', 'SoundComponent', 'ResComponent'];
|
||||
exports.default = vue_1.default.extend({
|
||||
components: { ViewComponent: create_view_1.default, ManagerComponent: create_manager_1.default, ControllerComponent: create_controller_1.default, ModelComponent: create_model_1.default, SoundComponent: create_sound_1.default, ResComponent: create_res_1.default },
|
||||
template: fs_1.readFileSync(path_1.join(Assets, 'components/app.html'), 'utf-8'),
|
||||
data() {
|
||||
return {
|
||||
menus: ['View', 'Manager', 'Controller', 'Model', 'Sound', '资源目录'],
|
||||
content: 'ViewComponent'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClick(index) {
|
||||
this.content = Menus[index];
|
||||
}
|
||||
},
|
||||
});
|
||||
31
extensions/app/engine/dist/panel/components/app.js
vendored
Normal file
31
extensions/app/engine/dist/panel/components/app.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const create_controller_1 = __importDefault(require("./create-controller"));
|
||||
const create_manager_1 = __importDefault(require("./create-manager"));
|
||||
const create_model_1 = __importDefault(require("./create-model"));
|
||||
const create_res_1 = __importDefault(require("./create-res"));
|
||||
const create_sound_1 = __importDefault(require("./create-sound"));
|
||||
const create_view_1 = __importDefault(require("./create-view"));
|
||||
const Assets = path_1.join(__dirname, '../../../res/panel');
|
||||
const Menus = ['ViewComponent', 'ManagerComponent', 'ControllerComponent', 'ModelComponent', 'SoundComponent', 'ResComponent'];
|
||||
exports.default = vue_1.default.extend({
|
||||
components: { ViewComponent: create_view_1.default, ManagerComponent: create_manager_1.default, ControllerComponent: create_controller_1.default, ModelComponent: create_model_1.default, SoundComponent: create_sound_1.default, ResComponent: create_res_1.default },
|
||||
template: fs_1.readFileSync(path_1.join(Assets, 'components/app.html'), 'utf-8'),
|
||||
data() {
|
||||
return {
|
||||
menus: ['View', 'Manager', 'Controller', 'Model', 'Sound', '资源目录'],
|
||||
content: 'ViewComponent'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClick(index) {
|
||||
this.content = Menus[index];
|
||||
}
|
||||
},
|
||||
});
|
||||
83
extensions/app/engine/dist/panel/components/create-controller.js
vendored
Normal file
83
extensions/app/engine/dist/panel/components/create-controller.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(name) {
|
||||
const basePath = '../../../extensions/app/assets/base/BaseController';
|
||||
return 'import BaseController from \'' + basePath + '\';\r\n' +
|
||||
'export class ' + name + ' extends BaseController<' + name + ', {\r\n' +
|
||||
' // 定义了事件,并同时定义参数列表和返回值\r\n' +
|
||||
' Refresh: (a: number) => boolean\r\n' +
|
||||
'}>() {\r\n' +
|
||||
' // Controller中发射事件, UI中监听事件:\r\n' +
|
||||
' // 1、UI中需要将 「extends BaseView」 改为=> 「extends BaseView.bindController(' + name + ')」\r\n' +
|
||||
' // 2、UI中使用「this.controller.on/once」监听事件, 使用「this.controller.emit」发射事件, 使用「this.controller.off/targetOff」取消监听事件\r\n' +
|
||||
' // 3、在外部(无法使用this.controller的地方)可以通过「app.controller.xxx」来调用对外导出的方法, 比如下面的refresh方法\r\n' +
|
||||
' refresh() {\r\n' +
|
||||
' this.emit(' + name + '.Event.Refresh, 1000); // 参数类型正确\r\n' +
|
||||
' this.emit(' + name + '.Event.Refresh, true); // 参数类型错误\r\n' +
|
||||
' const result = this.call(' + name + '.Event.Refresh, 1000); // 自动推导返回值类型\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-controller'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onClickCreate() {
|
||||
const name = this.inputName;
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
const rootPath = 'db://assets/app-builtin/app-controller';
|
||||
const controlName = `${utils_1.stringCase(name)}Controller`;
|
||||
const scriptUrl = `${rootPath}/${controlName}.ts`;
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: controlName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
if (fs_1.existsSync(utils_1.convertUrlToPath(scriptUrl))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 文件已存在, 请删除\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
// 目录如果不存在则创建
|
||||
if (!await utils_1.createFolderByUrl(rootPath, { meta: utils_1.getResMeta('app-controller'), readme: utils_1.getResReadme('app-controller') })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${rootPath}`;
|
||||
return;
|
||||
}
|
||||
// 创建script
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(controlName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
107
extensions/app/engine/dist/panel/components/create-manager.js
vendored
Normal file
107
extensions/app/engine/dist/panel/components/create-manager.js
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(name) {
|
||||
const basePath = '../../../../extensions/app/assets/base/BaseManager';
|
||||
return 'import { _decorator } from \'cc\';\r\n' +
|
||||
'import BaseManager from \'' + basePath + '\';\r\n' +
|
||||
'const { ccclass, property } = _decorator;\r\n' +
|
||||
'@ccclass(\'' + name + '\')\r\n' +
|
||||
'export class ' + name + ' extends BaseManager {\r\n' +
|
||||
' // [无序] 加载完成时触发\r\n' +
|
||||
' protected onLoad() { }\r\n\r\n' +
|
||||
' // [无序] 自身初始化完成, init执行完毕后被调用\r\n' +
|
||||
' protected onInited() { }\r\n\r\n' +
|
||||
' // [无序] 所有manager初始化完成\r\n' +
|
||||
' protected onFinished() { }\r\n\r\n' +
|
||||
' // [无序] 初始化manager,在初始化完成后,调用finish方法\r\n' +
|
||||
' protected init(finish: Function) {\r\n' +
|
||||
' super.init(finish);\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-manager'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onClickCreate() {
|
||||
const name = this.inputName;
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
const rootPath = 'db://assets/app-builtin/app-manager';
|
||||
const managerName = `${utils_1.stringCase(name)}Manager`;
|
||||
const folderName = name;
|
||||
const folderPath = `${rootPath}/${folderName}`;
|
||||
const scriptUrl = `${folderPath}/${managerName}.ts`;
|
||||
const prefabUrl = `${folderPath}/${managerName}.prefab`;
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: managerName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
if (fs_1.existsSync(utils_1.convertUrlToPath(folderPath))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 目录已存在, 请删除\n${folderPath}`;
|
||||
return;
|
||||
}
|
||||
// 目录如果不存在则创建
|
||||
if (!await utils_1.createFolderByUrl(rootPath, {
|
||||
meta: utils_1.getResMeta('app-manager'),
|
||||
readme: utils_1.getResReadme('app-manager'),
|
||||
subFolders: [
|
||||
{
|
||||
folder: folderName,
|
||||
readme: `1、${managerName}所在文件夹, 通过app.manager.${utils_1.stringCase(name, true)}的方式调用\n2、如不再需要,可以直接删除此文件夹`
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${folderPath}`;
|
||||
return;
|
||||
}
|
||||
// 创建script
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(managerName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
// 创建prefab
|
||||
const createPrefabResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createPrefab',
|
||||
args: [managerName, prefabUrl]
|
||||
});
|
||||
if (!createPrefabResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建预制体失败\n${prefabUrl}`;
|
||||
return;
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
105
extensions/app/engine/dist/panel/components/create-model.js
vendored
Normal file
105
extensions/app/engine/dist/panel/components/create-model.js
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(type, className) {
|
||||
if (type === 'data') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IModel } from \'' + BaseModel + '\';\r\n' +
|
||||
'// data中不能定义任何方法(更建议使用store)\r\n' +
|
||||
'export default class ' + className + ' implements IModel<' + className + '> {\r\n' +
|
||||
'}';
|
||||
}
|
||||
else if (type === 'config') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IModel } from \'' + BaseModel + '\';\r\n' +
|
||||
'// config中不能定义任何方法, 任何变量在外部访问都是readonly\r\n' +
|
||||
'// 如果config中的内容是服务器下发的,可以使用Object.assign覆盖config中的内容\r\n' +
|
||||
'export default class ' + className + ' implements IModel<' + className + '> {\r\n' +
|
||||
'}';
|
||||
}
|
||||
else if (type === 'store') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IStore } from \'' + BaseModel + '\';\r\n' +
|
||||
'// store中只允许在根路径下定义方法,任何变量在外部访问都是readonly\r\n' +
|
||||
'// store类型的引入是借鉴了Web前端框架中全局状态管理的思路,意图是让数据更安全,更可控。同时框架中还提供了数据绑定的扩展包,可以通过pkg的方式安装,实现「数据->视图」的单向绑定。\r\n' +
|
||||
'export default class ' + className + ' implements IStore<' + className + '> {\r\n' +
|
||||
' count = 0;\r\n' +
|
||||
' setCount(v: number) {\r\n' +
|
||||
' this.count = v;\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
else {
|
||||
return '// 🔥切记: 当前文件处于分包中, 由于加载顺序的原因,不可以在「主包」中使用此文件内导出的变量\r\n' +
|
||||
'// 存放直接导出的interface、type或enum等\r\n\r\n' +
|
||||
'// export type IString = string;\r\n' +
|
||||
'// export enum Type { None };';
|
||||
}
|
||||
}
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-model'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
typeSelects: ['store', 'data', 'config', 'export'],
|
||||
typeSelectIndex: 0,
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const type = this.typeSelects[this.typeSelectIndex];
|
||||
const name = this.inputName;
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
const rootPath = 'db://assets/app-builtin/app-model';
|
||||
const modelName = `${type}.${name}`;
|
||||
const scriptUrl = `${rootPath}/${modelName}.ts`;
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: modelName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
// 目录如果不存在则创建
|
||||
if (!await utils_1.createFolderByUrl(rootPath, { meta: utils_1.getResMeta('app-model'), readme: utils_1.getResReadme('app-model') })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${rootPath}`;
|
||||
return;
|
||||
}
|
||||
if (fs_1.existsSync(utils_1.convertUrlToPath(scriptUrl))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 文件已存在, 请删除\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(type, utils_1.stringCase(name))).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
62
extensions/app/engine/dist/panel/components/create-res.js
vendored
Normal file
62
extensions/app/engine/dist/panel/components/create-res.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
const typeNames = ['res-native', 'res-bundle', 'resources'];
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-res'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
typeSelects: ['公共静态目录', '公共动态目录', 'resources'],
|
||||
typeSelectIndex: 0,
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const folderName = typeNames[this.typeSelectIndex];
|
||||
const folderPath = `db://assets/${folderName}`;
|
||||
const name = utils_1.stringCase(this.inputName, true);
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(this.inputName) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
if (name === 'resources') {
|
||||
this.display = '[错误] 名字不合法\n1、不能使用resources作为名字';
|
||||
return;
|
||||
}
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: name, buttons: ['创建', '取消'], default: 0, cancel: 1 });
|
||||
if (createResponse.response == 1) {
|
||||
return;
|
||||
}
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
if (!await utils_1.createFolderByUrl(folderPath, {
|
||||
readme: utils_1.getResReadme(folderName),
|
||||
meta: folderName === 'resources' ? utils_1.getResMeta('resources') : undefined,
|
||||
subFolders: [
|
||||
{
|
||||
folder: name,
|
||||
meta: folderName === 'res-bundle' ? utils_1.getResMeta('custom-bundle') : undefined
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 创建失败';
|
||||
return;
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${folderPath}`;
|
||||
Editor.Message.send('assets', 'twinkle', folderPath);
|
||||
}
|
||||
},
|
||||
});
|
||||
45
extensions/app/engine/dist/panel/components/create-sound.js
vendored
Normal file
45
extensions/app/engine/dist/panel/components/create-sound.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-sound'),
|
||||
data() {
|
||||
return {
|
||||
display: '',
|
||||
typeSelects: ['音乐', '音效'],
|
||||
typeSelectIndex: 0,
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
const rootPath = 'db://assets/app-bundle/app-sound';
|
||||
if (!await utils_1.createFolderByUrl(rootPath, {
|
||||
meta: utils_1.getResMeta('app-sound'),
|
||||
readme: utils_1.getResReadme('app-sound'),
|
||||
subFolders: [
|
||||
{
|
||||
folder: this.typeSelectIndex === 0 ? 'music' : 'effect',
|
||||
readme: utils_1.getResReadme(this.typeSelectIndex === 0 ? 'sound-music' : 'sound-effect')
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 创建失败';
|
||||
return;
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
Editor.Message.send('assets', 'twinkle', rootPath);
|
||||
}
|
||||
},
|
||||
});
|
||||
249
extensions/app/engine/dist/panel/components/create-view.js
vendored
Normal file
249
extensions/app/engine/dist/panel/components/create-view.js
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
const vue_1 = __importDefault(require("../../../../vue"));
|
||||
const utils_1 = require("../../utils");
|
||||
/**
|
||||
* 获取脚本内容
|
||||
*/
|
||||
function getComScript(name = 'NewClass') {
|
||||
const isPage = name.toLowerCase().startsWith('page');
|
||||
const isPaper = name.toLowerCase().startsWith('paper');
|
||||
const basePath = isPaper ? '../../../../../../../extensions/app/assets/base/BaseView' : '../../../../../../extensions/app/assets/base/BaseView';
|
||||
return 'import { _decorator, Node } from \'cc\';\r\n' +
|
||||
'import BaseView from \'' + basePath + '\';\r\n' +
|
||||
`${isPage ? 'import { IMiniViewNames } from \'../../../../../app-builtin/app-admin/executor\';\r\n' : ''}` +
|
||||
'const { ccclass, property } = _decorator;\r\n' +
|
||||
'@ccclass(\'' + name + '\')\r\n' +
|
||||
'export class ' + name + ' extends BaseView {\r\n' +
|
||||
` ${isPage ? '// 子界面列表,数组顺序为子界面排列顺序\r\n' : ''}` +
|
||||
` ${isPage ? 'protected miniViews: IMiniViewNames = [];\r\n\r\n' : '\r\n'}` +
|
||||
' // 初始化的相关逻辑写在这\r\n' +
|
||||
' onLoad() {}\r\n\r\n' +
|
||||
' // 界面打开时的相关逻辑写在这(onShow可被多次调用-它与onHide不成对)\r\n' +
|
||||
' onShow(params: any) {\r\n' +
|
||||
` ${isPage ? 'this.showMiniViews({ views: this.miniViews });' : ''}\r\n` +
|
||||
' }\r\n\r\n' +
|
||||
' // 界面关闭时的相关逻辑写在这(已经关闭的界面不会触发onHide)\r\n' +
|
||||
' onHide(result: undefined) {\r\n' +
|
||||
` ${isPaper ? '' : '// app.manager.ui.show<' + name + '>({name: \'' + name + '\', onHide:(result) => { 接收到return的数据,并且有类型提示 }})\r\n'}` +
|
||||
` ${isPaper ? '' : 'return result;'}\r\n` +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
function getNaMetaUserData(name = 'new-class') {
|
||||
return Object.assign(Object.assign({}, utils_1.getResMeta('view-native')), { 'bundleName': `${name}` });
|
||||
}
|
||||
function getResMetaUserData(name = 'new-class') {
|
||||
return Object.assign(Object.assign({}, utils_1.getResMeta('view-resources')), { 'bundleName': `${name}-res` });
|
||||
}
|
||||
/**
|
||||
* UI类型(小写)
|
||||
*/
|
||||
const TypeSelects = ['page', 'paper', 'pop', 'top'];
|
||||
/**
|
||||
* 大驼峰UI名(带page前缀) => 串式UI目录名(不带page前缀)
|
||||
*/
|
||||
const PageNames = new Map();
|
||||
function updatePages() {
|
||||
PageNames.clear();
|
||||
// page目录
|
||||
const pageRootPath = path_1.join(Editor.Project.path, 'assets/app-bundle/app-view/page');
|
||||
// 读取page目录下所有文件
|
||||
const folderNames = fs_1.existsSync(pageRootPath) ? fs_1.readdirSync(pageRootPath) : [];
|
||||
// 大驼峰命名的UI名
|
||||
folderNames.forEach((folderName) => {
|
||||
// folderName为串式命名法
|
||||
const pagePath = path_1.join(pageRootPath, folderName);
|
||||
const isDirectory = fs_1.statSync(pagePath).isDirectory();
|
||||
if (isDirectory) {
|
||||
PageNames.set(`Page${utils_1.stringCase(folderName)}`, folderName);
|
||||
}
|
||||
});
|
||||
PageNames.set('通用', 'all');
|
||||
return Array.from(PageNames.keys());
|
||||
}
|
||||
exports.default = vue_1.default.extend({
|
||||
template: utils_1.getResPanel('create-view'),
|
||||
data() {
|
||||
return {
|
||||
showLoading: false,
|
||||
showSelectPage: false,
|
||||
showSelectGroup: true,
|
||||
inputName: '',
|
||||
display: '',
|
||||
typeSelects: TypeSelects,
|
||||
typeSelectIndex: 0,
|
||||
groupSelects: ['2D', '3D'],
|
||||
groupSelectIndex: 0,
|
||||
pageSelects: [],
|
||||
pageSelectIndex: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeGroupSelect(index) {
|
||||
this.groupSelectIndex = Number(index);
|
||||
},
|
||||
onChangeTypeSelect(index) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
if (index == '0') {
|
||||
this.showSelectGroup = true;
|
||||
}
|
||||
else {
|
||||
this.showSelectGroup = false;
|
||||
}
|
||||
if (index == '1') {
|
||||
this.pageSelectIndex = 0;
|
||||
this.pageSelects = updatePages();
|
||||
this.showSelectPage = true;
|
||||
}
|
||||
else {
|
||||
this.showSelectPage = false;
|
||||
}
|
||||
},
|
||||
onChangePageSelect(index) {
|
||||
this.pageSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const isPage = this.typeSelectIndex == 0;
|
||||
const isPaper = this.typeSelectIndex == 1;
|
||||
// ui归属(大驼峰)
|
||||
const owner = this.pageSelects[this.pageSelectIndex];
|
||||
// ui类型(小写)
|
||||
const type = this.typeSelects[this.typeSelectIndex];
|
||||
// ui名字(串式)
|
||||
const name = this.inputName;
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
if (name === 'all' || name === 'page' || name === 'paper' || name === 'pop' || name === 'top') {
|
||||
this.display = '[错误] 名字不合法\n1、不能使用all、page、paper、pop、top作为名字';
|
||||
return;
|
||||
}
|
||||
const is3D = isPage && this.groupSelectIndex == 1;
|
||||
const ownerName = PageNames.get(owner);
|
||||
const uiName = isPaper ?
|
||||
`${utils_1.stringCase(type)}${utils_1.stringCase(ownerName)}${utils_1.stringCase(name)}` :
|
||||
`${utils_1.stringCase(type)}${utils_1.stringCase(name)}`;
|
||||
const bundleName = isPaper ?
|
||||
`${type}-${ownerName}-${name}` :
|
||||
`${type}-${name}`;
|
||||
const bundleFolderUrl = 'db://assets/app-bundle';
|
||||
const viewFolderUrl = `${bundleFolderUrl}/app-view`;
|
||||
const typeFolderUrl = `${viewFolderUrl}/${type}`;
|
||||
const uiFolderUrl = isPaper ?
|
||||
`${typeFolderUrl}/${ownerName}/${name}` :
|
||||
`${typeFolderUrl}/${name}`;
|
||||
const nativeUrl = `${uiFolderUrl}/native`;
|
||||
const resourcesUrl = `${uiFolderUrl}/resources`;
|
||||
const expansionUrl = `${nativeUrl}/expansion`;
|
||||
const scriptUrl = `${nativeUrl}/${uiName}.ts`;
|
||||
const prefabUrl = `${nativeUrl}/${uiName}.prefab`;
|
||||
const sceneUrl = `${nativeUrl}/${uiName}.scene`;
|
||||
const singleColorUrl = `${resourcesUrl}/singleColor.png`;
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: uiName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
// 创建目录
|
||||
if (!await utils_1.createFolderByUrl(uiFolderUrl, { subPaths: ['native', 'resources', 'native/expansion'] })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${uiFolderUrl}`;
|
||||
return;
|
||||
}
|
||||
// 设置native分包
|
||||
await utils_1.delayFileExistsByUrl(`${nativeUrl}.meta`);
|
||||
const queryNativeMeta = await Editor.Message.request('asset-db', 'query-asset-meta', nativeUrl).catch(_ => null);
|
||||
if (!queryNativeMeta) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 设置native分包配置失败';
|
||||
return;
|
||||
}
|
||||
queryNativeMeta.userData = getNaMetaUserData(bundleName);
|
||||
await Editor.Message.request('asset-db', 'save-asset-meta', nativeUrl, JSON.stringify(queryNativeMeta)).catch(_ => null);
|
||||
// 设置resources分包
|
||||
await utils_1.delayFileExistsByUrl(`${resourcesUrl}.meta`);
|
||||
const queryResMeta = await Editor.Message.request('asset-db', 'query-asset-meta', resourcesUrl).catch(_ => null);
|
||||
if (!queryResMeta) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 设置resources分包配置失败';
|
||||
return;
|
||||
}
|
||||
queryResMeta.userData = getResMetaUserData(bundleName);
|
||||
await Editor.Message.request('asset-db', 'save-asset-meta', resourcesUrl, JSON.stringify(queryResMeta)).catch(_ => null);
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(bundleFolderUrl), '.app-bundle.md'), utils_1.getResReadme('app-bundle'));
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(viewFolderUrl), '.app-view.md'), utils_1.getResReadme('app-view'));
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(typeFolderUrl), `.${type}.md`), `1、所有${type}类型UI的根目录\n2、如不再需要,可以直接删除此文件夹`);
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(nativeUrl), '.native.md'), utils_1.getResReadme('view-native'));
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(resourcesUrl), '.resources.md'), utils_1.getResReadme('view-resources'));
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(expansionUrl), '.expansion.md'), utils_1.getResReadme('view-expansion'));
|
||||
if (isPaper) {
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(`${typeFolderUrl}/${ownerName}`), `.${ownerName}.md`), (ownerName === 'all' ? '1、归属于全体Page' : `1、归属于Page${utils_1.stringCase(ownerName)}`) + '\n2、如不再需要,可以直接删除此文件夹');
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(uiFolderUrl), `.${name}.md`), `${uiName}所在文件夹\n1、通过${ownerName === 'all' ? '在任意Page中配置miniViews属性并调用showMiniViews方法' : `在${owner}中配置miniViews属性并调用showMiniViews方法`}的方式加载\n2、如不再需要,可以直接删除此文件夹`);
|
||||
}
|
||||
else {
|
||||
fs_1.writeFileSync(path_1.join(utils_1.convertUrlToPath(uiFolderUrl), `.${name}.md`), `${uiName}所在文件夹\n1、通过app.manager.ui.show({ name:'${uiName}' })的方式加载\n2、如不再需要,可以直接删除此文件夹`);
|
||||
}
|
||||
// 创建script
|
||||
if (!fs_1.existsSync(utils_1.convertUrlToPath(scriptUrl))) {
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getComScript(uiName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 创建view
|
||||
if (!fs_1.existsSync(utils_1.convertUrlToPath(prefabUrl)) && !fs_1.existsSync(utils_1.convertUrlToPath(sceneUrl))) {
|
||||
if (is3D && isPage) {
|
||||
const createSceneResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createScene',
|
||||
args: [uiName, sceneUrl]
|
||||
}).catch(_ => null);
|
||||
if (!createSceneResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建场景失败\n${sceneUrl}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const createPrefabResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createPrefab',
|
||||
args: [uiName, prefabUrl, is3D]
|
||||
}).catch(_ => null);
|
||||
if (!createPrefabResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建预制体失败\n${prefabUrl}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${uiFolderUrl}`;
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
if (is3D) {
|
||||
Editor.Message.request('asset-db', 'open-asset', sceneUrl);
|
||||
}
|
||||
else {
|
||||
Editor.Message.request('asset-db', 'open-asset', prefabUrl);
|
||||
}
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
const base64 = 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAAA1BMVEX///+nxBvIAAAACklEQVQI12MAAgAABAABINItbwAAAABJRU5ErkJggg==';
|
||||
fs_1.writeFileSync(utils_1.convertUrlToPath(singleColorUrl), new Buffer(base64, 'base64'));
|
||||
Editor.Message.request('asset-db', 'refresh-asset', singleColorUrl).catch(_ => null);
|
||||
}
|
||||
}
|
||||
});
|
||||
29
extensions/app/engine/dist/panel/index.js
vendored
Normal file
29
extensions/app/engine/dist/panel/index.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
const Assets = path_1.join(__dirname, '../../res/panel');
|
||||
const app_1 = __importDefault(require("./components/app"));
|
||||
module.exports = Editor.Panel.define({
|
||||
template: fs_1.readFileSync(path_1.join(Assets, 'index.html'), 'utf-8'),
|
||||
style: fs_1.readFileSync(path_1.join(Assets, 'styles/index.css'), 'utf-8'),
|
||||
$: {
|
||||
app: '#app'
|
||||
},
|
||||
listeners: {
|
||||
show() { console.log('show'); },
|
||||
hide() { console.log('hide'); },
|
||||
},
|
||||
methods: {},
|
||||
ready() {
|
||||
if (!this.$.app)
|
||||
return;
|
||||
const com = new app_1.default();
|
||||
com.$mount(this.$.app);
|
||||
},
|
||||
beforeClose() { },
|
||||
close() { },
|
||||
});
|
||||
73
extensions/app/engine/dist/scene.js
vendored
Normal file
73
extensions/app/engine/dist/scene.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.methods = exports.unload = exports.load = void 0;
|
||||
const path_1 = require("path");
|
||||
module.paths.push(path_1.join(Editor.App.path, 'node_modules'));
|
||||
function load() { }
|
||||
exports.load = load;
|
||||
function unload() { }
|
||||
exports.unload = unload;
|
||||
// 在其他扩展脚本中,我们可以使用如下代码调用 rotateCamera 函数
|
||||
// const options: ExecuteSceneScriptMethodOptions = {
|
||||
// name: scene.ts 所在的扩展包名, 如: App,
|
||||
// method: scene.ts 中定义的方法, 如: rotateCamera,
|
||||
// args: 参数,可选, 只传递json
|
||||
// };
|
||||
// const result = await Editor.Message.request('scene', 'execute-scene-script', options);
|
||||
exports.methods = {
|
||||
async createPrefab(fileName, fileUrl, is3D = false) {
|
||||
const { Node, js, Layers } = require('cc');
|
||||
const node = new Node(fileName);
|
||||
node.layer = is3D ? Layers.Enum.UI_3D : Layers.Enum.UI_2D;
|
||||
while (true) {
|
||||
const result = js.getClassByName(fileName);
|
||||
if (result)
|
||||
break;
|
||||
await new Promise((next) => {
|
||||
setTimeout(next, 100);
|
||||
});
|
||||
}
|
||||
const com = node.addComponent(fileName);
|
||||
com.resetInEditor && com.resetInEditor();
|
||||
const info = cce.Prefab.generatePrefabDataFromNode(node);
|
||||
node.destroy();
|
||||
return Editor.Message.request('asset-db', 'create-asset', fileUrl, info.prefabData || info);
|
||||
},
|
||||
async createScene(fileName, fileUrl) {
|
||||
const { SceneAsset, Scene, Node, js, Layers, Camera, DirectionalLight } = require('cc');
|
||||
while (true) {
|
||||
const result = js.getClassByName(fileName);
|
||||
if (result)
|
||||
break;
|
||||
await new Promise((next) => {
|
||||
setTimeout(next, 100);
|
||||
});
|
||||
}
|
||||
const scene = new Scene(fileName);
|
||||
// 根节点
|
||||
const node = new Node(fileName);
|
||||
node.layer = Layers.Enum.DEFAULT;
|
||||
node.parent = scene;
|
||||
// 相机
|
||||
const camera = new Node('Camera');
|
||||
camera.addComponent(Camera);
|
||||
camera.layer = Layers.Enum.DEFAULT;
|
||||
camera.parent = node;
|
||||
// 灯光
|
||||
const light = new Node('Light');
|
||||
light.addComponent(DirectionalLight);
|
||||
light.layer = Layers.Enum.DEFAULT;
|
||||
light.parent = node;
|
||||
const com = node.addComponent(fileName);
|
||||
com.resetInEditor && com.resetInEditor();
|
||||
const sceneAsset = new SceneAsset();
|
||||
sceneAsset.scene = scene;
|
||||
const info = EditorExtends.serialize(sceneAsset);
|
||||
camera.destroy();
|
||||
light.destroy();
|
||||
node.destroy();
|
||||
scene.destroy();
|
||||
sceneAsset.destroy();
|
||||
return Editor.Message.request('asset-db', 'create-asset', fileUrl, info);
|
||||
},
|
||||
};
|
||||
190
extensions/app/engine/dist/utils.js
vendored
Normal file
190
extensions/app/engine/dist/utils.js
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.delayFileExistsByUrl = exports.delay = exports.createFolderByUrl = exports.getProjectPath = exports.convertUrlToPath = exports.stringCaseNegate = exports.stringCase = exports.getResPanel = exports.getResMeta = exports.getResReadme = exports.getResJson = void 0;
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
function getResJson(name) {
|
||||
const Assets = path_1.join(__dirname, '../res/json');
|
||||
const str = fs_1.readFileSync(path_1.join(Assets, `${name}.json`), 'utf-8');
|
||||
return str ? JSON.parse(str) : null;
|
||||
}
|
||||
exports.getResJson = getResJson;
|
||||
function getResReadme(name) {
|
||||
const Assets = path_1.join(__dirname, '../res/readme');
|
||||
return fs_1.readFileSync(path_1.join(Assets, `${name}.md`), 'utf-8');
|
||||
}
|
||||
exports.getResReadme = getResReadme;
|
||||
function getResMeta(name) {
|
||||
const Assets = path_1.join(__dirname, '../res/meta');
|
||||
const str = fs_1.readFileSync(path_1.join(Assets, `${name}.meta`), 'utf-8');
|
||||
return str ? JSON.parse(str) : null;
|
||||
}
|
||||
exports.getResMeta = getResMeta;
|
||||
function getResPanel(name) {
|
||||
const Assets = path_1.join(__dirname, '../res/panel');
|
||||
return fs_1.readFileSync(path_1.join(Assets, `components/${name}.html`), 'utf-8');
|
||||
}
|
||||
exports.getResPanel = getResPanel;
|
||||
/**
|
||||
* 将串式命名转成驼峰命名
|
||||
* @param str 串式字符串
|
||||
* @param lower 首字母是否小写(默认大写)
|
||||
* @returns
|
||||
*/
|
||||
function stringCase(str, lower = false) {
|
||||
str = str.replace(/-/g, '_');
|
||||
const arr = str.split('_');
|
||||
return arr.map(function (str, index) {
|
||||
if (index === 0 && lower) {
|
||||
return str.charAt(0).toLowerCase() + str.slice(1);
|
||||
}
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}).join('');
|
||||
}
|
||||
exports.stringCase = stringCase;
|
||||
/**
|
||||
* 将驼峰命名转成串式命名
|
||||
* @param str 驼峰字符串
|
||||
* @returns
|
||||
*/
|
||||
function stringCaseNegate(str) {
|
||||
return str.replace(/[A-Z]/g, (searchStr, startIndex) => {
|
||||
if (startIndex === 0) {
|
||||
return searchStr.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return '-' + searchStr.toLowerCase();
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.stringCaseNegate = stringCaseNegate;
|
||||
/**
|
||||
* db下的路径转换为真实路径
|
||||
*/
|
||||
function convertUrlToPath(url) {
|
||||
if (url.startsWith('db://assets')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, url.slice(5));
|
||||
}
|
||||
else if (url.startsWith('db://app')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, 'extensions/app/assets', url.slice(8));
|
||||
}
|
||||
else if (url.startsWith('db://pkg')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, 'extensions/pkg/node_modules', url.slice(8));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
exports.convertUrlToPath = convertUrlToPath;
|
||||
/**
|
||||
* 获取程序路径
|
||||
*/
|
||||
function getProjectPath() {
|
||||
return Editor.Project.path;
|
||||
}
|
||||
exports.getProjectPath = getProjectPath;
|
||||
/**
|
||||
* 根据db下的路径创建目录(不是文件)
|
||||
* 如果已存在不会重复创建
|
||||
*/
|
||||
async function createFolderByUrl(url, opts) {
|
||||
let pathHead = 'db://assets';
|
||||
if (!url && !url.startsWith(pathHead)) {
|
||||
return false;
|
||||
}
|
||||
// 修剪path
|
||||
const pathTail = url.endsWith('/') ? url.slice(pathHead.length + 1, -1).trim() : url.slice(pathHead.length + 1).trim();
|
||||
// 每一层的路径
|
||||
const pathArr = pathTail.split('/');
|
||||
// 创建主目录
|
||||
for (let index = 0; index < pathArr.length; index++) {
|
||||
pathHead += '/' + pathArr[index];
|
||||
if (!fs_1.existsSync(convertUrlToPath(pathHead))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', pathHead, null).catch(_ => null);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 主目录meta
|
||||
if (opts === null || opts === void 0 ? void 0 : opts.meta) {
|
||||
await delayFileExistsByUrl(`${url}.meta`);
|
||||
await delay(100);
|
||||
const queryMeta = await Editor.Message.request('asset-db', 'query-asset-meta', url).catch(_ => null);
|
||||
if (!queryMeta)
|
||||
return false;
|
||||
Object.assign(queryMeta.userData, opts.meta.userData);
|
||||
const result = await Editor.Message.request('asset-db', 'save-asset-meta', url, JSON.stringify(queryMeta)).catch(_ => null);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
// 主目录readme
|
||||
if (opts === null || opts === void 0 ? void 0 : opts.readme) {
|
||||
fs_1.writeFileSync(path_1.join(convertUrlToPath(url), `.${path_1.basename(url)}.md`), opts.readme);
|
||||
}
|
||||
// 创建子目录
|
||||
if (opts === null || opts === void 0 ? void 0 : opts.subPaths) {
|
||||
await delay(100);
|
||||
for (let index = 0; index < opts.subPaths.length; index++) {
|
||||
const subPath = `${pathHead}/${opts.subPaths[index]}`;
|
||||
if (!fs_1.existsSync(convertUrlToPath(subPath))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', subPath, null).catch(_ => null);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts === null || opts === void 0 ? void 0 : opts.subFolders) {
|
||||
await delay(100);
|
||||
for (let index = 0; index < opts.subFolders.length; index++) {
|
||||
const subOpts = opts.subFolders[index];
|
||||
const subUrl = `${pathHead}/${subOpts.folder}`;
|
||||
// 判断是否存在
|
||||
if (!fs_1.existsSync(convertUrlToPath(subUrl))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', subUrl, null).catch(_ => null);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
// meta
|
||||
if (subOpts.meta) {
|
||||
await delayFileExistsByUrl(`${subUrl}.meta`);
|
||||
const queryMeta = await Editor.Message.request('asset-db', 'query-asset-meta', subUrl).catch(_ => null);
|
||||
if (!queryMeta)
|
||||
return false;
|
||||
Object.assign(queryMeta.userData, subOpts.meta.userData);
|
||||
const result = await Editor.Message.request('asset-db', 'save-asset-meta', subUrl, JSON.stringify(queryMeta)).catch(_ => null);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
// readme
|
||||
if (subOpts.readme) {
|
||||
fs_1.writeFileSync(path_1.join(convertUrlToPath(subUrl), `.${path_1.basename(subUrl)}.md`), subOpts.readme);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.createFolderByUrl = createFolderByUrl;
|
||||
function delay(time) {
|
||||
return new Promise((next) => {
|
||||
setTimeout(() => {
|
||||
next(null);
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
exports.delay = delay;
|
||||
/**
|
||||
* 等待文件存在
|
||||
*/
|
||||
function delayFileExistsByUrl(url) {
|
||||
const path = convertUrlToPath(url);
|
||||
let timer = null;
|
||||
return new Promise((next) => {
|
||||
timer = setInterval(() => {
|
||||
if (fs_1.existsSync(path)) {
|
||||
if (timer)
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
next(null);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
exports.delayFileExistsByUrl = delayFileExistsByUrl;
|
||||
41
extensions/app/engine/package-lock.json
generated
Normal file
41
extensions/app/engine/package-lock.json
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "engine",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "engine",
|
||||
"devDependencies": {
|
||||
"@types/node": "16.0.1",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.4",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "16.0.1",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.4",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
11
extensions/app/engine/package.json
Executable file
11
extensions/app/engine/package.json
Executable file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "engine",
|
||||
"devDependencies": {
|
||||
"@types/node": "16.0.1",
|
||||
"typescript": "4.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"watch": "tsc -w"
|
||||
}
|
||||
}
|
||||
219
extensions/app/engine/res/json/builder.json
Normal file
219
extensions/app/engine/res/json/builder.json
Normal file
@@ -0,0 +1,219 @@
|
||||
{
|
||||
"bundleConfig": {
|
||||
"custom": {
|
||||
"auto_398Ij6Mc1B2Y7sW3e6BgFC": {
|
||||
"displayName": "app-builtin",
|
||||
"configs": {
|
||||
"native": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": false
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
},
|
||||
"miniGame": {
|
||||
"configMode": "overwrite",
|
||||
"overwriteSettings": {
|
||||
"bytedance-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"oppo-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"huawei-quick-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"vivo-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"xiaomi-quick-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"baidu-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"wechatgame": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"alipay-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"taobao-creative-app": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
},
|
||||
"taobao-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"link-sure": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": false
|
||||
},
|
||||
"qtt": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": false
|
||||
},
|
||||
"cocos-play": {
|
||||
"compressionType": "zip",
|
||||
"isRemote": true
|
||||
},
|
||||
"fb-instant-games": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"auto_f7NI9WxFVIO6e8LbJGF72k": {
|
||||
"displayName": "app-native",
|
||||
"configs": {
|
||||
"native": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": false
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
},
|
||||
"miniGame": {
|
||||
"configMode": "overwrite",
|
||||
"overwriteSettings": {
|
||||
"bytedance-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"oppo-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"huawei-quick-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"vivo-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"xiaomi-quick-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"baidu-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"wechatgame": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"alipay-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"taobao-creative-app": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
},
|
||||
"taobao-mini-game": {
|
||||
"compressionType": "subpackage",
|
||||
"isRemote": false
|
||||
},
|
||||
"link-sure": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": false
|
||||
},
|
||||
"qtt": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": false
|
||||
},
|
||||
"cocos-play": {
|
||||
"compressionType": "zip",
|
||||
"isRemote": true
|
||||
},
|
||||
"fb-instant-games": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_all_json",
|
||||
"isRemote": true
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"auto_11aBEBWDxI/6ryvKvFthEo": {
|
||||
"displayName": "app-res",
|
||||
"configs": {
|
||||
"native": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": false
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
},
|
||||
"miniGame": {
|
||||
"configMode": "fallback",
|
||||
"overwriteSettings": {},
|
||||
"fallbackOptions": {
|
||||
"isRemote": true
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"preferredOptions": {
|
||||
"compressionType": "merge_dep",
|
||||
"isRemote": true
|
||||
},
|
||||
"overwriteSettings": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"displayName": "i18n:builder.asset_bundle.defaultConfig",
|
||||
"configs": {
|
||||
"native": {
|
||||
"preferredOptions": {
|
||||
"isRemote": true,
|
||||
"compressionType": "merge_dep"
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"preferredOptions": {
|
||||
"isRemote": true,
|
||||
"compressionType": "merge_dep"
|
||||
},
|
||||
"fallbackOptions": {
|
||||
"compressionType": "merge_dep"
|
||||
}
|
||||
},
|
||||
"miniGame": {
|
||||
"fallbackOptions": {
|
||||
"isRemote": true,
|
||||
"compressionType": "merge_dep"
|
||||
},
|
||||
"configMode": "fallback"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
220
extensions/app/engine/res/mark.js
Normal file
220
extensions/app/engine/res/mark.js
Normal file
@@ -0,0 +1,220 @@
|
||||
(() => {
|
||||
// const folder = ['app', 'app-appinit', 'app-builtin', 'app-bundle', 'app-scene', 'app-sound', 'app-view', 'page', 'paper', 'pop', 'top'];
|
||||
// function updateAssetMark(assetDock) {
|
||||
// const assetItemList = assetDock.querySelectorAll('div.tree-node > ui-drag-item');
|
||||
// if (!assetItemList) return;
|
||||
|
||||
// const finished = [];
|
||||
|
||||
// assetItemList.forEach((item) => {
|
||||
// const currPaddingLeft = parseInt(item.style.paddingLeft);
|
||||
// if (currPaddingLeft > 50) {
|
||||
// item.style['border-left'] = '2px solid dimgray';
|
||||
// } else {
|
||||
// item.style['border-left'] = '';
|
||||
// }
|
||||
|
||||
// const labelList = item.getElementsByTagName('label');
|
||||
// if (!labelList) return;
|
||||
// const labelEl = Array.from(labelList).find(labelEl => {
|
||||
// labelEl.style.color = '';
|
||||
// return folder.indexOf(labelEl.innerText.trim()) >= 0;
|
||||
// });
|
||||
// if (!labelEl) return;
|
||||
|
||||
// const iconList = item.getElementsByTagName('ui-icon');
|
||||
// if (!iconList || iconList.length < 2) return;
|
||||
// const iconEl = Array.from(iconList).pop();
|
||||
// if (!iconEl) return;
|
||||
// iconEl.style.color = '';
|
||||
|
||||
// if (item.type !== 'cc.Asset') return;
|
||||
|
||||
// if (labelEl.innerText.trim() === 'app') {
|
||||
// iconEl['value'] = 'setting';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'mediumturquoise';
|
||||
// labelEl.style.color = 'whitesmoke';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-appinit') {
|
||||
// iconEl['value'] = 'home';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'sandybrown';
|
||||
// labelEl.style.color = 'whitesmoke';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-builtin') {
|
||||
// iconEl['value'] = 'service';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'deepskyblue';
|
||||
// labelEl.style.color = 'whitesmoke';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-bundle') {
|
||||
// iconEl['value'] = 'extension';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'mediumseagreen';
|
||||
// labelEl.style.color = 'whitesmoke';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-scene') {
|
||||
// iconEl['value'] = 'mini-game';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'gold';
|
||||
// labelEl.style.color = 'whitesmoke';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-sound') {
|
||||
// iconEl['value'] = 'music';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'yellowgreen';
|
||||
// labelEl.style.color = 'yellowgreen';
|
||||
// }
|
||||
// else if (labelEl.innerText.trim() === 'app-view') {
|
||||
// iconEl['value'] = 'particle';
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'tomato';
|
||||
// labelEl.style.color = 'tomato';
|
||||
// }
|
||||
// else if (finished.indexOf(labelEl.innerText.trim()) === -1) {
|
||||
// finished.push(labelEl.innerText.trim());
|
||||
// iconEl.removeAttribute('color');
|
||||
// iconEl.style.color = 'orange';
|
||||
// labelEl.style.color = 'orange';
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
function updateAssetMark(assetDock) {
|
||||
const treeNodeList = assetDock.querySelectorAll('div.tree-node');
|
||||
if (!treeNodeList) return;
|
||||
|
||||
treeNodeList.forEach((treeNode) => {
|
||||
const isExpand = treeNode.__vue__?.$props?.expand;
|
||||
const isDirectory = treeNode.__vue__?.$props?.asset?.isDirectory;
|
||||
const assetUrl = treeNode.__vue__?.$props?.asset?.url || '';
|
||||
const assetName = treeNode.__vue__?.$props?.asset?.name || '';
|
||||
const assetDirUrl = assetUrl.slice(0, assetUrl.length - assetName.length); // 结尾带/
|
||||
|
||||
const itemDiv = treeNode.getElementsByTagName('ui-drag-item')[0];
|
||||
|
||||
// 子节点-label
|
||||
const nameDiv = itemDiv.getElementsByClassName('name')[0];
|
||||
const nameUI = nameDiv ? nameDiv.getElementsByTagName('span')[0] : null;
|
||||
|
||||
// 子节点-icon
|
||||
const iconDiv = itemDiv.getElementsByClassName('icon')[0];
|
||||
const iconUI = iconDiv ? iconDiv.getElementsByTagName('ui-icon')[0] : null;
|
||||
|
||||
if (iconUI) iconUI['color'] = 'true';
|
||||
if (iconUI) iconUI.style.color = '';
|
||||
if (nameUI) nameUI.style.color = '';
|
||||
|
||||
if (iconDiv) iconDiv.style.height = '100%';
|
||||
if (iconDiv) iconDiv.style.backgroundColor = '';
|
||||
if (nameDiv) nameDiv.style.backgroundColor = '';
|
||||
|
||||
if (!isDirectory || !iconUI || !nameUI) return;
|
||||
|
||||
if (assetUrl === 'db://assets/app') {
|
||||
iconUI['value'] = 'setting';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'mediumturquoise';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-appinit') {
|
||||
iconUI['value'] = 'home';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'sandybrown';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-builtin') {
|
||||
iconUI['value'] = 'service';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'deepskyblue';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-bundle') {
|
||||
iconUI['value'] = 'extension';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'mediumseagreen';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-scene') {
|
||||
iconUI['value'] = 'mini-game';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'gold';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-bundle/app-sound') {
|
||||
iconUI['value'] = 'music';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'yellowgreen';
|
||||
nameUI.style.color = 'yellowgreen';
|
||||
}
|
||||
else if (assetUrl === 'db://assets/app-bundle/app-view') {
|
||||
iconUI['value'] = 'particle';
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'tomato';
|
||||
nameUI.style.color = 'tomato';
|
||||
}
|
||||
else if (assetDirUrl === 'db://assets/app-bundle/app-view/') {
|
||||
iconUI.removeAttribute('color');
|
||||
iconUI.style.color = 'orange';
|
||||
nameUI.style.color = 'orange';
|
||||
}
|
||||
else if (assetDirUrl === 'db://assets/app-bundle/app-view/page/' ||
|
||||
assetDirUrl === 'db://assets/app-bundle/app-view/paper/' ||
|
||||
assetDirUrl === 'db://assets/app-bundle/app-view/pop/' ||
|
||||
assetDirUrl === 'db://assets/app-bundle/app-view/top/'
|
||||
) {
|
||||
iconUI.removeAttribute('color');
|
||||
if (isExpand) {
|
||||
iconUI.style.color = 'gold';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
iconDiv.style.backgroundColor = 'brown';
|
||||
nameDiv.style.backgroundColor = 'brown';
|
||||
} else {
|
||||
iconUI.style.color = 'gold';
|
||||
nameUI.style.color = 'whitesmoke';
|
||||
iconDiv.style.backgroundColor = '';
|
||||
nameDiv.style.backgroundColor = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let retryCount = 0;
|
||||
const maxRetryCount = 10;
|
||||
|
||||
function initAssetMark() {
|
||||
// 资源管理器窗口
|
||||
const assetDock = document.querySelector('#dock')?.shadowRoot?.
|
||||
querySelector('dock-layout dock-layout dock-groups dock-panels > panel-frame[name=assets]')?.shadowRoot?.
|
||||
querySelector('div > div.separate-box > div:nth-child(1) > section > ui-drag-area');
|
||||
|
||||
if (!assetDock) {
|
||||
if (retryCount++ < maxRetryCount) {
|
||||
setTimeout(initAssetMark, 500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof MutationObserver === 'undefined') {
|
||||
setInterval(function () {
|
||||
updateAssetMark(assetDock);
|
||||
}, 50);
|
||||
} else {
|
||||
// 创建一个观察器实例并传入回调函数
|
||||
const observer = new MutationObserver(function () {
|
||||
updateAssetMark(assetDock);
|
||||
});
|
||||
|
||||
// 开始观察已配置的目标节点(观察目标节点的子节点的变化)
|
||||
observer.observe(assetDock, { childList: true, subtree: true });
|
||||
|
||||
// 你可以随时停止观察
|
||||
// observer.disconnect();
|
||||
}
|
||||
|
||||
updateAssetMark(assetDock);
|
||||
}
|
||||
|
||||
initAssetMark();
|
||||
})();
|
||||
7
extensions/app/engine/res/meta/app-admin.meta
Normal file
7
extensions/app/engine/res/meta/app-admin.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_398Ij6Mc1B2Y7sW3e6BgFC",
|
||||
"priority": 1
|
||||
}
|
||||
}
|
||||
7
extensions/app/engine/res/meta/app-controller.meta
Normal file
7
extensions/app/engine/res/meta/app-controller.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_398Ij6Mc1B2Y7sW3e6BgFC",
|
||||
"priority": 1
|
||||
}
|
||||
}
|
||||
7
extensions/app/engine/res/meta/app-manager.meta
Normal file
7
extensions/app/engine/res/meta/app-manager.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_398Ij6Mc1B2Y7sW3e6BgFC",
|
||||
"priority": 1
|
||||
}
|
||||
}
|
||||
7
extensions/app/engine/res/meta/app-model.meta
Normal file
7
extensions/app/engine/res/meta/app-model.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_398Ij6Mc1B2Y7sW3e6BgFC",
|
||||
"priority": 1
|
||||
}
|
||||
}
|
||||
7
extensions/app/engine/res/meta/app-sound.meta
Normal file
7
extensions/app/engine/res/meta/app-sound.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_11aBEBWDxI/6ryvKvFthEo",
|
||||
"priority": 8
|
||||
}
|
||||
}
|
||||
7
extensions/app/engine/res/meta/custom-bundle.meta
Normal file
7
extensions/app/engine/res/meta/custom-bundle.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "default",
|
||||
"priority": 1
|
||||
}
|
||||
}
|
||||
8
extensions/app/engine/res/meta/resources.meta
Normal file
8
extensions/app/engine/res/meta/resources.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "default",
|
||||
"bundleName": "resources",
|
||||
"priority": 8
|
||||
}
|
||||
}
|
||||
5
extensions/app/engine/res/meta/view-native.meta
Normal file
5
extensions/app/engine/res/meta/view-native.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_f7NI9WxFVIO6e8LbJGF72k",
|
||||
"priority": 1
|
||||
}
|
||||
5
extensions/app/engine/res/meta/view-resources.meta
Normal file
5
extensions/app/engine/res/meta/view-resources.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "auto_11aBEBWDxI/6ryvKvFthEo",
|
||||
"priority": 4
|
||||
}
|
||||
11
extensions/app/engine/res/panel/components/app.html
Normal file
11
extensions/app/engine/res/panel/components/app.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="container">
|
||||
<ui-tab value="0" @confirm="onClick($event.target.value)">
|
||||
<ui-button>{{menus[0]}}</ui-button>
|
||||
<ui-button>{{menus[1]}}</ui-button>
|
||||
<ui-button>{{menus[2]}}</ui-button>
|
||||
<ui-button>{{menus[3]}}</ui-button>
|
||||
<ui-button>{{menus[4]}}</ui-button>
|
||||
<ui-button>{{menus[5]}}</ui-button>
|
||||
</ui-tab>
|
||||
<component :is="content" />
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017438&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">名字</ui-label>
|
||||
<ui-input id="name" slot="content" placeholder="输入名字如: index" :value="inputName"
|
||||
@change="inputName=$event.target.value" show-clear>
|
||||
</ui-input>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017441&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">名字</ui-label>
|
||||
<ui-input id="name" slot="content" placeholder="输入名字如: index" :value="inputName"
|
||||
@change="inputName=$event.target.value" show-clear>
|
||||
</ui-input>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
36
extensions/app/engine/res/panel/components/create-model.html
Normal file
36
extensions/app/engine/res/panel/components/create-model.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017439&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">类型</ui-label>
|
||||
<ui-select id="type" slot="content" :value="typeSelectIndex"
|
||||
@confirm="onChangeTypeSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in typeSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">名字</ui-label>
|
||||
<ui-input id="name" slot="content" placeholder="输入名字如: index" :value="inputName"
|
||||
@change="inputName=$event.target.value" show-clear>
|
||||
</ui-input>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
36
extensions/app/engine/res/panel/components/create-res.html
Normal file
36
extensions/app/engine/res/panel/components/create-res.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017429&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">类型</ui-label>
|
||||
<ui-select id="type" slot="content" :value="typeSelectIndex"
|
||||
@confirm="onChangeTypeSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in typeSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">名字</ui-label>
|
||||
<ui-input id="name" slot="content" placeholder="输入文件夹名字如: index" :value="inputName"
|
||||
@change="inputName=$event.target.value" show-clear>
|
||||
</ui-input>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
29
extensions/app/engine/res/panel/components/create-sound.html
Normal file
29
extensions/app/engine/res/panel/components/create-sound.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017437&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">类型</ui-label>
|
||||
<ui-select id="type" slot="content" :value="typeSelectIndex"
|
||||
@confirm="onChangeTypeSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in typeSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
56
extensions/app/engine/res/panel/components/create-view.html
Normal file
56
extensions/app/engine/res/panel/components/create-view.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="content">
|
||||
<ui-link class="help" value="https://gitee.com/cocos2d-zp/xforge/wikis/pages?sort_id=13017440&doc_id=6236543">
|
||||
<ui-icon value="help"></ui-icon>
|
||||
</ui-link>
|
||||
|
||||
<ui-section header="输入" expand>
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">类型</ui-label>
|
||||
<ui-select id="type" slot="content" :value="typeSelectIndex"
|
||||
@confirm="onChangeTypeSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in typeSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-prop class="content-item" v-show="showSelectGroup">
|
||||
<ui-label slot="label">模版</ui-label>
|
||||
<ui-select id="group" slot="content" :value="groupSelectIndex"
|
||||
@confirm="onChangeGroupSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in groupSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-prop class="content-item" v-show="showSelectPage">
|
||||
<ui-label slot="label">归属</ui-label>
|
||||
<ui-select id="owner" slot="content" :value="pageSelectIndex"
|
||||
@confirm="onChangePageSelect($event.target.value)">
|
||||
<option :value="index" v-for="(name,index) in pageSelects">
|
||||
{{name}}
|
||||
</option>
|
||||
</ui-select>
|
||||
</ui-prop>
|
||||
|
||||
<ui-prop class="content-item">
|
||||
<ui-label slot="label">名字</ui-label>
|
||||
<ui-input id="name" slot="content" placeholder="输入界面名字如: index" :value="inputName"
|
||||
@change="inputName=$event.target.value" show-clear>
|
||||
</ui-input>
|
||||
</ui-prop>
|
||||
|
||||
<ui-button class="content-item" type="primary" @confirm="onClickCreate">
|
||||
创建
|
||||
</ui-button>
|
||||
</ui-section>
|
||||
|
||||
<ui-section header="输出" expand>
|
||||
<ui-label :value="display" style="white-space: pre"></ui-label>
|
||||
</ui-section>
|
||||
|
||||
<div class="loading" v-show="showLoading">
|
||||
<ui-loading class="loading-item"></ui-loading>
|
||||
</div>
|
||||
</div>
|
||||
1
extensions/app/engine/res/panel/index.html
Normal file
1
extensions/app/engine/res/panel/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<div id="app"></div>
|
||||
42
extensions/app/engine/res/panel/styles/index.css
Normal file
42
extensions/app/engine/res/panel/styles/index.css
Normal file
@@ -0,0 +1,42 @@
|
||||
#app {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
margin: 8px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-item {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.help {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.loading {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
/* 背景模糊 */
|
||||
/* backdrop-filter: blur(3px); */
|
||||
}
|
||||
|
||||
.loading-item {
|
||||
margin-top: 50%;
|
||||
}
|
||||
2
extensions/app/engine/res/readme/app-admin.md
Normal file
2
extensions/app/engine/res/readme/app-admin.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、一些配置类的资产(框架自动维护)
|
||||
2、不可删除此文件夹
|
||||
2
extensions/app/engine/res/readme/app-appinit.md
Normal file
2
extensions/app/engine/res/readme/app-appinit.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、框架初始化首屏
|
||||
2、不可删除此文件夹
|
||||
2
extensions/app/engine/res/readme/app-builtin.md
Normal file
2
extensions/app/engine/res/readme/app-builtin.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、存储内置功能的文件夹
|
||||
2、不可删除此文件夹
|
||||
2
extensions/app/engine/res/readme/app-bundle.md
Normal file
2
extensions/app/engine/res/readme/app-bundle.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、存储内置的Bundle的文件夹
|
||||
2、如不再需要,可以直接删除此文件夹
|
||||
4
extensions/app/engine/res/readme/app-controller.md
Normal file
4
extensions/app/engine/res/readme/app-controller.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存储控制器
|
||||
1、通过app.controller或import来使用(BaseView.bindController的参数只能使用import方式)
|
||||
2、通过菜单「App/创建/Controller」创建
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
4
extensions/app/engine/res/readme/app-manager.md
Normal file
4
extensions/app/engine/res/readme/app-manager.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存储管理器
|
||||
1、通过app.manager来使用
|
||||
2、通过菜单「App/创建/Manager」创建
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
5
extensions/app/engine/res/readme/app-model.md
Normal file
5
extensions/app/engine/res/readme/app-model.md
Normal file
@@ -0,0 +1,5 @@
|
||||
存储数据
|
||||
1、通过app.store、app.data或app.config来使用
|
||||
2、export类型数据通过import来使用, 但不可以被主包引用
|
||||
3、通过菜单「App/创建/Model」创建
|
||||
4、如不再需要,可以直接删除此文件夹
|
||||
2
extensions/app/engine/res/readme/app-scene.md
Normal file
2
extensions/app/engine/res/readme/app-scene.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、存储主场景的文件夹
|
||||
2、不可删除此文件夹
|
||||
4
extensions/app/engine/res/readme/app-sound.md
Normal file
4
extensions/app/engine/res/readme/app-sound.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存储音乐/音效资源的文件夹
|
||||
1、通过app.manager.sound管理
|
||||
2、通过菜单「App/创建/Sound」创建目录
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
4
extensions/app/engine/res/readme/app-view.md
Normal file
4
extensions/app/engine/res/readme/app-view.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存储UI资源的文件夹
|
||||
1、通过app.manager.ui管理
|
||||
2、通过菜单「App/创建/View」创建
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
2
extensions/app/engine/res/readme/app.md
Normal file
2
extensions/app/engine/res/readme/app.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、框架配置、生命周期及全局导出
|
||||
2、不可删除此文件夹
|
||||
4
extensions/app/engine/res/readme/res-bundle.md
Normal file
4
extensions/app/engine/res/readme/res-bundle.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存储动态资源的文件夹
|
||||
1、通过app.manager.loader管理
|
||||
2、所有业务自定义的Bundle文件夹存放在这里面
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
5
extensions/app/engine/res/readme/res-native.md
Normal file
5
extensions/app/engine/res/readme/res-native.md
Normal file
@@ -0,0 +1,5 @@
|
||||
存储静态资源的文件夹
|
||||
1、非公共脚本资源,尽量不放到主包内
|
||||
3、图片、字体等非脚本类公共资源,尽量不放到主包内(因为构建后这些资源会被拷贝到其它Bundle中)
|
||||
2、如果公共脚本资源体积较大,可以考虑放到Bundle内,保证首屏体积尽量小
|
||||
4、如不再需要,可以直接删除此文件夹
|
||||
4
extensions/app/engine/res/readme/resources.md
Normal file
4
extensions/app/engine/res/readme/resources.md
Normal file
@@ -0,0 +1,4 @@
|
||||
系统动态资源目录
|
||||
1、脚本资源一定不要放在此文件夹内🔥
|
||||
2、可使用app.manager.loader.load动态加载
|
||||
3、如不再需要,可以直接删除此文件夹
|
||||
3
extensions/app/engine/res/readme/sound-effect.md
Normal file
3
extensions/app/engine/res/readme/sound-effect.md
Normal file
@@ -0,0 +1,3 @@
|
||||
存储音效资源的文件夹
|
||||
1、通过app.manager.sound.playEffect播放
|
||||
2、如不再需要,可以直接删除此文件夹
|
||||
3
extensions/app/engine/res/readme/sound-music.md
Normal file
3
extensions/app/engine/res/readme/sound-music.md
Normal file
@@ -0,0 +1,3 @@
|
||||
存储音乐资源的文件夹
|
||||
1、通过app.manager.sound.playMusic播放
|
||||
2、如不再需要,可以直接删除此文件夹
|
||||
2
extensions/app/engine/res/readme/view-expansion.md
Normal file
2
extensions/app/engine/res/readme/view-expansion.md
Normal file
@@ -0,0 +1,2 @@
|
||||
1、只能存放脚本⚠️
|
||||
2、如不再需要,可以直接删除此文件夹
|
||||
4
extensions/app/engine/res/readme/view-native.md
Normal file
4
extensions/app/engine/res/readme/view-native.md
Normal file
@@ -0,0 +1,4 @@
|
||||
存放UI以及脚本的文件夹
|
||||
1、除了UI本身外,不允许存放其它任何预置体或场景资源🔥
|
||||
2、UI脚本在根目录下,其它脚本放到expansion目录下
|
||||
3、不可单独删除此文件夹
|
||||
6
extensions/app/engine/res/readme/view-resources.md
Normal file
6
extensions/app/engine/res/readme/view-resources.md
Normal file
@@ -0,0 +1,6 @@
|
||||
UI资源目录
|
||||
1、脚本资源一定不要放在此文件夹内🔥
|
||||
2、资源会随着UI销毁自动释放
|
||||
3、在UI脚本内可通过this.loadRes动态加载
|
||||
4、在UI子节点的脚本内可通过app.manager.ui.loadRes(this, ...)动态加载
|
||||
5、不可单独删除此文件夹
|
||||
15
extensions/app/engine/src/builder/hooks.ts
Normal file
15
extensions/app/engine/src/builder/hooks.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import path from 'path';
|
||||
import { BuildHook } from '../../@types/packages/builder/@types';
|
||||
import { adaptFileMD5 } from './utils/file';
|
||||
|
||||
export const onAfterBuild: BuildHook.onAfterBuild = async function (options, result) {
|
||||
if (options.platform !== 'web-mobile' && options.platform !== 'web-desktop') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.md5Cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
adaptFileMD5(path.join(result.dest, 'index.html'));
|
||||
};
|
||||
7
extensions/app/engine/src/builder/index.ts
Normal file
7
extensions/app/engine/src/builder/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { BuildPlugin } from "../../@types/packages/builder/@types";
|
||||
|
||||
export const configs: BuildPlugin.Configs = {
|
||||
'*': {
|
||||
hooks: './hooks',
|
||||
}
|
||||
};
|
||||
255
extensions/app/engine/src/builder/utils/file.ts
Normal file
255
extensions/app/engine/src/builder/utils/file.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import md5 from './md5';
|
||||
|
||||
const includeExts = ['.html', '.css', '.js', '.json'];
|
||||
const regExp = new RegExp('(?<=(\'|"|url\\(|URL\\())(?!//)[a-zA-Z0-9_\./-]+\\.(js|css|json|png|apng|jpg|jpeg|gif|svg)(?=(\'|"|\\)))', 'g');
|
||||
|
||||
/**
|
||||
* 获取文件夹内的文件
|
||||
*/
|
||||
function getFiles(dir: string): string[] {
|
||||
const result: string[] = [];
|
||||
|
||||
// 判断文件是否存在
|
||||
if (!fs.existsSync(dir)) return result;
|
||||
|
||||
// 如果不是文件夹则返回
|
||||
if (!fs.statSync(dir).isDirectory()) return result;
|
||||
|
||||
// 遍历文件夹
|
||||
fs.readdirSync(dir).forEach(item => {
|
||||
const item_path = path.join(dir, item);
|
||||
const isDir = fs.statSync(item_path).isDirectory();
|
||||
if (!isDir) result.push(item_path);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以某个文件为起点,对其引用的文件树进行md5
|
||||
* @param filepath 文件路径
|
||||
* @param exclude 排除的文件路径(不带md5,不支持相对路径),排除的文件不会遍历子文件树,默认其本身会进行md5
|
||||
*/
|
||||
export function adaptFileMD5(filepath: string, exclude: { path: string | RegExp, md5?: boolean }[] = []) {
|
||||
// 参数不合法
|
||||
if (!filepath) return false;
|
||||
|
||||
// 修正文件路径
|
||||
filepath = fs.existsSync(filepath) ? filepath : queryFile(filepath);
|
||||
if (!filepath) return false;
|
||||
|
||||
// 排除的文件
|
||||
const fileExt = path.extname(filepath);
|
||||
const filepathNoMD5 = getFilePathRemoveMD5(filepath);
|
||||
const excludeItem = exclude.find(item => {
|
||||
if (item.path instanceof RegExp) return item.path.test(filepath);
|
||||
else return item.path === filepathNoMD5;
|
||||
});
|
||||
const isExcluded = !!excludeItem || includeExts.indexOf(fileExt) === -1;
|
||||
|
||||
// 文件扩展名
|
||||
if (!isExcluded) {
|
||||
// 文件目录
|
||||
const fileDir = path.dirname(filepath);
|
||||
// 文件内容
|
||||
let fileText = fs.readFileSync(filepath, 'utf-8');
|
||||
// 文件内所有引用的相对路径(排重)
|
||||
const subRelativePaths = Array.from(new Set(fileText.match(regExp)));
|
||||
|
||||
for (let index = 0; index < subRelativePaths.length; index++) {
|
||||
// 子文件相对路径(读取到的)
|
||||
const subRelativePath = subRelativePaths[index];
|
||||
// 子文件路径(读取到的)
|
||||
const subFilePath = path.join(fileDir, subRelativePath);
|
||||
|
||||
// 如果当前引用的文件的路径带有md5戳,并且文件存在,则跳过
|
||||
if (isFileNameHasMD5(subFilePath) && fs.existsSync(subFilePath)) continue;
|
||||
|
||||
{
|
||||
// 实际的子文件路径(不确定有没有md5)
|
||||
const subFilePathReal = queryFile(subFilePath);
|
||||
// 实际的子文件不存在
|
||||
if (!subFilePathReal) {
|
||||
// console.warn('[跳过] [文件不存在]', filepath, subRelativePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果引用的文件路径不带md5,但是实际文件有md5,则
|
||||
if (!isFileNameHasMD5(subFilePath) && isFileNameHasMD5(subFilePathReal)) {
|
||||
|
||||
// 原始的子文件名
|
||||
const subFileBasename = path.basename(subRelativePath);
|
||||
// 实际的子文件名(带md5)
|
||||
const subFileBasenameReal = path.basename(subFilePathReal);
|
||||
// 替换
|
||||
fileText = fileText.replace(new RegExp(subRelativePath, 'g'), subRelativePath.replace(subFileBasename, subFileBasenameReal));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// 对它进行md5处理
|
||||
const result = adaptFileMD5(subFilePath, exclude);
|
||||
// 文件不存在
|
||||
if (!result) {
|
||||
// console.warn('[跳过] [文件不存在]', filepath, subRelativePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 实际的子文件路径(已经带上md5了)
|
||||
const subFilepathReal = queryFile(subFilePath);
|
||||
// 原始的子文件名
|
||||
const subFileBasename = path.basename(subRelativePath);
|
||||
// 实际的子文件名(带md5)
|
||||
const subFileBasenameReal = path.basename(subFilepathReal);
|
||||
|
||||
// 替换
|
||||
fileText = fileText.replace(new RegExp(subRelativePath, 'g'), subRelativePath.replace(subFileBasename, subFileBasenameReal));
|
||||
}
|
||||
}
|
||||
|
||||
// 重新写入文件内容
|
||||
fs.writeFileSync(filepath, fileText, 'utf-8');
|
||||
}
|
||||
|
||||
// 将文件md5重命名
|
||||
if (fileExt !== '.html' && excludeItem?.md5 !== false) {
|
||||
renameFileByMD5(filepath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换某个文件里引用的的文件名
|
||||
* @param {string} filepath 被替换的文件路径
|
||||
* @param {string} adaptDir adaptFile所在的文件夹
|
||||
* @param {string} adaptFile 文件名.后缀,不能包含其他东西
|
||||
*/
|
||||
export function adaptFilename(filepath: string, adaptDir: string, adaptFile: string) {
|
||||
if (!fs.existsSync(filepath)) return false;
|
||||
|
||||
const adaptName = adaptFile.split('.')[0];
|
||||
const adaptExtname = path.extname(adaptFile) || '';
|
||||
|
||||
let text = fs.readFileSync(filepath, 'utf-8');
|
||||
|
||||
const filePaths = getFiles(adaptDir);
|
||||
for (let index = 0; index < filePaths.length; index++) {
|
||||
const filePath = filePaths[index];
|
||||
const basename = path.basename(filePath);
|
||||
const name = basename.split('.')[0];
|
||||
const extname = path.extname(basename) || '';
|
||||
|
||||
if (basename !== adaptFile && name === adaptName && extname === adaptExtname) {
|
||||
const regExp = new RegExp(`(?<=('|"|\/))${name}[\.a-zA-Z0-9]*\\${extname}(?=('|"))`, 'g');
|
||||
text = text.replace(regExp, basename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(filepath, text, 'utf-8');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个文件是否有md5戳
|
||||
* @param {string} filename
|
||||
*/
|
||||
export function isFileNameHasMD5(filename: string) {
|
||||
filename = path.basename(filename);
|
||||
return filename !== getFileNameRemoveMD5(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* md5重命名文件名字
|
||||
* @param {string} filePath
|
||||
* @returns
|
||||
*/
|
||||
export function renameFileByMD5(filePath: string) {
|
||||
const basename = getFileNameRemoveMD5(filePath);
|
||||
const extname = path.extname(basename);
|
||||
if (!extname) return filePath;
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
if (!filename) return filePath;
|
||||
const dirname = path.dirname(filePath);
|
||||
|
||||
const txt = fs.readFileSync(filePath, 'utf-8');
|
||||
const renamePath = path.join(dirname, `${filename}.${md5(txt)}${extname}`);
|
||||
fs.renameSync(filePath, renamePath);
|
||||
return renamePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相同名字相同后缀, 但md5戳不一样的文件数组
|
||||
* @param {string} dir
|
||||
*/
|
||||
export function getFilesBySameNameDiffMD5(dir: string): { name: string; ext: string; files: string[]; }[] {
|
||||
// [ [ {name:'index',ext:'.js',files:['/test/index.js','/test/index.c67d.js']} ]
|
||||
const result = [];
|
||||
const files = getFiles(dir);
|
||||
files.forEach(filepath => {
|
||||
const basename = getFileNameRemoveMD5(filepath);
|
||||
if (!basename) return;
|
||||
const extname = path.extname(basename);
|
||||
if (!extname) return;
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
if (!filename) return;
|
||||
|
||||
const res = result.find(data => data.name === filename && data.ext === extname);
|
||||
if (res) return res.files.push(filepath);
|
||||
|
||||
result.push({
|
||||
name: filename,
|
||||
ext: extname,
|
||||
files: [filepath]
|
||||
});
|
||||
});
|
||||
return result.filter((data) => data.files.length >= 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件名中的md5字段去除
|
||||
* @param {string} filename
|
||||
* @returns
|
||||
*/
|
||||
export function getFileNameRemoveMD5(filename: string) {
|
||||
const basename = path.basename(filename)
|
||||
// a-jqw89a.js => a.js
|
||||
// a-jqw89a.min.js => a.min.js
|
||||
.replace(/-[a-z0-9]+\./, '.');
|
||||
|
||||
return basename.split('.').filter((str, index, array) => {
|
||||
if (index === 0 || index === array.length - 1) return true;
|
||||
return index == 1 && str === 'min';
|
||||
}).join('.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件路径中的md5字段
|
||||
* @param {string} filepath
|
||||
* @returns
|
||||
*/
|
||||
export function getFilePathRemoveMD5(filepath: string) {
|
||||
const dirname = path.dirname(filepath);
|
||||
return path.join(dirname, getFileNameRemoveMD5(filepath));
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入文件路径,可以索引到对应的带有md5的文件路径
|
||||
* @param {string} filepath 文件路径(带后缀)
|
||||
* @returns
|
||||
*/
|
||||
export function queryFile(filepath: string) {
|
||||
// 将文件名中的md5字段去除
|
||||
const filename = getFileNameRemoveMD5(filepath);
|
||||
const fileDir = path.dirname(filepath);
|
||||
|
||||
const filesList = getFiles(fileDir);
|
||||
return filesList.find(filepath => {
|
||||
return path.basename(filepath) === filename;
|
||||
}) || filesList.find(filepath => {
|
||||
return getFileNameRemoveMD5(filepath) === filename;
|
||||
});
|
||||
}
|
||||
388
extensions/app/engine/src/builder/utils/md5.ts
Normal file
388
extensions/app/engine/src/builder/utils/md5.ts
Normal file
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* JavaScript MD5
|
||||
* https://github.com/blueimp/JavaScript-MD5
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
* Based on
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
* Distributed under the BSD License
|
||||
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||||
*/
|
||||
|
||||
/* global define */
|
||||
|
||||
/* eslint-disable strict */
|
||||
|
||||
/**
|
||||
* Add integers, wrapping at 2^32.
|
||||
* This uses 16-bit operations internally to work around bugs in interpreters.
|
||||
*
|
||||
* @param {number} x First integer
|
||||
* @param {number} y Second integer
|
||||
* @returns {number} Sum
|
||||
*/
|
||||
function safeAdd(x: number, y: number): number {
|
||||
let lsw = (x & 0xffff) + (y & 0xffff);
|
||||
let msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*
|
||||
* @param {number} num 32-bit number
|
||||
* @param {number} cnt Rotation count
|
||||
* @returns {number} Rotated number
|
||||
*/
|
||||
function bitRotateLeft(num: number, cnt: number): number {
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} q q
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5cmn(q: number, a: number, b: number, x: number, s: number, t: number): number {
|
||||
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
|
||||
return md5cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
|
||||
return md5cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
|
||||
return md5cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
/**
|
||||
* Basic operation the algorithm uses.
|
||||
*
|
||||
* @param {number} a a
|
||||
* @param {number} b b
|
||||
* @param {number} c c
|
||||
* @param {number} d d
|
||||
* @param {number} x x
|
||||
* @param {number} s s
|
||||
* @param {number} t t
|
||||
* @returns {number} Result
|
||||
*/
|
||||
function md5ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
|
||||
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the MD5 of an array of little-endian words, and a bit length.
|
||||
*
|
||||
* @param {Array} x Array of little-endian words
|
||||
* @param {number} len Bit length
|
||||
* @returns {Array<number>} MD5 Array
|
||||
*/
|
||||
function binlMD5(x: Array<any>, len: number): Array<number> {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << len % 32;
|
||||
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||
|
||||
let i;
|
||||
let olda;
|
||||
let oldb;
|
||||
let oldc;
|
||||
let oldd;
|
||||
let a = 1732584193;
|
||||
let b = -271733879;
|
||||
let c = -1732584194;
|
||||
let d = 271733878;
|
||||
|
||||
for (i = 0; i < x.length; i += 16) {
|
||||
olda = a;
|
||||
oldb = b;
|
||||
oldc = c;
|
||||
oldd = d;
|
||||
|
||||
a = md5ff(a, b, c, d, x[i], 7, -680876936);
|
||||
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||||
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||||
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||||
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||||
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||||
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||||
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||||
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||||
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||||
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
|
||||
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||||
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||||
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||||
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||||
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||||
|
||||
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||||
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||||
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||||
b = md5gg(b, c, d, a, x[i], 20, -373897302);
|
||||
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||||
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||||
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||||
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||||
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||||
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||||
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||||
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||||
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||||
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||||
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||||
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||||
|
||||
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
|
||||
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||||
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||||
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||||
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||||
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||||
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||||
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||||
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||||
d = md5hh(d, a, b, c, x[i], 11, -358537222);
|
||||
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||||
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||||
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||||
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||||
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||||
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||||
|
||||
a = md5ii(a, b, c, d, x[i], 6, -198630844);
|
||||
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||||
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||||
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||||
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||||
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||||
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||||
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||||
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||||
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||||
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||||
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||||
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||||
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||||
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||||
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||||
|
||||
a = safeAdd(a, olda);
|
||||
b = safeAdd(b, oldb);
|
||||
c = safeAdd(c, oldc);
|
||||
d = safeAdd(d, oldd);
|
||||
}
|
||||
return [a, b, c, d];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of little-endian words to a string
|
||||
*
|
||||
* @param {Array<number>} input MD5 Array
|
||||
* @returns {string} MD5 string
|
||||
*/
|
||||
function binl2rstr(input: Array<number>): string {
|
||||
let i;
|
||||
let output = '';
|
||||
let length32 = input.length * 32;
|
||||
for (i = 0; i < length32; i += 8) {
|
||||
output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw string to an array of little-endian words
|
||||
* Characters >255 have their high-byte silently ignored.
|
||||
*
|
||||
* @param {string} input Raw input string
|
||||
* @returns {Array<number>} Array of little-endian words
|
||||
*/
|
||||
function rstr2binl(input: string): Array<number> {
|
||||
let i;
|
||||
let output = [];
|
||||
output[(input.length >> 2) - 1] = undefined;
|
||||
for (i = 0; i < output.length; i += 1) {
|
||||
output[i] = 0;
|
||||
}
|
||||
let length8 = input.length * 8;
|
||||
for (i = 0; i < length8; i += 8) {
|
||||
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the MD5 of a raw string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rstrMD5(s: string): string {
|
||||
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the HMAC-MD5 of a key and some data (raw strings)
|
||||
*
|
||||
* @param {string} key HMAC key
|
||||
* @param {string} data Raw input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rstrHMACMD5(key: string, data: string): string {
|
||||
let i;
|
||||
let bkey = rstr2binl(key);
|
||||
let ipad = [];
|
||||
let opad = [];
|
||||
let hash;
|
||||
ipad[15] = opad[15] = undefined;
|
||||
if (bkey.length > 16) {
|
||||
bkey = binlMD5(bkey, key.length * 8);
|
||||
}
|
||||
for (i = 0; i < 16; i += 1) {
|
||||
ipad[i] = bkey[i] ^ 0x36363636;
|
||||
opad[i] = bkey[i] ^ 0x5c5c5c5c;
|
||||
}
|
||||
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
|
||||
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw string to a hex string
|
||||
*
|
||||
* @param {string} input Raw input string
|
||||
* @returns {string} Hex encoded string
|
||||
*/
|
||||
function rstr2hex(input: string): string {
|
||||
let hexTab = '0123456789abcdef';
|
||||
let output = '';
|
||||
let x;
|
||||
let i;
|
||||
for (i = 0; i < input.length; i += 1) {
|
||||
x = input.charCodeAt(i);
|
||||
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string as UTF-8
|
||||
*
|
||||
* @param {string} input Input string
|
||||
* @returns {string} UTF8 string
|
||||
*/
|
||||
function str2rstrUTF8(input: string): string {
|
||||
return unescape(encodeURIComponent(input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes input string as raw MD5 string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rawMD5(s: string): string {
|
||||
return rstrMD5(str2rstrUTF8(s));
|
||||
}
|
||||
/**
|
||||
* Encodes input string as Hex encoded string
|
||||
*
|
||||
* @param {string} s Input string
|
||||
* @returns {string} Hex encoded string
|
||||
*/
|
||||
function hexMD5(s: string): string {
|
||||
return rstr2hex(rawMD5(s));
|
||||
}
|
||||
/**
|
||||
* Calculates the raw HMAC-MD5 for the given key and data
|
||||
*
|
||||
* @param {string} k HMAC key
|
||||
* @param {string} d Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function rawHMACMD5(k: string, d: string): string {
|
||||
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d));
|
||||
}
|
||||
/**
|
||||
* Calculates the Hex encoded HMAC-MD5 for the given key and data
|
||||
*
|
||||
* @param {string} k HMAC key
|
||||
* @param {string} d Input string
|
||||
* @returns {string} Raw MD5 string
|
||||
*/
|
||||
function hexHMACMD5(k: string, d: string): string {
|
||||
return rstr2hex(rawHMACMD5(k, d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates MD5 value for a given string.
|
||||
* If a key is provided, calculates the HMAC-MD5 value.
|
||||
* Returns a Hex encoded string unless the raw argument is given.
|
||||
*
|
||||
* @param {string} string Input string
|
||||
* @param {string} [key] HMAC key
|
||||
* @param {boolean} [raw] Raw output switch
|
||||
* @returns {string} MD5 output
|
||||
*/
|
||||
export default function md5(string: string, key?: string, raw?: boolean): string {
|
||||
if (!key) {
|
||||
if (!raw) {
|
||||
return hexMD5(string);
|
||||
}
|
||||
return rawMD5(string);
|
||||
}
|
||||
if (!raw) {
|
||||
return hexHMACMD5(key, string);
|
||||
}
|
||||
return rawHMACMD5(key, string);
|
||||
}
|
||||
87
extensions/app/engine/src/inspector/asset-directory.ts
Normal file
87
extensions/app/engine/src/inspector/asset-directory.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
'use strict';
|
||||
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
interface Asset {
|
||||
displayName: string;
|
||||
file: string;
|
||||
imported: boolean;
|
||||
importer: string;
|
||||
invalid: boolean;
|
||||
isDirectory: boolean;
|
||||
library: {
|
||||
[extname: string]: string;
|
||||
};
|
||||
name: string;
|
||||
url: string;
|
||||
uuid: string;
|
||||
visible: boolean;
|
||||
subAssets: {
|
||||
[id: string]: Asset;
|
||||
};
|
||||
}
|
||||
|
||||
interface Meta {
|
||||
files: string[];
|
||||
imported: boolean;
|
||||
importer: string;
|
||||
subMetas: {
|
||||
[id: string]: Meta;
|
||||
};
|
||||
userData: {
|
||||
[key: string]: any;
|
||||
};
|
||||
uuid: string;
|
||||
ver: string;
|
||||
}
|
||||
|
||||
type Selector<$> = { $: Record<keyof $, HTMLElement> } & { dispatch(str: string): void, assetList: Asset[], metaList: Meta[] };
|
||||
|
||||
export const $ = {
|
||||
'code': '#code',
|
||||
'section': '#section',
|
||||
};
|
||||
|
||||
export const template = `
|
||||
<ui-section id="section" header="文件夹说明" expand>
|
||||
<ui-code id="code"></ui-code>
|
||||
</ui-section>
|
||||
`;
|
||||
|
||||
type PanelThis = Selector<typeof $>;
|
||||
|
||||
export function update(this: PanelThis, assetList: Asset[], metaList: Meta[]) {
|
||||
this.assetList = assetList;
|
||||
this.metaList = metaList;
|
||||
|
||||
if (assetList.length === 0) {
|
||||
this.$.code.innerHTML = '';
|
||||
} else {
|
||||
this.$.code.innerHTML = assetList
|
||||
.filter((asset) => {
|
||||
const mdFile = join(asset.file, `.${asset.name}.md`);
|
||||
return existsSync(mdFile);
|
||||
})
|
||||
.map((asset) => {
|
||||
const mdFile = join(asset.file, `.${asset.name}.md`);
|
||||
const mdStr = readFileSync(mdFile, 'utf-8');
|
||||
return assetList.length > 1 ? `${asset.url}:\n ${mdStr}` : mdStr;
|
||||
})
|
||||
.join('\n') || '';
|
||||
}
|
||||
|
||||
if (this.$.code.innerHTML === '') {
|
||||
this.$.section.hidden = true;
|
||||
} else {
|
||||
this.$.section.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
export function ready(this: PanelThis) {
|
||||
// TODO something
|
||||
}
|
||||
|
||||
export function close(this: PanelThis,) {
|
||||
// TODO something
|
||||
}
|
||||
566
extensions/app/engine/src/main.ts
Executable file
566
extensions/app/engine/src/main.ts
Executable file
@@ -0,0 +1,566 @@
|
||||
|
||||
/**
|
||||
* @en Registration method for the main process of Extension
|
||||
* @zh 为扩展的主进程的注册方法
|
||||
*/
|
||||
/**
|
||||
* // 打开panel
|
||||
* Editor.Panel.open(`${插件名}.${panel名}`);
|
||||
* // 调用普通事件
|
||||
* Editor.Message.request(插件名, 消息名, ...args);
|
||||
* // 调用场景方法
|
||||
* Editor.Message.request('scene', 'execute-scene-script', {
|
||||
* //插件名
|
||||
* name: string,
|
||||
* //方法名
|
||||
* method: string,
|
||||
* //参数列表
|
||||
* args: any[]
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
// path.join不能正确处理'db://'结构,会把'//'变成'/'
|
||||
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
import { AssetInfo } from '../@types/packages/asset-db/@types/public';
|
||||
import { convertUrlToPath, createFolderByUrl, getResMeta, getResReadme, stringCase, stringCaseNegate } from './utils';
|
||||
const electron = require('electron');
|
||||
|
||||
const adminFolderName = 'app-admin';
|
||||
const controllerFolderName = 'app-controller';
|
||||
const managerFolderName = 'app-manager';
|
||||
const modelFolderName = 'app-model';
|
||||
const soundFolderName = 'app-sound';
|
||||
const viewFolderName = 'app-view';
|
||||
const builtinFolderName = 'app-builtin';
|
||||
const bundleFolderName = 'app-bundle';
|
||||
|
||||
const pkgFolderUrl = 'db://pkg/';
|
||||
const pkgFolderPath = convertUrlToPath(pkgFolderUrl);
|
||||
|
||||
const builtinFolderUrl = 'db://assets/' + builtinFolderName;
|
||||
const builtinFolderPath = convertUrlToPath(builtinFolderUrl);
|
||||
|
||||
const bundleFolderUrl = 'db://assets/' + bundleFolderName;
|
||||
const bundleFolderPath = convertUrlToPath(bundleFolderUrl);
|
||||
|
||||
const adminFolderUrl = builtinFolderUrl + '/' + adminFolderName;
|
||||
const adminFolderPath = builtinFolderPath + '/' + adminFolderName;
|
||||
|
||||
const controllerFolderUrl = builtinFolderUrl + '/' + controllerFolderName;
|
||||
const controllerFolderPath = builtinFolderPath + '/' + controllerFolderName;
|
||||
|
||||
const managerFolderUrl = builtinFolderUrl + '/' + managerFolderName;
|
||||
const managerFolderPath = builtinFolderPath + '/' + managerFolderName;
|
||||
|
||||
const modelFolderUrl = builtinFolderUrl + '/' + modelFolderName;
|
||||
const modelFolderPath = builtinFolderPath + '/' + modelFolderName;
|
||||
|
||||
const soundFolderUrl = bundleFolderUrl + '/' + soundFolderName;
|
||||
const soundFolderPath = bundleFolderPath + '/' + soundFolderName;
|
||||
|
||||
const viewFolderUrl = bundleFolderUrl + '/' + viewFolderName;
|
||||
const viewFolderPath = bundleFolderPath + '/' + viewFolderName;
|
||||
|
||||
const executorFileUrl = adminFolderUrl + '/executor.ts';
|
||||
const executorFilePath = adminFolderPath + '/executor.ts';
|
||||
|
||||
function isExecutor(info: AssetInfo, strict = true) {
|
||||
if (!strict) {
|
||||
if (info.path.endsWith('Controller') && info.type === 'cc.Script') return true;
|
||||
if (info.path.endsWith('Manager') && (info.type === 'cc.Script' || info.type === 'cc.Prefab')) return true;
|
||||
if ((info.name.startsWith('data.') || info.name.startsWith('config.') || info.name.startsWith('store.')) && info.type === 'cc.Script') return true;
|
||||
if ((info.name.startsWith('Page') || info.name.startsWith('Paper') || info.name.startsWith('Pop') || info.name.startsWith('Top'))
|
||||
&& (info.type === 'cc.Script' || info.type === 'cc.Prefab' || info.type === 'cc.Scene' || info.type === 'cc.SceneAsset')) return true;
|
||||
if (info.type === 'cc.AudioClip') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.path === builtinFolderUrl) return true;
|
||||
if (info.path === bundleFolderUrl) return true;
|
||||
if (info.path === managerFolderUrl) return true;
|
||||
if (info.path === controllerFolderUrl) return true;
|
||||
if (info.path === modelFolderUrl) return true;
|
||||
if (info.path === soundFolderUrl) return true;
|
||||
if (info.path === viewFolderUrl) return true;
|
||||
|
||||
if (info.path.startsWith(controllerFolderUrl)) {
|
||||
return info.path.endsWith('Controller') && info.type === 'cc.Script';
|
||||
}
|
||||
if (info.path.startsWith(managerFolderUrl)) {
|
||||
return info.path.endsWith('Manager') && (info.type === 'cc.Script' || info.type === 'cc.Prefab');
|
||||
}
|
||||
if (info.path.startsWith(modelFolderUrl)) {
|
||||
return (info.name.startsWith('data.') || info.name.startsWith('config.') || info.name.startsWith('store.')) && info.type === 'cc.Script';
|
||||
}
|
||||
if (info.path.startsWith(viewFolderUrl)) {
|
||||
return (info.name.startsWith('Page') || info.name.startsWith('Paper') || info.name.startsWith('Pop') || info.name.startsWith('Top'))
|
||||
&& (info.type === 'cc.Script' || info.type === 'cc.Prefab' || info.type === 'cc.Scene' || info.type === 'cc.SceneAsset');
|
||||
}
|
||||
if (info.path.startsWith(soundFolderUrl)) {
|
||||
return info.type === 'cc.AudioClip';
|
||||
}
|
||||
}
|
||||
|
||||
function compareStr(str1: string, str2: string) {
|
||||
if (str1 === str2) {
|
||||
return 0;
|
||||
}
|
||||
const len = Math.max(str1.length, str2.length);
|
||||
for (let i = 0, code1 = 0, code2 = 0; i < len; i++) {
|
||||
if (str1.length <= i) {
|
||||
return -1;
|
||||
} else if (str2.length <= i) {
|
||||
return 1;
|
||||
} else {
|
||||
code1 = str1.charCodeAt(i);
|
||||
code2 = str2.charCodeAt(i);
|
||||
if (code1 > code2) {
|
||||
return 1;
|
||||
} else if (code1 < code2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const viewSelect = ['Page', 'Paper', 'Pop', 'Top'];
|
||||
const viewRegExp = RegExp(`^(${viewSelect.join('|')})`);
|
||||
|
||||
function readFileSyncByPath(url: string) {
|
||||
const filepath = convertUrlToPath(url);
|
||||
return existsSync(filepath) ? readFileSync(filepath, 'utf8') : '';
|
||||
}
|
||||
|
||||
function isTSDefault(value: string[]) {
|
||||
// const varname = value[0];
|
||||
const filename = value[1];
|
||||
const dirname = value[2];
|
||||
const extname = value[3];
|
||||
|
||||
if (extname.endsWith('js')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const filepath = path.join(convertUrlToPath(dirname), filename + '.ts');
|
||||
const js = readFileSync(filepath, 'utf8');
|
||||
return js.search(/export\s+default/) >= 0;
|
||||
}
|
||||
|
||||
const keyWords = [
|
||||
'lib', 'manager', 'Manager', 'controller', 'Controller', 'data', 'config', 'store',
|
||||
'IViewName', 'IViewNames', 'IMiniViewName', 'IMiniViewNames', 'IMusicName', 'IMusicNames', 'IEffectName', 'IEffectNames',
|
||||
'ViewName', 'MiniViewName', 'MusicName', 'EffectName'
|
||||
];
|
||||
|
||||
async function clearExecutor() {
|
||||
if (!existsSync(executorFilePath)) return;
|
||||
|
||||
let result = '/* eslint-disable */\n' +
|
||||
'import { Component } from \'cc\';\n' +
|
||||
'import { app } from \'../../app/app\';\n' +
|
||||
'import { EDITOR,EDITOR_NOT_IN_PREVIEW } from \'cc/env\';\n\n';
|
||||
|
||||
result += 'export type IReadOnly<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : (T[P] extends Object ? IReadOnly<T[P]> : T[P]); };\n\n';
|
||||
|
||||
result += 'export type IViewName = "never"\n';
|
||||
result += 'export type IViewNames = IViewName[]\n';
|
||||
result += 'export type IMiniViewName = "never"\n';
|
||||
result += 'export type IMiniViewNames = IMiniViewName[]\n';
|
||||
result += 'export type IMusicName = "never"\n';
|
||||
result += 'export type IMusicNames = IMusicName[]\n';
|
||||
result += 'export type IEffectName = "never"\n';
|
||||
result += 'export type IEffectNames = IEffectName[]\n\n';
|
||||
|
||||
result += 'export type IApp = {\n';
|
||||
result += ' Controller: {},\n';
|
||||
result += ' controller: {},\n';
|
||||
result += ' Manager: {},\n';
|
||||
result += ' manager: {},\n';
|
||||
result += ' data: {},\n';
|
||||
result += ' config: {}\n';
|
||||
result += ' store: {}\n';
|
||||
result += '}\n';
|
||||
|
||||
// config
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.config, {})\n';
|
||||
// data
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.data, {})\n';
|
||||
// store
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.store, {})\n\n';
|
||||
// controller
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.Controller, {})\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.controller, {})\n\n';
|
||||
|
||||
// 修正windows系统中的\为/
|
||||
result = result.replace(/\\/g, '/');
|
||||
|
||||
// save
|
||||
if (readFileSyncByPath(executorFileUrl) !== result) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', executorFileUrl, result, {
|
||||
overwrite: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function updateExecutor() {
|
||||
// app-builtin文件夹不存在, 创建
|
||||
if (!existsSync(builtinFolderPath)) await createFolderByUrl(builtinFolderUrl, { readme: getResReadme(builtinFolderName) });
|
||||
// app-admin文件夹不存在, 创建
|
||||
if (!existsSync(adminFolderPath)) await createFolderByUrl(adminFolderUrl, { meta: getResMeta(adminFolderName), readme: getResReadme(adminFolderName) });
|
||||
|
||||
const mgrList: string[][] = [];
|
||||
const ctrList: string[][] = [];
|
||||
const dataList: string[][] = [];
|
||||
const confList: string[][] = [];
|
||||
const storeList: string[][] = [];
|
||||
|
||||
const viewScene: { [name in string]: boolean } = {};
|
||||
const miniViewKeys: { [name in string]: string } = {};
|
||||
const musicKeys: { [name in string]: string } = {};
|
||||
const effectKeys: { [name in string]: string } = {};
|
||||
|
||||
// app-controller app-manager app-model
|
||||
const result1: AssetInfo[] = await Editor.Message.request('asset-db', 'query-assets', { pattern: builtinFolderUrl + '/{app-controller,app-manager/*,app-model}/*.ts' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// app-sound
|
||||
const result2: AssetInfo[] = await Editor.Message.request('asset-db', 'query-assets', { pattern: soundFolderUrl + '/{music,effect}/**/*.*' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// app-view
|
||||
const result3: AssetInfo[] = await Editor.Message.request('asset-db', 'query-assets', { pattern: viewFolderUrl + '/{page,pop,top,paper/*}/*/native/*.{prefab,scene}' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// manager
|
||||
const result4: AssetInfo[] = await Editor.Message.request('asset-db', 'query-assets', { pattern: 'db://app/manager/**/*.ts' })
|
||||
.then(res => {
|
||||
return res.sort((a, b) => compareStr(a.name, b.name));
|
||||
})
|
||||
.catch(() => []);
|
||||
// 集合
|
||||
const results: AssetInfo[] = result1.slice().concat(result2).concat(result3).concat(result4);
|
||||
|
||||
for (let index = 0; index < results.length; index++) {
|
||||
const result = results[index];
|
||||
const fileUrl = result.url;
|
||||
// 文件名.扩展名
|
||||
const basename = path.basename(result.url || '') || '';
|
||||
// 扩展名
|
||||
const extname = path.extname(result.url || '') || '';
|
||||
// 文件名
|
||||
const filename = basename.slice(0, -extname.length);
|
||||
// 文件目录名
|
||||
const dirname = path.dirname(result.url || '') || '';
|
||||
|
||||
if (!basename) continue;
|
||||
if (!extname) continue;
|
||||
if (!filename) continue;
|
||||
if (!dirname) continue;
|
||||
|
||||
if (extname === '.ts') {
|
||||
// 变量名
|
||||
const varname = filename.replace(/[.-]/g, '_');
|
||||
|
||||
if (keyWords.indexOf(varname) >= 0) {
|
||||
console.log(`[跳过此文件] [${filename}] 原因: ${varname}与关键字中(${JSON.stringify(keyWords)})的一个重复`);
|
||||
}
|
||||
else if (fileUrl.startsWith(controllerFolderUrl)) {
|
||||
// 用户controller
|
||||
if (filename.endsWith('Controller')) {
|
||||
ctrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith(managerFolderUrl)) {
|
||||
// 用户manager
|
||||
if (filename.endsWith('Manager') && dirname.endsWith(stringCaseNegate(filename.slice(0, -7)))) {
|
||||
mgrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith('db://app/manager/')) {
|
||||
// 系统manager(系统Mgr的文件夹命名为了美观没有那么规范,所以和用户Mgr的逻辑有区别)
|
||||
if (filename.endsWith('Manager') && dirname.endsWith(filename.slice(0, -7).toLowerCase())) {
|
||||
mgrList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
else if (fileUrl.startsWith(modelFolderUrl)) {
|
||||
// model
|
||||
if (filename.startsWith('data.')) {
|
||||
dataList.push([varname, filename, dirname, extname]);
|
||||
} else if (filename.startsWith('config.')) {
|
||||
confList.push([varname, filename, dirname, extname]);
|
||||
} else if (filename.startsWith('store.')) {
|
||||
storeList.push([varname, filename, dirname, extname]);
|
||||
}
|
||||
}
|
||||
} else if (extname === '.prefab' || extname === '.scene') {
|
||||
if (fileUrl.startsWith(viewFolderUrl) && viewRegExp.test(filename)) {
|
||||
const dirArray = dirname.split('/');
|
||||
const index = dirArray.indexOf(viewFolderName);
|
||||
const viewDirArray = dirArray.slice(index + 1);
|
||||
|
||||
if (['page', 'paper', 'pop', 'top'].indexOf(viewDirArray[0].toLowerCase()) >= 0) {
|
||||
// 主界面
|
||||
if (filename === `${stringCase(viewDirArray[0], false)}${stringCase(viewDirArray[1], false)}`) {
|
||||
viewScene[filename] = extname === '.scene';
|
||||
}
|
||||
// 子界面
|
||||
else if (filename === `${stringCase(viewDirArray[0], false)}${stringCase(viewDirArray[1], false)}${stringCase(viewDirArray[2], false)}`) {
|
||||
miniViewKeys[filename] = `${stringCase(viewDirArray[0], false)}${stringCase(viewDirArray[1], false)}`;
|
||||
}
|
||||
} else {
|
||||
// 主界面
|
||||
if (filename === `${stringCase(viewDirArray[1], false)}${stringCase(viewDirArray[2], false)}`) {
|
||||
viewScene[filename] = extname === '.scene';
|
||||
}
|
||||
// 子界面
|
||||
else if (filename === `${stringCase(viewDirArray[1], false)}${stringCase(viewDirArray[2], false)}${stringCase(viewDirArray[3], false)}`) {
|
||||
miniViewKeys[filename] = `${stringCase(viewDirArray[0], false)}${stringCase(viewDirArray[1], false)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fileUrl.startsWith(soundFolderUrl)) {
|
||||
const dir = path.join(dirname.split(soundFolderName + '/').pop(), filename);
|
||||
if (dir.startsWith('music')) {
|
||||
// musicKeys
|
||||
musicKeys[dir] = dir;
|
||||
} else {
|
||||
// effectKeys
|
||||
effectKeys[dir] = dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// const pkgNames: string[] = [];
|
||||
// if (existsSync(pkgFolderPath)) {
|
||||
// readdirSync(pkgFolderPath).forEach(function (item) {
|
||||
// const item_path = path.join(pkgFolderPath, item);
|
||||
// const item_stat = statSync(item_path);
|
||||
// if (!item_stat.isDirectory()) return;
|
||||
// const item_name = path.basename(item_path);
|
||||
// if (item_name.startsWith('@')) {
|
||||
// readdirSync(item_path).forEach(function (sub) {
|
||||
// const sub_path = path.join(item_path, sub);
|
||||
// const sub_stat = statSync(sub_path);
|
||||
// if (!sub_stat.isDirectory()) return;
|
||||
// const sub_name = path.basename(sub_path);
|
||||
// pkgNames.push(item_name + '/' + sub_name);
|
||||
// });
|
||||
// } else {
|
||||
// pkgNames.push(item_name);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
let result = '/* eslint-disable */\n' +
|
||||
'import { Component,director,Director } from \'cc\';\n' +
|
||||
'import { app } from \'../../app/app\';\n' +
|
||||
'import { EDITOR,EDITOR_NOT_IN_PREVIEW } from \'cc/env\';\n\n';
|
||||
|
||||
result += 'export type IReadOnly<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : (T[P] extends Object ? IReadOnly<T[P]> : T[P]); };\n\n';
|
||||
|
||||
result += `export type IViewName = ${Object.keys(viewScene).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IViewNames = IViewName[]\n';
|
||||
result += `export type IMiniViewName = ${Object.keys(miniViewKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IMiniViewNames = IMiniViewName[]\n';
|
||||
result += `export type IMusicName = ${Object.keys(musicKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IMusicNames = IMusicName[]\n';
|
||||
result += `export type IEffectName = ${Object.keys(effectKeys).map(str => `"${str}"`).join('|') || '"never"'}\n`;
|
||||
result += 'export type IEffectNames = IEffectName[]\n\n';
|
||||
|
||||
// pkgNames.forEach(name => result += `import 'db://pkg/${name}'\n`);
|
||||
|
||||
const writeImport = function writeImport(arr: string[][], module: boolean) {
|
||||
return arr.forEach(function (value) {
|
||||
const varname = value[0];
|
||||
const filename = value[1];
|
||||
const dirname = value[2];
|
||||
|
||||
if (isTSDefault(value)) {
|
||||
result += `import ${varname} from '${path.join(path.relative(adminFolderPath, convertUrlToPath(dirname)), filename)}'\n`;
|
||||
} else if (module) {
|
||||
result += `import {${varname}} from '${path.join(path.relative(adminFolderPath, convertUrlToPath(dirname)), filename)}'\n`;
|
||||
} else {
|
||||
result += `import * as ${varname} from '${path.join(path.relative(adminFolderPath, convertUrlToPath(dirname)), filename)}'\n`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
writeImport(confList, false);
|
||||
writeImport(dataList, false);
|
||||
writeImport(storeList, false);
|
||||
writeImport(ctrList, true);
|
||||
writeImport(mgrList, true);
|
||||
|
||||
// controller
|
||||
let ctrStr = '';
|
||||
let CtrStr = '';
|
||||
ctrList.forEach(function ([varname], index, array) {
|
||||
CtrStr += `${varname.slice(0, -10)}:typeof ${varname}`;
|
||||
ctrStr += `${varname.slice(0, -10).toLowerCase()}:IReadOnly<${varname}>`;
|
||||
if (index < array.length - 1) {
|
||||
CtrStr += ',';
|
||||
ctrStr += ',';
|
||||
}
|
||||
});
|
||||
|
||||
// manager
|
||||
let mgrStr = '';
|
||||
let MgrStr = '';
|
||||
mgrList.forEach(function ([varname], index, array) {
|
||||
MgrStr += `${varname.slice(0, -7)}:Omit<typeof ${varname},keyof Component>`;
|
||||
if (varname === 'UIManager') {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname}<IViewName,IMiniViewName>,keyof Component>`;
|
||||
} else if (varname === 'SoundManager') {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname}<IEffectName,IMusicName>,keyof Component>`;
|
||||
} else {
|
||||
mgrStr += `${varname.slice(0, -7).toLowerCase()}:Omit<${varname},keyof Component>`;
|
||||
}
|
||||
if (index < array.length - 1) {
|
||||
MgrStr += ',';
|
||||
mgrStr += ',';
|
||||
}
|
||||
});
|
||||
|
||||
result += 'export type IApp = {\n';
|
||||
result += ` Controller: {${CtrStr}},\n`;
|
||||
result += ` controller: {${ctrStr}},\n`;
|
||||
result += ` Manager: {${MgrStr}},\n`;
|
||||
result += ` manager: {${mgrStr}},\n`;
|
||||
result += ` data: {${dataList.map(([varname]) => `${varname.slice(5)}:${varname}`).join(',')}},\n`;
|
||||
result += ` config: {${confList.map(([varname]) => `${varname.slice(7)}:IReadOnly<${varname}>`).join(',')}}\n`;
|
||||
result += ` store: {${storeList.map(([varname]) => `${varname.slice(6)}:IReadOnly<${varname}>`).join(',')}}\n`;
|
||||
result += '}\n\n';
|
||||
|
||||
result += 'function init(){\n';
|
||||
// config
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.config, {${confList.map(([varname]) => `${varname.slice(7)}:new ${varname}()`).join(',')}})\n`;
|
||||
// data
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.data, {${dataList.map(([varname]) => `${varname.slice(5)}:new ${varname}()`).join(',')}})\n`;
|
||||
// store
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.store, {${storeList.map(([varname]) => `${varname.slice(6)}:new ${varname}()`).join(',')}})\n\n`;
|
||||
// controller
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.Controller, {${ctrList.map(([varname]) => `${varname.slice(0, -10)}:${varname}`).join(',')}})\n`;
|
||||
result += `if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) Object.assign(app.controller, {${ctrList.map(([varname]) => `${varname.slice(0, -10).toLowerCase()}:new ${varname}()`).join(',')}})\n`;
|
||||
result += '}\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) director.on(Director.EVENT_RESET,init)\n';
|
||||
result += 'if(!EDITOR||!EDITOR_NOT_IN_PREVIEW) init()\n';
|
||||
|
||||
// 修正windows系统中的\为/
|
||||
result = result.replace(/\\/g, '/');
|
||||
|
||||
// save
|
||||
if (readFileSyncByPath(executorFileUrl) !== result) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', executorFileUrl, result, {
|
||||
overwrite: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
function callUpdateExecutor(clear = false) {
|
||||
if (timer) return;
|
||||
if (clear) {
|
||||
clearExecutor();
|
||||
callUpdateExecutor(false);
|
||||
} else {
|
||||
timer = setTimeout(() => {
|
||||
updateExecutor().finally(() => {
|
||||
timer = null;
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// 获得Creator主窗口
|
||||
function getMainWebContents() {
|
||||
const windows = electron.BrowserWindow.getAllWindows();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
const win = windows[i];
|
||||
if (win.webContents.getURL().includes('windows/main.html') || (win.title && win.title.includes('Cocos Creator'))) {
|
||||
return win.webContents;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function updateMark() {
|
||||
const webContents = getMainWebContents();
|
||||
if (webContents) {
|
||||
const hackCode = readFileSync(path.join(__dirname, '../res/mark.js'), 'utf-8');
|
||||
webContents.executeJavaScript(hackCode);
|
||||
}
|
||||
}
|
||||
|
||||
export const methods: { [key: string]: (...any: any) => any } = {
|
||||
['open-panel']() {
|
||||
Editor.Panel.open('app.open-panel');
|
||||
},
|
||||
['open-wiki']() {
|
||||
const url = 'https://gitee.com/cocos2d-zp/xforge/wikis/pages';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-issues']() {
|
||||
const url = 'https://gitee.com/cocos2d-zp/xforge/issues';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-github']() {
|
||||
const url = 'https://github.com/a1076559139/XForge';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['open-store']() {
|
||||
const url = 'https://store.cocos.com/app/search?name=xforge';
|
||||
Editor.Message.send('program', 'open-url', url);
|
||||
},
|
||||
['refresh-executor']() {
|
||||
// 点击更新
|
||||
callUpdateExecutor();
|
||||
console.log('[executor.ts] 刷新成功');
|
||||
},
|
||||
['scene:ready']() {
|
||||
//
|
||||
},
|
||||
['asset-db:ready']() {
|
||||
updateExecutor();
|
||||
updateMark();
|
||||
},
|
||||
['asset-db:asset-add'](uuid: string, info: AssetInfo) {
|
||||
if (!isExecutor(info)) return;
|
||||
callUpdateExecutor();
|
||||
},
|
||||
['asset-db:asset-change'](uuid: string, info: AssetInfo) {
|
||||
if (!isExecutor(info, false)) return;
|
||||
callUpdateExecutor();
|
||||
},
|
||||
['asset-db:asset-delete'](uuid: string, info: AssetInfo) {
|
||||
if (!isExecutor(info)) return;
|
||||
callUpdateExecutor(true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Hooks triggered after extension loading is complete
|
||||
* @zh 扩展加载完成后触发的钩子
|
||||
*/
|
||||
export function load() {
|
||||
Editor.Message.request('asset-db', 'query-ready').then(ready => {
|
||||
if (!ready) return;
|
||||
updateExecutor();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Hooks triggered after extension uninstallation is complete
|
||||
* @zh 扩展卸载完成后触发的钩子
|
||||
*/
|
||||
export function unload() { }
|
||||
34
extensions/app/engine/src/menu/index.ts
Normal file
34
extensions/app/engine/src/menu/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { AssetInfo } from '../../@types/packages/asset-db/@types/public';
|
||||
import tinyPNG from './tinyPNG';
|
||||
|
||||
function getMenu(assetInfo: AssetInfo) {
|
||||
return [
|
||||
{
|
||||
label: 'i18n:app.app',
|
||||
submenu: [
|
||||
{
|
||||
label: 'i18n:app.tiny',
|
||||
click() {
|
||||
tinyPNG(assetInfo.file);
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function onCreateMenu(assetInfo: AssetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
|
||||
export function onDBMenu(assetInfo: AssetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
|
||||
export function onPanelMenu(assetInfo: AssetInfo) {
|
||||
// return getMenu();
|
||||
}
|
||||
|
||||
export function onAssetMenu(assetInfo: AssetInfo) {
|
||||
return getMenu(assetInfo);
|
||||
}
|
||||
204
extensions/app/engine/src/menu/tinyPNG.ts
Normal file
204
extensions/app/engine/src/menu/tinyPNG.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
*
|
||||
* 参考: https://segmentfault.com/a/1190000015467084
|
||||
* 优化:通过 X-Forwarded-For 添加了动态随机伪IP,绕过 tinypng 的上传数量限制
|
||||
*
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import https from 'https';
|
||||
import path from 'path';
|
||||
import { URL } from 'url';
|
||||
|
||||
const exts = ['.png', '.jpg', '.jpeg'];
|
||||
const max = 5200000; // 5MB == 5242848.754299136
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
hostname: 'tinypng.com',
|
||||
path: '/backend/opt/shrink',
|
||||
headers: {
|
||||
'rejectUnauthorized': 'false',
|
||||
'Postman-Token': Date.now(),
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
|
||||
}
|
||||
};
|
||||
|
||||
// 生成随机IP, 赋值给 X-Forwarded-For
|
||||
function getRandomIP() {
|
||||
return Array.from(Array(4)).map(() => Math.floor(Math.random() * 255)).join('.');
|
||||
}
|
||||
|
||||
// 遍历文件列表
|
||||
function fileEach(folder: string, callback: (filePath: string) => any) {
|
||||
fs.readdir(folder, (err, files) => {
|
||||
if (err) console.error(err);
|
||||
files.forEach(file => {
|
||||
const filePath = path.join(folder, file);
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if (err) return console.error(err);
|
||||
if (stats.isDirectory()) {
|
||||
fileEach(filePath, callback);
|
||||
} else if (
|
||||
// 必须是文件,小于5MB,后缀 jpg||png
|
||||
stats.size <= max &&
|
||||
stats.isFile() &&
|
||||
exts.includes(path.extname(file))
|
||||
) {
|
||||
callback(filePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
interface IResponse {
|
||||
input: {
|
||||
size: number;
|
||||
type: string;
|
||||
};
|
||||
output: {
|
||||
size: number;
|
||||
type: string;
|
||||
width: number;
|
||||
height: number;
|
||||
ratio: number;
|
||||
url: string;
|
||||
};
|
||||
error: string;
|
||||
message: string;
|
||||
}
|
||||
// 压缩图片
|
||||
async function fileUpload(img_path: string): Promise<IResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 通过 X-Forwarded-For 头部伪造客户端IP
|
||||
options.headers['X-Forwarded-For'] = getRandomIP();
|
||||
const req = https.request(options, function (res) {
|
||||
res.on('data', buf => {
|
||||
const data = JSON.parse(buf.toString()) as IResponse;
|
||||
if (data.error) {
|
||||
reject(data.message);
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.write(fs.readFileSync(img_path), 'binary');
|
||||
req.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 该方法被循环调用,请求图片数据
|
||||
function fileUpdate(img_path: string, obj: IResponse): Promise<IResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = new URL(obj.output.url);
|
||||
const req = https.request(options, res => {
|
||||
let body = '';
|
||||
res.setEncoding('binary');
|
||||
res.on('data', function (data) {
|
||||
body += data;
|
||||
});
|
||||
|
||||
res.on('end', function () {
|
||||
fs.writeFile(img_path, body, 'binary', err => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(obj);
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 根据字节大小转成B、KB、MB
|
||||
function toSize(b: number) {
|
||||
if (b < 1024) {
|
||||
return b + 'B';
|
||||
}
|
||||
else if (b < 1024 * 1024) {
|
||||
return (b / 1024).toFixed(2) + 'KB';
|
||||
}
|
||||
else {
|
||||
return (b / 1024 / 1024).toFixed(2) + 'MB';
|
||||
}
|
||||
}
|
||||
|
||||
// 根据小数转成百分比字符串
|
||||
function toPercent(num: number) {
|
||||
return (num * 100).toFixed(2) + '%';
|
||||
}
|
||||
|
||||
async function fileTiny(filePath: string) {
|
||||
return fileUpload(filePath)
|
||||
.then(obj => fileUpdate(filePath, obj));
|
||||
}
|
||||
|
||||
export default function (folder: string) {
|
||||
// 路径是否存在
|
||||
if (!fs.existsSync(folder)) {
|
||||
console.log(`路径不存在:${folder}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const basename = path.basename(folder);
|
||||
console.log(`[${basename}] 压缩中...`);
|
||||
|
||||
// 是文件
|
||||
if (!fs.statSync(folder).isDirectory()) {
|
||||
if (!exts.includes(path.extname(folder))) {
|
||||
console.log(`[${basename}] 压缩失败!报错:只支持png、jpg与jpeg格式`);
|
||||
return;
|
||||
}
|
||||
fileTiny(folder)
|
||||
.then(obj => {
|
||||
console.log(
|
||||
'[1/1]',
|
||||
`[${basename}]`,
|
||||
`压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(
|
||||
'[1/1]',
|
||||
`[${basename}]`,
|
||||
`压缩失败!报错:${err}`
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
let finished = 0;
|
||||
// 是文件夹
|
||||
fileEach(folder, (filePath => {
|
||||
total++;
|
||||
const relativePath = path.relative(folder, filePath);
|
||||
fileTiny(filePath)
|
||||
.then(obj => {
|
||||
console.log(
|
||||
`[${++finished}/${total}]`,
|
||||
`[${relativePath}]`,
|
||||
`压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(
|
||||
`[${++finished}/${total}]`,
|
||||
`[${relativePath}]`,
|
||||
`压缩失败!报错:${err}`
|
||||
);
|
||||
});
|
||||
}));
|
||||
}
|
||||
29
extensions/app/engine/src/panel/components/app.ts
Normal file
29
extensions/app/engine/src/panel/components/app.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import Vue from '../../../../vue';
|
||||
|
||||
import ControllerComponent from './create-controller';
|
||||
import ManagerComponent from './create-manager';
|
||||
import ModelComponent from './create-model';
|
||||
import ResComponent from './create-res';
|
||||
import SoundComponent from './create-sound';
|
||||
import ViewComponent from './create-view';
|
||||
|
||||
const Assets = join(__dirname, '../../../res/panel');
|
||||
const Menus = ['ViewComponent', 'ManagerComponent', 'ControllerComponent', 'ModelComponent', 'SoundComponent', 'ResComponent'];
|
||||
|
||||
export default Vue.extend({
|
||||
components: { ViewComponent, ManagerComponent, ControllerComponent, ModelComponent, SoundComponent, ResComponent },
|
||||
template: readFileSync(join(Assets, 'components/app.html'), 'utf-8'),
|
||||
data() {
|
||||
return {
|
||||
menus: ['View', 'Manager', 'Controller', 'Model', 'Sound', '资源目录'],
|
||||
content: 'ViewComponent'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClick(index: number) {
|
||||
this.content = Menus[index];
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import { existsSync } from 'fs';
|
||||
import Vue from '../../../../vue';
|
||||
import { convertUrlToPath, createFolderByUrl, getResMeta, getResPanel, getResReadme, stringCase } from '../../utils';
|
||||
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(name: string) {
|
||||
const basePath = '../../../extensions/app/assets/base/BaseController';
|
||||
return 'import BaseController from \'' + basePath + '\';\r\n' +
|
||||
'export class ' + name + ' extends BaseController<' + name + ', {\r\n' +
|
||||
' // 定义了事件,并同时定义参数列表和返回值\r\n' +
|
||||
' Refresh: (a: number) => boolean\r\n' +
|
||||
'}>() {\r\n' +
|
||||
' // Controller中发射事件, UI中监听事件:\r\n' +
|
||||
' // 1、UI中需要将 「extends BaseView」 改为=> 「extends BaseView.bindController(' + name + ')」\r\n' +
|
||||
' // 2、UI中使用「this.controller.on/once」监听事件, 使用「this.controller.emit」发射事件, 使用「this.controller.off/targetOff」取消监听事件\r\n' +
|
||||
' // 3、在外部(无法使用this.controller的地方)可以通过「app.controller.xxx」来调用对外导出的方法, 比如下面的refresh方法\r\n' +
|
||||
' refresh() {\r\n' +
|
||||
' this.emit(' + name + '.Event.Refresh, 1000); // 参数类型正确\r\n' +
|
||||
' this.emit(' + name + '.Event.Refresh, true); // 参数类型错误\r\n' +
|
||||
' const result = this.call(' + name + '.Event.Refresh, 1000); // 自动推导返回值类型\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-controller'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onClickCreate() {
|
||||
const name = this.inputName;
|
||||
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
|
||||
const rootPath = 'db://assets/app-builtin/app-controller';
|
||||
const controlName = `${stringCase(name)}Controller`;
|
||||
const scriptUrl = `${rootPath}/${controlName}.ts`;
|
||||
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: controlName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
if (existsSync(convertUrlToPath(scriptUrl))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 文件已存在, 请删除\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 目录如果不存在则创建
|
||||
if (!await createFolderByUrl(rootPath, { meta: getResMeta('app-controller'), readme: getResReadme('app-controller') })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${rootPath}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(controlName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
116
extensions/app/engine/src/panel/components/create-manager.ts
Normal file
116
extensions/app/engine/src/panel/components/create-manager.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { existsSync } from 'fs';
|
||||
import Vue from '../../../../vue';
|
||||
import { convertUrlToPath, createFolderByUrl, getResMeta, getResPanel, getResReadme, stringCase } from '../../utils';
|
||||
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(name: string) {
|
||||
const basePath = '../../../../extensions/app/assets/base/BaseManager';
|
||||
return 'import { _decorator } from \'cc\';\r\n' +
|
||||
'import BaseManager from \'' + basePath + '\';\r\n' +
|
||||
'const { ccclass, property } = _decorator;\r\n' +
|
||||
'@ccclass(\'' + name + '\')\r\n' +
|
||||
'export class ' + name + ' extends BaseManager {\r\n' +
|
||||
' // [无序] 加载完成时触发\r\n' +
|
||||
' protected onLoad() { }\r\n\r\n' +
|
||||
' // [无序] 自身初始化完成, init执行完毕后被调用\r\n' +
|
||||
' protected onInited() { }\r\n\r\n' +
|
||||
' // [无序] 所有manager初始化完成\r\n' +
|
||||
' protected onFinished() { }\r\n\r\n' +
|
||||
' // [无序] 初始化manager,在初始化完成后,调用finish方法\r\n' +
|
||||
' protected init(finish: Function) {\r\n' +
|
||||
' super.init(finish);\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-manager'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onClickCreate() {
|
||||
const name = this.inputName;
|
||||
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
|
||||
const rootPath = 'db://assets/app-builtin/app-manager';
|
||||
const managerName = `${stringCase(name)}Manager`;
|
||||
const folderName = name;
|
||||
const folderPath = `${rootPath}/${folderName}`;
|
||||
const scriptUrl = `${folderPath}/${managerName}.ts`;
|
||||
const prefabUrl = `${folderPath}/${managerName}.prefab`;
|
||||
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: managerName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
if (existsSync(convertUrlToPath(folderPath))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 目录已存在, 请删除\n${folderPath}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 目录如果不存在则创建
|
||||
if (!await createFolderByUrl(rootPath, {
|
||||
meta: getResMeta('app-manager'),
|
||||
readme: getResReadme('app-manager'),
|
||||
subFolders: [
|
||||
{
|
||||
folder: folderName,
|
||||
readme: `1、${managerName}所在文件夹, 通过app.manager.${stringCase(name, true)}的方式调用\n2、如不再需要,可以直接删除此文件夹`
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${folderPath}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(managerName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建prefab
|
||||
const createPrefabResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createPrefab',
|
||||
args: [managerName, prefabUrl]
|
||||
});
|
||||
if (!createPrefabResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建预制体失败\n${prefabUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
111
extensions/app/engine/src/panel/components/create-model.ts
Normal file
111
extensions/app/engine/src/panel/components/create-model.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { existsSync } from 'fs';
|
||||
import Vue from '../../../../vue';
|
||||
import { convertUrlToPath, createFolderByUrl, getResMeta, getResPanel, getResReadme, stringCase } from '../../utils';
|
||||
|
||||
/**
|
||||
* 根据语言获取脚本内容
|
||||
*/
|
||||
function getScript(type: string, className: string) {
|
||||
if (type === 'data') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IModel } from \'' + BaseModel + '\';\r\n' +
|
||||
'// data中不能定义任何方法(更建议使用store)\r\n' +
|
||||
'export default class ' + className + ' implements IModel<' + className + '> {\r\n' +
|
||||
'}';
|
||||
} else if (type === 'config') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IModel } from \'' + BaseModel + '\';\r\n' +
|
||||
'// config中不能定义任何方法, 任何变量在外部访问都是readonly\r\n' +
|
||||
'// 如果config中的内容是服务器下发的,可以使用Object.assign覆盖config中的内容\r\n' +
|
||||
'export default class ' + className + ' implements IModel<' + className + '> {\r\n' +
|
||||
'}';
|
||||
} else if (type === 'store') {
|
||||
const BaseModel = '../../../extensions/app/assets/base/BaseModel';
|
||||
return 'import { IStore } from \'' + BaseModel + '\';\r\n' +
|
||||
'// store中只允许在根路径下定义方法,任何变量在外部访问都是readonly\r\n' +
|
||||
'// store类型的引入是借鉴了Web前端框架中全局状态管理的思路,意图是让数据更安全,更可控。同时框架中还提供了数据绑定的扩展包,可以通过pkg的方式安装,实现「数据->视图」的单向绑定。\r\n' +
|
||||
'export default class ' + className + ' implements IStore<' + className + '> {\r\n' +
|
||||
' count = 0;\r\n' +
|
||||
' setCount(v: number) {\r\n' +
|
||||
' this.count = v;\r\n' +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
} else {
|
||||
return '// 🔥切记: 当前文件处于分包中, 由于加载顺序的原因,不可以在「主包」中使用此文件内导出的变量\r\n' +
|
||||
'// 存放直接导出的interface、type或enum等\r\n\r\n' +
|
||||
'// export type IString = string;\r\n' +
|
||||
'// export enum Type { None };';
|
||||
}
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-model'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
|
||||
typeSelects: ['store', 'data', 'config', 'export'],
|
||||
typeSelectIndex: 0,
|
||||
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index: string) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const type = this.typeSelects[this.typeSelectIndex];
|
||||
const name = this.inputName;
|
||||
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
|
||||
const rootPath = 'db://assets/app-builtin/app-model';
|
||||
const modelName = `${type}.${name}`;
|
||||
const scriptUrl = `${rootPath}/${modelName}.ts`;
|
||||
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: modelName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
// 目录如果不存在则创建
|
||||
if (!await createFolderByUrl(rootPath, { meta: getResMeta('app-model'), readme: getResReadme('app-model') })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${rootPath}`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (existsSync(convertUrlToPath(scriptUrl))) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 文件已存在, 请删除\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getScript(type, stringCase(name))).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
66
extensions/app/engine/src/panel/components/create-res.ts
Normal file
66
extensions/app/engine/src/panel/components/create-res.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import Vue from '../../../../vue';
|
||||
import { createFolderByUrl, getResMeta, getResPanel, getResReadme, stringCase } from '../../utils';
|
||||
|
||||
const typeNames: ('res-bundle' | 'res-native' | 'resources')[] = ['res-native', 'res-bundle', 'resources'];
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-res'),
|
||||
data() {
|
||||
return {
|
||||
inputName: '',
|
||||
display: '',
|
||||
|
||||
typeSelects: ['公共静态目录', '公共动态目录', 'resources'],
|
||||
typeSelectIndex: 0,
|
||||
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index: string) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const folderName = typeNames[this.typeSelectIndex];
|
||||
const folderPath = `db://assets/${folderName}`;
|
||||
const name = stringCase(this.inputName, true);
|
||||
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(this.inputName) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
if (name === 'resources') {
|
||||
this.display = '[错误] 名字不合法\n1、不能使用resources作为名字';
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: name, buttons: ['创建', '取消'], default: 0, cancel: 1 });
|
||||
if (createResponse.response == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
if (!await createFolderByUrl(folderPath, {
|
||||
readme: getResReadme(folderName),
|
||||
meta: folderName === 'resources' ? getResMeta('resources') : undefined,
|
||||
subFolders: [
|
||||
{
|
||||
folder: name,
|
||||
meta: folderName === 'res-bundle' ? getResMeta('custom-bundle') : undefined
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 创建失败';
|
||||
return;
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${folderPath}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', folderPath);
|
||||
}
|
||||
},
|
||||
});
|
||||
47
extensions/app/engine/src/panel/components/create-sound.ts
Normal file
47
extensions/app/engine/src/panel/components/create-sound.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import Vue from '../../../../vue';
|
||||
import { createFolderByUrl, getResMeta, getResPanel, getResReadme } from '../../utils';
|
||||
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-sound'),
|
||||
data() {
|
||||
return {
|
||||
display: '',
|
||||
|
||||
typeSelects: ['音乐', '音效'],
|
||||
typeSelectIndex: 0,
|
||||
|
||||
showLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeTypeSelect(index: string) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
const rootPath = 'db://assets/app-bundle/app-sound';
|
||||
|
||||
if (!await createFolderByUrl(rootPath, {
|
||||
meta: getResMeta('app-sound'),
|
||||
readme: getResReadme('app-sound'),
|
||||
subFolders: [
|
||||
{
|
||||
folder: this.typeSelectIndex === 0 ? 'music' : 'effect',
|
||||
readme: getResReadme(this.typeSelectIndex === 0 ? 'sound-music' : 'sound-effect')
|
||||
}
|
||||
]
|
||||
})) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 创建失败';
|
||||
return;
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${rootPath}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', rootPath);
|
||||
}
|
||||
},
|
||||
});
|
||||
280
extensions/app/engine/src/panel/components/create-view.ts
Normal file
280
extensions/app/engine/src/panel/components/create-view.ts
Normal file
@@ -0,0 +1,280 @@
|
||||
import { existsSync, readdirSync, statSync, writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import Vue from '../../../../vue';
|
||||
import { convertUrlToPath, createFolderByUrl, delayFileExistsByUrl, getResMeta, getResPanel, getResReadme, stringCase } from '../../utils';
|
||||
|
||||
/**
|
||||
* 获取脚本内容
|
||||
*/
|
||||
function getComScript(name = 'NewClass') {
|
||||
const isPage = name.toLowerCase().startsWith('page');
|
||||
const isPaper = name.toLowerCase().startsWith('paper');
|
||||
|
||||
const basePath = isPaper ? '../../../../../../../extensions/app/assets/base/BaseView' : '../../../../../../extensions/app/assets/base/BaseView';
|
||||
|
||||
return 'import { _decorator, Node } from \'cc\';\r\n' +
|
||||
'import BaseView from \'' + basePath + '\';\r\n' +
|
||||
`${isPage ? 'import { IMiniViewNames } from \'../../../../../app-builtin/app-admin/executor\';\r\n' : ''}` +
|
||||
'const { ccclass, property } = _decorator;\r\n' +
|
||||
'@ccclass(\'' + name + '\')\r\n' +
|
||||
'export class ' + name + ' extends BaseView {\r\n' +
|
||||
` ${isPage ? '// 子界面列表,数组顺序为子界面排列顺序\r\n' : ''}` +
|
||||
` ${isPage ? 'protected miniViews: IMiniViewNames = [];\r\n\r\n' : '\r\n'}` +
|
||||
' // 初始化的相关逻辑写在这\r\n' +
|
||||
' onLoad() {}\r\n\r\n' +
|
||||
' // 界面打开时的相关逻辑写在这(onShow可被多次调用-它与onHide不成对)\r\n' +
|
||||
' onShow(params: any) {\r\n' +
|
||||
` ${isPage ? 'this.showMiniViews({ views: this.miniViews });' : ''}\r\n` +
|
||||
' }\r\n\r\n' +
|
||||
' // 界面关闭时的相关逻辑写在这(已经关闭的界面不会触发onHide)\r\n' +
|
||||
' onHide(result: undefined) {\r\n' +
|
||||
` ${isPaper ? '' : '// app.manager.ui.show<' + name + '>({name: \'' + name + '\', onHide:(result) => { 接收到return的数据,并且有类型提示 }})\r\n'}` +
|
||||
` ${isPaper ? '' : 'return result;'}\r\n` +
|
||||
' }\r\n' +
|
||||
'}';
|
||||
}
|
||||
|
||||
function getNaMetaUserData(name = 'new-class') {
|
||||
return {
|
||||
...getResMeta('view-native'),
|
||||
'bundleName': `${name}`
|
||||
};
|
||||
}
|
||||
|
||||
function getResMetaUserData(name = 'new-class') {
|
||||
return {
|
||||
...getResMeta('view-resources'),
|
||||
'bundleName': `${name}-res`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* UI类型(小写)
|
||||
*/
|
||||
const TypeSelects = ['page', 'paper', 'pop', 'top'];
|
||||
/**
|
||||
* 大驼峰UI名(带page前缀) => 串式UI目录名(不带page前缀)
|
||||
*/
|
||||
const PageNames: Map<string, string> = new Map();
|
||||
function updatePages() {
|
||||
PageNames.clear();
|
||||
|
||||
// page目录
|
||||
const pageRootPath = join(Editor.Project.path, 'assets/app-bundle/app-view/page');
|
||||
|
||||
// 读取page目录下所有文件
|
||||
const folderNames = existsSync(pageRootPath) ? readdirSync(pageRootPath) : [];
|
||||
|
||||
// 大驼峰命名的UI名
|
||||
folderNames.forEach((folderName) => {
|
||||
// folderName为串式命名法
|
||||
const pagePath = join(pageRootPath, folderName);
|
||||
const isDirectory = statSync(pagePath).isDirectory();
|
||||
if (isDirectory) {
|
||||
PageNames.set(`Page${stringCase(folderName)}`, folderName);
|
||||
}
|
||||
});
|
||||
|
||||
PageNames.set('通用', 'all');
|
||||
|
||||
return Array.from(PageNames.keys());
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
template: getResPanel('create-view'),
|
||||
data() {
|
||||
return {
|
||||
showLoading: false,
|
||||
showSelectPage: false,
|
||||
showSelectGroup: true,
|
||||
|
||||
inputName: '',
|
||||
display: '',
|
||||
|
||||
typeSelects: TypeSelects,
|
||||
typeSelectIndex: 0,
|
||||
|
||||
groupSelects: ['2D', '3D'],
|
||||
groupSelectIndex: 0,
|
||||
|
||||
pageSelects: [] as string[],
|
||||
pageSelectIndex: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onChangeGroupSelect(index: string) {
|
||||
this.groupSelectIndex = Number(index);
|
||||
},
|
||||
onChangeTypeSelect(index: string) {
|
||||
this.typeSelectIndex = Number(index);
|
||||
|
||||
if (index == '0') {
|
||||
this.showSelectGroup = true;
|
||||
} else {
|
||||
this.showSelectGroup = false;
|
||||
}
|
||||
|
||||
if (index == '1') {
|
||||
this.pageSelectIndex = 0;
|
||||
this.pageSelects = updatePages();
|
||||
this.showSelectPage = true;
|
||||
} else {
|
||||
this.showSelectPage = false;
|
||||
}
|
||||
},
|
||||
onChangePageSelect(index: string) {
|
||||
this.pageSelectIndex = Number(index);
|
||||
},
|
||||
async onClickCreate() {
|
||||
const isPage = this.typeSelectIndex == 0;
|
||||
const isPaper = this.typeSelectIndex == 1;
|
||||
|
||||
// ui归属(大驼峰)
|
||||
const owner = this.pageSelects[this.pageSelectIndex];
|
||||
// ui类型(小写)
|
||||
const type = this.typeSelects[this.typeSelectIndex];
|
||||
// ui名字(串式)
|
||||
const name = this.inputName;
|
||||
|
||||
if (/^[a-z][a-z0-9-]*[a-z0-9]+$/.test(name) === false) {
|
||||
this.display = '[错误] 名字不合法\n1、不能以数字开头\n2、不能有大写字母\n3、分隔符只能使用-\n4、不能以分隔符开头或结尾';
|
||||
return;
|
||||
}
|
||||
if (name === 'all' || name === 'page' || name === 'paper' || name === 'pop' || name === 'top') {
|
||||
this.display = '[错误] 名字不合法\n1、不能使用all、page、paper、pop、top作为名字';
|
||||
return;
|
||||
}
|
||||
|
||||
const is3D = isPage && this.groupSelectIndex == 1;
|
||||
const ownerName = PageNames.get(owner) as string;
|
||||
const uiName = isPaper ?
|
||||
`${stringCase(type)}${stringCase(ownerName)}${stringCase(name)}` :
|
||||
`${stringCase(type)}${stringCase(name)}`;
|
||||
const bundleName = isPaper ?
|
||||
`${type}-${ownerName}-${name}` :
|
||||
`${type}-${name}`;
|
||||
|
||||
const bundleFolderUrl = 'db://assets/app-bundle';
|
||||
const viewFolderUrl = `${bundleFolderUrl}/app-view`;
|
||||
const typeFolderUrl = `${viewFolderUrl}/${type}`;
|
||||
const uiFolderUrl = isPaper ?
|
||||
`${typeFolderUrl}/${ownerName}/${name}` :
|
||||
`${typeFolderUrl}/${name}`;
|
||||
const nativeUrl = `${uiFolderUrl}/native`;
|
||||
const resourcesUrl = `${uiFolderUrl}/resources`;
|
||||
const expansionUrl = `${nativeUrl}/expansion`;
|
||||
const scriptUrl = `${nativeUrl}/${uiName}.ts`;
|
||||
const prefabUrl = `${nativeUrl}/${uiName}.prefab`;
|
||||
const sceneUrl = `${nativeUrl}/${uiName}.scene`;
|
||||
const singleColorUrl = `${resourcesUrl}/singleColor.png`;
|
||||
|
||||
// 创建前确认
|
||||
const createResponse = await Editor.Dialog.info('请确认', { detail: uiName, buttons: ['创建并打开', '仅创建', '取消'], default: 0, cancel: 2 });
|
||||
if (createResponse.response == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.display = '创建中';
|
||||
this.showLoading = true;
|
||||
|
||||
// 创建目录
|
||||
if (!await createFolderByUrl(uiFolderUrl, { subPaths: ['native', 'resources', 'native/expansion'] })) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建目录失败\n${uiFolderUrl}`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置native分包
|
||||
await delayFileExistsByUrl(`${nativeUrl}.meta`);
|
||||
const queryNativeMeta = await Editor.Message.request('asset-db', 'query-asset-meta', nativeUrl).catch(_ => null);
|
||||
if (!queryNativeMeta) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 设置native分包配置失败';
|
||||
return;
|
||||
}
|
||||
queryNativeMeta.userData = getNaMetaUserData(bundleName);
|
||||
await Editor.Message.request('asset-db', 'save-asset-meta', nativeUrl, JSON.stringify(queryNativeMeta)).catch(_ => null);
|
||||
|
||||
// 设置resources分包
|
||||
await delayFileExistsByUrl(`${resourcesUrl}.meta`);
|
||||
const queryResMeta = await Editor.Message.request('asset-db', 'query-asset-meta', resourcesUrl).catch(_ => null);
|
||||
if (!queryResMeta) {
|
||||
this.showLoading = false;
|
||||
this.display = '[错误] 设置resources分包配置失败';
|
||||
return;
|
||||
}
|
||||
queryResMeta.userData = getResMetaUserData(bundleName);
|
||||
await Editor.Message.request('asset-db', 'save-asset-meta', resourcesUrl, JSON.stringify(queryResMeta)).catch(_ => null);
|
||||
|
||||
writeFileSync(join(convertUrlToPath(bundleFolderUrl), '.app-bundle.md'), getResReadme('app-bundle'));
|
||||
writeFileSync(join(convertUrlToPath(viewFolderUrl), '.app-view.md'), getResReadme('app-view'));
|
||||
writeFileSync(join(convertUrlToPath(typeFolderUrl), `.${type}.md`), `1、所有${type}类型UI的根目录\n2、如不再需要,可以直接删除此文件夹`);
|
||||
writeFileSync(join(convertUrlToPath(nativeUrl), '.native.md'), getResReadme('view-native'));
|
||||
writeFileSync(join(convertUrlToPath(resourcesUrl), '.resources.md'), getResReadme('view-resources'));
|
||||
writeFileSync(join(convertUrlToPath(expansionUrl), '.expansion.md'), getResReadme('view-expansion'));
|
||||
|
||||
if (isPaper) {
|
||||
writeFileSync(join(convertUrlToPath(`${typeFolderUrl}/${ownerName}`), `.${ownerName}.md`), (ownerName === 'all' ? '1、归属于全体Page' : `1、归属于Page${stringCase(ownerName)}`) + '\n2、如不再需要,可以直接删除此文件夹');
|
||||
writeFileSync(join(convertUrlToPath(uiFolderUrl), `.${name}.md`), `${uiName}所在文件夹\n1、通过${ownerName === 'all' ? '在任意Page中配置miniViews属性并调用showMiniViews方法' : `在${owner}中配置miniViews属性并调用showMiniViews方法`}的方式加载\n2、如不再需要,可以直接删除此文件夹`);
|
||||
} else {
|
||||
writeFileSync(join(convertUrlToPath(uiFolderUrl), `.${name}.md`), `${uiName}所在文件夹\n1、通过app.manager.ui.show({ name:'${uiName}' })的方式加载\n2、如不再需要,可以直接删除此文件夹`);
|
||||
}
|
||||
|
||||
// 创建script
|
||||
if (!existsSync(convertUrlToPath(scriptUrl))) {
|
||||
const createScriptResult = await Editor.Message.request('asset-db', 'create-asset', scriptUrl, getComScript(uiName)).catch(_ => null);
|
||||
if (!createScriptResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建脚本失败\n${scriptUrl}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建view
|
||||
if (!existsSync(convertUrlToPath(prefabUrl)) && !existsSync(convertUrlToPath(sceneUrl))) {
|
||||
if (is3D && isPage) {
|
||||
const createSceneResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createScene',
|
||||
args: [uiName, sceneUrl]
|
||||
}).catch(_ => null);
|
||||
if (!createSceneResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建场景失败\n${sceneUrl}`;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const createPrefabResult = await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: 'app',
|
||||
method: 'createPrefab',
|
||||
args: [uiName, prefabUrl, is3D]
|
||||
}).catch(_ => null);
|
||||
if (!createPrefabResult) {
|
||||
this.showLoading = false;
|
||||
this.display = `[错误] 创建预制体失败\n${prefabUrl}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.showLoading = false;
|
||||
this.display = `[成功] 创建成功\n${uiFolderUrl}`;
|
||||
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 是否打开
|
||||
if (createResponse.response == 0) {
|
||||
if (is3D) {
|
||||
Editor.Message.request('asset-db', 'open-asset', sceneUrl);
|
||||
} else {
|
||||
Editor.Message.request('asset-db', 'open-asset', prefabUrl);
|
||||
}
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
}
|
||||
|
||||
const base64 = 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAAA1BMVEX///+nxBvIAAAACklEQVQI12MAAgAABAABINItbwAAAABJRU5ErkJggg==';
|
||||
writeFileSync(convertUrlToPath(singleColorUrl), new Buffer(base64, 'base64'));
|
||||
Editor.Message.request('asset-db', 'refresh-asset', singleColorUrl).catch(_ => null);
|
||||
}
|
||||
}
|
||||
});
|
||||
27
extensions/app/engine/src/panel/index.ts
Normal file
27
extensions/app/engine/src/panel/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const Assets = join(__dirname, '../../res/panel');
|
||||
|
||||
import App from './components/app';
|
||||
|
||||
module.exports = Editor.Panel.define({
|
||||
template: readFileSync(join(Assets, 'index.html'), 'utf-8'),
|
||||
style: readFileSync(join(Assets, 'styles/index.css'), 'utf-8'),
|
||||
$: {
|
||||
app: '#app'
|
||||
},
|
||||
listeners: {
|
||||
show() { console.log('show'); },
|
||||
hide() { console.log('hide'); },
|
||||
},
|
||||
methods: {},
|
||||
ready() {
|
||||
if (!this.$.app) return;
|
||||
|
||||
const com = new App();
|
||||
com.$mount(this.$.app);
|
||||
},
|
||||
beforeClose() { },
|
||||
close() { },
|
||||
});
|
||||
85
extensions/app/engine/src/scene.ts
Normal file
85
extensions/app/engine/src/scene.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { join } from 'path';
|
||||
module.paths.push(join(Editor.App.path, 'node_modules'));
|
||||
|
||||
export function load() { }
|
||||
|
||||
export function unload() { }
|
||||
|
||||
// 在其他扩展脚本中,我们可以使用如下代码调用 rotateCamera 函数
|
||||
// const options: ExecuteSceneScriptMethodOptions = {
|
||||
// name: scene.ts 所在的扩展包名, 如: App,
|
||||
// method: scene.ts 中定义的方法, 如: rotateCamera,
|
||||
// args: 参数,可选, 只传递json
|
||||
// };
|
||||
// const result = await Editor.Message.request('scene', 'execute-scene-script', options);
|
||||
export const methods = {
|
||||
async createPrefab(fileName: string, fileUrl: string, is3D = false) {
|
||||
const { Node, js, Layers } = require('cc');
|
||||
|
||||
const node = new Node(fileName);
|
||||
node.layer = is3D ? Layers.Enum.UI_3D : Layers.Enum.UI_2D;
|
||||
|
||||
while (true) {
|
||||
const result = js.getClassByName(fileName);
|
||||
if (result) break;
|
||||
|
||||
await new Promise((next) => {
|
||||
setTimeout(next, 100);
|
||||
});
|
||||
}
|
||||
|
||||
const com = node.addComponent(fileName);
|
||||
com.resetInEditor && com.resetInEditor();
|
||||
|
||||
const info = cce.Prefab.generatePrefabDataFromNode(node) as any;
|
||||
node.destroy();
|
||||
|
||||
return Editor.Message.request('asset-db', 'create-asset', fileUrl, info.prefabData || info);
|
||||
},
|
||||
async createScene(fileName: string, fileUrl: string) {
|
||||
const { SceneAsset, Scene, Node, js, Layers, Camera, DirectionalLight } = require('cc');
|
||||
|
||||
while (true) {
|
||||
const result = js.getClassByName(fileName);
|
||||
if (result) break;
|
||||
|
||||
await new Promise((next) => {
|
||||
setTimeout(next, 100);
|
||||
});
|
||||
}
|
||||
|
||||
const scene = new Scene(fileName);
|
||||
|
||||
// 根节点
|
||||
const node = new Node(fileName);
|
||||
node.layer = Layers.Enum.DEFAULT;
|
||||
node.parent = scene;
|
||||
|
||||
// 相机
|
||||
const camera = new Node('Camera');
|
||||
camera.addComponent(Camera);
|
||||
camera.layer = Layers.Enum.DEFAULT;
|
||||
camera.parent = node;
|
||||
|
||||
// 灯光
|
||||
const light = new Node('Light');
|
||||
light.addComponent(DirectionalLight);
|
||||
light.layer = Layers.Enum.DEFAULT;
|
||||
light.parent = node;
|
||||
|
||||
const com = node.addComponent(fileName);
|
||||
com.resetInEditor && com.resetInEditor();
|
||||
|
||||
const sceneAsset = new SceneAsset();
|
||||
sceneAsset.scene = scene;
|
||||
|
||||
const info = EditorExtends.serialize(sceneAsset);
|
||||
camera.destroy();
|
||||
light.destroy();
|
||||
node.destroy();
|
||||
scene.destroy();
|
||||
sceneAsset.destroy();
|
||||
|
||||
return Editor.Message.request('asset-db', 'create-asset', fileUrl, info);
|
||||
},
|
||||
};
|
||||
4
extensions/app/engine/src/shims-vue.d.ts
vendored
Executable file
4
extensions/app/engine/src/shims-vue.d.ts
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
declare module 'vue/dist/vue' {
|
||||
import Vue from 'vue';
|
||||
export default Vue;
|
||||
}
|
||||
192
extensions/app/engine/src/utils.ts
Normal file
192
extensions/app/engine/src/utils.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { basename, join } from 'path';
|
||||
|
||||
export function getResJson(name: 'builder'): { bundleConfig: object, textureCompressConfig: object } {
|
||||
const Assets = join(__dirname, '../res/json');
|
||||
const str = readFileSync(join(Assets, `${name}.json`), 'utf-8');
|
||||
return str ? JSON.parse(str) : null;
|
||||
}
|
||||
|
||||
export function getResReadme(name: 'resources' | 'app' | 'app-appinit' | 'app-scene' | 'app-builtin' | 'app-bundle' | 'app-view' | 'app-admin' | 'app-controller' | 'app-manager' | 'app-model' | 'app-sound' | 'sound-effect' | 'sound-music' | 'view-expansion' | 'view-native' | 'res-bundle' | 'res-native' | 'view-resources') {
|
||||
const Assets = join(__dirname, '../res/readme');
|
||||
return readFileSync(join(Assets, `${name}.md`), 'utf-8');
|
||||
}
|
||||
|
||||
export function getResMeta(name: 'resources' | 'custom-bundle' | 'app-admin' | 'app-controller' | 'app-manager' | 'app-model' | 'app-sound' | 'view-native' | 'view-resources'): { userData: object } {
|
||||
const Assets = join(__dirname, '../res/meta');
|
||||
const str = readFileSync(join(Assets, `${name}.meta`), 'utf-8');
|
||||
return str ? JSON.parse(str) : null;
|
||||
}
|
||||
|
||||
export function getResPanel(name: string) {
|
||||
const Assets = join(__dirname, '../res/panel');
|
||||
return readFileSync(join(Assets, `components/${name}.html`), 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* 将串式命名转成驼峰命名
|
||||
* @param str 串式字符串
|
||||
* @param lower 首字母是否小写(默认大写)
|
||||
* @returns
|
||||
*/
|
||||
export function stringCase(str: string, lower = false) {
|
||||
str = str.replace(/-/g, '_');
|
||||
const arr = str.split('_');
|
||||
|
||||
return arr.map(function (str, index) {
|
||||
if (index === 0 && lower) {
|
||||
return str.charAt(0).toLowerCase() + str.slice(1);
|
||||
}
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 将驼峰命名转成串式命名
|
||||
* @param str 驼峰字符串
|
||||
* @returns
|
||||
*/
|
||||
export function stringCaseNegate(str: string) {
|
||||
return str.replace(/[A-Z]/g, (searchStr, startIndex) => {
|
||||
if (startIndex === 0) {
|
||||
return searchStr.toLowerCase();
|
||||
} else {
|
||||
return '-' + searchStr.toLowerCase();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* db下的路径转换为真实路径
|
||||
*/
|
||||
export function convertUrlToPath(url: string) {
|
||||
if (url.startsWith('db://assets')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, url.slice(5));
|
||||
} else if (url.startsWith('db://app')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, 'extensions/app/assets', url.slice(8));
|
||||
} else if (url.startsWith('db://pkg')) {
|
||||
url = Editor.Utils.Path.join(Editor.Project.path, 'extensions/pkg/node_modules', url.slice(8));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取程序路径
|
||||
*/
|
||||
export function getProjectPath() {
|
||||
return Editor.Project.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据db下的路径创建目录(不是文件)
|
||||
* 如果已存在不会重复创建
|
||||
*/
|
||||
export async function createFolderByUrl(url: string, opts?: { subPaths?: string[], meta?: { userData: object }, readme?: string, subFolders?: { folder: string, meta?: { userData: object }, readme?: string }[] }) {
|
||||
let pathHead = 'db://assets';
|
||||
|
||||
if (!url && !url.startsWith(pathHead)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 修剪path
|
||||
const pathTail = url.endsWith('/') ? url.slice(pathHead.length + 1, -1).trim() : url.slice(pathHead.length + 1).trim();
|
||||
|
||||
// 每一层的路径
|
||||
const pathArr = pathTail.split('/');
|
||||
|
||||
// 创建主目录
|
||||
for (let index = 0; index < pathArr.length; index++) {
|
||||
pathHead += '/' + pathArr[index];
|
||||
|
||||
if (!existsSync(convertUrlToPath(pathHead))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', pathHead, null).catch(_ => null);
|
||||
if (!result) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主目录meta
|
||||
if (opts?.meta) {
|
||||
await delayFileExistsByUrl(`${url}.meta`);
|
||||
await delay(100);
|
||||
const queryMeta = await Editor.Message.request('asset-db', 'query-asset-meta', url).catch(_ => null);
|
||||
if (!queryMeta) return false;
|
||||
Object.assign(queryMeta.userData, opts.meta.userData);
|
||||
|
||||
const result = await Editor.Message.request('asset-db', 'save-asset-meta', url, JSON.stringify(queryMeta)).catch(_ => null);
|
||||
if (!result) return false;
|
||||
}
|
||||
|
||||
// 主目录readme
|
||||
if (opts?.readme) {
|
||||
writeFileSync(join(convertUrlToPath(url), `.${basename(url)}.md`), opts.readme);
|
||||
}
|
||||
|
||||
// 创建子目录
|
||||
if (opts?.subPaths) {
|
||||
await delay(100);
|
||||
for (let index = 0; index < opts.subPaths.length; index++) {
|
||||
const subPath = `${pathHead}/${opts.subPaths[index]}`;
|
||||
if (!existsSync(convertUrlToPath(subPath))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', subPath, null).catch(_ => null);
|
||||
if (!result) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts?.subFolders) {
|
||||
await delay(100);
|
||||
for (let index = 0; index < opts.subFolders.length; index++) {
|
||||
const subOpts = opts.subFolders[index];
|
||||
const subUrl = `${pathHead}/${subOpts.folder}`;
|
||||
|
||||
// 判断是否存在
|
||||
if (!existsSync(convertUrlToPath(subUrl))) {
|
||||
const result = await Editor.Message.request('asset-db', 'create-asset', subUrl, null).catch(_ => null);
|
||||
if (!result) return false;
|
||||
}
|
||||
|
||||
// meta
|
||||
if (subOpts.meta) {
|
||||
await delayFileExistsByUrl(`${subUrl}.meta`);
|
||||
const queryMeta = await Editor.Message.request('asset-db', 'query-asset-meta', subUrl).catch(_ => null);
|
||||
if (!queryMeta) return false;
|
||||
Object.assign(queryMeta.userData, subOpts.meta.userData);
|
||||
|
||||
const result = await Editor.Message.request('asset-db', 'save-asset-meta', subUrl, JSON.stringify(queryMeta)).catch(_ => null);
|
||||
if (!result) return false;
|
||||
}
|
||||
|
||||
// readme
|
||||
if (subOpts.readme) {
|
||||
writeFileSync(join(convertUrlToPath(subUrl), `.${basename(subUrl)}.md`), subOpts.readme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function delay(time: number) {
|
||||
return new Promise((next) => {
|
||||
setTimeout(() => {
|
||||
next(null);
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待文件存在
|
||||
*/
|
||||
export function delayFileExistsByUrl(url: string) {
|
||||
const path = convertUrlToPath(url);
|
||||
let timer: NodeJS.Timer | null = null;
|
||||
return new Promise((next) => {
|
||||
timer = setInterval(() => {
|
||||
if (existsSync(path)) {
|
||||
if (timer) clearInterval(timer);
|
||||
timer = null;
|
||||
next(null);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
15
extensions/app/engine/tsconfig.json
Executable file
15
extensions/app/engine/tsconfig.json
Executable file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": false,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true
|
||||
}
|
||||
}
|
||||
13
extensions/app/i18n/en.js
Executable file
13
extensions/app/i18n/en.js
Executable file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
module.exports = {
|
||||
description: 'The core of the framework',
|
||||
app: 'App',
|
||||
create: 'Create',
|
||||
refresh: 'Refresh',
|
||||
help: 'Help',
|
||||
tiny: 'TinyPNG',
|
||||
menuCreateView: 'CreateUI',
|
||||
menuCreateManager: 'CreateManager',
|
||||
menuCreateControl: 'CreateControl',
|
||||
menuCreateModel: 'CreateModel',
|
||||
};
|
||||
13
extensions/app/i18n/zh.js
Executable file
13
extensions/app/i18n/zh.js
Executable file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
module.exports = {
|
||||
description: '框架核心',
|
||||
app: 'App',
|
||||
create: '创建',
|
||||
refresh: '刷新',
|
||||
help: '帮助',
|
||||
tiny: '压缩图片',
|
||||
menuCreateView: '创建UI',
|
||||
menuCreateManager: '创建Manager',
|
||||
menuCreateControl: '创建Control',
|
||||
menuCreateModel: '创建Model',
|
||||
};
|
||||
144
extensions/app/package.json
Executable file
144
extensions/app/package.json
Executable file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"package_version": 2,
|
||||
"name": "app",
|
||||
"version": "2.0.0",
|
||||
"author": "向前",
|
||||
"editor": ">=3.8.0",
|
||||
"license": "MIT",
|
||||
"description": "i18n:app.description",
|
||||
"main": "./engine/dist/main.js",
|
||||
"contributions": {
|
||||
"builder": "./engine/dist/builder/index.js",
|
||||
"scene": {
|
||||
"script": "./engine/dist/scene.js"
|
||||
},
|
||||
"asset-db": {
|
||||
"mount": {
|
||||
"path": "./assets",
|
||||
"readonly": true
|
||||
}
|
||||
},
|
||||
"inspector": {
|
||||
"section": {
|
||||
"asset": {
|
||||
"directory": "./engine/dist/inspector/asset-directory.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"open-panel": {
|
||||
"methods": [
|
||||
"open-panel"
|
||||
]
|
||||
},
|
||||
"open-wiki": {
|
||||
"methods": [
|
||||
"open-wiki"
|
||||
]
|
||||
},
|
||||
"open-issues": {
|
||||
"methods": [
|
||||
"open-issues"
|
||||
]
|
||||
},
|
||||
"open-github": {
|
||||
"methods": [
|
||||
"open-github"
|
||||
]
|
||||
},
|
||||
"open-store": {
|
||||
"methods": [
|
||||
"open-store"
|
||||
]
|
||||
},
|
||||
"refresh-executor": {
|
||||
"methods": [
|
||||
"refresh-executor"
|
||||
]
|
||||
},
|
||||
"scene:ready": {
|
||||
"methods": [
|
||||
"scene:ready"
|
||||
]
|
||||
},
|
||||
"asset-db:ready": {
|
||||
"methods": [
|
||||
"asset-db:ready"
|
||||
]
|
||||
},
|
||||
"asset-db:asset-add": {
|
||||
"methods": [
|
||||
"asset-db:asset-add"
|
||||
]
|
||||
},
|
||||
"asset-db:asset-change": {
|
||||
"methods": [
|
||||
"asset-db:asset-change"
|
||||
]
|
||||
},
|
||||
"asset-db:asset-delete": {
|
||||
"methods": [
|
||||
"asset-db:asset-delete"
|
||||
]
|
||||
}
|
||||
},
|
||||
"menu": [
|
||||
{
|
||||
"path": "i18n:app.app",
|
||||
"label": "i18n:app.create",
|
||||
"message": "open-panel"
|
||||
},
|
||||
{
|
||||
"path": "i18n:app.app",
|
||||
"label": "i18n:app.refresh",
|
||||
"message": "refresh-executor"
|
||||
},
|
||||
{
|
||||
"path": "i18n:app.app/i18n:app.help",
|
||||
"label": "文档",
|
||||
"message": "open-wiki"
|
||||
},
|
||||
{
|
||||
"path": "i18n:app.app/i18n:app.help",
|
||||
"label": "反馈",
|
||||
"message": "open-issues"
|
||||
},
|
||||
{
|
||||
"path": "i18n:app.app/i18n:app.help",
|
||||
"label": "商店",
|
||||
"message": "open-store"
|
||||
},
|
||||
{
|
||||
"path": "i18n:app.app/i18n:app.help",
|
||||
"label": "GitHub🌟",
|
||||
"message": "open-github"
|
||||
}
|
||||
],
|
||||
"assets": {
|
||||
"menu": {
|
||||
"methods": "./engine/dist/menu/index.js",
|
||||
"createMenu": "onCreateMenu",
|
||||
"assetMenu": "onAssetMenu",
|
||||
"dbMenu": "onDBMenu",
|
||||
"panelMenu": "onPanelMenu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panels": {
|
||||
"open-panel": {
|
||||
"title": "创建",
|
||||
"type": "dockable",
|
||||
"main": "./engine/dist/panel",
|
||||
"size": {
|
||||
"min-width": 400,
|
||||
"min-height": 300,
|
||||
"width": 600,
|
||||
"height": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run --prefix ./engine build",
|
||||
"watch": "npm run --prefix ./engine watch"
|
||||
}
|
||||
}
|
||||
12
extensions/app/tsconfig.json
Executable file
12
extensions/app/tsconfig.json
Executable file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../temp/tsconfig.cocos.json",
|
||||
"compilerOptions": {
|
||||
"strict": false,
|
||||
"types": [
|
||||
"../../temp/declarations/cc.custom-macro",
|
||||
"../../temp/declarations/jsb",
|
||||
"../../temp/declarations/cc",
|
||||
"../../temp/declarations/cc.env"
|
||||
]
|
||||
}
|
||||
}
|
||||
21
extensions/app/vue/LICENSE
Normal file
21
extensions/app/vue/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-present, Yuxi (Evan) You
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
386
extensions/app/vue/README.md
Normal file
386
extensions/app/vue/README.md
Normal file
@@ -0,0 +1,386 @@
|
||||
<p align="center"><a href="https://vuejs.org" target="_blank" rel="noopener noreferrer"><img width="100" src="https://vuejs.org/images/logo.png" alt="Vue logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/vuejs/vue/tree/dev"><img src="https://img.shields.io/circleci/project/github/vuejs/vue/dev.svg?sanitize=true" alt="Build Status"></a>
|
||||
<a href="https://codecov.io/github/vuejs/vue?branch=dev"><img src="https://img.shields.io/codecov/c/github/vuejs/vue/dev.svg?sanitize=true" alt="Coverage Status"></a>
|
||||
<a href="https://npmcharts.com/compare/vue?minimal=true"><img src="https://img.shields.io/npm/dm/vue.svg?sanitize=true" alt="Downloads"></a>
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/v/vue.svg?sanitize=true" alt="Version"></a>
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/l/vue.svg?sanitize=true" alt="License"></a>
|
||||
<a href="https://chat.vuejs.org/"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true" alt="Chat"></a>
|
||||
<br>
|
||||
<a href="https://app.saucelabs.com/builds/50f8372d79f743a3b25fb6ca4851ca4c"><img src="https://app.saucelabs.com/buildstatus/vuejs" alt="Build Status"></a>
|
||||
</p>
|
||||
|
||||
<h2 align="center">Supporting Vue.js</h2>
|
||||
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
|
||||
- [Become a backer or sponsor on Open Collective](https://opencollective.com/vuejs).
|
||||
- [One-time donation via PayPal or crypto-currencies](https://vuejs.org/support-vuejs/#One-time-Donations).
|
||||
|
||||
#### What's the difference between Patreon and OpenCollective?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
|
||||
<h3 align="center">Special Sponsors</h3>
|
||||
<!--special start-->
|
||||
|
||||
<p align="center">
|
||||
<a href="https://autocode.com/" target="_blank">
|
||||
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--special end-->
|
||||
|
||||
<h3 align="center">Platinum Sponsors</h3>
|
||||
|
||||
<!--platinum start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vehikl.com/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://passionatepeople.io/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.storyblok.com" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://nuxtjs.org/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--platinum end-->
|
||||
|
||||
<!--special-china start-->
|
||||
<h3 align="center">Platinum Sponsors (China)</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
|
||||
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--special-china end-->
|
||||
|
||||
<h3 align="center">Gold Sponsors</h3>
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vuemastery.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://laravel.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://htmlburger.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neds.com.au/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://icons8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.firesticktricks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://intygrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://en.shopware.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpnranks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bestvpn.co/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.y8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://js.devexpress.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://fastcoding.jp/javascript/ " target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foo.software" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://flatlogic.com/templates" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://moovweb.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cosmos.network/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.okayhq.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpsserver.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://aussiecasinohex.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://litslink.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://newicon.net" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://lowdefy.com?k=w432" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://quickbookstoolhub.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://linecorp.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/line_corporation.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://exmax.it/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/exmax.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
<h3 align="center">Sponsors via <a href="https://opencollective.com/vuejs">Open Collective</a></h3>
|
||||
|
||||
<h4 align="center">Platinum</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg?sanitize=true"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg?sanitize=true"></a>
|
||||
|
||||
<h4 align="center">Gold</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/5/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/5/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/6/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/6/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/7/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/7/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/8/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/8/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/9/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/9/avatar.svg?sanitize=true" height="60px"></a><a href="https://opencollective.com/vuejs/tiers/gold-sponsors/10/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/10/avatar.svg?sanitize=true" height="60px"></a>
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Vue (pronounced `/vjuː/`, like view) is a **progressive framework** for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. It consists of an approachable core library that focuses on the view layer only, and an ecosystem of supporting libraries that helps you tackle complexity in large Single-Page Applications.
|
||||
|
||||
#### Browser Compatibility
|
||||
|
||||
Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/compat-table/es5/) (IE8 and below are not supported).
|
||||
|
||||
## Ecosystem
|
||||
|
||||
| Project | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
|
||||
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
|
||||
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
|
||||
| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack |
|
||||
| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support |
|
||||
| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API |
|
||||
| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
|
||||
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
|
||||
|
||||
[vue-router]: https://github.com/vuejs/vue-router
|
||||
[vuex]: https://github.com/vuejs/vuex
|
||||
[vue-cli]: https://github.com/vuejs/vue-cli
|
||||
[vue-loader]: https://github.com/vuejs/vue-loader
|
||||
[vue-server-renderer]: https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer
|
||||
[vue-class-component]: https://github.com/vuejs/vue-class-component
|
||||
[vue-rx]: https://github.com/vuejs/vue-rx
|
||||
[vue-devtools]: https://github.com/vuejs/vue-devtools
|
||||
|
||||
[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
|
||||
[vuex-status]: https://img.shields.io/npm/v/vuex.svg
|
||||
[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.svg
|
||||
[vue-loader-status]: https://img.shields.io/npm/v/vue-loader.svg
|
||||
[vue-server-renderer-status]: https://img.shields.io/npm/v/vue-server-renderer.svg
|
||||
[vue-class-component-status]: https://img.shields.io/npm/v/vue-class-component.svg
|
||||
[vue-rx-status]: https://img.shields.io/npm/v/vue-rx.svg
|
||||
[vue-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg
|
||||
|
||||
[vue-router-package]: https://npmjs.com/package/vue-router
|
||||
[vuex-package]: https://npmjs.com/package/vuex
|
||||
[vue-cli-package]: https://npmjs.com/package/@vue/cli
|
||||
[vue-loader-package]: https://npmjs.com/package/vue-loader
|
||||
[vue-server-renderer-package]: https://npmjs.com/package/vue-server-renderer
|
||||
[vue-class-component-package]: https://npmjs.com/package/vue-class-component
|
||||
[vue-rx-package]: https://npmjs.com/package/vue-rx
|
||||
[vue-devtools-package]: https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd
|
||||
|
||||
## Documentation
|
||||
|
||||
To check out [live examples](https://vuejs.org/v2/examples/) and docs, visit [vuejs.org](https://vuejs.org).
|
||||
|
||||
## Questions
|
||||
|
||||
For questions and support please use [the official forum](https://forum.vuejs.org) or [community chat](https://chat.vuejs.org/). The issue list of this repo is **exclusively** for bug reports and feature requests.
|
||||
|
||||
## Issues
|
||||
|
||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
|
||||
|
||||
## Changelog
|
||||
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/vuejs/vue/releases).
|
||||
|
||||
## Stay In Touch
|
||||
|
||||
- [Twitter](https://twitter.com/vuejs)
|
||||
- [Blog](https://medium.com/the-vue-point)
|
||||
- [Job Board](https://vuejobs.com/?ref=vuejs)
|
||||
|
||||
## Contribution
|
||||
|
||||
Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request. If you have a Vue-related project/component/tool, add it with a pull request to [this curated list](https://github.com/vuejs/awesome-vue)!
|
||||
|
||||
Thank you to all the people who already contributed to Vue!
|
||||
|
||||
<a href="https://github.com/vuejs/vue/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://opensource.org/licenses/MIT)
|
||||
|
||||
Copyright (c) 2013-present, Yuxi (Evan) You
|
||||
12014
extensions/app/vue/dist/vue.js
vendored
Normal file
12014
extensions/app/vue/dist/vue.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
extensions/app/vue/package.json
Normal file
19
extensions/app/vue/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "vue",
|
||||
"version": "2.6.14",
|
||||
"main": "dist/vue.js",
|
||||
"module": "dist/vue.js",
|
||||
"types": "./types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/index.d.ts",
|
||||
"import": "./dist/vue.js",
|
||||
"default": "./dist/vue.js"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"vue"
|
||||
],
|
||||
"author": "Evan You",
|
||||
"license": "MIT"
|
||||
}
|
||||
39
extensions/app/vue/types/index.d.ts
vendored
Normal file
39
extensions/app/vue/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Vue } from "./vue";
|
||||
import "./umd";
|
||||
|
||||
export default Vue;
|
||||
|
||||
export {
|
||||
CreateElement,
|
||||
VueConstructor
|
||||
} from "./vue";
|
||||
|
||||
export {
|
||||
Component,
|
||||
AsyncComponent,
|
||||
ComponentOptions,
|
||||
FunctionalComponentOptions,
|
||||
RenderContext,
|
||||
PropType,
|
||||
PropOptions,
|
||||
ComputedOptions,
|
||||
WatchHandler,
|
||||
WatchOptions,
|
||||
WatchOptionsWithHandler,
|
||||
DirectiveFunction,
|
||||
DirectiveOptions
|
||||
} from "./options";
|
||||
|
||||
export {
|
||||
PluginFunction,
|
||||
PluginObject
|
||||
} from "./plugin";
|
||||
|
||||
export {
|
||||
VNodeChildren,
|
||||
VNodeChildrenArrayContents,
|
||||
VNode,
|
||||
VNodeComponentOptions,
|
||||
VNodeData,
|
||||
VNodeDirective
|
||||
} from "./vnode";
|
||||
207
extensions/app/vue/types/options.d.ts
vendored
Normal file
207
extensions/app/vue/types/options.d.ts
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
import { Vue, CreateElement, CombinedVueInstance } from "./vue";
|
||||
import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from "./vnode";
|
||||
|
||||
type Constructor = {
|
||||
new (...args: any[]): any;
|
||||
}
|
||||
|
||||
// we don't support infer props in async component
|
||||
// N.B. ComponentOptions<V> is contravariant, the default generic should be bottom type
|
||||
export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> =
|
||||
| typeof Vue
|
||||
| FunctionalComponentOptions<Props>
|
||||
| ComponentOptions<never, Data, Methods, Computed, Props>
|
||||
|
||||
type EsModule<T> = T | { default: T }
|
||||
|
||||
type ImportedComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= EsModule<Component<Data, Methods, Computed, Props>>
|
||||
|
||||
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= AsyncComponentPromise<Data, Methods, Computed, Props>
|
||||
| AsyncComponentFactory<Data, Methods, Computed, Props>
|
||||
|
||||
export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
|
||||
resolve: (component: Component<Data, Methods, Computed, Props>) => void,
|
||||
reject: (reason?: any) => void
|
||||
) => Promise<ImportedComponent<Data, Methods, Computed, Props>> | void;
|
||||
|
||||
export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
|
||||
component: Promise<ImportedComponent<Data, Methods, Computed, Props>>;
|
||||
loading?: ImportedComponent;
|
||||
error?: ImportedComponent;
|
||||
delay?: number;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the `Computed` type parameter on `ComponentOptions` is inferred,
|
||||
* it should have a property with the return type of every get-accessor.
|
||||
* Since there isn't a way to query for the return type of a function, we allow TypeScript
|
||||
* to infer from the shape of `Accessors<Computed>` and work backwards.
|
||||
*/
|
||||
export type Accessors<T> = {
|
||||
[K in keyof T]: (() => T[K]) | ComputedOptions<T[K]>
|
||||
}
|
||||
|
||||
type DataDef<Data, Props, V> = Data | ((this: Readonly<Props> & V) => Data)
|
||||
/**
|
||||
* This type should be used when an array of strings is used for a component's `props` value.
|
||||
*/
|
||||
export type ThisTypedComponentOptionsWithArrayProps<V extends Vue, Data, Methods, Computed, PropNames extends string> =
|
||||
object &
|
||||
ComponentOptions<V, DataDef<Data, Record<PropNames, any>, V>, Methods, Computed, PropNames[], Record<PropNames, any>> &
|
||||
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Record<PropNames, any>>>>;
|
||||
|
||||
/**
|
||||
* This type should be used when an object mapped to `PropOptions` is used for a component's `props` value.
|
||||
*/
|
||||
export type ThisTypedComponentOptionsWithRecordProps<V extends Vue, Data, Methods, Computed, Props> =
|
||||
object &
|
||||
ComponentOptions<V, DataDef<Data, Props, V>, Methods, Computed, RecordPropsDefinition<Props>, Props> &
|
||||
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Props>>>;
|
||||
|
||||
type DefaultData<V> = object | ((this: V) => object);
|
||||
type DefaultProps = Record<string, any>;
|
||||
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any };
|
||||
type DefaultComputed = { [key: string]: any };
|
||||
export interface ComponentOptions<
|
||||
V extends Vue,
|
||||
Data=DefaultData<V>,
|
||||
Methods=DefaultMethods<V>,
|
||||
Computed=DefaultComputed,
|
||||
PropsDef=PropsDefinition<DefaultProps>,
|
||||
Props=DefaultProps> {
|
||||
data?: Data;
|
||||
props?: PropsDef;
|
||||
propsData?: object;
|
||||
computed?: Accessors<Computed>;
|
||||
methods?: Methods;
|
||||
watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any>>;
|
||||
|
||||
el?: Element | string;
|
||||
template?: string;
|
||||
// hack is for functional component type inference, should not be used in user code
|
||||
render?(createElement: CreateElement, hack: RenderContext<Props>): VNode;
|
||||
renderError?(createElement: CreateElement, err: Error): VNode;
|
||||
staticRenderFns?: ((createElement: CreateElement) => VNode)[];
|
||||
|
||||
beforeCreate?(this: V): void;
|
||||
created?(): void;
|
||||
beforeDestroy?(): void;
|
||||
destroyed?(): void;
|
||||
beforeMount?(): void;
|
||||
mounted?(): void;
|
||||
beforeUpdate?(): void;
|
||||
updated?(): void;
|
||||
activated?(): void;
|
||||
deactivated?(): void;
|
||||
errorCaptured?(err: Error, vm: Vue, info: string): boolean | void;
|
||||
serverPrefetch?(this: V): Promise<void>;
|
||||
|
||||
directives?: { [key: string]: DirectiveFunction | DirectiveOptions };
|
||||
components?: { [key: string]: Component<any, any, any, any> | AsyncComponent<any, any, any, any> };
|
||||
transitions?: { [key: string]: object };
|
||||
filters?: { [key: string]: Function };
|
||||
|
||||
provide?: object | (() => object);
|
||||
inject?: InjectOptions;
|
||||
|
||||
model?: {
|
||||
prop?: string;
|
||||
event?: string;
|
||||
};
|
||||
|
||||
parent?: Vue;
|
||||
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
|
||||
name?: string;
|
||||
// TODO: support properly inferred 'extends'
|
||||
extends?: ComponentOptions<Vue> | typeof Vue;
|
||||
delimiters?: [string, string];
|
||||
comments?: boolean;
|
||||
inheritAttrs?: boolean;
|
||||
}
|
||||
|
||||
export interface FunctionalComponentOptions<Props = DefaultProps, PropDefs = PropsDefinition<Props>> {
|
||||
name?: string;
|
||||
props?: PropDefs;
|
||||
model?: {
|
||||
prop?: string;
|
||||
event?: string;
|
||||
};
|
||||
inject?: InjectOptions;
|
||||
functional: boolean;
|
||||
render?(this: undefined, createElement: CreateElement, context: RenderContext<Props>): VNode | VNode[];
|
||||
}
|
||||
|
||||
export interface RenderContext<Props=DefaultProps> {
|
||||
props: Props;
|
||||
children: VNode[];
|
||||
slots(): any;
|
||||
data: VNodeData;
|
||||
parent: Vue;
|
||||
listeners: { [key: string]: Function | Function[] };
|
||||
scopedSlots: { [key: string]: NormalizedScopedSlot };
|
||||
injections: any
|
||||
}
|
||||
|
||||
export type Prop<T> = { (): T } | { new(...args: never[]): T & object } | { new(...args: string[]): Function }
|
||||
|
||||
export type PropType<T> = Prop<T> | Prop<T>[];
|
||||
|
||||
export type PropValidator<T> = PropOptions<T> | PropType<T>;
|
||||
|
||||
export interface PropOptions<T=any> {
|
||||
type?: PropType<T>;
|
||||
required?: boolean;
|
||||
default?: T | null | undefined | (() => T | null | undefined);
|
||||
validator?(value: T): boolean;
|
||||
}
|
||||
|
||||
export type RecordPropsDefinition<T> = {
|
||||
[K in keyof T]: PropValidator<T[K]>
|
||||
}
|
||||
export type ArrayPropsDefinition<T> = (keyof T)[];
|
||||
export type PropsDefinition<T> = ArrayPropsDefinition<T> | RecordPropsDefinition<T>;
|
||||
|
||||
export interface ComputedOptions<T> {
|
||||
get?(): T;
|
||||
set?(value: T): void;
|
||||
cache?: boolean;
|
||||
}
|
||||
|
||||
export type WatchHandler<T> = string | ((val: T, oldVal: T) => void);
|
||||
|
||||
export interface WatchOptions {
|
||||
deep?: boolean;
|
||||
immediate?: boolean;
|
||||
}
|
||||
|
||||
export interface WatchOptionsWithHandler<T> extends WatchOptions {
|
||||
handler: WatchHandler<T>;
|
||||
}
|
||||
|
||||
export interface DirectiveBinding extends Readonly<VNodeDirective> {
|
||||
readonly modifiers: { [key: string]: boolean };
|
||||
}
|
||||
|
||||
export type DirectiveFunction = (
|
||||
el: HTMLElement,
|
||||
binding: DirectiveBinding,
|
||||
vnode: VNode,
|
||||
oldVnode: VNode
|
||||
) => void;
|
||||
|
||||
export interface DirectiveOptions {
|
||||
bind?: DirectiveFunction;
|
||||
inserted?: DirectiveFunction;
|
||||
update?: DirectiveFunction;
|
||||
componentUpdated?: DirectiveFunction;
|
||||
unbind?: DirectiveFunction;
|
||||
}
|
||||
|
||||
export type InjectKey = string | symbol;
|
||||
|
||||
export type InjectOptions = {
|
||||
[key: string]: InjectKey | { from?: InjectKey, default?: any }
|
||||
} | string[];
|
||||
8
extensions/app/vue/types/plugin.d.ts
vendored
Normal file
8
extensions/app/vue/types/plugin.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Vue as _Vue } from "./vue";
|
||||
|
||||
export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
|
||||
|
||||
export interface PluginObject<T> {
|
||||
install: PluginFunction<T>;
|
||||
[key: string]: any;
|
||||
}
|
||||
48
extensions/app/vue/types/umd.d.ts
vendored
Normal file
48
extensions/app/vue/types/umd.d.ts
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import * as V from "./index";
|
||||
import {
|
||||
DefaultData,
|
||||
DefaultProps,
|
||||
DefaultMethods,
|
||||
DefaultComputed,
|
||||
PropsDefinition
|
||||
} from "./options";
|
||||
|
||||
// Expose some types for backward compatibility...
|
||||
declare namespace Vue {
|
||||
// vue.d.ts
|
||||
export type CreateElement = V.CreateElement;
|
||||
export type VueConstructor<V extends Vue = Vue> = V.VueConstructor<V>;
|
||||
|
||||
// options.d.ts
|
||||
export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = V.Component<Data, Methods, Computed, Props>;
|
||||
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = V.AsyncComponent<Data, Methods, Computed, Props>;
|
||||
export type ComponentOptions<V extends Vue, Data=DefaultData<V>, Methods=DefaultMethods<V>, Computed=DefaultComputed, PropsDef=PropsDefinition<DefaultProps>, Props=DefaultProps> = V.ComponentOptions<V, Data, Methods, Computed, PropsDef, Props>;
|
||||
export type FunctionalComponentOptions<Props = DefaultProps, PropDefs = PropsDefinition<Props>> = V.FunctionalComponentOptions<Props, PropDefs>;
|
||||
export type RenderContext<Props=DefaultProps> = V.RenderContext<Props>;
|
||||
export type PropType<T> = V.PropType<T>;
|
||||
export type PropOptions<T=any> = V.PropOptions<T>;
|
||||
export type ComputedOptions<T> = V.ComputedOptions<T>;
|
||||
export type WatchHandler<T> = V.WatchHandler<T>;
|
||||
export type WatchOptions = V.WatchOptions;
|
||||
export type WatchOptionsWithHandler<T> = V.WatchOptionsWithHandler<T>;
|
||||
export type DirectiveFunction = V.DirectiveFunction;
|
||||
export type DirectiveOptions = V.DirectiveOptions;
|
||||
|
||||
// plugin.d.ts
|
||||
export type PluginFunction<T> = V.PluginFunction<T>;
|
||||
export type PluginObject<T> = V.PluginObject<T>;
|
||||
|
||||
// vnode.d.ts
|
||||
export type VNodeChildren = V.VNodeChildren;
|
||||
export type VNodeChildrenArrayContents = V.VNodeChildrenArrayContents;
|
||||
export type VNode = V.VNode;
|
||||
export type VNodeComponentOptions = V.VNodeComponentOptions;
|
||||
export type VNodeData = V.VNodeData;
|
||||
export type VNodeDirective = V.VNodeDirective;
|
||||
}
|
||||
|
||||
declare class Vue extends V.default {}
|
||||
|
||||
export = Vue;
|
||||
|
||||
export as namespace Vue;
|
||||
76
extensions/app/vue/types/vnode.d.ts
vendored
Normal file
76
extensions/app/vue/types/vnode.d.ts
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Vue } from "./vue";
|
||||
|
||||
export type ScopedSlot = (props: any) => ScopedSlotReturnValue;
|
||||
type ScopedSlotReturnValue = VNode | string | boolean | null | undefined | ScopedSlotReturnArray;
|
||||
interface ScopedSlotReturnArray extends Array<ScopedSlotReturnValue> {}
|
||||
|
||||
// Scoped slots are guaranteed to return Array of VNodes starting in 2.6
|
||||
export type NormalizedScopedSlot = (props: any) => ScopedSlotChildren;
|
||||
export type ScopedSlotChildren = VNode[] | undefined;
|
||||
|
||||
// Relaxed type compatible with $createElement
|
||||
export type VNodeChildren = VNodeChildrenArrayContents | [ScopedSlot] | string | boolean | null | undefined;
|
||||
export interface VNodeChildrenArrayContents extends Array<VNodeChildren | VNode> {}
|
||||
|
||||
export interface VNode {
|
||||
tag?: string;
|
||||
data?: VNodeData;
|
||||
children?: VNode[];
|
||||
text?: string;
|
||||
elm?: Node;
|
||||
ns?: string;
|
||||
context?: Vue;
|
||||
key?: string | number | symbol | boolean;
|
||||
componentOptions?: VNodeComponentOptions;
|
||||
componentInstance?: Vue;
|
||||
parent?: VNode;
|
||||
raw?: boolean;
|
||||
isStatic?: boolean;
|
||||
isRootInsert: boolean;
|
||||
isComment: boolean;
|
||||
}
|
||||
|
||||
export interface VNodeComponentOptions {
|
||||
Ctor: typeof Vue;
|
||||
propsData?: object;
|
||||
listeners?: object;
|
||||
children?: VNode[];
|
||||
tag?: string;
|
||||
}
|
||||
|
||||
export interface VNodeData {
|
||||
key?: string | number;
|
||||
slot?: string;
|
||||
scopedSlots?: { [key: string]: ScopedSlot | undefined };
|
||||
ref?: string;
|
||||
refInFor?: boolean;
|
||||
tag?: string;
|
||||
staticClass?: string;
|
||||
class?: any;
|
||||
staticStyle?: { [key: string]: any };
|
||||
style?: string | object[] | object;
|
||||
props?: { [key: string]: any };
|
||||
attrs?: { [key: string]: any };
|
||||
domProps?: { [key: string]: any };
|
||||
hook?: { [key: string]: Function };
|
||||
on?: { [key: string]: Function | Function[] };
|
||||
nativeOn?: { [key: string]: Function | Function[] };
|
||||
transition?: object;
|
||||
show?: boolean;
|
||||
inlineTemplate?: {
|
||||
render: Function;
|
||||
staticRenderFns: Function[];
|
||||
};
|
||||
directives?: VNodeDirective[];
|
||||
keepAlive?: boolean;
|
||||
}
|
||||
|
||||
export interface VNodeDirective {
|
||||
name: string;
|
||||
value?: any;
|
||||
oldValue?: any;
|
||||
expression?: string;
|
||||
arg?: string;
|
||||
oldArg?: string;
|
||||
modifiers?: { [key: string]: boolean };
|
||||
}
|
||||
132
extensions/app/vue/types/vue.d.ts
vendored
Normal file
132
extensions/app/vue/types/vue.d.ts
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
Component,
|
||||
AsyncComponent,
|
||||
ComponentOptions,
|
||||
FunctionalComponentOptions,
|
||||
WatchOptionsWithHandler,
|
||||
WatchHandler,
|
||||
DirectiveOptions,
|
||||
DirectiveFunction,
|
||||
RecordPropsDefinition,
|
||||
ThisTypedComponentOptionsWithArrayProps,
|
||||
ThisTypedComponentOptionsWithRecordProps,
|
||||
WatchOptions,
|
||||
} from "./options";
|
||||
import { VNode, VNodeData, VNodeChildren, NormalizedScopedSlot } from "./vnode";
|
||||
import { PluginFunction, PluginObject } from "./plugin";
|
||||
|
||||
export interface CreateElement {
|
||||
(tag?: string | Component<any, any, any, any> | AsyncComponent<any, any, any, any> | (() => Component), children?: VNodeChildren): VNode;
|
||||
(tag?: string | Component<any, any, any, any> | AsyncComponent<any, any, any, any> | (() => Component), data?: VNodeData, children?: VNodeChildren): VNode;
|
||||
}
|
||||
|
||||
export interface Vue {
|
||||
readonly $el: Element;
|
||||
readonly $options: ComponentOptions<Vue>;
|
||||
readonly $parent: Vue;
|
||||
readonly $root: Vue;
|
||||
readonly $children: Vue[];
|
||||
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined };
|
||||
readonly $slots: { [key: string]: VNode[] | undefined };
|
||||
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
|
||||
readonly $isServer: boolean;
|
||||
readonly $data: Record<string, any>;
|
||||
readonly $props: Record<string, any>;
|
||||
readonly $ssrContext: any;
|
||||
readonly $vnode: VNode;
|
||||
readonly $attrs: Record<string, string>;
|
||||
readonly $listeners: Record<string, Function | Function[]>;
|
||||
|
||||
$mount(elementOrSelector?: Element | string, hydrating?: boolean): this;
|
||||
$forceUpdate(): void;
|
||||
$destroy(): void;
|
||||
$set: typeof Vue.set;
|
||||
$delete: typeof Vue.delete;
|
||||
$watch(
|
||||
expOrFn: string,
|
||||
callback: (this: this, n: any, o: any) => void,
|
||||
options?: WatchOptions
|
||||
): (() => void);
|
||||
$watch<T>(
|
||||
expOrFn: (this: this) => T,
|
||||
callback: (this: this, n: T, o: T) => void,
|
||||
options?: WatchOptions
|
||||
): (() => void);
|
||||
$on(event: string | string[], callback: Function): this;
|
||||
$once(event: string | string[], callback: Function): this;
|
||||
$off(event?: string | string[], callback?: Function): this;
|
||||
$emit(event: string, ...args: any[]): this;
|
||||
$nextTick(callback: (this: this) => void): void;
|
||||
$nextTick(): Promise<void>;
|
||||
$createElement: CreateElement;
|
||||
}
|
||||
|
||||
export type CombinedVueInstance<Instance extends Vue, Data, Methods, Computed, Props> = Data & Methods & Computed & Props & Instance;
|
||||
export type ExtendedVue<Instance extends Vue, Data, Methods, Computed, Props> = VueConstructor<CombinedVueInstance<Instance, Data, Methods, Computed, Props> & Vue>;
|
||||
|
||||
export interface VueConfiguration {
|
||||
silent: boolean;
|
||||
optionMergeStrategies: any;
|
||||
devtools: boolean;
|
||||
productionTip: boolean;
|
||||
performance: boolean;
|
||||
errorHandler(err: Error, vm: Vue, info: string): void;
|
||||
warnHandler(msg: string, vm: Vue, trace: string): void;
|
||||
ignoredElements: (string | RegExp)[];
|
||||
keyCodes: { [key: string]: number | number[] };
|
||||
async: boolean;
|
||||
}
|
||||
|
||||
export interface VueConstructor<V extends Vue = Vue> {
|
||||
new <Data = object, Methods = object, Computed = object, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): CombinedVueInstance<V, Data, Methods, Computed, Record<PropNames, any>>;
|
||||
// ideally, the return type should just contain Props, not Record<keyof Props, any>. But TS requires to have Base constructors with the same return type.
|
||||
new <Data = object, Methods = object, Computed = object, Props = object>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Record<keyof Props, any>>;
|
||||
new (options?: ComponentOptions<V>): CombinedVueInstance<V, object, object, object, Record<keyof object, any>>;
|
||||
|
||||
extend<Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;
|
||||
extend<Data, Methods, Computed, Props>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;
|
||||
extend<PropNames extends string = never>(definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
|
||||
extend<Props>(definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>;
|
||||
extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>;
|
||||
|
||||
nextTick<T>(callback: (this: T) => void, context?: T): void;
|
||||
nextTick(): Promise<void>
|
||||
set<T>(object: object, key: string | number, value: T): T;
|
||||
set<T>(array: T[], key: number, value: T): T;
|
||||
delete(object: object, key: string | number): void;
|
||||
delete<T>(array: T[], key: number): void;
|
||||
|
||||
directive(
|
||||
id: string,
|
||||
definition?: DirectiveOptions | DirectiveFunction
|
||||
): DirectiveOptions;
|
||||
filter(id: string, definition?: Function): Function;
|
||||
|
||||
component(id: string): VueConstructor;
|
||||
component<VC extends VueConstructor>(id: string, constructor: VC): VC;
|
||||
component<Data, Methods, Computed, Props>(id: string, definition: AsyncComponent<Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;
|
||||
component<Data, Methods, Computed, PropNames extends string = never>(id: string, definition?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;
|
||||
component<Data, Methods, Computed, Props>(id: string, definition?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;
|
||||
component<PropNames extends string>(id: string, definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
|
||||
component<Props>(id: string, definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>;
|
||||
component(id: string, definition?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>;
|
||||
|
||||
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): VueConstructor<V>;
|
||||
use(plugin: PluginObject<any> | PluginFunction<any>, ...options: any[]): VueConstructor<V>;
|
||||
mixin(mixin: VueConstructor | ComponentOptions<Vue>): VueConstructor<V>;
|
||||
compile(template: string): {
|
||||
render(createElement: typeof Vue.prototype.$createElement): VNode;
|
||||
staticRenderFns: (() => VNode)[];
|
||||
};
|
||||
|
||||
observable<T>(obj: T): T;
|
||||
|
||||
util: {
|
||||
warn(msg: string, vm?: InstanceType<VueConstructor>): void;
|
||||
};
|
||||
|
||||
config: VueConfiguration;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export const Vue: VueConstructor;
|
||||
6
extensions/pkg/README.md
Normal file
6
extensions/pkg/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 注意
|
||||
通用模块开发完毕后,在发布之前一定要打开CocosCreator生成meta文件(否则如果有依赖关系编辑器无法正确识别)。
|
||||
|
||||
# 添加和移除
|
||||
* 添加: 执行 npm run add xxx
|
||||
* 移除: 执行 npm run emove xxx
|
||||
152
extensions/pkg/index.js
Normal file
152
extensions/pkg/index.js
Normal file
@@ -0,0 +1,152 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const spawn = require('child_process').spawn;
|
||||
|
||||
/**
|
||||
* 执行cmd指令
|
||||
* @param {string} cmd
|
||||
* @param {string[]} args
|
||||
* @param {SpawnOptionsWithoutStdio} options
|
||||
* @returns
|
||||
*/
|
||||
async function executeCmd(cmd, args/**,options */) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let result = spawn(cmd, args, { shell: true });
|
||||
result.on('close', function (code) {
|
||||
resolve(code);
|
||||
});
|
||||
result.stdout.on('data', function (data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
result.stderr.on('error', function (data) {
|
||||
reject(data.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件夹
|
||||
* @param {string} dir
|
||||
* @returns
|
||||
*/
|
||||
function deleteDirectory(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
|
||||
fs.readdirSync(dir).forEach((file) => {
|
||||
const fileDir = path.join(dir, file);
|
||||
if (fs.statSync(fileDir).isDirectory()) {
|
||||
deleteDirectory(fileDir); //递归删除文件夹
|
||||
} else {
|
||||
fs.unlinkSync(fileDir); //删除文件
|
||||
}
|
||||
});
|
||||
|
||||
fs.rmdirSync(dir);
|
||||
}
|
||||
|
||||
function getPackageName(fullName) {
|
||||
// 匹配包名(可能包含 @scope/)和版本号
|
||||
const match = fullName.match(/^(@[^/]+\/[^@]+|@[^@]+\/[^@]+|[^@]+)/);
|
||||
return match ? match[0] : fullName;
|
||||
}
|
||||
|
||||
const assetsDir = path.join(__dirname, 'node_modules');
|
||||
const packageDir = path.join(__dirname, 'package');
|
||||
|
||||
const exportDirName = 'pkg-export';
|
||||
const exportDir = path.join(__dirname, '../../assets', exportDirName);
|
||||
|
||||
async function main() {
|
||||
// 移除旧目录
|
||||
if (fs.existsSync(packageDir)) {
|
||||
if (fs.existsSync(path.join(packageDir, 'package.json'))) {
|
||||
const _json = fs.readFileSync(path.join(packageDir, 'package.json'), 'utf-8');
|
||||
const _data = JSON.parse(_json);
|
||||
|
||||
const json = fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8');
|
||||
const data = JSON.parse(json);
|
||||
data.dependencies = _data.dependencies;
|
||||
fs.writeFileSync(path.join(__dirname, 'package.json'), JSON.stringify(data, null, '\t'), 'utf-8');
|
||||
}
|
||||
deleteDirectory(packageDir);
|
||||
console.log('\n> 移除旧目录: extensions/pkg/package');
|
||||
}
|
||||
|
||||
// npm指令
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
|
||||
const cmdIndex = process.argv.findIndex(item => item === 'update' || item === 'add' || item === 'remove');
|
||||
const cmd = process.argv[cmdIndex];
|
||||
|
||||
const prefix = '--prefix=' + __dirname;
|
||||
const registry = process.argv.find(item => item.indexOf('--registry=') !== -1) || '--registry=https://registry.npmmirror.com';
|
||||
|
||||
if (cmd === 'update') {
|
||||
const args = [prefix, registry, 'update'];
|
||||
const code = await executeCmd(npm, args);
|
||||
if (code !== 0)
|
||||
throw new Error(`错误码: ${code}`);
|
||||
else
|
||||
console.log('\n✅: 已更新安装包');
|
||||
} else if (cmd === 'add') {
|
||||
const pkgInput = process.argv[cmdIndex + 1];
|
||||
const pkgName = getPackageName(pkgInput);
|
||||
if (!pkgName)
|
||||
throw new Error('输入要安装的包名字');
|
||||
const args = [prefix, registry, 'install', pkgInput];
|
||||
const code = await executeCmd(npm, args);
|
||||
if (code !== 0) {
|
||||
throw new Error(`错误码: ${code}`);
|
||||
} else {
|
||||
// 如果不存在文件夹则创建
|
||||
if (!fs.existsSync(assetsDir)) {
|
||||
fs.mkdirSync(assetsDir);
|
||||
}
|
||||
if (!fs.existsSync(exportDir)) {
|
||||
fs.mkdirSync(exportDir);
|
||||
}
|
||||
// 更新提示描述
|
||||
fs.writeFileSync(path.join(exportDir, '.' + exportDirName + '.md'), '用于辅助触发扩展包的自动import', 'utf-8');
|
||||
// 创建提示文件
|
||||
if (!fs.existsSync(path.join(exportDir, pkgName + '.ts'))) {
|
||||
if (pkgName.indexOf('/') !== -1) {
|
||||
const dir = path.join(exportDir, pkgName.split('/')[0]);
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
fs.writeFileSync(path.join(exportDir, pkgName + '.ts'), `export * from 'db://pkg/${pkgName}';`, 'utf-8');
|
||||
}
|
||||
console.log(`\n✅: 已成功安装包 ${pkgName}`);
|
||||
}
|
||||
} else if (cmd === 'remove') {
|
||||
const pkgInput = process.argv[cmdIndex + 1];
|
||||
const pkgName = getPackageName(pkgInput);
|
||||
if (!pkgName)
|
||||
throw new Error('输入要卸载的包名字');
|
||||
const args = [prefix, registry, 'uninstall', pkgName];
|
||||
const code = await executeCmd(npm, args);
|
||||
if (code !== 0) {
|
||||
throw new Error(`错误码: ${code}`);
|
||||
} else {
|
||||
// 如果未删除成功 则 强制删除
|
||||
if (fs.existsSync(path.join(assetsDir, pkgName))) {
|
||||
deleteDirectory(path.join(assetsDir, pkgName));
|
||||
}
|
||||
if (fs.existsSync(path.join(assetsDir, pkgName + '.meta'))) {
|
||||
fs.unlinkSync(path.join(assetsDir, pkgName + '.meta'));
|
||||
}
|
||||
if (fs.existsSync(path.join(exportDir, pkgName + '.ts'))) {
|
||||
fs.unlinkSync(path.join(exportDir, pkgName + '.ts'));
|
||||
}
|
||||
if (fs.existsSync(path.join(exportDir, pkgName + '.ts.meta'))) {
|
||||
fs.unlinkSync(path.join(exportDir, pkgName + '.ts.meta'));
|
||||
}
|
||||
console.log(`\n✅: 已卸载安装包 ${pkgName}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error('请输入正确的指令');
|
||||
}
|
||||
|
||||
console.log('\n🔥: 如果编辑器报错,请点击资源管理器右上角的刷新按钮\n🔥: 如果运行时代码没更新,请点击编辑器菜单「开发者->缓存->清除代码缓存」');
|
||||
}
|
||||
main();
|
||||
22
extensions/pkg/package.json
Executable file
22
extensions/pkg/package.json
Executable file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"package_version": 2,
|
||||
"name": "pkg",
|
||||
"version": "1.0.0",
|
||||
"author": "向前",
|
||||
"license": "MIT",
|
||||
"editor": ">=3.6.0",
|
||||
"description": "用于存放扩展包",
|
||||
"contributions": {
|
||||
"asset-db": {
|
||||
"mount": {
|
||||
"path": "./node_modules",
|
||||
"readonly": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"add": "node ./index.js add",
|
||||
"remove": "node ./index.js remove",
|
||||
"update": "node ./index.js update"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user