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); return this.fromStaticRenderable(tile.static(), connection);
} }
/**
*
* @param renderable
*/
private getStaticRectList( private getStaticRectList(
renderable: ITextureRenderable renderable: ITextureRenderable
): AutotileFrameList { ): AutotileFrameList {
@ -194,11 +198,17 @@ export class AutotileProcessor implements IAutotileProcessor {
} }
} }
/**
*
* @param ox
* @param oy
* @param connection
*/
private getConnectedRect( private getConnectedRect(
ox: number, ox: number,
oy: number, oy: number,
connection: ConnectedAutotile connection: ConnectedAutotile
): ConnectedAutotile | null { ): ConnectedAutotile {
const { lt, rt, rb, lb } = connection; const { lt, rt, rb, lb } = connection;
return { 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 './manager';
export * from './types';
export * from './utils';

View File

@ -19,12 +19,14 @@ import {
IMaterialAssetData, IMaterialAssetData,
BlockCls, BlockCls,
IBigImageData, IBigImageData,
IAssetBuilder IAssetBuilder,
IMaterialAsset
} from './types'; } from './types';
import { logger } from '@motajs/common'; import { logger } from '@motajs/common';
import { getClsByString } from './utils'; import { getClsByString } from './utils';
import { isNil } from 'lodash-es'; import { isNil } from 'lodash-es';
import { AssetBuilder } from './builder'; import { AssetBuilder } from './builder';
import { MaterialAsset } from './asset';
export class MaterialManager implements IMaterialManager { export class MaterialManager implements IMaterialManager {
readonly tileStore: ITextureStore = new TextureStore(); readonly tileStore: ITextureStore = new TextureStore();
@ -34,7 +36,8 @@ export class MaterialManager implements IMaterialManager {
readonly bigImageStore: ITextureStore = new TextureStore(); 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(); readonly bigImageData: Map<number, ITexture> = new Map();
/** tileset 中 `Math.floor(id / 10000) + 1` 映射到 tileset 对应索引的映射,用于处理图块超出 10000 的 tileset */ /** tileset 中 `Math.floor(id / 10000) + 1` 映射到 tileset 对应索引的映射,用于处理图块超出 10000 的 tileset */
@ -60,6 +63,9 @@ export class MaterialManager implements IMaterialManager {
/** 是否已经构建过素材 */ /** 是否已经构建过素材 */
private built: boolean = false; private built: boolean = false;
/** 标记列表 */
private readonly markList: symbol[] = [];
constructor() { constructor() {
this.assetBuilder.pipe(this.assetStore); this.assetBuilder.pipe(this.assetStore);
} }
@ -264,6 +270,23 @@ export class MaterialManager implements IMaterialManager {
return newTexture; 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 { cacheTileset(identifier: number): ITexture | null {
const newTexture = this.getTilesetOwnTexture(identifier); const newTexture = this.getTilesetOwnTexture(identifier);
if (!newTexture) return null; if (!newTexture) return null;
@ -273,6 +296,7 @@ export class MaterialManager implements IMaterialManager {
this.numIdMap.set(identifier, `X${identifier}`); this.numIdMap.set(identifier, `X${identifier}`);
const data = this.assetBuilder.addTexture(newTexture); const data = this.assetBuilder.addTexture(newTexture);
newTexture.toAsset(data); newTexture.toAsset(data);
this.checkAssetDirty(data);
return newTexture; return newTexture;
} }
@ -295,10 +319,11 @@ export class MaterialManager implements IMaterialManager {
const data = this.assetBuilder.addTextureList(toAdd); const data = this.assetBuilder.addTextureList(toAdd);
const res = [...data]; const res = [...data];
res.forEach(v => { res.forEach(data => {
v.assetMap.keys().forEach(tex => { data.assetMap.keys().forEach(tex => {
if (set.has(tex)) tex.toAsset(v); if (set.has(tex)) tex.toAsset(data);
}); });
this.checkAssetDirty(data);
}); });
return toAdd; return toAdd;
@ -313,13 +338,13 @@ export class MaterialManager implements IMaterialManager {
const data = this.assetBuilder.addTextureList(this.tileStore.values()); const data = this.assetBuilder.addTextureList(this.tileStore.values());
const arr = [...data]; const arr = [...data];
const res: IMaterialAssetData[] = []; const res: IMaterialAssetData[] = [];
arr.forEach((v, i) => { arr.forEach(v => {
const alias = `asset-${i}`; const alias = `asset-${v.index}`;
this.assetStore.alias(i, alias); this.assetStore.alias(v.index, alias);
this.assetDataStore.set(i, v); this.assetDataStore.set(v.index, new MaterialAsset(v));
const data: IMaterialAssetData = { const data: IMaterialAssetData = {
data: v, data: v,
identifier: i, identifier: v.index,
alias, alias,
store: this.assetStore store: this.assetStore
}; };
@ -331,11 +356,11 @@ export class MaterialManager implements IMaterialManager {
return res; return res;
} }
getAsset(identifier: number): ITextureComposedData | null { getAsset(identifier: number): IMaterialAsset | null {
return this.assetDataStore.get(identifier) ?? null; return this.assetDataStore.get(identifier) ?? null;
} }
getAssetByAlias(alias: string): ITextureComposedData | null { getAssetByAlias(alias: string): IMaterialAsset | null {
const id = this.assetStore.identifierOf(alias); const id = this.assetStore.identifierOf(alias);
if (isNil(id)) return null; if (isNil(id)) return null;
return this.assetDataStore.get(id) ?? null; return this.assetDataStore.get(id) ?? null;
@ -406,4 +431,14 @@ export class MaterialManager implements IMaterialManager {
if (isNil(identifier)) return null; if (isNil(identifier)) return null;
return this.bigImageData.get(identifier) ?? 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; 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 { export interface IAutotileProcessor {
/** 该自动元件处理器使用的素材管理器 */ /** 该自动元件处理器使用的素材管理器 */
readonly manager: IMaterialManager; readonly manager: IMaterialManager;
@ -162,7 +193,98 @@ export interface IAutotileProcessor {
): Generator<IAutotileRenderable, void> | null; ): 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 等内容单独分开存储 */ /** 贴图存储,把 terrains 等内容单独分开存储 */
readonly tileStore: ITextureStore; readonly tileStore: ITextureStore;
/** tilesets 贴图存储,每个 tileset 是一个贴图对象 */ /** tilesets 贴图存储,每个 tileset 是一个贴图对象 */
@ -174,6 +296,9 @@ export interface IMaterialManager {
/** bigImage 存储,存储大怪物数据 */ /** bigImage 存储,存储大怪物数据 */
readonly bigImageStore: ITextureStore; readonly bigImageStore: ITextureStore;
/** 图集信息存储 */
readonly assetDataStore: Iterable<[number, IMaterialAsset]>;
/** 图块类型映射 */ /** 图块类型映射 */
readonly clsMap: Map<number, BlockCls>; readonly clsMap: Map<number, BlockCls>;
@ -231,42 +356,6 @@ export interface IMaterialManager {
identifier: IIndexedIdentifier identifier: IIndexedIdentifier
): IMaterialData; ): 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 * tileset
* @param identifier tileset * @param identifier tileset
@ -286,18 +375,6 @@ export interface IMaterialManager {
*/ */
buildAssets(): Iterable<IMaterialAssetData>; buildAssets(): Iterable<IMaterialAssetData>;
/**
*
* @param identifier
*/
getAsset(identifier: number): ITextureComposedData | null;
/**
*
* @param alias
*/
getAssetByAlias(alias: string): ITextureComposedData | null;
/** /**
* *
* @param identifier * @param identifier
@ -310,18 +387,6 @@ export interface IMaterialManager {
*/ */
getRenderableByAlias(alias: string): ITextureRenderable | null; getRenderableByAlias(alias: string): ITextureRenderable | null;
/**
*
* @param identifier
*/
getBlockCls(identifier: number): BlockCls;
/**
*
* @param alias id
*/
getBlockClsByAlias(alias: string): BlockCls;
/** /**
* *
* @param alias id * @param alias id
@ -340,24 +405,6 @@ export interface IMaterialManager {
* @param image `bigImage` * @param image `bigImage`
*/ */
setBigImage(identifier: number, image: ITexture): IBigImageData; 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 { export interface IAssetBuilder {