194 lines
4.7 KiB
TypeScript
194 lines
4.7 KiB
TypeScript
|
|
/**
|
|||
|
|
* Priority-based asset loading queue
|
|||
|
|
* 基于优先级的资产加载队列
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { AssetGUID, IAssetLoadOptions } from '../types/AssetTypes';
|
|||
|
|
import { IAssetLoadQueue } from '../interfaces/IAssetManager';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Queue item
|
|||
|
|
* 队列项
|
|||
|
|
*/
|
|||
|
|
interface QueueItem {
|
|||
|
|
guid: AssetGUID;
|
|||
|
|
priority: number;
|
|||
|
|
options?: IAssetLoadOptions;
|
|||
|
|
timestamp: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Asset load queue implementation
|
|||
|
|
* 资产加载队列实现
|
|||
|
|
*/
|
|||
|
|
export class AssetLoadQueue implements IAssetLoadQueue {
|
|||
|
|
private readonly _queue: QueueItem[] = [];
|
|||
|
|
private readonly _guidToIndex = new Map<AssetGUID, number>();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Add to queue
|
|||
|
|
* 添加到队列
|
|||
|
|
*/
|
|||
|
|
enqueue(guid: AssetGUID, priority: number, options?: IAssetLoadOptions): void {
|
|||
|
|
// 检查是否已在队列中 / Check if already in queue
|
|||
|
|
if (this._guidToIndex.has(guid)) {
|
|||
|
|
this.reprioritize(guid, priority);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const item: QueueItem = {
|
|||
|
|
guid,
|
|||
|
|
priority,
|
|||
|
|
options,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 二分查找插入位置 / Binary search for insertion position
|
|||
|
|
const index = this.findInsertIndex(priority);
|
|||
|
|
this._queue.splice(index, 0, item);
|
|||
|
|
|
|||
|
|
// 更新索引映射 / Update index mapping
|
|||
|
|
this.updateIndices(index);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Remove from queue
|
|||
|
|
* 从队列移除
|
|||
|
|
*/
|
|||
|
|
dequeue(): { guid: AssetGUID; options?: IAssetLoadOptions } | null {
|
|||
|
|
if (this._queue.length === 0) return null;
|
|||
|
|
|
|||
|
|
const item = this._queue.shift();
|
|||
|
|
if (!item) return null;
|
|||
|
|
|
|||
|
|
// 更新索引映射 / Update index mapping
|
|||
|
|
this._guidToIndex.delete(item.guid);
|
|||
|
|
this.updateIndices(0);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
guid: item.guid,
|
|||
|
|
options: item.options
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Check if queue is empty
|
|||
|
|
* 检查队列是否为空
|
|||
|
|
*/
|
|||
|
|
isEmpty(): boolean {
|
|||
|
|
return this._queue.length === 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get queue size
|
|||
|
|
* 获取队列大小
|
|||
|
|
*/
|
|||
|
|
getSize(): number {
|
|||
|
|
return this._queue.length;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Clear queue
|
|||
|
|
* 清空队列
|
|||
|
|
*/
|
|||
|
|
clear(): void {
|
|||
|
|
this._queue.length = 0;
|
|||
|
|
this._guidToIndex.clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Reprioritize item
|
|||
|
|
* 重新设置优先级
|
|||
|
|
*/
|
|||
|
|
reprioritize(guid: AssetGUID, newPriority: number): void {
|
|||
|
|
const index = this._guidToIndex.get(guid);
|
|||
|
|
if (index === undefined) return;
|
|||
|
|
|
|||
|
|
const item = this._queue[index];
|
|||
|
|
if (!item || item.priority === newPriority) return;
|
|||
|
|
|
|||
|
|
// 移除旧项 / Remove old item
|
|||
|
|
this._queue.splice(index, 1);
|
|||
|
|
this._guidToIndex.delete(guid);
|
|||
|
|
|
|||
|
|
// 重新插入 / Reinsert with new priority
|
|||
|
|
item.priority = newPriority;
|
|||
|
|
const newIndex = this.findInsertIndex(newPriority);
|
|||
|
|
this._queue.splice(newIndex, 0, item);
|
|||
|
|
|
|||
|
|
// 更新索引 / Update indices
|
|||
|
|
this.updateIndices(Math.min(index, newIndex));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Find insertion index for priority
|
|||
|
|
* 查找优先级的插入索引
|
|||
|
|
*/
|
|||
|
|
private findInsertIndex(priority: number): number {
|
|||
|
|
let left = 0;
|
|||
|
|
let right = this._queue.length;
|
|||
|
|
|
|||
|
|
while (left < right) {
|
|||
|
|
const mid = Math.floor((left + right) / 2);
|
|||
|
|
// 高优先级在前 / Higher priority first
|
|||
|
|
if (this._queue[mid].priority >= priority) {
|
|||
|
|
left = mid + 1;
|
|||
|
|
} else {
|
|||
|
|
right = mid;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return left;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Update indices after modification
|
|||
|
|
* 修改后更新索引
|
|||
|
|
*/
|
|||
|
|
private updateIndices(startIndex: number): void {
|
|||
|
|
for (let i = startIndex; i < this._queue.length; i++) {
|
|||
|
|
this._guidToIndex.set(this._queue[i].guid, i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get queue items (for debugging)
|
|||
|
|
* 获取队列项(用于调试)
|
|||
|
|
*/
|
|||
|
|
getItems(): ReadonlyArray<{
|
|||
|
|
guid: AssetGUID;
|
|||
|
|
priority: number;
|
|||
|
|
waitTime: number;
|
|||
|
|
}> {
|
|||
|
|
const now = Date.now();
|
|||
|
|
return this._queue.map((item) => ({
|
|||
|
|
guid: item.guid,
|
|||
|
|
priority: item.priority,
|
|||
|
|
waitTime: now - item.timestamp
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Remove specific item from queue
|
|||
|
|
* 从队列中移除特定项
|
|||
|
|
*/
|
|||
|
|
remove(guid: AssetGUID): boolean {
|
|||
|
|
const index = this._guidToIndex.get(guid);
|
|||
|
|
if (index === undefined) return false;
|
|||
|
|
|
|||
|
|
this._queue.splice(index, 1);
|
|||
|
|
this._guidToIndex.delete(guid);
|
|||
|
|
this.updateIndices(index);
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Check if guid is in queue
|
|||
|
|
* 检查guid是否在队列中
|
|||
|
|
*/
|
|||
|
|
contains(guid: AssetGUID): boolean {
|
|||
|
|
return this._guidToIndex.has(guid);
|
|||
|
|
}
|
|||
|
|
}
|