添加项目规则;修复几处潜在问题

This commit is contained in:
gongxh
2025-11-27 10:54:14 +08:00
parent 5c800cceeb
commit 4e2726dd1b
23 changed files with 3081 additions and 68 deletions

View File

@@ -1,55 +0,0 @@
# Claude Code ignore rules for kunpolibrary
# 昆坡库项目过滤规则,减少上下文消耗
# Demo and example files - 示例和演示文件
demo/
**/demo/
# Dependencies - 依赖包
node_modules/
**/node_modules/
# Generated/build output - 构建产物
dist/
**/dist/
# Type definitions - 类型定义文件
libs/
**/libs/
# Images and assets - 图片和静态资源
image/
**/image/
*.jpg
*.jpeg
*.png
*.gif
*.ico
# Other common build artifacts - 其他常见构建产物
build/
**/build/
temp/
**/temp/
.temp/
**/.temp/
# Cache directories - 缓存目录
.cache/
**/.cache/
# Log files - 日志文件
*.log
logs/
**/logs/
# IDE and editor files - IDE和编辑器文件
.vscode/
.idea/
*.swp
*.swo
*~
# OS generated files - 操作系统生成的文件
.DS_Store
Thumbs.db

133
.cursor/rules/README.md Normal file
View File

@@ -0,0 +1,133 @@
# KunpoCC Cursor Rules
这个目录包含了 KunpoCC 项目的 Cursor AI 编程助手规则文件。这些规则帮助 Cursor 更好地理解项目架构和编码规范,提供更准确的代码建议和自动完成。
## 规则文件结构
### 📋 [project-overview.mdc](./project-overview.mdc)
**总体项目规范** - 始终应用
- 项目架构和目录结构
- 开发流程和质量保证
- 版本管理和部署规范
- 适用范围:所有文件
### 🔧 [typescript-general.mdc](./typescript-general.mdc)
**TypeScript 通用规范** - 始终应用
- 命名约定和代码风格
- 类型定义和泛型使用
- JSDoc 注释规范
- 错误处理模式
- 适用范围:`src/**/*.ts`
### 🎮 [cocos-creator.mdc](./cocos-creator.mdc)
**Cocos Creator 开发规范**
- Component 基类设计模式
- 生命周期管理
- 平台适配和节点管理
- 适配器模式应用
- 适用范围:`src/cocos/**/*.ts`, `src/global/**/*.ts`
### 🖼️ [fairygui.mdc](./fairygui.mdc)
**FairyGUI UI 系统规范**
- 窗口基类和生命周期
- 窗口管理器模式
- 装饰器系统使用
- 资源管理和屏幕适配
- 适用范围:`src/fgui/**/*.ts`, `src/ui/**/*.ts`
### 🎨 [decorator-patterns.mdc](./decorator-patterns.mdc)
**装饰器模式规范**
- namespace 封装模式
- 类装饰器和属性装饰器
- 方法装饰器和元数据管理
- 动态注册支持
- 适用范围:`**/*Decorator*.ts`, `**/*decorator*.ts`
### 📊 [data-binding.mdc](./data-binding.mdc)
**数据绑定系统规范**
- DataBase 基类设计
- 强类型绑定装饰器
- 绑定管理器和批量更新
- 路径解析和类型安全
- 适用范围:`src/data/**/*.ts`, `**/*Data*.ts`
### 🐛 [logging-debugging.mdc](./logging-debugging.mdc)
**日志系统和调试规范** - 始终应用
- 统一日志接口和级别
- 调试模式管理
- 全局调试工具
- 性能监控日志
- 适用范围:`src/tool/log.ts`, `**/*.ts`
### 🏗️ [architecture-patterns.mdc](./architecture-patterns.mdc)
**架构模式规范**
- 单例管理器模式
- 抽象基类设计
- 接口和契约定义
- 工厂模式和适配器模式
- 适用范围:`src/**/*.ts`
### 📱 [minigame-platform.mdc](./minigame-platform.mdc)
**小游戏平台规范**
- 平台检测和分类
- 平台适配器设计
- 统一接口封装
- 平台特定功能实现
- 适用范围:`src/minigame/**/*.ts`, `src/global/Platform.ts`
### 🔄 [hot-update.mdc](./hot-update.mdc)
**热更新系统规范**
- 管理器单例模式
- Promise 结果模式
- manifest 管理
- 进度监控和错误处理
- 适用范围:`src/hotupdate/**/*.ts`
## 规则应用方式
### 自动应用的规则
以下规则会自动应用到相关文件:
- `project-overview.mdc` - 所有文件
- `typescript-general.mdc` - 所有 TypeScript 文件
- `logging-debugging.mdc` - 所有文件
### 条件应用的规则
其他规则通过文件路径模式匹配自动应用到相关文件。
### 手动引用规则
你也可以在与 Cursor 的对话中手动引用特定的规则文件:
```
请参考 FairyGUI 规范来实现这个窗口类
请按照数据绑定规范来设计这个数据类
```
## 使用建议
### 开发新功能时
1. 先查看 `project-overview.mdc` 了解整体架构
2. 根据功能类型查看相应的专门规范
3. 遵循 `typescript-general.mdc` 的基本编码规范
### 重构代码时
1. 参考 `architecture-patterns.mdc` 的设计模式
2. 检查是否符合相关模块的特定规范
3. 确保日志和错误处理符合规范
### 添加新平台支持时
1. 参考 `minigame-platform.mdc` 的适配模式
2. 遵循统一接口设计原则
3. 添加相应的平台检测和错误处理
## 规则维护
### 更新规则
- 当项目架构发生重大变更时,及时更新相关规则
- 新增功能模块时,考虑是否需要新的规则文件
- 定期检查规则的准确性和完整性
### 规则版本控制
- 规则文件纳入版本控制
- 重大规则变更记录在项目 CHANGELOG 中
- 确保团队成员了解规则更新
这些规则文件帮助确保代码质量和一致性,同时让 Cursor AI 能够更好地理解项目上下文,提供更准确的编程辅助。

View File

