289 lines
8.9 KiB
TypeScript
289 lines
8.9 KiB
TypeScript
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<T>(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<T extends object>(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;
|