feat: 图集脏标记

This commit is contained in:
unanmed 2025-10-28 23:58:37 +08:00
parent fd9d21efa4
commit 637647dc17
5 changed files with 220 additions and 92 deletions

View File

@ -0,0 +1,30 @@
import { ITextureComposedData } from '@motajs/render-assets';
import { IMaterialAsset } from './types';
export class MaterialAsset implements IMaterialAsset {
/** 标记列表 */
private readonly marks: Map<symbol, number> = new Map();
/** 脏标记,所有值小于此标记的都视为需要更新 */
private dirtyFlag: number = 0;
constructor(readonly data: ITextureComposedData) {}
dirty(): void {
this.dirtyFlag++;
}
mark(): symbol {
const symbol = Symbol();
this.marks.set(symbol, this.dirtyFlag);
return symbol;
}
unmark(mark: symbol): void {
this.marks.delete(mark);
}
dirtySince(mark: symbol): boolean {
const value = this.marks.get(mark) ?? -1;
return value < this.dirtyFlag;
}
}

View File

@ -171,6 +171,10 @@ export class AutotileProcessor implements IAutotileProcessor {
return this.fromStaticRenderable(tile.static(), connection);
}
/**
*
* @param renderable
*/
private getStaticRectList(
renderable: ITextureRenderable
): AutotileFrameList {
@ -194,11 +198,17 @@ export class AutotileProcessor implements IAutotileProcessor {
}
}
/**
*
* @param ox
* @param oy
* @param connection
*/
private getConnectedRect(
ox: number,
oy: number,
connection: ConnectedAutotile
): ConnectedAutotile | null {
): ConnectedAutotile {
const { lt, rt, rb, lb } = connection;
return {

View File

@ -7,4 +7,10 @@ export function createMaterial() {
});
}
export * from './autotile';
export * from './builder';
export * from './fallback';
export * from './ins';
export * from './manager';
export * from './types';
export * from './utils';

View File