@@ -0,0 +1,383 @@
---
description: "架构模式和设计原则规范"
globs: ["src/**/*.ts"]
alwaysApply: false
type: "architecture"
---
# 架构模式和设计原则
## 单例管理器模式
### 管理器类设计规范
```typescript
export class WindowManager {
/** 使用私有静态属性存储状态 */
private static _groups: Map<string, WindowGroup> = new Map();
private static _windows: Map<string, IWindow> = new Map();
private static _resPool: WindowResPool;
/** 禁用构造函数 */
private constructor() {}
/** 提供静态方法访问功能 */
public static showWindow(windowName: string): Promise<void> {
// 实现逻辑
}
/** 内部方法使用下划线前缀和 @internal 注释 */
/**
* 添加窗口 (框架内部使用)
* @internal
*/
public static _addWindow(name: string, window: IWindow): void {
this._windows.set(name, window);
}
}
```
### 管理器初始化模式
```typescript
export class SomeManager {
private static _initialized: boolean = false;
/**
* 初始化管理器 (框架内部调用)
* @internal
*/
public static _init(dependencies: Dependencies): void {
if (this._initialized) {
warn("管理器已经初始化");
return;
}
this._initialized = true;
// 初始化逻辑
}
private static ensureInitialized(): void {
if (!this._initialized) {
throw new Error("管理器未初始化,请先调用 _init 方法");
}
}
}
```
## 抽象基类模式
### 基类设计原则
```typescript
/**
* 抽象基类 - 定义共同接口和默认实现
*/
export abstract class WindowBase extends Component {
/** 共同属性 */
protected _gcom: GComponent;
protected _isShow: boolean = false;
/** 抽象方法 - 子类必须实现 */
protected abstract onInit(): void;
/** 虚方法 - 子类可选择重写 */
protected onShow(userdata?: any): void {
// 默认实现
}
protected onClose(): void {
// 默认实现
}
/** 最终方法 - 不允许重写 */
public final show(userdata?: any): void {
if (this._isShow) return;
this.onShow(userdata);
this._isShow = true;
}
}
/**
* 具体实现类
*/
export abstract class Window extends WindowBase {
/** 进一步的抽象和默认实现 */
protected onAdapted(): void {
// 适配逻辑
}
/** 新增的生命周期方法 */
protected onHide(): void { }
protected onShowFromHide(): void { }
protected onCover(): void { }
protected onRecover(): void { }
}
```
### 模块基类设计
```typescript
export abstract class ModuleBase extends Component implements IModule {
/** 模块标识 */
public moduleName: string;
/** 框架调用的初始化方法 */
public init(): void {
debug(`模块初始化: ${this.moduleName}`);
this.onInit();
}
/** 子类实现的初始化逻辑 */
protected abstract onInit(): void;
}
```
## 接口和契约设计
### 接口定义规范
```typescript
/**
* 窗口接口 - 定义窗口必须实现的方法
*/
export interface IWindow {
/** 窗口显示 */
_show(userdata?: any): void;
/** 窗口隐藏 */
_hide(): void;
/** 窗口关闭 */
_close(): void;
/** 窗口恢复 */
_recover(): void;
/** 屏幕尺寸变化适配 */
screenResize(): void;
}
/**
* 模块接口
*/
export interface IModule {
/** 模块名称 */
moduleName: string;
/** 模块初始化 */
init(): void;
}
```
### 配置接口设计
```typescript
export interface IPackageConfigRes {
[windowName: string]: {
group: string;
pkg: string;
bundle?: string;
};
}
export interface FrameConfig {
/** 开启debug 默认: false */
debug?: boolean;
}
```
## 工厂模式应用
### 动态注册工厂
```typescript
export class ComponentExtendHelper {
private static _componentMaps: Map<string, any> = new Map();
/**
* 注册组件类型
*/
public static register(): void {
for (const { ctor, res } of _uidecorator.getComponentMaps().values()) {
// 使用 FairyGUI 的工厂方法注册
UIObjectFactory.setPackageItemExtension(
`ui://${res.pkg}/${res.name}`,
ctor
);
}
}
/**
* 动态注册单个组件
*/
public static dynamicRegister(ctor: any, pkg: string, name: string): void {
UIObjectFactory.setPackageItemExtension(`ui://${pkg}/${name}`, ctor);
}
}
```
## 资源池模式
### 资源管理设计
```typescript
export class WindowResPool {
/** 资源信息映射 */
private _windowInfos: Map<string, WindowHeaderInfo> = new Map();
private _headerInfos: Map<string, WindowHeaderInfo> = new Map();
/** 引用计数管理 */
private _refCounts: Map<string, number> = new Map();
/**
* 添加资源引用
*/
public addResRef(windowName: string): void {
const count = this._refCounts.get(windowName) || 0;
this._refCounts.set(windowName, count + 1);
}
/**
* 释放资源引用
*/
public releaseWindowRes(windowName: string): void {
const count = this._refCounts.get(windowName) || 0;
if (count > 0) {
const newCount = count - 1;
this._refCounts.set(windowName, newCount);
// 引用为0时释放资源
if (newCount === 0) {
this.unloadResource(windowName);
}
}
}
}
```
## 事件驱动架构
### 事件系统集成
```typescript
// 使用外部事件系统
import { EventEmitter } from "kunpocc-event";
export class DataBase extends EventEmitter {
protected notify(path: string, value: any): void {
// 触发事件通知
this.emit(`change:${path}`, value);
// 同时支持绑定系统
BindManager.notifyChange(`${this.constructor.name}:${path}`, value, this);
}
}
```
### 生命周期事件
```typescript
export class WindowManager {
/** 窗口生命周期事件 */
public static readonly events = {
WINDOW_SHOW: 'window:show',
WINDOW_HIDE: 'window:hide',
WINDOW_CLOSE: 'window:close'
} as const;
public static showWindow(windowName: string): void {
// 业务逻辑...
// 触发事件
GlobalEvent.emit(this.events.WINDOW_SHOW, { windowName });
}
}
```
## 适配器模式
### 平台适配设计
```typescript
export abstract class PlatformAdapter {
/** 平台特定的实现 */
public abstract showBanner(): void;
public abstract vibrate(): void;
public abstract getSystemInfo(): SystemInfo;
}
export class WechatAdapter extends PlatformAdapter {
public showBanner(): void {
wx.createBannerAd(/* ... */);
}
public vibrate(): void {
wx.vibrateShort();
}
}
export class AlipayAdapter extends PlatformAdapter {
public showBanner(): void {
my.createBannerAd(/* ... */);
}
public vibrate(): void {
my.vibrate();
}
}
```
### 引擎适配
```typescript
export class CocosAdapter {
public init(): void {
this.initUI();
this.initInput();
this.initAudio();
}
private initUI(): void {
// 初始化UI系统适配
const uiModule = new CocosUIModule();
uiModule.init();
}
}
```
## 依赖注入模式
### 服务定位器模式
```typescript
export class ServiceLocator {
private static _services: Map<string, any> = new Map();
public static register<T>(name: string, service: T): void {
this._services.set(name, service);
}
public static get<T>(name: string): T {
const service = this._services.get(name);
if (!service) {
throw new Error(`Service not found: ${name}`);
}
return service as T;
}
}
// 使用示例
ServiceLocator.register('WindowManager', WindowManager);
const windowManager = ServiceLocator.get<typeof WindowManager>('WindowManager');
```
## 架构最佳实践
### 1. 职责分离
- 管理器负责全局状态和协调
- 基类提供共同功能和接口
- 具体实现类专注业务逻辑
### 2. 依赖管理
- 使用接口定义依赖契约
- 通过工厂和注入管理依赖关系
- 避免循环依赖
### 3. 扩展性设计
- 使用装饰器支持动态注册
- 提供插件化的扩展点
- 保持向后兼容性
### 4. 错误处理
- 在架构边界处理错误
- 提供降级和容错机制
- 记录详细的错误信息

View File

@@ -0,0 +1,171 @@
---
description: "Cocos Creator 3.x 开发规范和最佳实践"
globs: ["src/cocos/**/*.ts", "src/global/**/*.ts"]
alwaysApply: false
type: "framework-specific"
---
# Cocos Creator 3.x 开发规范
## 组件基类设计
### 继承 Component 的标准模式
```typescript
import { _decorator, Component } from "cc";
const { property } = _decorator;
export abstract class CocosEntry extends Component {
@property({ displayName: "uiConfig", type: JsonAsset, tooltip: "编辑器导出的UI配置" })
uiConfig: JsonAsset = null;
@property({ displayName: "游戏帧率" })
fps: number = 60;
/**
* 虚函数,子类需要实现
* kunpo库初始化完成后调用
*/
public abstract onInit(): void;
}
```
### 模块基类模式
```typescript
export abstract class ModuleBase extends Component implements IModule {
/** 模块名称 */
public moduleName: string;
/** 模块初始化 (内部使用) */
public init(): void { }
/** 模块初始化完成后调用的函数 */
protected abstract onInit(): void;
}
```
## 生命周期管理
### 组件生命周期规范
- `start()`: 用于框架初始化,标记为 `@internal`
- `onInit()`: 用户自定义初始化,需要子类实现
- `onDestroy()`: 清理资源和取消事件监听
### 时间和更新管理
```typescript
// 使用统一的时间系统
import { GlobalTimer, InnerTimer } from "../global";
private initTime(): void {
Time._configBoot();
InnerTimer.initTimer();
GlobalTimer.initTimer();
this.schedule(this.tick.bind(this), 0, macro.REPEAT_FOREVER);
}
private tick(dt: number): void {
InnerTimer.update(dt);
GlobalTimer.update(dt);
}
```
## 平台适配模式
### 平台检测和初始化
```typescript
private initPlatform(): void {
Platform.isNative = sys.isNative;
Platform.isMobile = sys.isMobile;
Platform.isNativeMobile = sys.isNative && sys.isMobile;
switch (sys.platform) {
case sys.Platform.WECHAT_GAME:
Platform.isWX = true;
Platform.platform = PlatformType.WX;
break;
case sys.Platform.ALIPAY_MINI_GAME:
Platform.isAlipay = true;
Platform.platform = PlatformType.Alipay;
break;
// ... 其他平台
}
}
```
### 平台特定功能
- 使用 `Platform` 类进行统一的平台判断
- 小游戏平台适配通过专门的适配类实现
- 避免在业务代码中直接使用 `sys` 对象
## 节点管理
### 持久化节点模式
```typescript
protected start(): void {
// 设置为持久化节点
director.addPersistRootNode(this.node);
this.node.setSiblingIndex(this.node.children.length - 1);
}
```
### 组件查找模式
```typescript
private initModule(): void {
// 递归查找所有子节点中的模块组件
for (const module of this.getComponentsInChildren(ModuleBase)) {
debug(`module:${module.moduleName}`);
module.init();
}
}
```
## 适配器模式
### 引擎适配器设计
- 通过 `CocosAdapter` 统一处理引擎特定功能
- UI系统通过 `CocosUIModule` 进行适配
- 窗口容器使用 `CocosWindowContainer`
```typescript
class CocosAdapter {
init(): void {
// 初始化引擎特定功能
this.initUI();
this.initScreen();
}
}
```
## 资源管理
### 配置文件处理
```typescript
// 使用 JsonAsset 处理配置
@property({ type: JsonAsset })
uiConfig: JsonAsset = null;
protected start(): void {
PropsHelper.setConfig(this.uiConfig?.json);
}
```
### Bundle 资源管理
- UI 资源通过 bundle 参数指定包名
- 支持动态资源加载和释放
- 使用资源池管理资源生命周期
## 调试和开发工具
### 全局调试接口
```typescript
// 暴露调试接口到全局对象
let _global = globalThis || window || global;
(_global as any)["getKunpoRegisterWindowMaps"] = function () {
return _uidecorator.getWindowMaps() as any;
};
```
### 帧率控制
```typescript
// 统一的帧率设置
game.frameRate = this.fps;
```

View File

@@ -0,0 +1,347 @@
---
description: "强类型数据绑定系统开发规范"
globs: ["src/data/**/*.ts", "**/*Data*.ts"]
alwaysApply: false
type: "data-architecture"
---
# 强类型数据绑定系统规范
## 数据基类设计
### DataBase 基类模式
```typescript
export class DataBase {
/** 数据变化监听器 */
private _watchers: Map<string, Function[]> = new Map();
/**
* 注册属性监听器
* @param path 属性路径
* @param callback 回调函数
*/
public watch(path: string, callback: Function): void {
if (!this._watchers.has(path)) {
this._watchers.set(path, []);
}
this._watchers.get(path)!.push(callback);
}
/**
* 触发属性变化通知
* @param path 属性路径
* @param value 新值
*/
protected notify(path: string, value: any): void {
if (this._watchers.has(path)) {
this._watchers.get(path)!.forEach(callback => {
callback(value);
});
}
}
}
```
### 数据类定义规范
```typescript
class GameData extends DataBase {
private _level: number = 1;
private _coins: number = 0;
private _items: Item[] = [];
// 使用 getter/setter 实现响应式
get level(): number {
return this._level;
}
set level(value: number) {
if (this._level !== value) {
this._level = value;
this.notify('level', value);
}
}
get coins(): number {
return this._coins;
}
set coins(value: number) {
if (this._coins !== value) {
this._coins = value;
this.notify('coins', value);
}
}
// 复杂属性的变化通知
addItem(item: Item): void {
this._items.push(item);
this.notify('items', this._items);
this.notify('items.length', this._items.length);
}
}
```
## 装饰器绑定系统
### 强类型属性绑定
```typescript
export namespace data {
/**
* 强类型属性绑定装饰器
* @param dataClass 数据类构造函数
* @param selector 类型安全的路径选择器
* @param callback 变化回调函数
* @param immediate 是否立即触发
*/
export function bindProp<T extends DataBase>(
dataClass: new () => T,
selector: (data: T) => any,
callback: (item: any, value?: any, data?: T) => void,
immediate: boolean = false
) {
return function (target: any, prop: string | symbol) {
const path = `${dataClass.name}:${extractPathFromSelector(selector)}`;
let ctor = target.constructor;
ctor[BIND_METADATA_KEY] = ctor[BIND_METADATA_KEY] || [];
ctor[BIND_METADATA_KEY].push({
prop, callback, path, immediate, isMethod: false
});
};
}
}
```
### 方法绑定装饰器
```typescript
/**
* 强类型方法绑定装饰器
* @param dataClass 数据类构造函数
* @param selector 类型安全的路径选择器
* @param immediate 是否立即触发
*/
export function bindMethod<T extends DataBase>(
dataClass: new () => T,
selector: (data: T) => any,
immediate: boolean = false
) {
return function (target: any, method: string | symbol, descriptor?: PropertyDescriptor) {
const path = `${dataClass.name}:${extractPathFromSelector(selector)}`;
let ctor = target.constructor;
ctor[BIND_METADATA_KEY] = ctor[BIND_METADATA_KEY] || [];
ctor[BIND_METADATA_KEY].push({
prop: method,
callback: descriptor!.value,
path,
immediate,
isMethod: true
});
return descriptor;
};
}
```
## 使用示例
### UI 数据绑定示例
```typescript
class PlayerData extends DataBase {
name: string = "";
level: number = 1;
exp: number = 0;
maxExp: number = 100;
// 计算属性
get expProgress(): number {
return this.exp / this.maxExp;
}
}
@uiclass("main", "player", "PlayerPanel")
export class PlayerPanel extends Window {
@uiprop nameLabel: GLabel;
@uiprop levelLabel: GLabel;
@uiprop expBar: GProgressBar;
// 绑定玩家名称到标签
@data.bindProp(PlayerData, data => data.name, function(item, value) {
this.nameLabel.text = value;
})
private _nameBinding: any;
// 绑定等级显示
@data.bindMethod(PlayerData, data => data.level)
private onLevelChanged(value: number): void {
this.levelLabel.text = `Lv.${value}`;
}
// 绑定经验条
@data.bindMethod(PlayerData, data => data.expProgress)
private onExpChanged(progress: number): void {
this.expBar.value = progress * 100;
}
protected onInit(): void {
// 初始化绑定
data.initializeBindings(this);
}
protected onClose(): void {
// 清理绑定
data.cleanupBindings(this);
}
}
```
## 绑定管理器
### BindManager 设计
```typescript
export class BindManager {
private static _bindings: Map<string, BindInfo[]> = new Map();
/**
* 添加绑定信息
*/
public static addBinding(bindInfo: BindInfo): void {
const key = bindInfo.path;
if (!this._bindings.has(key)) {
this._bindings.set(key, []);
}
this._bindings.get(key)!.push(bindInfo);
// 如果需要立即触发
if (bindInfo.immediate) {
this.triggerBinding(bindInfo);
}
}
/**
* 清理目标对象的绑定
*/
public static cleanup(target: any): void {
this._bindings.forEach((bindings, path) => {
const newBindings = bindings.filter(binding => binding.target !== target);
if (newBindings.length === 0) {
this._bindings.delete(path);
} else {
this._bindings.set(path, newBindings);
}
});
}
/**
* 触发路径对应的所有绑定
*/
public static notifyChange(path: string, value: any, data: any): void {
const bindings = this._bindings.get(path);
if (bindings) {
bindings.forEach(binding => {
try {
if (binding.isMethod) {
binding.callback.call(binding.target, value, data);
} else {
binding.callback.call(binding.target, binding.target[binding.prop], value, data);
}
} catch (error) {
console.error(`绑定回调执行错误: ${path}`, error);
}
});
}
}
}
```
## 路径解析器
### 路径提取函数
```typescript
/**
* 从选择器函数中提取路径字符串
* 支持编译期类型检查的运行时路径解析
*/
function extractPathFromSelector(selector: Function): string {
const fnString = selector.toString();
// 匹配箭头函数: data => data.property.path
let match = fnString.match(/\w+\s*=>\s*\w+\.(.+)/);
if (!match) {
// 匹配普通函数: function(data) { return data.property.path; }
match = fnString.match(/return\s+\w+\.(.+);?\s*}/);
}
if (!match) {
throw new Error('无效的路径选择器函数,请使用 data => data.property.path 格式');
}
return match[1].trim();
}
```
## 批量更新优化
### BatchUpdater 设计
```typescript
export class BatchUpdater {
private static _pendingUpdates: Set<string> = new Set();
private static _updateTimer: number = 0;
/**
* 批量更新通知
* @param path 变化路径
* @param value 新值
* @param data 数据对象
*/
public static scheduleUpdate(path: string, value: any, data: any): void {
this._pendingUpdates.add(path);
if (this._updateTimer === 0) {
this._updateTimer = requestAnimationFrame(() => {
this.flushUpdates();
});
}
}
/**
* 执行批量更新
*/
private static flushUpdates(): void {
this._pendingUpdates.forEach(path => {
// 获取最新值并触发更新
const [dataClassName, propertyPath] = path.split(':');
const dataInstance = DataRegistry.getInstance(dataClassName);
if (dataInstance) {
const value = this.getValueByPath(dataInstance, propertyPath);
BindManager.notifyChange(path, value, dataInstance);
}
});
this._pendingUpdates.clear();
this._updateTimer = 0;
}
}
```
## 数据绑定最佳实践
### 1. 类型安全
- 使用泛型约束确保绑定的类型安全
- 路径选择器函数提供编译期检查
- 避免字符串路径,优先使用选择器函数
### 2. 性能优化
- 使用批量更新减少频繁触发
- 及时清理不需要的绑定
- 避免在绑定回调中进行重度计算
### 3. 内存管理
- 在组件销毁时调用 `data.cleanupBindings()`
- 避免循环引用导致的内存泄漏
- 使用弱引用管理临时绑定
### 4. 调试支持
- 提供绑定信息的调试接口
- 记录绑定的创建和销毁日志
- 支持绑定状态的实时监控

View File

@@ -0,0 +1,276 @@
---
description: "装饰器模式和元数据管理规范"
globs: ["**/*Decorator*.ts", "**/*decorator*.ts"]
alwaysApply: false
type: "design-pattern"
---
# 装饰器模式开发规范
## 装饰器设计原则
### namespace 封装模式
```typescript
export namespace _uidecorator {
/** 元数据存储键 */
const UIPropMeta = "__uipropmeta__";
const UICBMeta = "__uicbmeta__";
/** 注册映射 */
const uiclassMap: Map<any, UIWindowInfo> = new Map();
/** 对外接口 */
export function getWindowMaps(): Map<any, UIWindowInfo> {
return uiclassMap;
}
}
```
### 装饰器工厂模式
```typescript
/**
* 类装饰器工厂
* @param groupName 窗口组名称
* @param pkgName fgui包名
* @param name 窗口名
* @param bundle 可选bundle名
*/
export function uiclass(groupName: string, pkgName: string, name: string, bundle?: string): Function {
return function (ctor: any): any {
// 元数据收集
uiclassMap.set(ctor, {
ctor: ctor,
props: ctor[UIPropMeta] || null,
callbacks: ctor[UICBMeta] || null,
res: {
group: groupName,
pkg: pkgName,
name: name,
bundle: bundle || ""
}
});
// 动态注册支持
_registerFinish && WindowManager.dynamicRegisterWindow(ctor, groupName, pkgName, name, bundle || "");
return ctor;
};
}
```
## 属性装饰器模式
### 属性标记装饰器
```typescript
/**
* UI属性装饰器
* @param target 实例成员的类的原型
* @param name 属性名
*/
export function uiprop(target: Object, name: string): any {
ObjectHelper.getObjectProp(target.constructor, UIPropMeta)[name] = 1;
}
/**
* UI控制器装饰器
*/
export function uicontrol(target: Object, name: string): any {
ObjectHelper.getObjectProp(target.constructor, UIControlMeta)[name] = 1;
}
/**
* UI动画装饰器
*/
export function uitransition(target: Object, name: string): any {
ObjectHelper.getObjectProp(target.constructor, UITransitionMeta)[name] = 1;
}
```
### 使用示例
```typescript
@uiclass("popup", "common", "SettingsWindow")
export class SettingsWindow extends Window {
@uiprop
btnClose: GButton;
@uiprop
list: GList;
@uicontrol
tabController: GController;
@uitransition
showAnim: GTransition;
}
```
## 方法装饰器模式
### 方法绑定装饰器
```typescript
/**
* 点击事件装饰器
* @param target 实例成员的类的原型
* @param name 方法名
* @param descriptor 属性描述符
*/
export function uiclick(target: Object, name: string, descriptor: PropertyDescriptor): void {
ObjectHelper.getObjectProp(target.constructor, UICBMeta)[name] = descriptor.value;
}
```
### 使用示例
```typescript
export class SettingsWindow extends Window {
@uiclick
private onBtnCloseClick(): void {
WindowManager.closeWindow("SettingsWindow");
}
@uiclick
private onBtnSaveClick(): void {
this.saveSettings();
}
}
```
## 数据绑定装饰器
### 强类型绑定装饰器
```typescript
export namespace data {
const BIND_METADATA_KEY = Symbol('__bind_metadata__');
/**
* 属性绑定装饰器
* @param dataClass 数据类构造函数
* @param selector 路径选择器函数
* @param callback 回调函数
* @param immediate 是否立即触发
*/
export function bindProp<T extends DataBase>(
dataClass: new () => T,
selector: (data: T) => any,
callback: (item: any, value?: any, data?: T) => void,
immediate: boolean = false
) {
return function (target: any, prop: string | symbol) {
const path = `${dataClass.name}:${extractPathFromSelector(selector)}`;
let ctor = target.constructor;
ctor[BIND_METADATA_KEY] = ctor[BIND_METADATA_KEY] || [];
ctor[BIND_METADATA_KEY].push({
prop, callback, path, immediate, isMethod: false
});
};
}
/**
* 方法绑定装饰器
*/
export function bindMethod<T extends DataBase>(
dataClass: new () => T,
selector: (data: T) => any,
immediate: boolean = false
) {
return function (target: any, method: string | symbol, descriptor?: PropertyDescriptor) {
const path = `${dataClass.name}:${extractPathFromSelector(selector)}`;
let ctor = target.constructor;
ctor[BIND_METADATA_KEY] = ctor[BIND_METADATA_KEY] || [];
ctor[BIND_METADATA_KEY].push({
prop: method,
callback: descriptor!.value,
path, immediate,
isMethod: true
});
return descriptor;
};
}
}
```
### 数据绑定使用示例
```typescript
class GameData extends DataBase {
level: number = 1;
coins: number = 0;
}
export class GameUI extends Window {
@uiprop
levelLabel: GLabel;
@uiprop
coinsLabel: GLabel;
// 绑定属性到UI
@data.bindProp(GameData, data => data.level, function(item, value) {
this.levelLabel.text = `Level: ${value}`;
})
private _levelBinding: any;
// 绑定方法到数据变化
@data.bindMethod(GameData, data => data.coins)
private onCoinsChanged(value: number): void {
this.coinsLabel.text = `Coins: ${value}`;
}
}
```
## 条件装饰器
### 条件注册装饰器
```typescript
export namespace _conditionDecorator {
const cdClassMap: Map<number, any> = new Map();
export function getConditionMaps(): Map<number, any> {
return cdClassMap;
}
/**
* 条件装饰器
* @param conditionType 条件类型ID
*/
export function conditionClass(conditionType: number): Function {
return function (ctor: any): void {
cdClassMap.set(conditionType, ctor);
return ctor;
};
}
}
```
### 条件使用示例
```typescript
@conditionClass(1001)
export class LevelCondition extends ConditionBase {
protected check(): boolean {
return GameData.getInstance().level >= this.targetLevel;
}
}
```
## 装饰器最佳实践
### 元数据收集模式
1. 使用 Symbol 作为元数据键避免冲突
2. 在类原型上存储元数据信息
3. 提供统一的元数据访问接口
### 动态注册支持
```typescript
let _registerFinish: boolean = false;
export function setRegisterFinish(): void {
_registerFinish = true;
}
// 在装饰器中支持动态注册
_registerFinish && WindowManager.dynamicRegisterWindow(ctor, groupName, pkgName, name, bundle);
```
### 类型安全
- 使用泛型约束确保装饰器类型安全
- 提供明确的参数类型定义
- 避免使用 any 类型,优先使用具体类型

256
.cursor/rules/fairygui.mdc Normal file
View File

@@ -0,0 +1,256 @@
---
description: "FairyGUI UI 系统开发规范"
globs: ["src/fgui/**/*.ts", "src/ui/**/*.ts"]
alwaysApply: false
type: "ui-framework"
---
# FairyGUI UI 系统开发规范
## 窗口基类设计模式
### 窗口继承层次
```typescript
// 基础窗口类 - 提供核心功能
export abstract class WindowBase extends Component {
// 核心窗口管理逻辑
}
// 抽象窗口类 - 定义生命周期
export abstract class Window extends WindowBase {
protected abstract onInit(): void;
protected onClose(): void { }
protected onShow(userdata?: any): void { }
protected onHide(): void { }
protected onShowFromHide(): void { }
protected onCover(): void { }
protected onRecover(): void { }
}
```
### 窗口生命周期管理
- `onInit()`: 窗口初始化,必须实现
- `onShow()`: 窗口显示时调用
- `onHide()`: 窗口隐藏时调用
- `onClose()`: 窗口关闭时调用
- `onCover()`: 被其他窗口覆盖时调用
- `onRecover()`: 从覆盖状态恢复时调用
- `onShowFromHide()`: 从隐藏状态重新显示时调用
## 窗口管理器模式
### 静态管理器设计
```typescript
export class WindowManager {
/** 窗口组映射 */
private static _groups: Map<string, WindowGroup> = new Map();
/** 所有窗口映射 */
private static _windows: Map<string, IWindow> = new Map();
/** 资源池 */
private static _resPool: WindowResPool;
/**
* 异步显示窗口(自动加载资源)
*/
public static showWindow(windowName: string, userdata?: any): Promise<void> {
return new Promise((resolve, reject) => {
this._resPool.loadWindowRes(windowName, {
complete: () => {
this.showWindowIm(windowName, userdata);
resolve();
},
fail: (pkgs: string[]) => reject(pkgs)
});
});
}
/**
* 立即显示窗口(资源已加载)
*/
public static showWindowIm(windowName: string, userdata?: any): void {
const info = this._resPool.get(windowName);
const windowGroup = this.getWindowGroup(info.group);
this._resPool.addResRef(windowName);
windowGroup.showWindow(info, userdata);
}
}
```
### 窗口组管理
- 使用 `WindowGroup` 管理同类型窗口
- 支持窗口层级和遮挡关系
- 自动处理窗口恢复和覆盖
## 装饰器系统
### UI 装饰器使用规范
```typescript
// 窗口类装饰器
@uiclass("popup", "common", "SettingsWindow", "ui")
export class SettingsWindow extends Window {
// UI 属性装饰器
@uiprop
btnClose: GButton;
@uiprop
list: GList;
// UI 控制器装饰器
@uicontrol
controller: GController;
// UI 动画装饰器
@uitransition
showTransition: GTransition;
// 点击事件装饰器
@uiclick
private onBtnCloseClick(): void {
WindowManager.closeWindow("SettingsWindow");
}
}
// 组件装饰器
@uicom("common", "CustomButton")
export class CustomButton extends GButton {
// 自定义组件逻辑
}
// Header 装饰器
@uiheader("common", "CommonHeader", "ui")
export class CommonHeader extends WindowHeader {
// 通用头部逻辑
}
```
### 装饰器参数规范
- `@uiclass(group, pkg, name, bundle?)`: 窗口类注册
- `group`: 窗口组名
- `pkg`: FairyGUI 包名
- `name`: 组件名(与 FairyGUI 中一致)
- `bundle`: 可选的 bundle 名称
- `@uicom(pkg, name)`: 自定义组件注册
- `@uiheader(pkg, name, bundle?)`: 窗口头部注册
## 资源管理模式
### 资源池设计
```typescript
export class WindowResPool {
private _windowInfos: Map<string, WindowHeaderInfo> = new Map();
private _headerInfos: Map<string, WindowHeaderInfo> = new Map();
/**
* 加载窗口资源
*/
loadWindowRes(windowName: string, callbacks: {
complete: () => void;
fail: (pkgs: string[]) => void;
}): void {
// 检查包资源是否已加载
// 自动加载依赖的UI包
// 调用相应的回调
}
/**
* 释放窗口资源
*/
releaseWindowRes(windowName: string): void {
// 减少引用计数
// 必要时卸载资源
}
}
```
### 包配置管理
```typescript
interface IPackageConfigRes {
[windowName: string]: {
group: string;
pkg: string;
bundle?: string;
};
}
// 初始化包配置
WindowManager.initPackageConfig(packageConfig);
```
## UI 组件扩展
### 组件扩展模式
```typescript
export class ComponentExtendHelper {
private static _componentMaps: Map<string, any> = new Map();
/**
* 注册自定义组件
*/
public static register(): void {
for (const { ctor, res } of _uidecorator.getComponentMaps().values()) {
UIObjectFactory.setPackageItemExtension(
`ui://${res.pkg}/${res.name}`,
ctor
);
}
}
/**
* 动态注册组件
*/
public static dynamicRegister(ctor: any, pkg: string, name: string): void {
UIObjectFactory.setPackageItemExtension(
`ui://${pkg}/${name}`,
ctor
);
}
}
```
## 窗口头部系统
### WindowHeader 模式
```typescript
export class WindowHeader {
/** 头部组件实例 */
protected _header: GComponent;
/**
* 创建头部
*/
public createHeader(pkg: string, name: string): GComponent {
this._header = UIPackage.createObject(pkg, name).asCom;
return this._header;
}
/**
* 头部适配
*/
public adapter(window: GComponent): void {
// 头部适配逻辑
// 处理安全区域
// 设置头部位置和尺寸
}
}
```
## 屏幕适配
### 屏幕尺寸变化处理
```typescript
// 在 WindowManager 中处理屏幕变化
public static _screenResize(): void {
this._windows.forEach((window: IWindow) => {
window.screenResize();
});
this._groups.forEach((group: WindowGroup) => {
group._screenResize();
});
}
// 在窗口中实现屏幕适配
protected screenResize(): void {
// 处理窗口在屏幕尺寸变化时的适配逻辑
}
```

View File

@@ -0,0 +1,413 @@
---
description: "热更新系统开发规范"
globs: ["src/hotupdate/**/*.ts"]
alwaysApply: false
type: "system-module"
---
# 热更新系统开发规范
## 热更新架构设计
### 管理器单例模式
```typescript
export class HotUpdateManager {
private static _instance: HotUpdateManager;
/** 获取单例实例 */
public static getInstance(): HotUpdateManager {
if (!this._instance) {
this._instance = new HotUpdateManager();
}
return this._instance;
}
/** 禁用直接构造 */
private constructor() {}
/** 配置属性 */
public manifestUrl: string = "";
public versionUrl: string = "";
/** 初始化热更新 */
public init(manifestUrl: string, versionUrl: string): void {
this.manifestUrl = manifestUrl;
this.versionUrl = versionUrl;
}
}
```
### 热更新状态码定义
```typescript
export enum HotUpdateCode {
/** 成功 */
Succeed = 0,
/** 已是最新版本 */
LatestVersion = 1,
/** 检查更新失败 */
CheckFailed = 2,
/** 下载失败 */
DownloadFailed = 3,
/** 解压失败 */
UnzipFailed = 4,
/** 网络错误 */
NetworkError = 5,
/** 空间不足 */
NoSpace = 6,
/** 未知错误 */
UnknownError = 7
}
```
## Promise 结果模式
### 统一结果接口
```typescript
export interface IPromiseResult {
/** 状态码 */
code: HotUpdateCode;
/** 消息描述 */
message: string;
/** 扩展数据 */
data?: any;
}
```
### 热更新配置接口
```typescript
export interface IHotUpdateConfig {
/** 版本号 */
version: string;
/** 远程manifest文件URL */
remoteManifestUrl: string;
/** 远程version文件URL */
remoteVersionUrl: string;
/** 资源包URL */
packageUrl: string;
/** 资源文件列表 */
assets?: { [key: string]: any };
/** 搜索路径 */
searchPaths?: string[];
}
```
## 热更新核心实现
### HotUpdate 核心类
```typescript
export class HotUpdate {
private _am: jsb.AssetsManager;
private _updating: boolean = false;
constructor(manifestUrl: string) {
// 初始化 AssetsManager
this._am = new jsb.AssetsManager(manifestUrl, jsb.fileUtils.getWritablePath() + 'remote-assets');
this._am.setEventCallback(this.onUpdateEvent.bind(this));
this._am.setVerifyCallback(this.onVerifyCallback.bind(this));
}
/**
* 检查更新
* @returns Promise<IPromiseResult>
*/
public checkUpdate(): Promise<IPromiseResult> {
return new Promise((resolve) => {
if (this._updating) {
resolve({ code: HotUpdateCode.UnknownError, message: "正在更新中" });
return;
}
if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
resolve({ code: HotUpdateCode.CheckFailed, message: "本地manifest加载失败" });
return;
}
this._am.setEventCallback((event) => {
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
resolve({ code: HotUpdateCode.CheckFailed, message: "本地manifest不存在" });
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
resolve({ code: HotUpdateCode.NetworkError, message: "下载manifest失败" });
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
resolve({ code: HotUpdateCode.LatestVersion, message: "已是最新版本" });
break;
case jsb.EventAssetsManager.NEW_VERSION_FOUND:
resolve({ code: HotUpdateCode.Succeed, message: "发现新版本" });
break;
}
});
this._am.checkUpdate();
});
}
/**
* 执行热更新
* @returns Promise<IPromiseResult>
*/
public hotUpdate(): Promise<IPromiseResult> {
return new Promise((resolve) => {
if (this._updating) {
resolve({ code: HotUpdateCode.UnknownError, message: "正在更新中" });
return;
}
this._updating = true;
this._am.setEventCallback((event) => {
switch (event.getEventCode()) {
case jsb.EventAssetsManager.UPDATE_FINISHED:
this._updating = false;
resolve({ code: HotUpdateCode.Succeed, message: "更新完成" });
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
this._updating = false;
resolve({ code: HotUpdateCode.DownloadFailed, message: "更新失败" });
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
this._updating = false;
resolve({ code: HotUpdateCode.UnzipFailed, message: "解压失败" });
break;
}
});
this._am.update();
});
}
/**
* 事件回调处理
*/
private onUpdateEvent(event: jsb.EventAssetsManager): void {
const code = event.getEventCode();
debug(`热更新事件: ${code}`);
switch (code) {
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
const progress = event.getPercent();
debug(`更新进度: ${progress}%`);
break;
case jsb.EventAssetsManager.ASSET_UPDATED:
const assetId = event.getAssetId();
debug(`资源更新: ${assetId}`);
break;
}
}
/**
* 验证回调
*/
private onVerifyCallback(path: string, asset: any): boolean {
// 资源验证逻辑
return true;
}
}
```
## manifest 管理
### 本地 manifest 刷新
```typescript
/**
* 替换 project.manifest 中的内容并刷新本地manifest
*/
private refreshLocalManifest(manifest: IHotUpdateConfig, versionManifest: IHotUpdateConfig): Promise<IPromiseResult> {
return new Promise((resolve) => {
// 版本比较
if (Utils.compareVersion(manifest.version, versionManifest.version) >= 0) {
resolve({ code: HotUpdateCode.LatestVersion, message: "已是最新版本" });
return;
}
// 更新 manifest 配置
manifest.remoteManifestUrl = Utils.addUrlParam(versionManifest.remoteManifestUrl, "timeStamp", `${Time.now()}`);
manifest.remoteVersionUrl = Utils.addUrlParam(versionManifest.remoteVersionUrl, "timeStamp", `${Time.now()}`);
manifest.packageUrl = versionManifest.packageUrl;
// 计算 manifest 根目录
let manifestRoot = "";
let manifestUrl = HotUpdateManager.getInstance().manifestUrl;
let found = manifestUrl.lastIndexOf("/");
if (found === -1) {
found = manifestUrl.lastIndexOf("\\");
}
if (found !== -1) {
manifestRoot = manifestUrl.substring(0, found + 1);
}
// 解析并设置本地 manifest
this._am.getLocalManifest().parseJSONString(JSON.stringify(manifest), manifestRoot);
resolve({ code: HotUpdateCode.Succeed, message: "更新热更新配置成功" });
});
}
```
## 版本比较工具
### 版本号比较函数
```typescript
export class Utils {
/**
* 版本号比较
* @param versionA 版本A
* @param versionB 版本B
* @returns 0: 相等, 1: A > B, -1: A < B
*/
public static compareVersion(versionA: string, versionB: string): number {
const a = versionA.split('.');
const b = versionB.split('.');
for (let i = 0; i < Math.max(a.length, b.length); i++) {
const numA = parseInt(a[i] || '0', 10);
const numB = parseInt(b[i] || '0', 10);
if (numA > numB) return 1;
if (numA < numB) return -1;
}
return 0;
}
/**
* 给URL添加参数
*/
public static addUrlParam(url: string, key: string, value: string): string {
const separator = url.indexOf('?') !== -1 ? '&' : '?';
return `${url}${separator}${key}=${encodeURIComponent(value)}`;
}
}
```
## 进度监控
### 更新进度回调
```typescript
export interface HotUpdateProgress {
/** 当前进度百分比 (0-100) */
percent: number;
/** 已下载字节数 */
downloadedBytes: number;
/** 总字节数 */
totalBytes: number;
/** 当前下载的文件 */
currentFile?: string;
}
export interface HotUpdateCallbacks {
/** 进度回调 */
onProgress?: (progress: HotUpdateProgress) => void;
/** 完成回调 */
onComplete?: (result: IPromiseResult) => void;
/** 错误回调 */
onError?: (error: IPromiseResult) => void;
}
export class HotUpdate {
public updateWithCallbacks(callbacks: HotUpdateCallbacks): void {
this._am.setEventCallback((event) => {
switch (event.getEventCode()) {
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
callbacks.onProgress?.({
percent: event.getPercent(),
downloadedBytes: event.getDownloadedBytes(),
totalBytes: event.getTotalBytes()
});
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
callbacks.onComplete?.({ code: HotUpdateCode.Succeed, message: "更新完成" });
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
callbacks.onError?.({ code: HotUpdateCode.DownloadFailed, message: "更新失败" });
break;
}
});
this._am.update();
}
}
```
## 错误处理和重试
### 重试机制
```typescript
export class HotUpdate {
private _retryCount: number = 0;
private readonly _maxRetryCount: number = 3;
/**
* 带重试的热更新
*/
public async hotUpdateWithRetry(): Promise<IPromiseResult> {
for (let i = 0; i < this._maxRetryCount; i++) {
try {
const result = await this.hotUpdate();
if (result.code === HotUpdateCode.Succeed) {
return result;
}
// 网络错误可以重试
if (result.code === HotUpdateCode.NetworkError && i < this._maxRetryCount - 1) {
warn(`热更新失败,准备重试 (${i + 1}/${this._maxRetryCount})`);
await this.delay(1000 * (i + 1)); // 递增延迟
continue;
}
return result;
} catch (error) {
error('热更新异常', error);
if (i === this._maxRetryCount - 1) {
return { code: HotUpdateCode.UnknownError, message: `重试${this._maxRetryCount}次后仍然失败` };
}
}
}
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
```
## 热更新最佳实践
### 1. 版本管理
- 使用语义化版本号 (major.minor.patch)
- 提供版本比较和检查功能
- 记录版本更新历史
### 2. 网络处理
- 实现重试机制处理网络不稳定
- 添加超时控制
- 支持断点续传
### 3. 用户体验
- 提供详细的进度反馈
- 支持后台下载
- 提供更新取消选项
### 4. 错误恢复
- 验证下载文件完整性
- 支持回滚到上一版本
- 提供修复工具清理损坏文件
### 5. 安全性
- 验证manifest签名
- 检查文件哈希值
- 使用HTTPS传输

View File

@@ -0,0 +1,258 @@
---
description: "日志系统和调试规范"
globs: ["src/tool/log.ts", "**/*.ts"]
alwaysApply: true
type: "logging"
---
# 日志系统和调试规范
## 统一日志接口
### 日志级别定义
```typescript
import { debug, info, log, warn, error } from "../tool/log";
/**
* 日志级别使用指南:
* - debug: 调试信息,仅在开发模式显示
* - log: 一般信息输出
* - info: 信息性消息,带有特殊图标
* - warn: 警告信息,黄色背景
* - error: 错误消息,红色背景
*/
```
### 日志使用规范
```typescript
// ✅ 正确的日志使用
export class WindowManager {
public static showWindow(windowName: string): void {
debug(`显示窗口: ${windowName}`); // 调试信息
if (!this._windows.has(windowName)) {
warn(`窗口不存在 ${windowName}`); // 警告
return;
}
try {
this.doShowWindow(windowName);
log(`窗口 ${windowName} 显示成功`); // 普通信息
} catch (e) {
error(`显示窗口失败: ${windowName}`, e); // 错误信息
}
}
}
```
## 调试模式管理
### 调试开关设计
```typescript
// header.ts - 调试配置
export let KUNPO_DEBUG: boolean = false;
/**
* 启用或禁用调试模式
* @param enable 是否启用调试模式
*/
export function enableDebugMode(enable: boolean): void {
if (enable === true) {
KUNPO_DEBUG = true;
warn("调试模式已开启");
} else {
KUNPO_DEBUG = false;
}
}
// log.ts - 条件日志输出
function debug(...args: any[]): void {
KUNPO_DEBUG && console.log("kunpo:", ...args);
}
```
### 框架配置集成
```typescript
interface FrameConfig {
/** 开启debug 默认: false */
debug?: boolean;
}
export class CocosEntry extends Component {
public getConfig(): FrameConfig {
return {
debug: true // 在开发环境设置为 true
};
}
protected start(): void {
const config = this.getConfig();
enableDebugMode(config.debug); // 根据配置启用调试
}
}
```
## 日志格式规范
### 统一前缀格式
```typescript
// 所有日志都带有 "kunpo:" 前缀
function log(...args: any[]) {
console.log("kunpo:", ...args);
}
function debug(...args: any[]): void {
KUNPO_DEBUG && console.log("kunpo:", ...args);
}
```
### 结构化日志信息
```typescript
// ✅ 推荐的日志格式
debug(`窗口注册 - 窗口名:${name} 包名:${pkg} 组名:${group}`);
log(`模块初始化完成: ${moduleName}`);
warn(`资源加载失败: ${resourcePath}`);
error(`网络请求异常: ${url}`, errorDetails);
// ❌ 避免的日志格式
debug("window registered"); // 信息不够具体
log(window); // 直接输出对象
```
## 开发调试工具
### 全局调试接口
```typescript
// 暴露调试接口到全局对象
let _global = globalThis || window || global;
(_global as any)["getKunpoRegisterWindowMaps"] = function () {
return _uidecorator.getWindowMaps() as any;
};
(_global as any)["getKunpoRegisterComponentMaps"] = function () {
return _uidecorator.getComponentMaps() as any;
};
(_global as any)["getKunpoRegisterHeaderMaps"] = function () {
return _uidecorator.getHeaderMaps() as any;
};
```
### 运行时信息输出
```typescript
// 系统信息调试
private initPlatform(): void {
debug(`系统类型: ${sys.os}`);
debug(`平台类型: ${PlatformType[Platform.platform]}`);
debug(`是否原生: ${Platform.isNative}`);
debug(`是否移动端: ${Platform.isMobile}`);
}
// 模块注册调试
public static registerUI(): void {
for (const { ctor, res } of _uidecorator.getWindowMaps().values()) {
debug(`窗口注册 - 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`);
}
}
```
## 错误处理和日志
### Promise 错误处理
```typescript
public static showWindow(windowName: string, userdata?: any): Promise<void> {
return new Promise((resolve, reject) => {
debug(`准备显示窗口: ${windowName}`);
this._resPool.loadWindowRes(windowName, {
complete: () => {
debug(`窗口资源加载完成: ${windowName}`);
this.showWindowIm(windowName, userdata);
resolve();
},
fail: (pkgs: string[]) => {
error(`窗口资源加载失败: ${windowName}`, pkgs);
reject(pkgs);
}
});
});
}
```
### 异常捕获和记录
```typescript
try {
this.doSomethingRisky();
} catch (error) {
// 记录详细的错误信息
error(`操作执行失败: ${operation}`, {
error: error.message,
stack: error.stack,
context: this.getContext()
});
// 根据错误类型决定是否继续执行
if (error instanceof CriticalError) {
throw error; // 关键错误需要向上抛出
}
}
```
## 性能监控日志
### 时间统计
```typescript
export class WindowManager {
public static showWindow(windowName: string): Promise<void> {
const startTime = performance.now();
debug(`开始显示窗口: ${windowName}`);
return new Promise((resolve) => {
this._resPool.loadWindowRes(windowName, {
complete: () => {
const loadTime = performance.now() - startTime;
debug(`窗口显示完成: ${windowName}, 耗时: ${loadTime.toFixed(2)}ms`);
resolve();
}
});
});
}
}
```
### 资源使用监控
```typescript
export class WindowResPool {
private logResourceUsage(): void {
if (KUNPO_DEBUG) {
const windowCount = this._windowInfos.size;
const headerCount = this._headerInfos.size;
debug(`资源池状态 - 窗口: ${windowCount}, 头部: ${headerCount}`);
}
}
}
```
## 调试最佳实践
### 1. 日志分级使用
- `debug`: 仅开发时需要的详细信息
- `log`: 系统运行的关键节点信息
- `warn`: 可能的问题但不影响运行
- `error`: 必须处理的错误情况
### 2. 信息完整性
- 包含足够的上下文信息
- 记录输入参数和状态
- 包含时间戳和调用路径
### 3. 性能考虑
- 避免在日志中进行重度计算
- 使用条件编译减少生产环境开销
- 延迟计算日志参数
### 4. 安全性
- 避免输出敏感信息到日志
- 在生产环境关闭详细日志
- 注意日志文件的权限设置

View File

@@ -0,0 +1,449 @@
---
description: "小游戏平台开发规范"
globs: ["src/minigame/**/*.ts", "src/global/Platform.ts"]
alwaysApply: false
type: "platform-specific"
---
# 小游戏平台开发规范
## 平台检测和分类
### 平台类型定义
```typescript
export enum PlatformType {
Unknown = 0,
Browser = 1,
WX = 2, // 微信小游戏
Alipay = 3, // 支付宝小游戏
Bytedance = 4, // 字节跳动小游戏
HuaweiQuick = 5 // 华为快游戏
}
export class Platform {
/** 平台类型 */
public static platform: PlatformType = PlatformType.Unknown;
/** 平台标识 */
public static isWX: boolean = false;
public static isAlipay: boolean = false;
public static isBytedance: boolean = false;
public static isHuaweiQuick: boolean = false;
public static isBrowser: boolean = false;
/** 设备类型 */
public static isNative: boolean = false;
public static isMobile: boolean = false;
public static isNativeMobile: boolean = false;
/** 系统类型 */
public static isAndroid: boolean = false;
public static isIOS: boolean = false;
public static isHarmonyOS: boolean = false;
}
```
### 平台初始化模式
```typescript
export class CocosEntry extends Component {
private initPlatform(): void {
// 设备类型检测
Platform.isNative = sys.isNative;
Platform.isMobile = sys.isMobile;
Platform.isNativeMobile = sys.isNative && sys.isMobile;
// 系统类型检测
switch (sys.os) {
case sys.OS.ANDROID:
Platform.isAndroid = true;
debug("系统类型 Android");
break;
case sys.OS.IOS:
Platform.isIOS = true;
debug("系统类型 IOS");
break;
case sys.OS.OPENHARMONY:
Platform.isHarmonyOS = true;
debug("系统类型 HarmonyOS");
break;
}
// 平台类型检测
switch (sys.platform) {
case sys.Platform.WECHAT_GAME:
Platform.isWX = true;
Platform.platform = PlatformType.WX;
break;
case sys.Platform.ALIPAY_MINI_GAME:
Platform.isAlipay = true;
Platform.platform = PlatformType.Alipay;
break;
case sys.Platform.BYTEDANCE_MINI_GAME:
Platform.isBytedance = true;
Platform.platform = PlatformType.Bytedance;
break;
case sys.Platform.HUAWEI_QUICK_GAME:
Platform.isHuaweiQuick = true;
Platform.platform = PlatformType.HuaweiQuick;
break;
default:
Platform.isBrowser = true;
Platform.platform = PlatformType.Browser;
break;
}
debug(`platform: ${PlatformType[Platform.platform]}`);
}
}
```
## 平台适配器设计
### 通用适配器接口
```typescript
export interface IMiniGameAdapter {
/** 显示分享菜单 */
showShareMenu(): void;
/** 分享应用 */
shareAppMessage(options: ShareOptions): void;
/** 显示 loading */
showLoading(options: LoadingOptions): void;
/** 隐藏 loading */
hideLoading(): void;
/** 显示 toast */
showToast(options: ToastOptions): void;
/** 获取系统信息 */
getSystemInfo(): Promise<SystemInfo>;
/** 震动反馈 */
vibrateShort(): void;
vibrateLong(): void;
}
```
### 微信小游戏适配
```typescript
export class WechatCommon implements IMiniGameAdapter {
public showShareMenu(): void {
if (Platform.isWX && wx.showShareMenu) {
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
});
}
}
public shareAppMessage(options: ShareOptions): void {
if (Platform.isWX && wx.shareAppMessage) {
wx.shareAppMessage({
title: options.title,
imageUrl: options.imageUrl,
query: options.query,
success: options.success,
fail: options.fail
});
}
}
public showLoading(options: LoadingOptions): void {
if (Platform.isWX && wx.showLoading) {
wx.showLoading({
title: options.title || '加载中...',
mask: options.mask !== false
});
}
}
public getSystemInfo(): Promise<SystemInfo> {
return new Promise((resolve, reject) => {
if (Platform.isWX && wx.getSystemInfo) {
wx.getSystemInfo({
success: resolve,
fail: reject
});
} else {
reject(new Error('不支持的平台'));
}
});
}
}
```
### 支付宝小游戏适配
```typescript
export class AlipayCommon implements IMiniGameAdapter {
public showShareMenu(): void {
// 支付宝特定实现
}
public shareAppMessage(options: ShareOptions): void {
if (Platform.isAlipay && my.shareAppMessage) {
my.shareAppMessage({
title: options.title,
desc: options.desc,
path: options.path,
success: options.success,
fail: options.fail
});
}
}
public showLoading(options: LoadingOptions): void {
if (Platform.isAlipay && my.showLoading) {
my.showLoading({
content: options.title || '加载中...'
});
}
}
}
```
### 字节跳动小游戏适配
```typescript
export class BytedanceCommon implements IMiniGameAdapter {
public shareAppMessage(options: ShareOptions): void {
if (Platform.isBytedance && tt.shareAppMessage) {
tt.shareAppMessage({
title: options.title,
imageUrl: options.imageUrl,
query: options.query,
success: options.success,
fail: options.fail
});
}
}
public vibrateShort(): void {
if (Platform.isBytedance && tt.vibrateShort) {
tt.vibrateShort({
success: () => debug('震动成功'),
fail: (err) => warn('震动失败', err)
});
}
}
}
```
## 统一接口封装
### MiniHelper 统一接口
```typescript
export class MiniHelper {
private static _adapter: IMiniGameAdapter | null = null;
/** 初始化适配器 */
public static init(): void {
switch (Platform.platform) {
case PlatformType.WX:
this._adapter = new WechatCommon();
break;
case PlatformType.Alipay:
this._adapter = new AlipayCommon();
break;
case PlatformType.Bytedance:
this._adapter = new BytedanceCommon();
break;
default:
warn('当前平台不支持小游戏功能');
break;
}
}
/** 统一的分享接口 */
public static share(options: ShareOptions): void {
if (this._adapter) {
this._adapter.shareAppMessage(options);
} else {
warn('未初始化小游戏适配器');
}
}
/** 统一的震动接口 */
public static vibrate(type: 'short' | 'long' = 'short'): void {
if (this._adapter) {
if (type === 'short') {
this._adapter.vibrateShort();
} else {
this._adapter.vibrateLong();
}
}
}
/** 统一的系统信息获取 */
public static async getSystemInfo(): Promise<SystemInfo | null> {
if (this._adapter) {
try {
return await this._adapter.getSystemInfo();
} catch (error) {
error('获取系统信息失败', error);
return null;
}
}
return null;
}
}
```
## 平台特定功能
### 广告系统封装
```typescript
interface AdOptions {
adUnitId: string;
success?: () => void;
fail?: (error: any) => void;
}
export class AdManager {
/** 显示激励视频广告 */
public static showRewardedVideoAd(options: AdOptions): void {
switch (Platform.platform) {
case PlatformType.WX:
this.showWXRewardedAd(options);
break;
case PlatformType.Alipay:
this.showAlipayRewardedAd(options);
break;
default:
options.fail?.('当前平台不支持广告');
break;
}
}
private static showWXRewardedAd(options: AdOptions): void {
if (wx.createRewardedVideoAd) {
const rewardedVideoAd = wx.createRewardedVideoAd({
adUnitId: options.adUnitId
});
rewardedVideoAd.onLoad(() => {
rewardedVideoAd.show();
});
rewardedVideoAd.onClose((res) => {
if (res && res.isEnded) {
options.success?.();
} else {
options.fail?.('用户取消观看');
}
});
}
}
}
```
### 支付系统封装
```typescript
interface PaymentOptions {
amount: number;
orderInfo: string;
success?: (result: any) => void;
fail?: (error: any) => void;
}
export class PaymentManager {
public static pay(options: PaymentOptions): void {
switch (Platform.platform) {
case PlatformType.WX:
this.wxPay(options);
break;
case PlatformType.Alipay:
this.alipayPay(options);
break;
default:
options.fail?.('当前平台不支持支付');
break;
}
}
private static wxPay(options: PaymentOptions): void {
// 微信支付实现
}
private static alipayPay(options: PaymentOptions): void {
// 支付宝支付实现
}
}
```
## 数据存储适配
### 本地存储封装
```typescript
export class StorageManager {
/** 设置数据 */
public static setItem(key: string, value: any): void {
try {
const jsonValue = JSON.stringify(value);
switch (Platform.platform) {
case PlatformType.WX:
wx.setStorageSync(key, jsonValue);
break;
case PlatformType.Alipay:
my.setStorageSync({ key, data: jsonValue });
break;
default:
localStorage.setItem(key, jsonValue);
break;
}
} catch (error) {
error('存储数据失败', key, error);
}
}
/** 获取数据 */
public static getItem<T>(key: string, defaultValue?: T): T | null {
try {
let jsonValue: string | null = null;
switch (Platform.platform) {
case PlatformType.WX:
jsonValue = wx.getStorageSync(key);
break;
case PlatformType.Alipay:
jsonValue = my.getStorageSync({ key }).data;
break;
default:
jsonValue = localStorage.getItem(key);
break;
}
if (jsonValue) {
return JSON.parse(jsonValue) as T;
}
return defaultValue || null;
} catch (error) {
error('读取数据失败', key, error);
return defaultValue || null;
}
}
}
```
## 平台开发最佳实践
### 1. 统一接口设计
- 为所有平台提供一致的API接口
- 使用适配器模式处理平台差异
- 提供降级方案处理不支持的功能
### 2. 平台检测
- 在应用启动时进行平台检测
- 使用枚举定义平台类型
- 提供便捷的平台判断属性
### 3. 错误处理
- 对不支持的平台提供友好的错误信息
- 使用 try-catch 处理平台API调用
- 提供回调函数处理异步操作结果
### 4. 性能优化
- 延迟加载平台特定功能
- 避免在不支持的平台上创建无用对象
- 使用条件编译减少包体积

View File

@@ -0,0 +1,260 @@
---
description: "KunpoCC 项目总体开发规范"
globs: ["**/*.ts", "**/*.md", "**/*.json"]
alwaysApply: true
type: "project-guidelines"
---
# KunpoCC 项目总体开发规范
## 项目介绍
KunpoCC 是一个基于 Cocos Creator 3.x 的游戏开发框架库,提供了一套完整的游戏开发工具和模块:
- **UI 管理系统**: 基于 FairyGUI 的窗口管理和组件系统
- **数据绑定系统**: 强类型的响应式数据绑定框架
- **平台适配**: 微信、支付宝、字节跳动等小游戏平台支持
- **热更新系统**: 完整的资源热更新解决方案
- **工具模块**: 时间管理、日志系统、数学工具等实用工具
## 项目结构规范
### 目录组织
```
src/
├── cocos/ # Cocos Creator 适配层
├── condition/ # 条件管理系统 (红点系统)
├── data/ # 数据绑定系统
├── fgui/ # FairyGUI 窗口基类
├── global/ # 全局工具和配置
├── hotupdate/ # 热更新系统
├── interface/ # 通用接口定义
├── minigame/ # 小游戏平台适配
├── module/ # 模块基类
├── tool/ # 工具函数集合
└── ui/ # UI 管理系统
```
### 文件命名规范
- **类文件**: PascalCase (如 `WindowManager.ts`)
- **接口文件**: 以 `I` 开头 (如 `IWindow.ts`)
- **工具文件**: 功能描述命名 (如 `log.ts`, `Math.ts`)
- **装饰器文件**: 以 `Decorator` 结尾 (如 `UIDecorator.ts`)
## 编码规范总览
### 类型系统
```typescript
// 严格的 TypeScript 配置
{
"strict": true,
"strictNullChecks": false, // 项目特殊需求
"experimentalDecorators": true
}
// 优先使用接口和泛型
interface IWindow {
_show(userdata?: any): void;
_close(): void;
}
// 使用泛型约束确保类型安全
public static getWindow<T extends IWindow>(name: string): T | null {
return this._windows.get(name) as T;
}
```
### 装饰器系统
```typescript
// UI 装饰器
@uiclass("popup", "common", "SettingsWindow")
export class SettingsWindow extends Window {
@uiprop btnClose: GButton;
@uiclick private onBtnCloseClick(): void { }
}
// 数据绑定装饰器
@data.bindProp(GameData, data => data.level, function(item, value) {
this.levelLabel.text = `Level: ${value}`;
})
private _levelBinding: any;
// 条件装饰器
@conditionClass(1001)
export class LevelCondition extends ConditionBase { }
```
### 架构模式
```typescript
// 单例管理器模式
export class WindowManager {
private static _instance: WindowManager;
public static getInstance(): WindowManager { }
}
// 抽象基类模式
export abstract class Window extends WindowBase {
protected abstract onInit(): void;
protected onShow(userdata?: any): void { }
}
// 适配器模式
export class CocosAdapter implements IAdapter {
public init(): void { }
}
```
## 开发流程
### 1. 新增功能模块
1. 在相应目录创建模块文件
2. 实现必要的接口和基类
3. 添加相应的装饰器支持
4. 编写单元测试
5. 更新文档和示例
### 2. 窗口开发
```typescript
@uiclass("main", "game", "GameWindow")
export class GameWindow extends Window {
@uiprop playerPanel: GComponent;
@uiprop settingsBtn: GButton;
@uiclick
private onSettingsBtnClick(): void {
WindowManager.showWindow("SettingsWindow");
}
protected onInit(): void {
// 窗口初始化逻辑
}
}
```
### 3. 数据系统集成
```typescript
class GameData extends DataBase {
private _score: number = 0;
get score(): number { return this._score; }
set score(value: number) {
if (this._score !== value) {
this._score = value;
this.notify('score', value);
}
}
}
```
## 质量保证
### 日志和调试
```typescript
import { debug, warn, error, log } from "../tool/log";
// 统一的日志格式
debug(`窗口注册 - 窗口名:${name} 包名:${pkg}`);
warn(`资源加载失败: ${resourcePath}`);
error(`网络请求异常: ${url}`, errorDetails);
```
### 错误处理
```typescript
// Promise 错误处理
public static showWindow(name: string): Promise<void> {
return new Promise((resolve, reject) => {
try {
// 业务逻辑
resolve();
} catch (error) {
error('窗口显示失败', error);
reject(error);
}
});
}
```
### 性能优化
- 使用资源池管理UI资源生命周期
- 实现批量更新减少频繁触发
- 及时清理事件监听和数据绑定
- 使用对象池复用临时对象
## 文档和注释
### JSDoc 规范
```typescript
/**
* @Author: Gongxh
* @Date: 2024-12-07
* @Description: 窗口管理类
*/
/**
* 显示指定名称的窗口
* @param windowName - 窗口的名称
* @param userdata - 可选的用户数据
* @returns Promise<void>
* @internal - 标记内部方法
*/
public static showWindow(windowName: string, userdata?: any): Promise<void> {
```
### 代码注释原则
- 公共API必须有完整的JSDoc注释
- 复杂逻辑添加行内注释说明
- 内部方法使用 `@internal` 标记
- 废弃功能使用 `@deprecated` 标记
## 版本管理
### 语义化版本
- **主版本号**: 不兼容的API修改
- **次版本号**: 向后兼容的功能性新增
- **修订号**: 向后兼容的问题修正
### 变更记录
- 维护 CHANGELOG.md 记录版本变更
- 每个版本包含新增功能、修复问题、破坏性变更
- 提供迁移指南帮助用户升级
## 测试规范
### 单元测试
```typescript
describe('WindowManager', () => {
test('should show window correctly', () => {
// 测试逻辑
});
test('should handle window not found', () => {
// 错误处理测试
});
});
```
### 集成测试
- 测试模块间的交互
- 验证装饰器系统的完整性
- 测试平台适配功能
## 部署和发布
### 构建配置
```json
{
"scripts": {
"build": "rollup -c rollup.config.mjs",
"build:all": "npm run build && npm run copy"
}
}
```
### 发布检查清单
1. 代码通过所有测试
2. 文档更新完整
3. 版本号正确更新
4. CHANGELOG.md 记录变更
5. 类型定义文件正确生成
这个规范文档作为项目开发的总体指导,具体的技术细节请参考各个专门的规则文件。

View File

@@ -0,0 +1,111 @@
---
description: "KunpoCC TypeScript 通用开发规范"
globs: ["src/**/*.ts"]
alwaysApply: true
type: "code-style"
---
# KunpoCC TypeScript 通用开发规范
## 代码风格和命名规范
### 命名约定
- **类名**: 使用 PascalCase (如 `WindowManager`, `DataBase`)
- **接口**: 以 `I` 开头,使用 PascalCase (如 `IWindow`, `IModule`)
- **方法和属性**: 使用 camelCase (如 `showWindow`, `onInit`)
- **常量**: 全大写,下划线分隔 (如 `KUNPO_DEBUG`, `TAG`)
- **私有方法**: 以下划线开头 (如 `_init`, `_removeWindow`)
- **内部方法**: 添加 `@internal` JSDoc 注释
### 类型定义
```typescript
// 优先使用接口定义对象结构
interface size {
width: number;
height: number;
}
// 使用泛型约束确保类型安全
public static getWindow<T extends IWindow>(name: string): T | null {
return this._windows.get(name) as T;
}
```
## 注释规范
### JSDoc 注释要求
- 所有公共方法必须有完整的 JSDoc 注释
- 包含参数说明、返回值说明和描述
- 内部方法使用 `@internal` 标记
```typescript
/**
* @Author: Gongxh
* @Date: 2024-12-07
* @Description: 窗口管理类
*/
/**
* 显示指定名称的窗口,并传递可选的用户数据
* @param windowName - 窗口的名称
* @param userdata - 可选参数,用于传递给窗口的用户数据
* @internal
*/
public static showWindowIm(windowName: string, userdata?: any): void {
```
## 错误处理和日志
### 使用统一的日志系统
```typescript
import { debug, warn, error, log } from "../tool/log";
// 调试信息(仅在 debug 模式下显示)
debug("窗口注册完成", windowName);
// 警告信息
warn(`窗口不存在 ${windowName} 不需要关闭`);
// 错误信息
error("初始化失败", errorMessage);
```
### 错误处理模式
```typescript
// 使用 Promise 进行异步错误处理
public static showWindow(windowName: string, userdata?: any): Promise<void> {
return new Promise((resolve, reject) => {
this._resPool.loadWindowRes(windowName, {
complete: () => {
this.showWindowIm(windowName, userdata);
resolve();
},
fail: (pkgs: string[]) => {
reject(pkgs);
}
});
});
}
```
## TypeScript 最佳实践
### 严格类型检查
- 启用 `strict: true`
- 禁用 `strictNullChecks: false` (项目特殊要求)
- 使用明确的类型注解,避免 `any`
### 装饰器使用
- 启用 `experimentalDecorators: true`
- 遵循项目的装饰器模式 (详见装饰器规范)
### 模块导入
```typescript
// 使用相对路径导入
import { WindowBase } from "./WindowBase";
import { debug, warn } from "../tool/log";
// 导出时保持清晰的结构
export { WindowManager } from "./ui/WindowManager";
export { _uidecorator } from "./ui/UIDecorator";
```

View File

@@ -1,6 +1,6 @@
{ {
"name": "kunpocc", "name": "kunpocc",
"version": "1.1.9", "version": "1.1.10",
"description": "基于creator3.0+的kunpocc库", "description": "基于creator3.0+的kunpocc库",
"main": "./dist/kunpocc.cjs", "main": "./dist/kunpocc.cjs",
"module": "./dist/kunpocc.mjs", "module": "./dist/kunpocc.mjs",

View File

@@ -118,6 +118,9 @@ export class ConditionManager {
*/ */
public static _removeConditionNode(conditionNode: ConditionNode): void { public static _removeConditionNode(conditionNode: ConditionNode): void {
let types = this._nodeToConditionTypes.get(conditionNode); let types = this._nodeToConditionTypes.get(conditionNode);
if (!types) {
return;
}
for (const conditionType of types.values()) { for (const conditionType of types.values()) {
let nodes = this._typeToNotifyNodes.get(conditionType); let nodes = this._typeToNotifyNodes.get(conditionType);
nodes.delete(conditionNode); nodes.delete(conditionNode);

View File

@@ -36,7 +36,7 @@ export abstract class ConditionBase {
public _updateCondition(): boolean { public _updateCondition(): boolean {
let canNotify = this.evaluate(); let canNotify = this.evaluate();
if (canNotify == this._canNotify) { if (canNotify == this._canNotify) {
return; return false;
} }
this._canNotify = canNotify; this._canNotify = canNotify;
return true; return true;

View File

@@ -7,9 +7,9 @@
import { GComponent } from "fairygui-cc"; import { GComponent } from "fairygui-cc";
import { Screen } from "../global/Screen"; import { Screen } from "../global/Screen";
import { AdapterType } from "../kunpocc";
import { IWindow } from "../ui/IWindow"; import { IWindow } from "../ui/IWindow";
import { IWindowHeader } from "../ui/IWindowHeader"; import { IWindowHeader } from "../ui/IWindowHeader";
import { AdapterType } from "../ui/header";
export abstract class WindowHeader extends GComponent implements IWindowHeader { export abstract class WindowHeader extends GComponent implements IWindowHeader {

View File

@@ -5,8 +5,8 @@
*/ */
import { native } from "cc"; import { native } from "cc";
import { Platform } from "../global/Platform";
import { ICheckUpdatePromiseResult } from "../interface/PromiseResult"; import { ICheckUpdatePromiseResult } from "../interface/PromiseResult";
import { Platform } from "../kunpocc";
import { log } from "../tool/log"; import { log } from "../tool/log";
import { HotUpdate, HotUpdateCode } from "./HotUpdate"; import { HotUpdate, HotUpdateCode } from "./HotUpdate";

View File

@@ -5,11 +5,11 @@
*/ */
import { Platform } from "../global/Platform"; import { Platform } from "../global/Platform";
import { BytedanceCommon } from "../kunpocc";
import { AlipayAds } from "./alipay/AlipayAds"; import { AlipayAds } from "./alipay/AlipayAds";
import { AlipayCommon } from "./alipay/AlipayCommon"; import { AlipayCommon } from "./alipay/AlipayCommon";
import { AlipayPay } from "./alipay/AlipayPay"; import { AlipayPay } from "./alipay/AlipayPay";
import { BytedanceAds } from "./bytedance/BytedanceAds"; import { BytedanceAds } from "./bytedance/BytedanceAds";
import { BytedanceCommon } from "./bytedance/BytedanceCommon";
import { BytedancePay } from "./bytedance/BytedancePay"; import { BytedancePay } from "./bytedance/BytedancePay";
import { IMiniRewardAds } from "./interface/IMiniAds"; import { IMiniRewardAds } from "./interface/IMiniAds";
import { IMiniCommon } from "./interface/IMiniCommon"; import { IMiniCommon } from "./interface/IMiniCommon";

View File

@@ -4,7 +4,7 @@
* @Description: 微信广告 * @Description: 微信广告
*/ */
import { warn } from "../../kunpocc"; import { warn } from "../../tool/log";
import { MiniErrorCode } from "../header"; import { MiniErrorCode } from "../header";
import { IMiniRewardAds } from "../interface/IMiniAds"; import { IMiniRewardAds } from "../interface/IMiniAds";

View File

@@ -106,11 +106,17 @@ export class BinaryHeap<T extends HeapNode> {
const size = --this._size; const size = --this._size;
const nodes = this._nodes; const nodes = this._nodes;
const newNode = (nodes[node.index] = nodes[size]);
newNode.index = node.index;
nodes[size] = null; // 如果删除的不是最后一个元素,需要调整堆
this.update(newNode); if (node.index < size) {
const newNode = (nodes[node.index] = nodes[size]);
newNode.index = node.index;
nodes[size] = null;
this.update(newNode);
} else {
nodes[size] = null;
}
node.index = -1; node.index = -1;
} }

View File

@@ -83,6 +83,7 @@ export class Timer {
const timerNode = this._pool.get(timerId); const timerNode = this._pool.get(timerId);
if (timerNode) { if (timerNode) {
timerNode.pause = true;
timerNode.pauseRemainTime = timerNode.expireTime - this._elapsedTime; timerNode.pauseRemainTime = timerNode.expireTime - this._elapsedTime;
this._heap.remove(timerNode); this._heap.remove(timerNode);
this._pausedTimers.set(timerId, timerNode); this._pausedTimers.set(timerId, timerNode);

View File

@@ -177,7 +177,7 @@ export class WindowGroup {
let isMoved = false; let isMoved = false;
if (this.size == 0) { if (this.size == 0) {
warn(`WindowGroup.moveWindowToTop: window group 【${this._name}】 is empty`); warn(`WindowGroup.moveWindowToTop: window group 【${this._name}】 is empty`);
return; return false;
} }
if (this._windowNames[this.size - 1] == name) { if (this._windowNames[this.size - 1] == name) {
// 已经在最顶层了 // 已经在最顶层了
@@ -185,7 +185,7 @@ export class WindowGroup {
const index = this._windowNames.indexOf(name); const index = this._windowNames.indexOf(name);
if (index == -1) { if (index == -1) {
warn(`WindowGroup.moveWindowToTop: window 【${name}】 not found in window group 【${this._name}`); warn(`WindowGroup.moveWindowToTop: window 【${name}】 not found in window group 【${this._name}`);
return; return false;
} }
if (index < this._windowNames.length - 1) { if (index < this._windowNames.length - 1) {
this._windowNames.splice(index, 1); this._windowNames.splice(index, 1);
@@ -202,6 +202,7 @@ export class WindowGroup {
window._setDepth(this._root.numChildren - 1); window._setDepth(this._root.numChildren - 1);
// 处理窗口显示和隐藏状态 // 处理窗口显示和隐藏状态
this._processWindowHideStatus(this.size - 1, isMoved); this._processWindowHideStatus(this.size - 1, isMoved);
return true;
} }
/** /**

View File

@@ -6,7 +6,7 @@
import { assetManager, resources } from "cc"; import { assetManager, resources } from "cc";
import { UIObjectFactory, UIPackage } from "fairygui-cc"; import { UIObjectFactory, UIPackage } from "fairygui-cc";
import { warn } from "../kunpocc"; import { warn } from "../tool/log";
import { IPackageConfigRes } from "./IPackageConfig"; import { IPackageConfigRes } from "./IPackageConfig";
export interface WindowInfo { export interface WindowInfo {