Files
esengine/packages/asset-system/src/core/AssetPathResolver.ts
T
YHHandGitHub 3fb6f919f8 Feature/tilemap editor (#237)
* feat: 添加 Tilemap 编辑器插件和组件生命周期支持

* feat(editor-core): 添加声明式插件注册 API

* feat(editor-core): 改进tiledmap结构合并tileset进tiledmapeditor

* feat: 添加 editor-runtime SDK 和插件系统改进

* fix(ci): 修复SceneResourceManager里变量未使用问题
2025-11-25 22:23:19 +08:00

242 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Asset path resolver for different platforms and protocols
* 不同平台和协议的资产路径解析器
*/
import { AssetPlatform } from '../types/AssetTypes';
import { PathValidator } from '../utils/PathValidator';
/**
* Asset path resolver configuration
* 资产路径解析器配置
*/
export interface IAssetPathConfig {
/** Base URL for web assets | Web资产的基础URL */
baseUrl?: string;
/** Asset directory path | 资产目录路径 */
assetDir?: string;
/** Asset host for asset:// protocol | 资产协议的主机名 */
assetHost?: string;
/** Current platform | 当前平台 */
platform?: AssetPlatform;
/** Custom path transformer | 自定义路径转换器 */
pathTransformer?: (path: string) => string;
}
/**
* Asset path resolver
* 资产路径解析器
*/
export class AssetPathResolver {
private config: IAssetPathConfig;
constructor(config: IAssetPathConfig = {}) {
this.config = {
baseUrl: '',
assetDir: 'assets',
platform: AssetPlatform.H5,
...config
};
}
/**
* Update configuration
* 更新配置
*/
updateConfig(config: Partial<IAssetPathConfig>): void {
this.config = { ...this.config, ...config };
}
/**
* Resolve asset path to full URL
* 解析资产路径为完整URL
*/
resolve(path: string): string {
// Validate input path
const validation = PathValidator.validate(path);
if (!validation.valid) {
console.warn(`Invalid asset path: ${path} - ${validation.reason}`);
// Sanitize the path instead of throwing
path = PathValidator.sanitize(path);
if (!path) {
throw new Error(`Cannot resolve invalid path: ${validation.reason}`);
}
}
// Already a full URL
// 已经是完整URL
if (this.isAbsoluteUrl(path)) {
return path;
}
// Data URL
// 数据URL
if (path.startsWith('data:')) {
return path;
}
// Normalize the path
path = PathValidator.normalize(path);
// Apply custom transformer if provided
// 应用自定义转换器(如果提供)
if (this.config.pathTransformer) {
path = this.config.pathTransformer(path);
// Transformer output is trusted (may be absolute path or asset:// URL)
// 转换器输出是可信的(可能是绝对路径或 asset:// URL
return path;
}
// Platform-specific resolution
// 平台特定解析
switch (this.config.platform) {
case AssetPlatform.H5:
return this.resolveH5Path(path);
case AssetPlatform.WeChat:
return this.resolveWeChatPath(path);
case AssetPlatform.Playable:
return this.resolvePlayablePath(path);
case AssetPlatform.Android:
case AssetPlatform.iOS:
return this.resolveMobilePath(path);
case AssetPlatform.Editor:
return this.resolveEditorPath(path);
default:
return this.resolveH5Path(path);
}
}
/**
* Resolve path for H5 platform
* 解析H5平台路径
*/
private resolveH5Path(path: string): string {
// Remove leading slash if present
// 移除开头的斜杠(如果存在)
path = path.replace(/^\//, '');
// Combine with base URL and asset directory
// 与基础URL和资产目录结合
const base = this.config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');
const assetDir = this.config.assetDir || 'assets';
return `${base}/${assetDir}/${path}`.replace(/\/+/g, '/');
}
/**
* Resolve path for WeChat Mini Game
* 解析微信小游戏路径
*/
private resolveWeChatPath(path: string): string {
// WeChat mini games use relative paths
// 微信小游戏使用相对路径
return `${this.config.assetDir}/${path}`.replace(/\/+/g, '/');
}
/**
* Resolve path for Playable Ads platform
* 解析试玩广告平台路径
*/
private resolvePlayablePath(path: string): string {
// Playable ads typically use base64 embedded resources or relative paths
// 试玩广告通常使用base64内嵌资源或相对路径
// If custom transformer is provided (e.g., for base64 encoding)
// 如果提供了自定义转换器(例如用于base64编码)
if (this.config.pathTransformer) {
return this.config.pathTransformer(path);
}
// Default to relative path without directory prefix
// 默认使用不带目录前缀的相对路径
return path;
}
/**
* Resolve path for mobile platform (Android/iOS)
* 解析移动平台路径(Android/iOS
*/
private resolveMobilePath(path: string): string {
// Mobile platforms use relative paths or file:// protocol
// 移动平台使用相对路径或file://协议
return `./${this.config.assetDir}/${path}`.replace(/\/+/g, '/');
}
/**
* Resolve path for Editor platform (Tauri)
* 解析编辑器平台路径(Tauri)
*/
private resolveEditorPath(path: string): string {
// For Tauri editor, use pathTransformer if provided
// 对于Tauri编辑器,使用pathTransformer(如果提供)
if (this.config.pathTransformer) {
return this.config.pathTransformer(path);
}
// Use configurable asset host or default to 'localhost'
// 使用可配置的资产主机或默认为 'localhost'
const host = this.config.assetHost || 'localhost';
const sanitizedPath = PathValidator.sanitize(path);
return `asset://${host}/${sanitizedPath}`;
}
/**
* Check if path is absolute URL
* 检查路径是否为绝对URL
*/
private isAbsoluteUrl(path: string): boolean {
return /^(https?:\/\/|file:\/\/|asset:\/\/)/.test(path);
}
/**
* Get asset directory from path
* 从路径获取资产目录
*/
getAssetDirectory(path: string): string {
const resolved = this.resolve(path);
const lastSlash = resolved.lastIndexOf('/');
return lastSlash >= 0 ? resolved.substring(0, lastSlash) : '';
}
/**
* Get asset filename from path
* 从路径获取资产文件名
*/
getAssetFilename(path: string): string {
const resolved = this.resolve(path);
const lastSlash = resolved.lastIndexOf('/');
return lastSlash >= 0 ? resolved.substring(lastSlash + 1) : resolved;
}
/**
* Join paths
* 连接路径
*/
join(...paths: string[]): string {
return paths.join('/').replace(/\/+/g, '/');
}
/**
* Normalize path
* 规范化路径
*/
normalize(path: string): string {
return path.replace(/\\/g, '/').replace(/\/+/g, '/');
}
}
/**
* Global asset path resolver instance
* 全局资产路径解析器实例
*/
export const globalPathResolver = new AssetPathResolver();