@ -19,12 +19,14 @@ import {
IMaterialAssetData,
BlockCls,
IBigImageData,
IAssetBuilder
IAssetBuilder,
IMaterialAsset
} from './types';
import { logger } from '@motajs/common';
import { getClsByString } from './utils';
import { isNil } from 'lodash-es';
import { AssetBuilder } from './builder';
import { MaterialAsset } from './asset';
export class MaterialManager implements IMaterialManager {
readonly tileStore: ITextureStore = new TextureStore();
@ -34,7 +36,8 @@ export class MaterialManager implements IMaterialManager {
readonly bigImageStore: ITextureStore = new TextureStore();
/** 图集信息存储 */
readonly assetDataStore: Map<number, ITextureComposedData> = new Map();
readonly assetDataStore: Map<number, IMaterialAsset> = new Map();
/** 大怪物数据 */
readonly bigImageData: Map<number, ITexture> = new Map();
/** tileset 中 `Math.floor(id / 10000) + 1` 映射到 tileset 对应索引的映射,用于处理图块超出 10000 的 tileset */
@ -60,6 +63,9 @@ export class MaterialManager implements IMaterialManager {
/** 是否已经构建过素材 */
private built: boolean = false;
/** 标记列表 */
private readonly markList: symbol[] = [];
constructor() {
this.assetBuilder.pipe(this.assetStore);
}
@ -264,6 +270,23 @@ export class MaterialManager implements IMaterialManager {
return newTexture;
}
/**
*
* @param data
*/
private checkAssetDirty(data: ITextureComposedData) {
const asset = this.assetDataStore.get(data.index);
if (asset) {
// 如果不是新图集,需要标记为脏
asset.dirty();
} else {
// 如果有新图集,需要添加
const alias = `asset-${data.index}`;
this.assetStore.alias(data.index, alias);
this.assetDataStore.set(data.index, new MaterialAsset(data));
}
}
cacheTileset(identifier: number): ITexture | null {
const newTexture = this.getTilesetOwnTexture(identifier);
if (!newTexture) return null;
@ -273,6 +296,7 @@ export class MaterialManager implements IMaterialManager {
this.numIdMap.set(identifier, `X${identifier}`);
const data = this.assetBuilder.addTexture(newTexture);
newTexture.toAsset(data);
this.checkAssetDirty(data);
return newTexture;
}
@ -295,10 +319,11 @@ export class MaterialManager implements IMaterialManager {
const data = this.assetBuilder.addTextureList(toAdd);
const res = [...data];
res.forEach(v => {
v.assetMap.keys().forEach(tex => {
if (set.has(tex)) tex.toAsset(v);
res.forEach(data => {
data.assetMap.keys().forEach(tex => {
if (set.has(tex)) tex.toAsset(data);
});
this.checkAssetDirty(data);
});
return toAdd;
@ -313,13 +338,13 @@ export class MaterialManager implements IMaterialManager {
const data = this.assetBuilder.addTextureList(this.tileStore.values());
const arr = [...data];
const res: IMaterialAssetData[] = [];
arr.forEach((v, i) => {
const alias = `asset-${i}`;
this.assetStore.alias(i, alias);
this.assetDataStore.set(i, v);
arr.forEach(v => {
const alias = `asset-${v.index}`;
this.assetStore.alias(v.index, alias);
this.assetDataStore.set(v.index, new MaterialAsset(v));
const data: IMaterialAssetData = {
data: v,
identifier: i,
identifier: v.index,
alias,
store: this.assetStore
};
@ -331,11 +356,11 @@ export class MaterialManager implements IMaterialManager {
return res;
}
getAsset(identifier: number): ITextureComposedData | null {
getAsset(identifier: number): IMaterialAsset | null {
return this.assetDataStore.get(identifier) ?? null;
}
getAssetByAlias(alias: string): ITextureComposedData | null {
getAssetByAlias(alias: string): IMaterialAsset | null {
const id = this.assetStore.identifierOf(alias);
if (isNil(id)) return null;
return this.assetDataStore.get(id) ?? null;
@ -406,4 +431,14 @@ export class MaterialManager implements IMaterialManager {
if (isNil(identifier)) return null;
return this.bigImageData.get(identifier) ?? null;
}
getIfBigImage(identifier: number): ITexture | null {
const bigImage = this.bigImageData.get(identifier) ?? null;
if (bigImage) return bigImage;
if (identifier < 10000) {
return this.tileStore.getTexture(identifier);
} else {
return this.cacheTileset(identifier);
}
}
}

View File

@ -90,6 +90,37 @@ export interface IBigImageData {
readonly store: ITextureStore;
}
export interface IAssetDirtyMarker {
/**
*
*/
dirty(): void;
}
export interface IAssetDirtyTracker {
/**
*
*/
mark(): symbol;
/**
*
* @param mark
*/
unmark(mark: symbol): void;
/**
*
* @param mark
*/
dirtySince(mark: symbol): boolean;
}
export interface IMaterialAsset extends IAssetDirtyTracker, IAssetDirtyMarker {
/** 图集的贴图数据 */
readonly data: ITextureComposedData;
}
export interface IAutotileProcessor {
/** 该自动元件处理器使用的素材管理器 */
readonly manager: IMaterialManager;
@ -162,7 +193,98 @@ export interface IAutotileProcessor {
): Generator<IAutotileRenderable, void> | null;
}
export interface IMaterialManager {
export interface IMaterialGetter {
/**
*
* @param identifier
*/
getTile(identifier: number): ITexture | null;
/**
*
* @param identifier
*/
getBlockCls(identifier: number): BlockCls;
/**
* `bigImage`
* @param identifier
*/
isBigImage(identifier: number): boolean;
/**
* `bigImage`
* @param identifier
*/
getBigImage(identifier: number): ITexture | null;
/**
* `bigImage` `bigImage`
* `null`
* @param identifier
*/
getIfBigImage(identifier: number): ITexture | null;
/**
*
* @param identifier
*/
getAsset(identifier: number): IMaterialAsset | null;
/**
*
* @param identifier
*/
getTileset(identifier: number): ITexture | null;
/**
*
* @param identifier
*/
getImage(identifier: number): ITexture | null;
}
export interface IMaterialAliasGetter {
/**
* id
* @param alias id
*/
getTileByAlias(alias: string): ITexture | null;
/**
*
* @param alias
*/
getTilesetByAlias(alias: string): ITexture | null;
/**
*
* @param alias
*/
getImageByAlias(alias: string): ITexture | null;
/**
*
* @param alias
*/
getAssetByAlias(alias: string): IMaterialAsset | null;
/**
*
* @param alias id
*/
getBlockClsByAlias(alias: string): BlockCls;
/**
* `bigImage`
* @param alias id
*/
getBigImageByAlias(alias: string): ITexture | null;
}
export interface IMaterialManager
extends IMaterialGetter,
IMaterialAliasGetter {
/** 贴图存储,把 terrains 等内容单独分开存储 */
readonly tileStore: ITextureStore;
/** tilesets 贴图存储,每个 tileset 是一个贴图对象 */
@ -174,6 +296,9 @@ export interface IMaterialManager {
/** bigImage 存储,存储大怪物数据 */
readonly bigImageStore: ITextureStore;
/** 图集信息存储 */
readonly assetDataStore: Iterable<[number, IMaterialAsset]>;
/** 图块类型映射 */
readonly clsMap: Map<number, BlockCls>;
@ -231,42 +356,6 @@ export interface IMaterialManager {
identifier: IIndexedIdentifier
): IMaterialData;
/**
*
* @param identifier
*/
getTile(identifier: number): ITexture | null;
/**
*
* @param identifier
*/
getTileset(identifier: number): ITexture | null;
/**
*
* @param identifier
*/
getImage(identifier: number): ITexture | null;
/**
* id
* @param alias id
*/
getTileByAlias(alias: string): ITexture | null;
/**
*
* @param alias
*/
getTilesetByAlias(alias: string): ITexture | null;
/**
*
* @param alias
*/
getImageByAlias(alias: string): ITexture | null;
/**
* tileset
* @param identifier tileset
@ -286,18 +375,6 @@ export interface IMaterialManager {
*/
buildAssets(): Iterable<IMaterialAssetData>;
/**
*
* @param identifier
*/
getAsset(identifier: number): ITextureComposedData | null;
/**
*
* @param alias
*/
getAssetByAlias(alias: string): ITextureComposedData | null;
/**
*
* @param identifier
@ -310,18 +387,6 @@ export interface IMaterialManager {
*/
getRenderableByAlias(alias: string): ITextureRenderable | null;
/**
*
* @param identifier
*/
getBlockCls(identifier: number): BlockCls;
/**
*
* @param alias id
*/
getBlockClsByAlias(alias: string): BlockCls;
/**
*
* @param alias id
@ -340,24 +405,6 @@ export interface IMaterialManager {
* @param image `bigImage`
*/
setBigImage(identifier: number, image: ITexture): IBigImageData;
/**
* `bigImage`
* @param identifier
*/
isBigImage(identifier: number): boolean;
/**
* `bigImage`
* @param identifier
*/
getBigImage(identifier: number): ITexture | null;
/**
* `bigImage`
* @param alias id
*/
getBigImageByAlias(alias: string): ITexture | null;
}
export interface IAssetBuilder {