import { Vec2, Vec3, Vec4, Color, Size, Rect, Quat, Mat4 } from 'cc'; import LogUtils from '@max-studio/core/utils/LogUtils'; /** * 配置表解析工具类 * 提供通用的数据类型解析函数 * * ⚠️ 此文件由配置表生成器自动生成,请勿手动修改! * 如需修改,请编辑 configs/plugins/ConfigTableGenerator.ts 中的 generateConfigParseUtils 方法 */ export class ConfigParseUtils { /** * 解析Vec2类型 */ public static parseVec2(value: any): Vec2 { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Vec2(parts[0] || 0, parts[1] || 0); } return new Vec2(0, 0); } /** * 解析Vec3类型 */ public static parseVec3(value: any): Vec3 { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Vec3(parts[0] || 0, parts[1] || 0, parts[2] || 0); } return new Vec3(0, 0, 0); } /** * 解析Vec4类型 */ public static parseVec4(value: any): Vec4 { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Vec4(parts[0] || 0, parts[1] || 0, parts[2] || 0, parts[3] || 0); } return new Vec4(0, 0, 0, 0); } /** * 解析Color类型 */ public static parseColor(value: any): Color { if (typeof value === 'string') { if (value.startsWith('#')) { // 十六进制颜色 const hex = value.slice(1); const r = Number.parseInt(hex.substring(0, 2), 16); const g = Number.parseInt(hex.substring(2, 4), 16); const b = Number.parseInt(hex.substring(4, 6), 16); const a = hex.length > 6 ? Number.parseInt(hex.substring(6, 8), 16) : 255; return new Color(r, g, b, a); } else { // 逗号分隔的RGBA值 const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Color(parts[0] || 0, parts[1] || 0, parts[2] || 0, parts[3] !== undefined ? parts[3] : 255); } } return new Color(0, 0, 0, 255); } /** * 解析Size类型 */ public static parseSize(value: any): Size { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Size(parts[0] || 0, parts[1] || 0); } return new Size(0, 0); } /** * 解析Rect类型 */ public static parseRect(value: any): Rect { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Rect(parts[0] || 0, parts[1] || 0, parts[2] || 0, parts[3] || 0); } return new Rect(0, 0, 0, 0); } /** * 解析Quat类型 */ public static parseQuat(value: any): Quat { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); return new Quat(parts[0] || 0, parts[1] || 0, parts[2] || 0, parts[3] !== undefined ? parts[3] : 1); } return new Quat(0, 0, 0, 1); } /** * 解析Mat4类型 */ public static parseMat4(value: any): Mat4 { if (typeof value === 'string') { const parts = value.split(',').map(v => Number.parseFloat(v.trim()) || 0); const mat = new Mat4(); try { mat.set( parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12], parts[13], parts[14], parts[15] ); } catch (err) { LogUtils.error('ConfigParseUtils', '解析Mat4失败:', err); } return mat; } return new Mat4(); } /** * 解析布尔值 */ static parseBoolean(value: any): boolean { if (typeof value === 'boolean') { return value; } if (typeof value === 'string') { const lowerValue = value.toLowerCase(); return lowerValue === 'true' || lowerValue === '1' || lowerValue === 'yes'; } if (typeof value === 'number') { return value !== 0; } return false; } /** * 解析整数 */ public static parseInt(value: string | number): number { if (typeof value === 'number') return Math.floor(value); if (typeof value === 'string') return Number.parseInt(value.trim()) || 0; return 0; } /** * 解析浮点数 */ static parseFloat(value: any): number { return Number.parseFloat(value) || 0; } /** * 解析字符串 */ static parseString(value: any): string { return String(value || ''); } /** * 解析字符串数组 */ static parseStringArray(value: any): string[] { if (Array.isArray(value)) { return value.map(item => String(item || '')); } if (typeof value === 'string') { return value.split(',').map(item => item.trim()).filter(item => item.length > 0); } return []; } /** * 解析数字数组 */ static parseNumberArray(value: any): number[] { if (Array.isArray(value)) { return value.map(item => Number.parseFloat(item) || 0); } if (typeof value === 'string') { return value.split(',').map(item => Number.parseFloat(item.trim()) || 0); } return []; } /** * 深度冻结对象,确保所有嵌套属性都不可修改 */ public static deepFreeze(obj: T): T { if (obj === null || typeof obj !== 'object') { return obj; } // 检查是否为 ArrayBuffer views 或其他不可冻结的对象 if (ArrayBuffer.isView(obj) || obj instanceof ArrayBuffer) { return obj; } // 检查是否为 Date、RegExp 等内置对象 if (obj instanceof Date || obj instanceof RegExp) { return obj; } try { // 递归冻结所有属性(先冻结子对象) Object.getOwnPropertyNames(obj).forEach(prop => { const value = (obj as any)[prop]; if (value !== null && typeof value === 'object') { this.deepFreeze(value); } }); // 最后冻结对象本身 Object.freeze(obj); // 对于数组,还需要防止索引赋值 if (Array.isArray(obj)) { Object.seal(obj); } } catch (err) { // 如果冻结失败,记录警告但不中断程序 LogUtils.warn('ConfigParseUtils', '无法冻结对象:', obj, err); } return obj; } /** * 创建配置数据的只读代理,提供更好的错误提示 */ public static createReadonlyProxy(obj: T, configName: string = '配置数据'): T { return new Proxy(obj, { set(target, property, value) { const errorMsg = `❌ 禁止修改${configName}的属性 "${String(property)}"!配置数据在运行时应保持不可变。`; LogUtils.error('ConfigParseUtils', errorMsg); throw new Error(errorMsg); }, defineProperty(target, property, descriptor) { const errorMsg = `❌ 禁止定义${configName}的属性 "${String(property)}"!配置数据在运行时应保持不可变。`; LogUtils.error('ConfigParseUtils', errorMsg); throw new Error(errorMsg); }, deleteProperty(target, property) { const errorMsg = `❌ 禁止删除${configName}的属性 "${String(property)}"!配置数据在运行时应保持不可变。`; LogUtils.error('ConfigParseUtils', errorMsg); throw new Error(errorMsg); } }); } } // 导出便捷的解析函数 export const { parseVec2, parseVec3, parseVec4, parseColor, parseSize, parseRect, parseQuat, parseMat4, parseBoolean, parseInt, parseFloat, parseString, parseStringArray, parseNumberArray, deepFreeze, createReadonlyProxy } = ConfigParseUtils;