Feature/physics and tilemap enhancement (#247)

* feat(behavior-tree,tilemap): 修复编辑器连线缩放问题并增强插件系统

* feat(node-editor,blueprint): 新增通用节点编辑器和蓝图可视化脚本系统

* feat(editor,tilemap): 优化编辑器UI样式和Tilemap编辑器功能

* fix: 修复CodeQL安全警告和CI类型检查错误

* fix: 修复CodeQL安全警告和CI类型检查错误

* fix: 修复CodeQL安全警告和CI类型检查错误
This commit is contained in:
YHH
2025-11-29 23:00:48 +08:00
committed by GitHub
parent f03b73b58e
commit 359886c72f
198 changed files with 33879 additions and 13121 deletions

View File

@@ -135,7 +135,19 @@ export class AssetManager implements IAssetManager {
}
// 创建加载器 / Create loader
const loader = this._loaderFactory.createLoader(metadata.type);
let loader = this._loaderFactory.createLoader(metadata.type);
// 如果没有找到 loader 且类型是 Custom尝试重新解析类型
// If no loader found and type is Custom, try to re-resolve the type
if (!loader && metadata.type === AssetType.Custom) {
const newType = this.resolveAssetType(metadata.path);
if (newType !== AssetType.Custom) {
// 更新 metadata 类型 / Update metadata type
this._database.updateAsset(guid, { type: newType });
loader = this._loaderFactory.createLoader(newType);
}
}
if (!loader) {
throw AssetLoadError.unsupportedType(guid, metadata.type);
}
@@ -238,17 +250,7 @@ export class AssetManager implements IAssetManager {
let metadata = this._database.getMetadataByPath(path);
if (!metadata) {
// 动态创建元数据 / Create metadata dynamically
const fileExt = path.substring(path.lastIndexOf('.')).toLowerCase();
let assetType = AssetType.Custom;
// 根据文件扩展名确定资产类型 / Determine asset type by file extension
if (['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'].includes(fileExt)) {
assetType = AssetType.Texture;
} else if (['.json'].includes(fileExt)) {
assetType = AssetType.Json;
} else if (['.txt', '.md', '.xml', '.yaml'].includes(fileExt)) {
assetType = AssetType.Text;
}
const assetType = this.resolveAssetType(path);
// 生成唯一GUID / Generate unique GUID
const dynamicGuid = `dynamic_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
@@ -271,15 +273,59 @@ export class AssetManager implements IAssetManager {
this._database.addAsset(metadata);
this._pathToGuid.set(path, metadata.guid);
} else {
// 如果之前缓存的类型是 Custom检查是否现在有注册的 loader 可以处理
// If previously cached as Custom, check if a registered loader can now handle it
if (metadata.type === AssetType.Custom) {
const newType = this.resolveAssetType(path);
if (newType !== AssetType.Custom) {
metadata.type = newType;
}
}
this._pathToGuid.set(path, metadata.guid);
}
return this.loadAsset<T>(metadata.guid, options);
}
// 同样检查已缓存的资产,如果类型是 Custom 但现在有 loader 可以处理
// Also check cached assets, if type is Custom but now a loader can handle it
const entry = this._assets.get(guid);
if (entry && entry.metadata.type === AssetType.Custom) {
const newType = this.resolveAssetType(path);
if (newType !== AssetType.Custom) {
entry.metadata.type = newType;
}
}
return this.loadAsset<T>(guid, options);
}
/**
* Resolve asset type from path
* 从路径解析资产类型
*/
private resolveAssetType(path: string): AssetType {
// 首先尝试从已注册的加载器获取资产类型 / First try to get asset type from registered loaders
const loaderType = (this._loaderFactory as AssetLoaderFactory).getAssetTypeByPath(path);
if (loaderType !== null) {
return loaderType;
}
// 如果没有找到匹配的加载器,使用默认的扩展名映射 / Fallback to default extension mapping
const fileExt = path.substring(path.lastIndexOf('.')).toLowerCase();
// 默认支持的基础类型 / Default supported basic types
if (['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'].includes(fileExt)) {
return AssetType.Texture;
} else if (['.json'].includes(fileExt)) {
return AssetType.Json;
} else if (['.txt', '.md', '.xml', '.yaml'].includes(fileExt)) {
return AssetType.Text;
}
return AssetType.Custom;
}
/**
* Load multiple assets
* 批量加载资产

View File

@@ -73,6 +73,18 @@ export interface IAssetLoaderFactory {
* 检查类型是否有加载器
*/
hasLoader(type: AssetType): boolean;
/**
* Get asset type by file extension
* 根据文件扩展名获取资产类型
*/
getAssetTypeByExtension(extension: string): AssetType | null;
/**
* Get asset type by file path
* 根据文件路径获取资产类型
*/
getAssetTypeByPath(path: string): AssetType | null;
}
/**

View File

@@ -72,6 +72,57 @@ export class AssetLoaderFactory implements IAssetLoaderFactory {
return this._loaders.has(type);
}
/**
* Get asset type by file extension
* 根据文件扩展名获取资产类型
*
* @param extension - File extension including dot (e.g., '.btree', '.png')
* @returns Asset type if a loader supports this extension, null otherwise
*/
getAssetTypeByExtension(extension: string): AssetType | null {
const ext = extension.toLowerCase();
for (const [type, loader] of this._loaders) {
if (loader.supportedExtensions.some(e => e.toLowerCase() === ext)) {
return type;
}
}
return null;
}
/**
* Get asset type by file path
* 根据文件路径获取资产类型
*
* Checks for compound extensions (like .tilemap.json) first, then simple extensions
*
* @param path - File path
* @returns Asset type if a loader supports this file, null otherwise
*/
getAssetTypeByPath(path: string): AssetType | null {
const lowerPath = path.toLowerCase();
// First check compound extensions (e.g., .tilemap.json)
for (const [type, loader] of this._loaders) {
for (const ext of loader.supportedExtensions) {
if (ext.includes('.') && ext.split('.').length > 2) {
// This is a compound extension like .tilemap.json
if (lowerPath.endsWith(ext.toLowerCase())) {
return type;
}
}
}
}
// Then check simple extensions
const lastDot = path.lastIndexOf('.');
if (lastDot !== -1) {
const ext = path.substring(lastDot).toLowerCase();
return this.getAssetTypeByExtension(ext);
}
return null;
}
/**
* Get all registered loaders
* 获取所有注册的加载器

View File

@@ -33,45 +33,50 @@ export enum AssetState {
}
/**
* Asset types supported by the system
* 系统支持的资产类型
* Asset type - string based for extensibility
* 资产类型 - 使用字符串以支持插件扩展
*
* Plugins can define their own asset types by using custom strings.
* Built-in types are provided as constants below.
* 插件可以通过使用自定义字符串定义自己的资产类型。
* 内置类型作为常量提供如下。
*/
export enum AssetType {
export type AssetType = string;
/**
* Built-in asset types provided by asset-system
* asset-system 提供的内置资产类型
*/
export const AssetType = {
/** 纹理 */
Texture = 'texture',
Texture: 'texture',
/** 网格 */
Mesh = 'mesh',
Mesh: 'mesh',
/** 材质 */
Material = 'material',
Material: 'material',
/** 着色器 */
Shader = 'shader',
Shader: 'shader',
/** 音频 */
Audio = 'audio',
Audio: 'audio',
/** 字体 */
Font = 'font',
Font: 'font',
/** 预制体 */
Prefab = 'prefab',
Prefab: 'prefab',
/** 场景 */
Scene = 'scene',
Scene: 'scene',
/** 脚本 */
Script = 'script',
Script: 'script',
/** 动画片段 */
AnimationClip = 'animation',
/** 行为树 */
BehaviorTree = 'behaviortree',
/** 瓦片地图 */
Tilemap = 'tilemap',
/** 瓦片集 */
Tileset = 'tileset',
AnimationClip: 'animation',
/** JSON数据 */
Json = 'json',
Json: 'json',
/** 文本 */
Text = 'text',
Text: 'text',
/** 二进制 */
Binary = 'binary',
Binary: 'binary',
/** 自定义 */
Custom = 'custom'
}
Custom: 'custom'
} as const;
/**
* Platform variants for assets