Glyph Bank Naming Alignment with Runtime DEC-0006
This commit is contained in:
parent
76b5717cd8
commit
99e9102004
@ -1,4 +1,5 @@
|
|||||||
{"type":"meta","next_id":{"DSC":25,"AGD":28,"DEC":25,"PLN":48,"LSN":40,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":27,"AGD":29,"DEC":26,"PLN":49,"LSN":40,"CLSN":1}}
|
||||||
|
{"type":"discussion","id":"DSC-0026","status":"open","ticket":"glyph-bank-naming-alignment-with-runtime","title":"Glyph Bank Naming Alignment with Runtime DEC-0006","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["packer","studio","naming","asset-contract","runtime-alignment","glyph-bank"],"agendas":[{"id":"AGD-0028","file":"AGD-0028-glyph-bank-naming-alignment-with-runtime.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0025","file":"DEC-0025-glyph-bank-local-alignment-with-runtime.md","status":"in_progress","created_at":"2026-04-10","updated_at":"2026-04-10","ref_agenda":"AGD-0028"}],"plans":[{"id":"PLN-0048","file":"PLN-0048-implement-glyph-bank-local-alignment.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10","ref_decisions":["DEC-0025"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"packer-pipeline-metadata-ownership","title":"Pipeline Metadata Ownership and Runtime Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["packer","metadata","runtime-contract","tooling","studio"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0025-packer-pipeline-metadata-ownership/LSN-0039-runtime-header-boundary-and-tooling-owned-pipeline-metadata.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"packer-pipeline-metadata-ownership","title":"Pipeline Metadata Ownership and Runtime Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["packer","metadata","runtime-contract","tooling","studio"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0025-packer-pipeline-metadata-ownership/LSN-0039-runtime-header-boundary-and-tooling-owned-pipeline-metadata.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||||
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"jacoco-reports-consolidation","title":"JaCoCo Reports Consolidation in Gradle","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["infra","gradle","jacoco","coverage","jenkins"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0038","file":"discussion/lessons/DSC-0024-jacoco-reports-consolidation/LSN-0038-jacoco-reports-consolidation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"jacoco-reports-consolidation","title":"JaCoCo Reports Consolidation in Gradle","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["infra","gradle","jacoco","coverage","jenkins"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0038","file":"discussion/lessons/DSC-0024-jacoco-reports-consolidation/LSN-0038-jacoco-reports-consolidation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
||||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
||||||
|
|||||||
@ -20,8 +20,8 @@ This lesson preserves the first-wave producer contract for tile-bank assets.
|
|||||||
|
|
||||||
### Tile bank packing emits one canonical payload per asset with explicit normalization and early structural validation
|
### Tile bank packing emits one canonical payload per asset with explicit normalization and early structural validation
|
||||||
|
|
||||||
**What:** The first-wave contract emits one canonical `TILES/indexed_v1` payload per asset, normalizes artifacts by explicit `artifacts[*].index`, packs one fixed `256 x 256` row-major sheet with packed `u4` pixels and `RGB565` palette blocks, treats palette identity as semantic rather than positional, and surfaces structural blockers early in walker/materialization.
|
**What:** The first-wave contract emits one canonical `GLYPH/indexed_v1` payload per asset, normalizes artifacts by explicit `artifacts[*].index`, packs one fixed `256 x 256` row-major sheet with packed `u4` pixels and `RGB565` palette blocks, treats palette identity as semantic rather than positional, and surfaces structural blockers early in walker/materialization.
|
||||||
**Why:** The repository needed one explicit producer contract for tile banks rather than a mix of implicit artifact ordering, late byte-emission surprises, and unstable palette identity.
|
**Why:** The repository needed one explicit producer contract for glyph banks rather than a mix of implicit artifact ordering, late byte-emission surprises, and unstable palette identity.
|
||||||
**Trade-offs:** This contract is more explicit and restrictive than ad hoc per-artifact packing, but it yields stable reviewability, predictable runtime metadata, and earlier validation.
|
**Trade-offs:** This contract is more explicit and restrictive than ad hoc per-artifact packing, but it yields stable reviewability, predictable runtime metadata, and earlier validation.
|
||||||
|
|
||||||
## Patterns and Algorithms
|
## Patterns and Algorithms
|
||||||
|
|||||||
@ -16,7 +16,7 @@ tags:
|
|||||||
|
|
||||||
## Pain
|
## Pain
|
||||||
|
|
||||||
Studio already has a retained agenda for palette management in the `tile bank` form session, but that agenda exists only under `docs/studio/agendas/` and therefore sits outside the discussion-framework lifecycle.
|
Studio already has a retained agenda for palette management in the `glyph bank` form session, but that agenda exists only under `docs/studio/agendas/` and therefore sits outside the discussion-framework lifecycle.
|
||||||
|
|
||||||
Without importing it into `discussion/`, the canonical discussion surface would lose the still-open Studio question about:
|
Without importing it into `discussion/`, the canonical discussion surface would lose the still-open Studio question about:
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ Legacy source: `docs/studio/agendas/Palette Management in Studio Agenda.md`
|
|||||||
Domain owner: `docs/studio`
|
Domain owner: `docs/studio`
|
||||||
Cross-domain impact: `docs/packer`
|
Cross-domain impact: `docs/packer`
|
||||||
|
|
||||||
The retained agenda is intentionally scoped to `tile bank`.
|
The retained agenda is intentionally scoped to `glyph bank`.
|
||||||
|
|
||||||
The imported context keeps the same baseline:
|
The imported context keeps the same baseline:
|
||||||
|
|
||||||
- every `*.png` input of a tile bank is one tile;
|
- every `*.png` input of a glyph bank is one tile;
|
||||||
- each tile yields one extracted palette during cache construction;
|
- each tile yields one extracted palette during cache construction;
|
||||||
- developers may also work with favorite palettes and asset palettes;
|
- developers may also work with favorite palettes and asset palettes;
|
||||||
- each bank may integrate at most `64` palettes;
|
- each bank may integrate at most `64` palettes;
|
||||||
@ -57,8 +57,8 @@ The current UI shape already converged on:
|
|||||||
- [ ] Should extracted tile palettes always enter the candidate set automatically, or can the developer suppress some of them before curation?
|
- [ ] Should extracted tile palettes always enter the candidate set automatically, or can the developer suppress some of them before curation?
|
||||||
- [ ] Should clicking a palette on the `selected` side be the only interaction needed to change the previewed palette in the first wave?
|
- [ ] Should clicking a palette on the `selected` side be the only interaction needed to change the previewed palette in the first wave?
|
||||||
- [ ] Which palette operations are read-only in the first wave, and which require staged preview/apply treatment?
|
- [ ] Which palette operations are read-only in the first wave, and which require staged preview/apply treatment?
|
||||||
- [ ] Which parts of this interaction model should remain explicitly `tile bank`-specific, and which parts are reusable Studio form-session primitives?
|
- [ ] Which parts of this interaction model should remain explicitly `glyph bank`-specific, and which parts are reusable Studio form-session primitives?
|
||||||
- [ ] Does the first release need only an asset-scoped `tile bank` section, or also a project-level palette browser for discovery and favorites management?
|
- [ ] Does the first release need only an asset-scoped `glyph bank` section, or also a project-level palette browser for discovery and favorites management?
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ The current UI shape already converged on:
|
|||||||
|
|
||||||
### Option B - Asset-Scoped Curated Selection
|
### Option B - Asset-Scoped Curated Selection
|
||||||
- **Approach:** Treat bank palettes as an asset-scoped curated selection built from tile-derived palettes, favorites, and asset palettes, with Studio owning the curation UX and packer owning persistence.
|
- **Approach:** Treat bank palettes as an asset-scoped curated selection built from tile-derived palettes, favorites, and asset palettes, with Studio owning the curation UX and packer owning persistence.
|
||||||
- **Pro:** Matches the concrete `tile bank` workflow and keeps authority boundaries clear.
|
- **Pro:** Matches the concrete `glyph bank` workflow and keeps authority boundaries clear.
|
||||||
- **Con:** Requires explicit UX for capacity, identity, deduplication, and preview semantics.
|
- **Con:** Requires explicit UX for capacity, identity, deduplication, and preview semantics.
|
||||||
- **Maintainability:** Strong. It makes responsibilities explicit and keeps family-specific rules close to the workflow that needs them.
|
- **Maintainability:** Strong. It makes responsibilities explicit and keeps family-specific rules close to the workflow that needs them.
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ The current UI shape already converged on:
|
|||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
The imported agenda keeps the original recommendation intact: palette management should be first-class for `tile bank`, but Studio must not become the persistence authority.
|
The imported agenda keeps the original recommendation intact: palette management should be first-class for `glyph bank`, but Studio must not become the persistence authority.
|
||||||
|
|
||||||
That means the key open problem is not whether palettes exist. It is how Studio explains and curates them safely:
|
That means the key open problem is not whether palettes exist. It is how Studio explains and curates them safely:
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ That means the key open problem is not whether palettes exist. It is how Studio
|
|||||||
- clear source and identity display;
|
- clear source and identity display;
|
||||||
- explicit `1..64` capacity feedback;
|
- explicit `1..64` capacity feedback;
|
||||||
- a preview model that stays tied to the selected bank palettes;
|
- a preview model that stays tied to the selected bank palettes;
|
||||||
- a boundary between `tile bank`-specific UX and reusable Studio primitives.
|
- a boundary between `glyph bank`-specific UX and reusable Studio primitives.
|
||||||
|
|
||||||
The retained source already converged on a pragmatic first wave:
|
The retained source already converged on a pragmatic first wave:
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ Recommended direction: adopt **Option B**.
|
|||||||
|
|
||||||
The imported agenda preserves the retained Studio direction:
|
The imported agenda preserves the retained Studio direction:
|
||||||
|
|
||||||
1. palette management belongs to the `tile bank` asset workflow;
|
1. palette management belongs to the `glyph bank` asset workflow;
|
||||||
2. Studio aggregates candidate palettes from tile-derived extraction, favorites, and asset palettes;
|
2. Studio aggregates candidate palettes from tile-derived extraction, favorites, and asset palettes;
|
||||||
3. the first wave uses a custom-rendered transfer list with an explicit `1..64` selected range;
|
3. the first wave uses a custom-rendered transfer list with an explicit `1..64` selected range;
|
||||||
4. the right-side preview panel stays tied to the current selected palette set;
|
4. the right-side preview panel stays tied to the current selected palette set;
|
||||||
|
|||||||
@ -53,7 +53,7 @@ The packer now exposes:
|
|||||||
### Option A - Keep fixed 64-palette serialization
|
### Option A - Keep fixed 64-palette serialization
|
||||||
- **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots.
|
- **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots.
|
||||||
- **Pro:** No runtime change and current specs/tests remain stable.
|
- **Pro:** No runtime change and current specs/tests remain stable.
|
||||||
- **Con:** Every tile bank keeps paying the full palette cost.
|
- **Con:** Every glyph bank keeps paying the full palette cost.
|
||||||
- **Maintainability:** Medium.
|
- **Maintainability:** Medium.
|
||||||
|
|
||||||
### Option B - Move to variable palette serialization now
|
### Option B - Move to variable palette serialization now
|
||||||
|
|||||||
@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
id: AGD-0028
|
||||||
|
ticket: glyph-bank-naming-alignment-with-runtime
|
||||||
|
title: Glyph Bank Naming Alignment with Runtime DEC-0006
|
||||||
|
status: accepted
|
||||||
|
created: 2026-04-10
|
||||||
|
resolved: 2026-04-10
|
||||||
|
decision: DEC-0025
|
||||||
|
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pain
|
||||||
|
|
||||||
|
O runtime já aceitou a `DEC-0006` em `../runtime`, travando que o artefato gráfico concreto hoje chamado `GlyphBank` passa a ser canonicamente `GlyphBank`, com `BankType::GLYPH`, sem renomear `TileMap`, `TileLayer` ou `TileSize`.
|
||||||
|
|
||||||
|
Este repositório ainda usa vocabulário centrado em `glyph bank` no contrato de asset, nas specs do packer, em partes do Studio e nos fixtures. Se esse repositório não alinhar a nomenclatura, o ecossistema passa a operar com contrato misto entre `runtime` e `studio/packer`, exatamente o estado que a decisão upstream proibiu para superfícies ativas.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
1. A decisão externa de referência é `../runtime/discussion/workflow/decisions/DEC-0006-glyph-bank-domain-naming-contract.md`.
|
||||||
|
2. Ela define que a mudança é **rename-only**: sem alterar formato, layout, payload, codec, metadata ou semântica de renderização.
|
||||||
|
3. Ela também fixa o boundary editorial:
|
||||||
|
- o artefato gráfico concreto migra para `GlyphBank` / `Glyph*`;
|
||||||
|
- conceitos geométricos e de mapa/camada continuam `tile`.
|
||||||
|
4. Neste repositório, os impactos visíveis hoje incluem:
|
||||||
|
- `AssetFamilyCatalog.TILE_BANK`;
|
||||||
|
- `OutputFormatCatalog.TILES_INDEXED_V1`;
|
||||||
|
- specs que falam em `tile_bank`, `TILES/indexed_v1` e `bank_type = TILES`;
|
||||||
|
- classes e testes do Studio/Packer nomeados como `TileBank`;
|
||||||
|
- fixtures e `asset.json` de teste usando `type = tile_bank` e `format = TILES/indexed_v1`.
|
||||||
|
5. O owner primário aqui parece ser `packer`, com impacto explícito também em `studio`.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
- [x] O alinhamento local deve migrar o contrato serializado imediatamente para `glyph_bank` / `GLYPH/indexed_v1` / `bank_type = GLYPH`, ou precisamos de uma fase explícita de compatibilidade de leitura para manifests e fixtures legados?
|
||||||
|
Resposta: migrar imediatamente o contrato serializado. Não haverá fase de compatibilidade.
|
||||||
|
- [x] O `AssetFamilyCatalog.TILE_BANK` deve ser renomeado no código local junto com o contrato serializado, ou o código pode adotar uma estratégia temporária de alias interno sem expor vocabulário misto nas superfícies mantidas?
|
||||||
|
Resposta: renomear junto com o contrato serializado. Não haverá alias nem camada de compatibilidade.
|
||||||
|
- [x] Quais superfícies do Studio ainda são realmente específicas do artefato concreto e devem virar `Glyph*`, e quais continuam corretamente no domínio geométrico `tile`?
|
||||||
|
Resposta: o Studio deve seguir a nomenclatura 1:1 do artefato concreto. Superfícies do artefato concreto migram para `Glyph*`; conceitos geométricos continuam `tile`.
|
||||||
|
- [x] O rename local deve ser tratado como uma única wave transversal `packer + studio + specs + fixtures`, ou precisamos fatiar entre contrato serializado e nomenclatura interna?
|
||||||
|
Resposta: uma única wave transversal. Trata-se de rename-only, sem mudança funcional.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### Option A - Full Local Alignment with Runtime Naming
|
||||||
|
- **Approach:** Migrar as superfícies mantidas deste repositório para `GlyphBank`/`glyph_bank`/`GLYPH` de forma consistente, preservando `tile` apenas onde o significado é geométrico ou de mapa/camada.
|
||||||
|
- **Pro:** Alinha totalmente com a `DEC-0006` upstream e elimina vocabulário misto entre repositórios ativos.
|
||||||
|
- **Con:** Toca contrato serializado, fixtures, specs e nomes internos ao mesmo tempo.
|
||||||
|
- **Maintainability:** Alta, porque reduz ambiguidade estrutural entre artifact bank e tile-domain concepts.
|
||||||
|
|
||||||
|
### Option B - Compatibility Alias Around a Deferred Rename
|
||||||
|
- **Approach:** Aceitar a direção do runtime, mas manter `tile_bank` / `TILES/indexed_v1` como contrato serializado temporário neste repositório, renomeando só docs e algumas APIs internas por enquanto.
|
||||||
|
- **Pro:** Reduz churn imediato no packer e nos fixtures.
|
||||||
|
- **Con:** Mantém exatamente o vocabulário misto que a decisão upstream quer evitar nas superfícies ativas.
|
||||||
|
- **Maintainability:** Baixa, porque exige conviver com dois nomes para o mesmo artefato concreto.
|
||||||
|
|
||||||
|
### Option C - Editorial Alignment Only
|
||||||
|
- **Approach:** Atualizar apenas specs/lessons/discussion docs para refletir `GlyphBank`, mantendo código e contrato serializado locais como estão até uma wave futura.
|
||||||
|
- **Pro:** Menor custo inicial.
|
||||||
|
- **Con:** Cria desalinhamento entre documentação e implementação local, além de não resolver o contrato ativo.
|
||||||
|
- **Maintainability:** Baixa, porque transforma o problema em dívida operacional documentada em vez de resolvê-lo.
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
A `DEC-0006` do runtime já fechou o ponto conceitual mais importante: `tile` ficou reservado para mapa/camada/geometria, enquanto o banco gráfico concreto passa a ser `glyph`.
|
||||||
|
|
||||||
|
O que continua aberto neste repositório não é a direção conceitual, mas a estratégia local de propagação:
|
||||||
|
|
||||||
|
- se o packer deve mudar o contrato serializado já nesta wave;
|
||||||
|
- se precisamos de leitura compatível para assets/fixtures legados;
|
||||||
|
- como separar corretamente as classes/strings do Studio entre domínio concreto de banco e domínio geométrico.
|
||||||
|
|
||||||
|
O risco dominante é fazer rename mecânico. Aqui, assim como no runtime, há superfícies onde `tile` ainda é o nome certo.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
|
||||||
|
Recomendação consolidada: seguir integralmente a direção da `DEC-0006` do runtime e emitir uma decisão local owner `packer`, com impacto explícito em `studio`, para alinhar este repositório ao novo nome canônico do artefato concreto.
|
||||||
|
|
||||||
|
A resolução desta agenda fica:
|
||||||
|
|
||||||
|
1. o contrato serializado local migra imediatamente para `glyph_bank`, `GLYPH/indexed_v1` e `bank_type = GLYPH`;
|
||||||
|
2. não haverá camada de compatibilidade, alias interno, nem fase de leitura legada para o vocabulário antigo;
|
||||||
|
3. o Studio deve seguir a nomenclatura do artefato concreto em modo 1:1;
|
||||||
|
4. `tile` permanece apenas onde o significado for geométrico, de layer ou de map;
|
||||||
|
5. a propagação local será uma única wave transversal em `packer + studio + specs + fixtures`;
|
||||||
|
6. a mudança é estritamente rename-only, sem alteração de formato, layout, payload, metadata, codec ou comportamento.
|
||||||
|
|
||||||
|
Próximo passo sugerido: converter esta agenda em decisão local e travar os propagation targets para `packer`, `studio`, specs e fixtures.
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
id: DEC-0025
|
||||||
|
ticket: glyph-bank-naming-alignment-with-runtime
|
||||||
|
title: Glyph Bank Local Alignment with Runtime
|
||||||
|
status: in_progress
|
||||||
|
created: 2026-04-10
|
||||||
|
accepted: 2026-04-10
|
||||||
|
agenda: AGD-0028
|
||||||
|
plans: [PLN-0048]
|
||||||
|
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
This repository MUST align its active `packer` and `studio` surfaces with the runtime naming contract accepted in `../runtime` `DEC-0006`.
|
||||||
|
|
||||||
|
The concrete graphical bank artifact currently referred to locally through `tile bank`, `TileBank`, `tile_bank`, `TILES/indexed_v1`, and `bank_type = TILES` MUST migrate to `GlyphBank`, `glyph_bank`, `GLYPH/indexed_v1`, and `bank_type = GLYPH`, according to the surface involved.
|
||||||
|
|
||||||
|
This migration MUST be treated as rename-only. It MUST NOT change payload layout, metadata semantics, codec behavior, packing behavior, runtime contract meaning, Studio behavior, or any other functional behavior.
|
||||||
|
|
||||||
|
The migration MUST happen as one single transversal wave across `packer`, `studio`, specs, fixtures, tests, and maintained discussion/lesson surfaces in this repository.
|
||||||
|
|
||||||
|
There MUST NOT be a compatibility layer, alias, fallback parser, or dual-vocabulary phase for the previous `tile bank` naming on active maintained surfaces.
|
||||||
|
|
||||||
|
`tile` MUST remain in place wherever the correct meaning is geometric, map-related, layer-related, or otherwise outside the concrete graphical bank artifact boundary.
|
||||||
|
|
||||||
|
Studio MUST follow the concrete artifact naming 1:1 for the renamed artifact surfaces. It MUST NOT keep local alternative terminology for the same artifact.
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
The upstream runtime decision already closed the conceptual split between the concrete graphical bank artifact and the broader tile-domain vocabulary.
|
||||||
|
|
||||||
|
If this repository keeps the old local naming while the runtime adopts `GlyphBank`, the project enters a mixed-contract state where active repositories describe the same concrete artifact through incompatible names. That directly undermines the purpose of the upstream decision.
|
||||||
|
|
||||||
|
A no-compatibility, single-wave rename is the only option that preserves one active canonical vocabulary instead of institutionalizing drift between specs, fixtures, code, and UI.
|
||||||
|
|
||||||
|
Keeping `tile` only where the meaning is geometric or map/layer-oriented preserves the domain distinction that motivated the runtime decision in the first place.
|
||||||
|
|
||||||
|
## Technical Specification
|
||||||
|
|
||||||
|
1. The canonical local asset-family name for the concrete graphical bank artifact MUST migrate from `tile_bank` to `glyph_bank`.
|
||||||
|
2. The canonical local output format name for the concrete graphical bank artifact MUST migrate from `TILES/indexed_v1` to `GLYPH/indexed_v1`.
|
||||||
|
3. The canonical runtime-facing `bank_type` value emitted by the packer for the concrete graphical bank artifact MUST migrate from `TILES` to `GLYPH`.
|
||||||
|
4. Code symbols, class names, helpers, tests, and maintained strings that refer to the concrete graphical bank artifact MUST migrate from `Tile*`/`tile bank` naming to `Glyph*`/`glyph bank` naming as appropriate to the local language surface.
|
||||||
|
5. Specs and maintained lessons/docs in this repository MUST describe the concrete graphical bank artifact using `Glyph*` naming after the migration.
|
||||||
|
6. `tile` naming MUST remain unchanged in surfaces that describe geometric tile size, tile layers, tile maps, grid semantics, or other non-artifact tile-domain concepts.
|
||||||
|
7. Implementations MUST NOT preserve active dual support for both `tile bank` and `glyph bank` terminology in the serialized contract.
|
||||||
|
8. Fixtures and test assets maintained by this repository MUST migrate to the new serialized contract names in the same wave as the implementation.
|
||||||
|
9. This decision does not authorize any behavior change beyond naming propagation.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- No compatibility parser or alias layer for the old serialized names.
|
||||||
|
- No staged split between `packer` and `studio`; the rename is one coordinated wave.
|
||||||
|
- No rename of geometric or map/layer `tile` concepts.
|
||||||
|
- No change to payload bytes, metadata structure, codec semantics, or packing algorithms as part of this decision.
|
||||||
|
|
||||||
|
## Propagation Targets
|
||||||
|
|
||||||
|
- Specs:
|
||||||
|
- Update packer specs that currently define `tile_bank`, `TILES/indexed_v1`, or `bank_type = TILES`.
|
||||||
|
- Update Studio-facing maintained discussion/spec text where the concrete artifact is still described as `tile bank`.
|
||||||
|
- Code:
|
||||||
|
- Rename local packer asset-family, output-format, and emitted bank-type surfaces to the new canonical glyph naming.
|
||||||
|
- Rename Studio artifact-specific composition/support/coordinator surfaces that refer to the concrete graphical bank artifact.
|
||||||
|
- Preserve `tile` naming in geometric and map/layer surfaces.
|
||||||
|
- Tests and Fixtures:
|
||||||
|
- Update fixtures and test manifests that still serialize the old `tile_bank` and `TILES/indexed_v1` contract.
|
||||||
|
- Update tests and helper names to remove mixed vocabulary for the concrete artifact.
|
||||||
|
- Docs and Lessons:
|
||||||
|
- Rewrite maintained lessons and active workflow artifacts by meaning, not mechanical token replacement.
|
||||||
|
|
||||||
|
## Revision Log
|
||||||
|
|
||||||
|
- 2026-04-10: Accepted and linked to PLN-0048 for implementation planning.
|
||||||
|
- 2026-04-10: Initial draft from AGD-0028.
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0048
|
||||||
|
ticket: glyph-bank-naming-alignment-with-runtime
|
||||||
|
title: Implement Glyph Bank Local Alignment
|
||||||
|
status: done
|
||||||
|
created: 2026-04-10
|
||||||
|
completed: 2026-04-10
|
||||||
|
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Implement DEC-0025 by renaming the concrete graphical bank artifact from `tile bank` to `glyph bank` across active `packer` and `studio` code, serialized contract surfaces, specs, fixtures, tests, and maintained repository documentation, with no compatibility layer and no functional behavior change.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
The runtime repository already accepted `DEC-0006`, which reserves `tile` for geometric, map, and layer concepts while moving the concrete graphical bank artifact to `GlyphBank` and `GLYPH`. This repository still exposes the old naming through local asset-family values, output formats, emitted bank types, Studio asset-family handling, specs, and fixtures. The accepted local decision locks a one-wave rename with no fallback parsing, no aliasing, and no staged split between `packer` and `studio`.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### Included
|
||||||
|
- Rename the serialized asset-family contract from `tile_bank` to `glyph_bank`.
|
||||||
|
- Rename the serialized output-format contract from `TILES/indexed_v1` to `GLYPH/indexed_v1`.
|
||||||
|
- Rename emitted runtime-facing `bank_type` values from `TILES` to `GLYPH`.
|
||||||
|
- Rename packer and Studio artifact-specific code surfaces that still describe the concrete graphical bank as `Tile*` or `glyph bank`.
|
||||||
|
- Update fixtures, tests, specs, and maintained lessons/discussion artifacts that refer to the concrete graphical bank artifact.
|
||||||
|
- Preserve `tile` terminology where the meaning remains geometric, map-related, layer-related, or otherwise outside the artifact boundary.
|
||||||
|
|
||||||
|
### Excluded
|
||||||
|
- Any payload, layout, metadata, codec, or packing behavior change.
|
||||||
|
- Any compatibility parser, alias layer, or dual support for the previous serialized names.
|
||||||
|
- Renaming geometric tile-size concepts or map/layer terminology that is still semantically correct.
|
||||||
|
- Any broader runtime-side rename work already owned by `../runtime`.
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1 - Rename the packer serialized contract surface
|
||||||
|
|
||||||
|
**What:** Migrate the local packer contract enums and parser-facing surfaces from `tile_bank` / `TILES/indexed_v1` / `TILES` to `glyph_bank` / `GLYPH/indexed_v1` / `GLYPH`.
|
||||||
|
**How:** Rename `AssetFamilyCatalog.TILE_BANK`, `OutputFormatCatalog.TILES_INDEXED_V1`, parser validation strings, materialized `bank_type` values, and any packer-owned contract constants or messages tied to the concrete artifact. Keep semantics unchanged and do not introduce compatibility parsing for the old names.
|
||||||
|
**File(s):** `prometeu-packer/prometeu-packer-api/src/main/java/p/packer/messages/assets/AssetFamilyCatalog.java`; `prometeu-packer/prometeu-packer-api/src/main/java/p/packer/messages/assets/OutputFormatCatalog.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDeclarationParser.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerOutputContractCatalog.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
|
||||||
|
**Dependencies:** None.
|
||||||
|
|
||||||
|
### Step 2 - Rename packer artifact-specific implementation surfaces
|
||||||
|
|
||||||
|
**What:** Rename packer implementation types, walkers, requirements, helper methods, and diagnostics that describe the concrete graphical bank artifact.
|
||||||
|
**How:** Rename artifact-specific `TileBank` classes, helpers, and strings to `Glyph*` equivalents while preserving `tile` in geometric concepts such as `tileSize`. Adjust callsites consistently so active code no longer uses mixed vocabulary for the concrete artifact.
|
||||||
|
**File(s):** `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/models/PackerGlyphBankRequirements.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
|
||||||
|
**Dependencies:** Step 1.
|
||||||
|
|
||||||
|
### Step 3 - Rename Studio artifact-specific surfaces 1:1
|
||||||
|
|
||||||
|
**What:** Align Studio asset-family handling, bank composition support, palette overhauling gating, list/details presentation, and artifact labels with the new glyph naming.
|
||||||
|
**How:** Rename Studio classes, switches, and i18n keys/labels that refer to the concrete graphical bank artifact, keeping the rename artifact-specific and preserving any remaining geometric `tile` semantics outside that boundary. Studio must use the same canonical artifact vocabulary as the packer contract.
|
||||||
|
**File(s):** `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetDetailsGlyphBankCompositionFamilySupport.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetBankCapacityService.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetDetailsBankCompositionCoordinator.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/palette/AssetDetailsPaletteOverhaulingCoordinator.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/AssetDetailsUiSupport.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/list/AssetListItemControl.java`; `prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java`
|
||||||
|
**Dependencies:** Steps 1 and 2.
|
||||||
|
|
||||||
|
### Step 4 - Update specs, lessons, and maintained discussion text by meaning
|
||||||
|
|
||||||
|
**What:** Rewrite maintained documentation so the concrete graphical bank artifact uses glyph naming, while tile-domain concepts remain tile-domain concepts.
|
||||||
|
**How:** Update packer specs and maintained lessons/discussions manually by artifact meaning. Replace artifact-specific `tile bank` references with `glyph bank`, `glyph_bank`, `GLYPH/indexed_v1`, or `GLYPH` as appropriate, but preserve `tile` where it refers to tile geometry, tilemaps, layers, or palette-per-tile semantics.
|
||||||
|
**File(s):** `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`; `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`; `discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md`; `discussion/workflow/agendas/AGD-0002-palette-management-in-studio.md`; `discussion/workflow/agendas/AGD-0005-variable-tile-bank-palette-serialization.md`
|
||||||
|
**Dependencies:** Step 1.
|
||||||
|
|
||||||
|
### Step 5 - Migrate fixtures and tests in the same wave
|
||||||
|
|
||||||
|
**What:** Rename manifests, fixture content, test expectations, and helper names to the new serialized contract and artifact vocabulary.
|
||||||
|
**How:** Update test assets and fixtures that still use `type = tile_bank` and `format = TILES/indexed_v1`, then update unit and integration tests in `prometeu-packer` and `prometeu-studio` so expectations point to `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH`. Keep assertion coverage focused on proving no behavior change beyond naming.
|
||||||
|
**File(s):** `test-projects/main/assets/**/asset.json`; `prometeu-packer/prometeu-packer-v1/src/test/resources/fixtures/workspaces/**/asset.json`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDeclarationParserTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDetailsServiceTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/FileSystemPackerWorkspaceServiceTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerGlyphBankWalkerTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerRuntimeAssetMaterializerTest.java`; `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/bank/AssetDetailsBankCompositionCoordinatorTest.java`; `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/palette/AssetDetailsPaletteOverhaulingCoordinatorTest.java`
|
||||||
|
**Dependencies:** Steps 1 through 4.
|
||||||
|
|
||||||
|
### Step 6 - Validate the one-wave rename
|
||||||
|
|
||||||
|
**What:** Run focused verification across packer and Studio to prove the new vocabulary is canonical and behavior is unchanged.
|
||||||
|
**How:** Execute the relevant test suites, review representative specs/fixtures, and search for residual concrete-artifact `tile bank` references. Classify any remaining `tile` occurrence as either correct geometric/domain meaning or a rename miss to be fixed before completion.
|
||||||
|
**File(s):** all files touched by Steps 1 through 5
|
||||||
|
**Dependencies:** Steps 1 through 5.
|
||||||
|
|
||||||
|
## Test Requirements
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
- Update packer parser, walker, materializer, and workspace-service tests to use `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH`.
|
||||||
|
- Update Studio asset-details and palette/bank tests to use the renamed artifact-family symbols and labels.
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
- Run packer tests that exercise manifest parsing, fixture loading, pack execution, and emitted `bank_type` values.
|
||||||
|
- Run Studio tests that exercise asset-family-specific bank composition and palette overhauling paths.
|
||||||
|
|
||||||
|
### Manual Verification
|
||||||
|
|
||||||
|
- Inspect updated packer specs to confirm artifact-specific references use glyph naming while geometric tile concepts remain unchanged.
|
||||||
|
- Search the repository for residual `tile bank` / `TileBank` / `tile_bank` / `TILES/indexed_v1` references and classify each remaining hit.
|
||||||
|
- Inspect representative fixture manifests and packed output expectations to confirm the rename is contract-wide and behavior-preserving.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] Active local serialized contract surfaces use `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH` for the concrete graphical bank artifact.
|
||||||
|
- [ ] No compatibility layer or alias remains for the old serialized names on active maintained surfaces.
|
||||||
|
- [ ] Packer artifact-specific code no longer uses mixed `Tile*`/`Glyph*` vocabulary for the same concrete artifact.
|
||||||
|
- [ ] Studio artifact-specific code follows the renamed glyph vocabulary 1:1.
|
||||||
|
- [ ] Maintained specs and lessons describe the concrete graphical bank artifact with glyph naming while preserving geometric/map/layer tile terminology where appropriate.
|
||||||
|
- [ ] Fixtures and tests are migrated in the same wave as the implementation.
|
||||||
|
- [ ] Relevant packer and Studio tests pass after the rename.
|
||||||
|
- [ ] No functional behavior change is introduced beyond naming propagation.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Accepted decision `DEC-0025`.
|
||||||
|
- Upstream runtime naming contract in `../runtime` `DEC-0006`.
|
||||||
|
- Coordinated updates across `prometeu-packer`, `prometeu-studio`, maintained docs, and fixture manifests.
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
|
||||||
|
- Blind mechanical renaming can incorrectly touch geometric tile semantics that are explicitly out of scope.
|
||||||
|
- Removing old serialized names without compatibility means any missed fixture or parser path will fail fast and block the wave.
|
||||||
|
- Studio and packer may drift if one side is renamed more aggressively than the other during implementation.
|
||||||
|
- Historical or maintained discussion artifacts can keep mixed terminology if they are not reviewed semantically.
|
||||||
@ -58,7 +58,7 @@ Rules:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
- `tile_bank`
|
- `glyph_bank`
|
||||||
- `sound_bank`
|
- `sound_bank`
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
@ -203,7 +203,7 @@ The `asset.json` schema is versioned independently from:
|
|||||||
- runtime-facing artifact schema
|
- runtime-facing artifact schema
|
||||||
- format contract versions
|
- format contract versions
|
||||||
|
|
||||||
Format-specific contracts evolve through values such as `TILES/indexed_v1`.
|
Format-specific contracts evolve through values such as `GLYPH/indexed_v1`.
|
||||||
|
|
||||||
## Non-Goals
|
## Non-Goals
|
||||||
|
|
||||||
|
|||||||
@ -145,15 +145,15 @@ Offset ambiguity guardrail:
|
|||||||
- internal pipeline indexing data (for example per-sample ranges for audio banks) must live under `asset_table[].metadata`;
|
- internal pipeline indexing data (for example per-sample ranges for audio banks) must live under `asset_table[].metadata`;
|
||||||
- internal indexing fields must not be interpreted as payload slicing fields.
|
- internal indexing fields must not be interpreted as payload slicing fields.
|
||||||
|
|
||||||
## Format-Specific Baseline: `TILES/indexed_v1`
|
## Format-Specific Baseline: `GLYPH/indexed_v1`
|
||||||
|
|
||||||
The first-wave producer contract for `TILES/indexed_v1` is fixed and runtime-aligned.
|
The first-wave producer contract for `GLYPH/indexed_v1` is fixed and runtime-aligned.
|
||||||
|
|
||||||
### Tile Selection and Identity
|
### Tile Selection and Identity
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- only selected artifacts participate in the emitted tile bank;
|
- only selected artifacts participate in the emitted glyph bank;
|
||||||
- `1 artifact = 1 tile` in v1;
|
- `1 artifact = 1 tile` in v1;
|
||||||
- artifacts are normalized by ascending `artifacts[*].index`;
|
- artifacts are normalized by ascending `artifacts[*].index`;
|
||||||
- emitted `tile_id` equals the normalized artifact index;
|
- emitted `tile_id` equals the normalized artifact index;
|
||||||
@ -176,7 +176,7 @@ Rules:
|
|||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- the serialized payload for `TILES/indexed_v1` is:
|
- the serialized payload for `GLYPH/indexed_v1` is:
|
||||||
1. one packed `u4` pixel plane for the full emitted sheet;
|
1. one packed `u4` pixel plane for the full emitted sheet;
|
||||||
2. one palette block of `64 * 16 * 2 = 2048` bytes;
|
2. one palette block of `64 * 16 * 2 = 2048` bytes;
|
||||||
- packed pixel bytes must be emitted by the packer, not inferred later by the runtime;
|
- packed pixel bytes must be emitted by the packer, not inferred later by the runtime;
|
||||||
@ -189,7 +189,7 @@ Rules:
|
|||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- emitted tile-bank entries use:
|
- emitted tile-bank entries use:
|
||||||
- `bank_type = TILES`
|
- `bank_type = GLYPH`
|
||||||
- `codec = NONE`
|
- `codec = NONE`
|
||||||
- tile-bank v1 metadata must expose at least:
|
- tile-bank v1 metadata must expose at least:
|
||||||
- `tile_size`
|
- `tile_size`
|
||||||
@ -208,7 +208,7 @@ Rules:
|
|||||||
- bank palettes are declared under `output.pipeline.palettes`;
|
- bank palettes are declared under `output.pipeline.palettes`;
|
||||||
- each palette declaration uses the shape `{ "index": <int>, "palette": { ... } }`;
|
- each palette declaration uses the shape `{ "index": <int>, "palette": { ... } }`;
|
||||||
- palette ordering is ascending numeric `index`, never raw array position;
|
- palette ordering is ascending numeric `index`, never raw array position;
|
||||||
- palette ids in the emitted tile bank are the normalized declared palette indices;
|
- palette ids in the emitted glyph bank are the normalized declared palette indices;
|
||||||
- any tile in the bank may be rendered with any palette in the bank at runtime;
|
- any tile in the bank may be rendered with any palette in the bank at runtime;
|
||||||
- palette selection is a runtime draw concern, not a tile-payload embedding concern.
|
- palette selection is a runtime draw concern, not a tile-payload embedding concern.
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package p.packer.messages.assets;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public enum AssetFamilyCatalog {
|
public enum AssetFamilyCatalog {
|
||||||
TILE_BANK("tile_bank"),
|
GLYPH_BANK("glyph_bank"),
|
||||||
SOUND_BANK("sound_bank"),
|
SOUND_BANK("sound_bank"),
|
||||||
UNKNOWN("unknown");
|
UNKNOWN("unknown");
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public enum OutputFormatCatalog {
|
public enum OutputFormatCatalog {
|
||||||
TILES_INDEXED_V1(AssetFamilyCatalog.TILE_BANK, "TILES/indexed_v1", "TILES/indexed_v1"),
|
GLYPH_INDEXED_V1(AssetFamilyCatalog.GLYPH_BANK, "GLYPH/indexed_v1", "GLYPH/indexed_v1"),
|
||||||
SOUND_V1(AssetFamilyCatalog.SOUND_BANK, "SOUND/v1", "SOUND/v1"),
|
SOUND_V1(AssetFamilyCatalog.SOUND_BANK, "SOUND/v1", "SOUND/v1"),
|
||||||
UNKNOWN(AssetFamilyCatalog.UNKNOWN, "unknown", "Unknown");
|
UNKNOWN(AssetFamilyCatalog.UNKNOWN, "unknown", "Unknown");
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
package p.packer.models;
|
||||||
|
|
||||||
|
public record PackerGlyphBankRequirements(int tileSize) {
|
||||||
|
}
|
||||||
@ -1,4 +0,0 @@
|
|||||||
package p.packer.models;
|
|
||||||
|
|
||||||
public record PackerTileBankRequirements(int tileSize) {
|
|
||||||
}
|
|
||||||
@ -17,21 +17,21 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class PackerAssetWalker {
|
public class PackerAssetWalker {
|
||||||
private static final int TILE_BANK_EMITTED_SHEET_SIZE = 256;
|
private static final int GLYPH_BANK_EMITTED_SHEET_SIZE = 256;
|
||||||
private static final int TILE_BANK_MAX_PALETTES = 64;
|
private static final int GLYPH_BANK_MAX_PALETTES = 64;
|
||||||
private static final Set<OutputFormatCatalog> TILE_BANK_SUPPORTED_FORMATS = Set.of(
|
private static final Set<OutputFormatCatalog> GLYPH_BANK_SUPPORTED_FORMATS = Set.of(
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1
|
OutputFormatCatalog.GLYPH_INDEXED_V1
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final Set<OutputFormatCatalog> SOUND_BANK_SUPPORTED_FORMATS = Set.of(
|
private static final Set<OutputFormatCatalog> SOUND_BANK_SUPPORTED_FORMATS = Set.of(
|
||||||
OutputFormatCatalog.SOUND_V1
|
OutputFormatCatalog.SOUND_V1
|
||||||
);
|
);
|
||||||
|
|
||||||
private final PackerTileBankWalker tileBankWalker;
|
private final PackerGlyphBankWalker glyphBankWalker;
|
||||||
private final PackerSoundBankWalker soundBankWalker;
|
private final PackerSoundBankWalker soundBankWalker;
|
||||||
|
|
||||||
public PackerAssetWalker(final ObjectMapper mapper) {
|
public PackerAssetWalker(final ObjectMapper mapper) {
|
||||||
this.tileBankWalker = new PackerTileBankWalker(mapper);
|
this.glyphBankWalker = new PackerGlyphBankWalker(mapper);
|
||||||
this.soundBankWalker = new PackerSoundBankWalker(mapper);
|
this.soundBankWalker = new PackerSoundBankWalker(mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,18 +47,18 @@ public class PackerAssetWalker {
|
|||||||
final Optional<PackerAssetCacheEntry> priorAssetCache) {
|
final Optional<PackerAssetCacheEntry> priorAssetCache) {
|
||||||
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
||||||
switch (declaration.assetFamily()) {
|
switch (declaration.assetFamily()) {
|
||||||
case TILE_BANK -> {
|
case GLYPH_BANK -> {
|
||||||
var metadata = declaration.outputMetadata();
|
var metadata = declaration.outputMetadata();
|
||||||
if (MapUtils.isEmpty(metadata)) {
|
if (MapUtils.isEmpty(metadata)) {
|
||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.WARNING,
|
PackerDiagnosticSeverity.WARNING,
|
||||||
PackerDiagnosticCategory.HYGIENE,
|
PackerDiagnosticCategory.HYGIENE,
|
||||||
"Output metadata for tile bank cannot be empty, using default values",
|
"Output metadata for glyph bank cannot be empty, using default values",
|
||||||
assetRoot,
|
assetRoot,
|
||||||
false));
|
false));
|
||||||
metadata = Map.of("tile_size", "16x16");
|
metadata = Map.of("tile_size", "16x16");
|
||||||
}
|
}
|
||||||
final var requirementBuildResult = buildTileBankRequirements(declaration, metadata);
|
final var requirementBuildResult = buildGlyphBankRequirements(declaration, metadata);
|
||||||
if (requirementBuildResult.hasError()) {
|
if (requirementBuildResult.hasError()) {
|
||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
@ -68,11 +68,11 @@ public class PackerAssetWalker {
|
|||||||
true));
|
true));
|
||||||
return new PackerWalkResult(List.of(), diagnostics);
|
return new PackerWalkResult(List.of(), diagnostics);
|
||||||
}
|
}
|
||||||
diagnostics.addAll(tileBankDeclarationDiagnostics(assetRoot, declaration, requirementBuildResult.requirements));
|
diagnostics.addAll(glyphBankDeclarationDiagnostics(assetRoot, declaration, requirementBuildResult.requirements));
|
||||||
final var walkResult = tileBankWalker.walk(assetRoot, requirementBuildResult.requirements, priorAssetCache);
|
final var walkResult = glyphBankWalker.walk(assetRoot, requirementBuildResult.requirements, priorAssetCache);
|
||||||
diagnostics.addAll(walkResult.diagnostics());
|
diagnostics.addAll(walkResult.diagnostics());
|
||||||
diagnostics.addAll(tileBankSelectedArtifactDiagnostics(assetRoot, declaration, walkResult));
|
diagnostics.addAll(glyphBankSelectedArtifactDiagnostics(assetRoot, declaration, walkResult));
|
||||||
diagnostics.addAll(tileBankFragileIndexDiagnostics(declaration, walkResult));
|
diagnostics.addAll(glyphBankFragileIndexDiagnostics(declaration, walkResult));
|
||||||
return new PackerWalkResult(walkResult.probeResults(), diagnostics);
|
return new PackerWalkResult(walkResult.probeResults(), diagnostics);
|
||||||
}
|
}
|
||||||
case SOUND_BANK -> {
|
case SOUND_BANK -> {
|
||||||
@ -81,7 +81,7 @@ public class PackerAssetWalker {
|
|||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.WARNING,
|
PackerDiagnosticSeverity.WARNING,
|
||||||
PackerDiagnosticCategory.HYGIENE,
|
PackerDiagnosticCategory.HYGIENE,
|
||||||
"Output metadata for tile bank cannot be empty, using default values",
|
"Output metadata for sound bank cannot be empty, using default values",
|
||||||
assetRoot,
|
assetRoot,
|
||||||
false));
|
false));
|
||||||
metadata = Map.of("sample_rate", "44100", "channels", "1");
|
metadata = Map.of("sample_rate", "44100", "channels", "1");
|
||||||
@ -113,15 +113,15 @@ public class PackerAssetWalker {
|
|||||||
return PackerWalkResult.EMPTY;
|
return PackerWalkResult.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequirementBuildResult<PackerTileBankRequirements> buildTileBankRequirements(
|
private RequirementBuildResult<PackerGlyphBankRequirements> buildGlyphBankRequirements(
|
||||||
final PackerAssetDeclaration declaration,
|
final PackerAssetDeclaration declaration,
|
||||||
final Map<String, String> metadata) {
|
final Map<String, String> metadata) {
|
||||||
if (!TILE_BANK_SUPPORTED_FORMATS.contains(declaration.outputFormat())) {
|
if (!GLYPH_BANK_SUPPORTED_FORMATS.contains(declaration.outputFormat())) {
|
||||||
return RequirementBuildResult.fail("Unsupported output format for tile bank: " + declaration.outputFormat());
|
return RequirementBuildResult.fail("Unsupported output format for glyph bank: " + declaration.outputFormat());
|
||||||
}
|
}
|
||||||
final var tileSizeStr = metadata.get("tile_size");
|
final var tileSizeStr = metadata.get("tile_size");
|
||||||
if (StringUtils.isBlank(tileSizeStr)) {
|
if (StringUtils.isBlank(tileSizeStr)) {
|
||||||
return RequirementBuildResult.fail("Tile size metadata for tile bank cannot be empty");
|
return RequirementBuildResult.fail("Tile size metadata for glyph bank cannot be empty");
|
||||||
}
|
}
|
||||||
final int tileSize;
|
final int tileSize;
|
||||||
switch (tileSizeStr) {
|
switch (tileSizeStr) {
|
||||||
@ -135,16 +135,16 @@ public class PackerAssetWalker {
|
|||||||
tileSize = 32;
|
tileSize = 32;
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
return RequirementBuildResult.fail("Unsupported tile size for tile bank: " + tileSizeStr);
|
return RequirementBuildResult.fail("Unsupported tile size for glyph bank: " + tileSizeStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RequirementBuildResult.success(new PackerTileBankRequirements(tileSize));
|
return RequirementBuildResult.success(new PackerGlyphBankRequirements(tileSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PackerDiagnostic> tileBankDeclarationDiagnostics(
|
private List<PackerDiagnostic> glyphBankDeclarationDiagnostics(
|
||||||
final Path assetRoot,
|
final Path assetRoot,
|
||||||
final PackerAssetDeclaration declaration,
|
final PackerAssetDeclaration declaration,
|
||||||
final PackerTileBankRequirements requirements) {
|
final PackerGlyphBankRequirements requirements) {
|
||||||
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
||||||
final List<PackerAssetArtifactSelection> artifacts = declaration.artifacts();
|
final List<PackerAssetArtifactSelection> artifacts = declaration.artifacts();
|
||||||
final Set<Integer> seenIndices = new java.util.HashSet<>();
|
final Set<Integer> seenIndices = new java.util.HashSet<>();
|
||||||
@ -169,8 +169,8 @@ public class PackerAssetWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final int tileCapacity = (TILE_BANK_EMITTED_SHEET_SIZE / requirements.tileSize())
|
final int tileCapacity = (GLYPH_BANK_EMITTED_SHEET_SIZE / requirements.tileSize())
|
||||||
* (TILE_BANK_EMITTED_SHEET_SIZE / requirements.tileSize());
|
* (GLYPH_BANK_EMITTED_SHEET_SIZE / requirements.tileSize());
|
||||||
if (artifacts.size() > tileCapacity) {
|
if (artifacts.size() > tileCapacity) {
|
||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
@ -191,18 +191,18 @@ public class PackerAssetWalker {
|
|||||||
assetRoot,
|
assetRoot,
|
||||||
true));
|
true));
|
||||||
}
|
}
|
||||||
if (declaredPalettes.size() > TILE_BANK_MAX_PALETTES) {
|
if (declaredPalettes.size() > GLYPH_BANK_MAX_PALETTES) {
|
||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
PackerDiagnosticCategory.STRUCTURAL,
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
"Tile bank cannot declare more than " + TILE_BANK_MAX_PALETTES + " palettes.",
|
"Glyph bank cannot declare more than " + GLYPH_BANK_MAX_PALETTES + " palettes.",
|
||||||
assetRoot,
|
assetRoot,
|
||||||
true));
|
true));
|
||||||
}
|
}
|
||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PackerDiagnostic> tileBankSelectedArtifactDiagnostics(
|
private List<PackerDiagnostic> glyphBankSelectedArtifactDiagnostics(
|
||||||
final Path assetRoot,
|
final Path assetRoot,
|
||||||
final PackerAssetDeclaration declaration,
|
final PackerAssetDeclaration declaration,
|
||||||
final PackerWalkResult walkResult) {
|
final PackerWalkResult walkResult) {
|
||||||
@ -225,7 +225,7 @@ public class PackerAssetWalker {
|
|||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PackerDiagnostic> tileBankFragileIndexDiagnostics(
|
private List<PackerDiagnostic> glyphBankFragileIndexDiagnostics(
|
||||||
final PackerAssetDeclaration declaration,
|
final PackerAssetDeclaration declaration,
|
||||||
final PackerWalkResult walkResult) {
|
final PackerWalkResult walkResult) {
|
||||||
final List<DeclaredPalette> declaredPalettes = declaredPalettes(declaration);
|
final List<DeclaredPalette> declaredPalettes = declaredPalettes(declaration);
|
||||||
|
|||||||
@ -7,19 +7,17 @@ import p.packer.models.*;
|
|||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBankRequirements> {
|
public class PackerGlyphBankWalker extends PackerAbstractBankWalker<PackerGlyphBankRequirements> {
|
||||||
private static final int MAX_COLORS_PER_PALETTE = 15;
|
private static final int MAX_COLORS_PER_PALETTE = 15;
|
||||||
private static final int COLOR_KEY_RGB = 0x00FF00FF;
|
private static final int COLOR_KEY_RGB = 0x00FF00FF;
|
||||||
private static final Set<String> SUPPORTED_MIME_TYPES = Set.of(
|
private static final Set<String> SUPPORTED_MIME_TYPES = Set.of(
|
||||||
"image/png"
|
"image/png"
|
||||||
);
|
);
|
||||||
|
|
||||||
public PackerTileBankWalker(ObjectMapper mapper) {
|
public PackerGlyphBankWalker(ObjectMapper mapper) {
|
||||||
super(mapper);
|
super(mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +40,7 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
|
|||||||
protected PackerProbeResult processFileProbe(
|
protected PackerProbeResult processFileProbe(
|
||||||
final PackerFileProbe fileProbe,
|
final PackerFileProbe fileProbe,
|
||||||
final Path assetRoot,
|
final Path assetRoot,
|
||||||
final PackerTileBankRequirements requirements) {
|
final PackerGlyphBankRequirements requirements) {
|
||||||
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
||||||
|
|
||||||
final var image = readImage(fileProbe, diagnostics);
|
final var image = readImage(fileProbe, diagnostics);
|
||||||
@ -63,7 +61,7 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
|
|||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
PackerDiagnosticCategory.STRUCTURAL,
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
"Invalid tile dimensions for " + fileProbe.path().getFileName()
|
"Invalid glyph dimensions for " + fileProbe.path().getFileName()
|
||||||
+ ": expected " + requirements.tileSize() + "x" + requirements.tileSize()
|
+ ": expected " + requirements.tileSize() + "x" + requirements.tileSize()
|
||||||
+ " but got " + width + "x" + height,
|
+ " but got " + width + "x" + height,
|
||||||
fileProbe.path(),
|
fileProbe.path(),
|
||||||
@ -140,7 +138,6 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
|
|||||||
return new PackerProbeResult(fileProbe, Map.of("tile", tile, "palette", palette), diagnostics);
|
return new PackerProbeResult(fileProbe, Map.of("tile", tile, "palette", palette), diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private boolean hasReusableTileMetadata(final Map<String, Object> metadata) {
|
private boolean hasReusableTileMetadata(final Map<String, Object> metadata) {
|
||||||
final Object tileValue = metadata.get("tile");
|
final Object tileValue = metadata.get("tile");
|
||||||
if (!(tileValue instanceof Map<?, ?> tile)) {
|
if (!(tileValue instanceof Map<?, ?> tile)) {
|
||||||
@ -37,7 +37,7 @@ import java.util.*;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class FileSystemPackerWorkspaceService implements PackerWorkspaceService {
|
public final class FileSystemPackerWorkspaceService implements PackerWorkspaceService {
|
||||||
private static final int TILE_BANK_COLOR_KEY_RGB565 = 0xF81F;
|
private static final int GLYPH_BANK_COLOR_KEY_RGB565 = 0xF81F;
|
||||||
|
|
||||||
private final ObjectMapper mapper;
|
private final ObjectMapper mapper;
|
||||||
private final PackerWorkspaceFoundation workspaceFoundation;
|
private final PackerWorkspaceFoundation workspaceFoundation;
|
||||||
@ -816,7 +816,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
if (declaration == null) {
|
if (declaration == null) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
if (declaration.assetFamily() == AssetFamilyCatalog.TILE_BANK) {
|
if (declaration.assetFamily() == AssetFamilyCatalog.GLYPH_BANK) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
return List.of(new PackerDiagnostic(
|
return List.of(new PackerDiagnostic(
|
||||||
@ -909,10 +909,10 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
|
|
||||||
private PackedAsset packRuntimeAsset(PackerRuntimeAsset runtimeAsset) {
|
private PackedAsset packRuntimeAsset(PackerRuntimeAsset runtimeAsset) {
|
||||||
final PackerAssetDeclaration declaration = runtimeAsset.parsedDeclaration().declaration();
|
final PackerAssetDeclaration declaration = runtimeAsset.parsedDeclaration().declaration();
|
||||||
if (declaration == null || declaration.assetFamily() != AssetFamilyCatalog.TILE_BANK) {
|
if (declaration == null || declaration.assetFamily() != AssetFamilyCatalog.GLYPH_BANK) {
|
||||||
throw new IllegalStateException("Unsupported pack output family for current implementation.");
|
throw new IllegalStateException("Unsupported pack output family for current implementation.");
|
||||||
}
|
}
|
||||||
return packTileBank(runtimeAsset, declaration);
|
return packGlyphBank(runtimeAsset, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEffectivelyIncludedInPackSet(PackerRuntimeAsset runtimeAsset) {
|
private boolean isEffectivelyIncludedInPackSet(PackerRuntimeAsset runtimeAsset) {
|
||||||
@ -923,7 +923,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
return declaration == null || !declaration.artifacts().isEmpty();
|
return declaration == null || !declaration.artifacts().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackedAsset packTileBank(PackerRuntimeAsset runtimeAsset, PackerAssetDeclaration declaration) {
|
private PackedAsset packGlyphBank(PackerRuntimeAsset runtimeAsset, PackerAssetDeclaration declaration) {
|
||||||
final int tileSize = parseTileSize(declaration.outputMetadata().get("tile_size"));
|
final int tileSize = parseTileSize(declaration.outputMetadata().get("tile_size"));
|
||||||
final int width = 256;
|
final int width = 256;
|
||||||
final int height = 256;
|
final int height = 256;
|
||||||
@ -955,7 +955,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
});
|
});
|
||||||
|
|
||||||
final byte[] packedPixels = packNibbles(sheetPixels);
|
final byte[] packedPixels = packNibbles(sheetPixels);
|
||||||
final byte[] paletteBytes = emitTileBankPalettes(declaration);
|
final byte[] paletteBytes = emitGlyphBankPalettes(declaration);
|
||||||
final byte[] payload = new byte[packedPixels.length + paletteBytes.length];
|
final byte[] payload = new byte[packedPixels.length + paletteBytes.length];
|
||||||
System.arraycopy(packedPixels, 0, payload, 0, packedPixels.length);
|
System.arraycopy(packedPixels, 0, payload, 0, packedPixels.length);
|
||||||
System.arraycopy(paletteBytes, 0, payload, packedPixels.length, paletteBytes.length);
|
System.arraycopy(paletteBytes, 0, payload, packedPixels.length, paletteBytes.length);
|
||||||
@ -965,7 +965,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
runtimeMetadata.put("width", width);
|
runtimeMetadata.put("width", width);
|
||||||
runtimeMetadata.put("height", height);
|
runtimeMetadata.put("height", height);
|
||||||
runtimeMetadata.put("palette_count", 64);
|
runtimeMetadata.put("palette_count", 64);
|
||||||
runtimeMetadata.put("palette_authored", countAuthoredTileBankPalettes(declaration));
|
runtimeMetadata.put("palette_authored", countAuthoredGlyphBankPalettes(declaration));
|
||||||
runtimeMetadata.put("codec", Map.of());
|
runtimeMetadata.put("codec", Map.of());
|
||||||
declaration.outputMetadata().forEach((key, value) -> {
|
declaration.outputMetadata().forEach((key, value) -> {
|
||||||
if (!"tile_size".equals(key)) {
|
if (!"tile_size".equals(key)) {
|
||||||
@ -981,7 +981,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
return new PackedAsset(
|
return new PackedAsset(
|
||||||
registryEntry.assetId(),
|
registryEntry.assetId(),
|
||||||
declaration.name(),
|
declaration.name(),
|
||||||
"TILES",
|
"GLYPH",
|
||||||
"NONE",
|
"NONE",
|
||||||
payload,
|
payload,
|
||||||
width * height + 2048,
|
width * height + 2048,
|
||||||
@ -1009,7 +1009,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
return packed;
|
return packed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] emitTileBankPalettes(PackerAssetDeclaration declaration) {
|
private byte[] emitGlyphBankPalettes(PackerAssetDeclaration declaration) {
|
||||||
final byte[] bytes = new byte[64 * 16 * 2];
|
final byte[] bytes = new byte[64 * 16 * 2];
|
||||||
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
|
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
|
||||||
if (!(palettesNode instanceof com.fasterxml.jackson.databind.node.ArrayNode palettesArray)) {
|
if (!(palettesNode instanceof com.fasterxml.jackson.databind.node.ArrayNode palettesArray)) {
|
||||||
@ -1026,8 +1026,8 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final int paletteBaseOffset = (paletteIndex * 16) * 2;
|
final int paletteBaseOffset = (paletteIndex * 16) * 2;
|
||||||
bytes[paletteBaseOffset] = (byte) (TILE_BANK_COLOR_KEY_RGB565 & 0xFF);
|
bytes[paletteBaseOffset] = (byte) (GLYPH_BANK_COLOR_KEY_RGB565 & 0xFF);
|
||||||
bytes[paletteBaseOffset + 1] = (byte) ((TILE_BANK_COLOR_KEY_RGB565 >>> 8) & 0xFF);
|
bytes[paletteBaseOffset + 1] = (byte) ((GLYPH_BANK_COLOR_KEY_RGB565 >>> 8) & 0xFF);
|
||||||
final JsonNode convertedNode = paletteNode.path("convertedRgb565");
|
final JsonNode convertedNode = paletteNode.path("convertedRgb565");
|
||||||
if (!convertedNode.isArray()) {
|
if (!convertedNode.isArray()) {
|
||||||
continue;
|
continue;
|
||||||
@ -1042,7 +1042,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countAuthoredTileBankPalettes(PackerAssetDeclaration declaration) {
|
private int countAuthoredGlyphBankPalettes(PackerAssetDeclaration declaration) {
|
||||||
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
|
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
|
||||||
return palettesNode instanceof ArrayNode palettesArray ? palettesArray.size() : 0;
|
return palettesNode instanceof ArrayNode palettesArray ? palettesArray.size() : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -121,7 +121,7 @@ public final class PackerAssetDeclarationParser {
|
|||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
PackerDiagnosticCategory.STRUCTURAL,
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
"Field 'type' must be one of: tile_bank, palette_bank, sound_bank.",
|
"Field 'type' must be one of: glyph_bank, palette_bank, sound_bank.",
|
||||||
manifestPath,
|
manifestPath,
|
||||||
true));
|
true));
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -29,7 +29,7 @@ final class PackerOutputContractCatalog {
|
|||||||
codecs.addAll(outputFormat.availableCodecs());
|
codecs.addAll(outputFormat.availableCodecs());
|
||||||
} else {
|
} else {
|
||||||
final String normalizedFormat = outputFormat.manifestValue().trim().toUpperCase(Locale.ROOT);
|
final String normalizedFormat = outputFormat.manifestValue().trim().toUpperCase(Locale.ROOT);
|
||||||
if (normalizedFormat.startsWith("TILES/")
|
if (normalizedFormat.startsWith("GLYPH/")
|
||||||
|| normalizedFormat.startsWith("PALETTE/")
|
|| normalizedFormat.startsWith("PALETTE/")
|
||||||
|| normalizedFormat.startsWith("SOUND/")
|
|| normalizedFormat.startsWith("SOUND/")
|
||||||
|| normalizedFormat.startsWith("AUDIO/")) {
|
|| normalizedFormat.startsWith("AUDIO/")) {
|
||||||
@ -54,7 +54,7 @@ final class PackerOutputContractCatalog {
|
|||||||
|
|
||||||
private static List<PackerCodecConfigurationField> metadataFieldsFor(OutputFormatCatalog outputFormat) {
|
private static List<PackerCodecConfigurationField> metadataFieldsFor(OutputFormatCatalog outputFormat) {
|
||||||
return switch (outputFormat) {
|
return switch (outputFormat) {
|
||||||
case TILES_INDEXED_V1 -> List.of(new PackerCodecConfigurationField(
|
case GLYPH_INDEXED_V1 -> List.of(new PackerCodecConfigurationField(
|
||||||
"tile_size",
|
"tile_size",
|
||||||
"TileSize",
|
"TileSize",
|
||||||
PackerCodecConfigurationFieldType.ENUM,
|
PackerCodecConfigurationFieldType.ENUM,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import p.packer.models.PackerAssetCacheEntry;
|
import p.packer.models.PackerAssetCacheEntry;
|
||||||
import p.packer.models.PackerFileCacheEntry;
|
import p.packer.models.PackerFileCacheEntry;
|
||||||
import p.packer.models.PackerTileIndexedV1;
|
import p.packer.models.PackerTileIndexedV1;
|
||||||
import p.packer.models.PackerTileBankRequirements;
|
import p.packer.models.PackerGlyphBankRequirements;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@ -18,7 +18,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
final class PackerTileBankWalkerTest {
|
final class PackerGlyphBankWalkerTest {
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
@TempDir
|
@TempDir
|
||||||
@ -30,7 +30,7 @@ final class PackerTileBankWalkerTest {
|
|||||||
final Path filePath = assetRoot.resolve("tile.png");
|
final Path filePath = assetRoot.resolve("tile.png");
|
||||||
writeTile(filePath);
|
writeTile(filePath);
|
||||||
|
|
||||||
final PackerTileBankWalker walker = new PackerTileBankWalker(MAPPER);
|
final PackerGlyphBankWalker walker = new PackerGlyphBankWalker(MAPPER);
|
||||||
final PackerAssetCacheEntry priorCache = new PackerAssetCacheEntry(
|
final PackerAssetCacheEntry priorCache = new PackerAssetCacheEntry(
|
||||||
1,
|
1,
|
||||||
"contract",
|
"contract",
|
||||||
@ -45,7 +45,7 @@ final class PackerTileBankWalkerTest {
|
|||||||
"palette", Map.of("originalArgb8888", List.of(0xFFFFFFFF))),
|
"palette", Map.of("originalArgb8888", List.of(0xFFFFFFFF))),
|
||||||
List.of())));
|
List.of())));
|
||||||
|
|
||||||
final var result = walker.walk(assetRoot, new PackerTileBankRequirements(16), Optional.of(priorCache));
|
final var result = walker.walk(assetRoot, new PackerGlyphBankRequirements(16), Optional.of(priorCache));
|
||||||
|
|
||||||
final PackerTileIndexedV1 tile = (PackerTileIndexedV1) result.probeResults().getFirst().metadata().get("tile");
|
final PackerTileIndexedV1 tile = (PackerTileIndexedV1) result.probeResults().getFirst().metadata().get("tile");
|
||||||
assertNotNull(tile);
|
assertNotNull(tile);
|
||||||
@ -135,9 +135,9 @@ final class PackerRuntimeAssetMaterializerTest {
|
|||||||
1,
|
1,
|
||||||
"uuid",
|
"uuid",
|
||||||
"asset",
|
"asset",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
artifacts,
|
artifacts,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
metadata,
|
metadata,
|
||||||
pipelineMetadata,
|
pipelineMetadata,
|
||||||
|
|||||||
@ -141,7 +141,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertEquals(PackerOperationStatus.SUCCESS, result.status());
|
assertEquals(PackerOperationStatus.SUCCESS, result.status());
|
||||||
assertEquals(1, result.packSummary().assets().size());
|
assertEquals(1, result.packSummary().assets().size());
|
||||||
assertEquals(1, result.packSummary().assets().getFirst().artifactCount());
|
assertEquals(1, result.packSummary().assets().getFirst().artifactCount());
|
||||||
assertEquals(OutputFormatCatalog.TILES_INDEXED_V1, result.packSummary().assets().getFirst().outputFormat());
|
assertEquals(OutputFormatCatalog.GLYPH_INDEXED_V1, result.packSummary().assets().getFirst().outputFormat());
|
||||||
assertEquals("16x16", result.packSummary().assets().getFirst().outputMetadata().get("tile_size"));
|
assertEquals("16x16", result.packSummary().assets().getFirst().outputMetadata().get("tile_size"));
|
||||||
assertEquals(64L, ((Map<?, ?>) ((Map<?, ?>) result.packSummary().assets().getFirst().outputPipeline().get("samples")).get("1")).get("length"));
|
assertEquals(64L, ((Map<?, ?>) ((Map<?, ?>) result.packSummary().assets().getFirst().outputPipeline().get("samples")).get("1")).get("length"));
|
||||||
assertEquals(0L, result.packSummary().assets().getFirst().lastModified());
|
assertEquals(0L, result.packSummary().assets().getFirst().lastModified());
|
||||||
@ -232,14 +232,14 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void packValidationBlocksTileBanksWithoutDeclaredPalettes() throws Exception {
|
void packValidationBlocksGlyphBanksWithoutDeclaredPalettes() throws Exception {
|
||||||
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-validation-no-palettes"));
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-validation-no-palettes"));
|
||||||
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
||||||
final Path manifestPath = assetRoot.resolve("asset.json");
|
final Path manifestPath = assetRoot.resolve("asset.json");
|
||||||
writeTilePng(assetRoot.resolve("confirm.png"), 16);
|
writeTilePng(assetRoot.resolve("confirm.png"), 16);
|
||||||
|
|
||||||
final ObjectNode manifest = (ObjectNode) MAPPER.readTree(manifestPath.toFile());
|
final ObjectNode manifest = (ObjectNode) MAPPER.readTree(manifestPath.toFile());
|
||||||
manifest.putObject("output").put("format", "TILES/indexed_v1").put("codec", "NONE");
|
manifest.putObject("output").put("format", "GLYPH/indexed_v1").put("codec", "NONE");
|
||||||
final var artifacts = manifest.putArray("artifacts");
|
final var artifacts = manifest.putArray("artifacts");
|
||||||
artifacts.addObject().put("file", "confirm.png").put("index", 0);
|
artifacts.addObject().put("file", "confirm.png").put("index", 0);
|
||||||
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
||||||
@ -278,7 +278,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void packWorkspaceEmitsTileBankArtifactsFromFrozenSnapshot() throws Exception {
|
void packWorkspaceEmitsGlyphBankArtifactsFromFrozenSnapshot() throws Exception {
|
||||||
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-success"));
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-success"));
|
||||||
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
||||||
final Path manifestPath = assetRoot.resolve("asset.json");
|
final Path manifestPath = assetRoot.resolve("asset.json");
|
||||||
@ -330,7 +330,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertEquals(0xF81F, readLeUnsignedShort(assetsPa, paletteStart));
|
assertEquals(0xF81F, readLeUnsignedShort(assetsPa, paletteStart));
|
||||||
assertEquals(0xF800, readLeUnsignedShort(assetsPa, paletteStart + 2));
|
assertEquals(0xF800, readLeUnsignedShort(assetsPa, paletteStart + 2));
|
||||||
assertEquals(1, assetTable.get(0).path("asset_id").asInt());
|
assertEquals(1, assetTable.get(0).path("asset_id").asInt());
|
||||||
assertEquals("TILES", assetTable.get(0).path("bank_type").asText());
|
assertEquals("GLYPH", assetTable.get(0).path("bank_type").asText());
|
||||||
assertEquals("NONE", assetTable.get(0).path("codec").asText());
|
assertEquals("NONE", assetTable.get(0).path("codec").asText());
|
||||||
assertEquals(16, assetTable.get(0).path("metadata").path("tile_size").asInt());
|
assertEquals(16, assetTable.get(0).path("metadata").path("tile_size").asInt());
|
||||||
assertEquals(256, assetTable.get(0).path("metadata").path("width").asInt());
|
assertEquals(256, assetTable.get(0).path("metadata").path("width").asInt());
|
||||||
@ -491,8 +491,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/new-atlas",
|
"ui/new-atlas",
|
||||||
"new_atlas",
|
"new_atlas",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
true));
|
true));
|
||||||
|
|
||||||
@ -521,8 +521,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/new-atlas",
|
"ui/new-atlas",
|
||||||
"new_atlas",
|
"new_atlas",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
true));
|
true));
|
||||||
|
|
||||||
@ -539,7 +539,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertEquals("new_atlas", detailsResult.details().summary().identity().assetName());
|
assertEquals("new_atlas", detailsResult.details().summary().identity().assetName());
|
||||||
assertNotNull(detailsResult.details().summary().identity().assetUuid());
|
assertNotNull(detailsResult.details().summary().identity().assetUuid());
|
||||||
assertTrue(detailsResult.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
assertTrue(detailsResult.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
||||||
assertTrue(detailsResult.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty")));
|
assertTrue(detailsResult.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for glyph bank cannot be empty")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -555,8 +555,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/new-atlas",
|
"ui/new-atlas",
|
||||||
"new_atlas",
|
"new_atlas",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
true));
|
true));
|
||||||
|
|
||||||
@ -987,7 +987,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
"name": "ui_atlas",
|
"name": "ui_atlas",
|
||||||
"type": "IMAGE/bank",
|
"type": "IMAGE/bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "none"
|
"codec": "none"
|
||||||
},
|
},
|
||||||
"preload": {
|
"preload": {
|
||||||
@ -1002,7 +1002,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
"name": "ui_clone",
|
"name": "ui_clone",
|
||||||
"type": "IMAGE/bank",
|
"type": "IMAGE/bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "none"
|
"codec": "none"
|
||||||
},
|
},
|
||||||
"preload": {
|
"preload": {
|
||||||
@ -1053,8 +1053,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/delete-me",
|
"ui/delete-me",
|
||||||
"delete_me",
|
"delete_me",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
false));
|
false));
|
||||||
final Path assetRoot = projectRoot.resolve("assets/ui/delete-me");
|
final Path assetRoot = projectRoot.resolve("assets/ui/delete-me");
|
||||||
@ -1081,8 +1081,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/source-atlas",
|
"ui/source-atlas",
|
||||||
"source_atlas",
|
"source_atlas",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
true));
|
true));
|
||||||
Files.writeString(projectRoot.resolve("assets/ui/source-atlas/atlas.png"), "fixture");
|
Files.writeString(projectRoot.resolve("assets/ui/source-atlas/atlas.png"), "fixture");
|
||||||
@ -1148,16 +1148,16 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/source",
|
"ui/source",
|
||||||
"source",
|
"source",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
false));
|
false));
|
||||||
final CreateAssetResult target = service.createAsset(new CreateAssetRequest(
|
final CreateAssetResult target = service.createAsset(new CreateAssetRequest(
|
||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/target",
|
"ui/target",
|
||||||
"target",
|
"target",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
false));
|
false));
|
||||||
|
|
||||||
@ -1223,7 +1223,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"audio/bad",
|
"audio/bad",
|
||||||
"bad_asset",
|
"bad_asset",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.SOUND_V1,
|
OutputFormatCatalog.SOUND_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
false));
|
false));
|
||||||
@ -1243,16 +1243,16 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/atlas-a",
|
"ui/atlas-a",
|
||||||
"atlas_a",
|
"atlas_a",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
true)));
|
true)));
|
||||||
final Future<CreateAssetResult> second = executor.submit(() -> service.createAsset(new CreateAssetRequest(
|
final Future<CreateAssetResult> second = executor.submit(() -> service.createAsset(new CreateAssetRequest(
|
||||||
project(projectRoot),
|
project(projectRoot),
|
||||||
"ui/atlas-b",
|
"ui/atlas-b",
|
||||||
"atlas_b",
|
"atlas_b",
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
false)));
|
false)));
|
||||||
|
|
||||||
|
|||||||
@ -29,8 +29,8 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
assertEquals(1, result.declaration().schemaVersion());
|
assertEquals(1, result.declaration().schemaVersion());
|
||||||
assertEquals("fixture-uuid-1", result.declaration().assetUuid());
|
assertEquals("fixture-uuid-1", result.declaration().assetUuid());
|
||||||
assertEquals("ui_atlas", result.declaration().name());
|
assertEquals("ui_atlas", result.declaration().name());
|
||||||
assertEquals(AssetFamilyCatalog.TILE_BANK, result.declaration().assetFamily());
|
assertEquals(AssetFamilyCatalog.GLYPH_BANK, result.declaration().assetFamily());
|
||||||
assertEquals("TILES/indexed_v1", result.declaration().outputFormat().displayName());
|
assertEquals("GLYPH/indexed_v1", result.declaration().outputFormat().displayName());
|
||||||
assertEquals(OutputCodecCatalog.NONE, result.declaration().outputCodec());
|
assertEquals(OutputCodecCatalog.NONE, result.declaration().outputCodec());
|
||||||
assertEquals(Map.of(), result.declaration().outputPipelineMetadata());
|
assertEquals(Map.of(), result.declaration().outputPipelineMetadata());
|
||||||
assertTrue(result.declaration().preloadEnabled());
|
assertTrue(result.declaration().preloadEnabled());
|
||||||
@ -75,9 +75,9 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "uuid-pipeline",
|
"asset_uuid": "uuid-pipeline",
|
||||||
"name": "pipeline_asset",
|
"name": "pipeline_asset",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE",
|
"codec": "NONE",
|
||||||
"pipeline": []
|
"pipeline": []
|
||||||
},
|
},
|
||||||
@ -99,9 +99,9 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "uuid-palette-contract",
|
"asset_uuid": "uuid-palette-contract",
|
||||||
"name": "palette_asset",
|
"name": "palette_asset",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE",
|
"codec": "NONE",
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"palettes": [
|
"palettes": [
|
||||||
@ -135,9 +135,9 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "uuid-palette-duplicate",
|
"asset_uuid": "uuid-palette-duplicate",
|
||||||
"name": "palette_asset",
|
"name": "palette_asset",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE",
|
"codec": "NONE",
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"palettes": [
|
"palettes": [
|
||||||
@ -203,9 +203,9 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "uuid-outside",
|
"asset_uuid": "uuid-outside",
|
||||||
"name": "bad_asset",
|
"name": "bad_asset",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"inputs": { "sprites": ["../outside.png"] },
|
"inputs": { "sprites": ["../outside.png"] },
|
||||||
"output": { "format": "TILES/indexed_v1", "codec": "NONE" },
|
"output": { "format": "GLYPH/indexed_v1", "codec": "NONE" },
|
||||||
"preload": { "enabled": true }
|
"preload": { "enabled": true }
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
@ -225,7 +225,7 @@ final class PackerAssetDeclarationParserTest {
|
|||||||
"asset_uuid": "uuid-video",
|
"asset_uuid": "uuid-video",
|
||||||
"name": "bad_asset",
|
"name": "bad_asset",
|
||||||
"type": "video_bank",
|
"type": "video_bank",
|
||||||
"output": { "format": "TILES/indexed_v1", "codec": "NONE" },
|
"output": { "format": "GLYPH/indexed_v1", "codec": "NONE" },
|
||||||
"preload": { "enabled": true }
|
"preload": { "enabled": true }
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
|||||||
@ -44,14 +44,14 @@ final class PackerAssetDetailsServiceTest {
|
|||||||
assertEquals(PackerBuildParticipation.INCLUDED, result.details().summary().buildParticipation());
|
assertEquals(PackerBuildParticipation.INCLUDED, result.details().summary().buildParticipation());
|
||||||
assertEquals("fixture-uuid-1", result.details().summary().identity().assetUuid());
|
assertEquals("fixture-uuid-1", result.details().summary().identity().assetUuid());
|
||||||
assertEquals("ui_atlas", result.details().summary().identity().assetName());
|
assertEquals("ui_atlas", result.details().summary().identity().assetName());
|
||||||
assertEquals("TILES/indexed_v1", result.details().outputFormat().displayName());
|
assertEquals("GLYPH/indexed_v1", result.details().outputFormat().displayName());
|
||||||
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
|
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
|
||||||
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
||||||
assertNotNull(result.details().bankComposition());
|
assertNotNull(result.details().bankComposition());
|
||||||
assertTrue(result.details().bankComposition().selectedFiles().isEmpty());
|
assertTrue(result.details().bankComposition().selectedFiles().isEmpty());
|
||||||
assertTrue(result.details().pipelinePalettes().isEmpty());
|
assertTrue(result.details().pipelinePalettes().isEmpty());
|
||||||
assertTrue(result.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
assertTrue(result.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
||||||
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty")));
|
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for glyph bank cannot be empty")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"inputs": "wrong",
|
"inputs": "wrong",
|
||||||
"output": {
|
"output": {
|
||||||
"codec": ""
|
"codec": ""
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version": 9,
|
"schema_version": 9,
|
||||||
"asset_uuid": "future-uuid-1",
|
"asset_uuid": "future-uuid-1",
|
||||||
"name": "future_asset",
|
"name": "future_asset",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE"
|
"codec": "NONE"
|
||||||
},
|
},
|
||||||
"preload": {
|
"preload": {
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "fixture-uuid-1",
|
"asset_uuid": "fixture-uuid-1",
|
||||||
"name": "ui_atlas",
|
"name": "ui_atlas",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE"
|
"codec": "NONE"
|
||||||
},
|
},
|
||||||
"preload": {
|
"preload": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"inputs": "wrong",
|
"inputs": "wrong",
|
||||||
"output": {
|
"output": {
|
||||||
"codec": ""
|
"codec": ""
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"asset_uuid": "uuid-1",
|
"asset_uuid": "uuid-1",
|
||||||
"name": "ui_atlas",
|
"name": "ui_atlas",
|
||||||
"type": "tile_bank",
|
"type": "glyph_bank",
|
||||||
"output": {
|
"output": {
|
||||||
"format": "TILES/indexed_v1",
|
"format": "GLYPH/indexed_v1",
|
||||||
"codec": "NONE"
|
"codec": "NONE"
|
||||||
},
|
},
|
||||||
"preload": {
|
"preload": {
|
||||||
|
|||||||
@ -190,7 +190,7 @@ public enum I18n {
|
|||||||
ASSETS_LABEL_BUILD_PARTICIPATION("assets.label.buildParticipation"),
|
ASSETS_LABEL_BUILD_PARTICIPATION("assets.label.buildParticipation"),
|
||||||
ASSETS_LABEL_ASSET_ID("assets.label.assetId"),
|
ASSETS_LABEL_ASSET_ID("assets.label.assetId"),
|
||||||
ASSETS_LABEL_TYPE("assets.label.type"),
|
ASSETS_LABEL_TYPE("assets.label.type"),
|
||||||
ASSETS_TYPE_TILE_BANK("assets.type.tileBank"),
|
ASSETS_TYPE_GLYPH_BANK("assets.type.glyphBank"),
|
||||||
ASSETS_TYPE_PALETTE_BANK("assets.type.paletteBank"),
|
ASSETS_TYPE_PALETTE_BANK("assets.type.paletteBank"),
|
||||||
ASSETS_TYPE_SOUND_BANK("assets.type.soundBank"),
|
ASSETS_TYPE_SOUND_BANK("assets.type.soundBank"),
|
||||||
ASSETS_TYPE_UNKNOWN("assets.type.unknown"),
|
ASSETS_TYPE_UNKNOWN("assets.type.unknown"),
|
||||||
|
|||||||
@ -113,7 +113,7 @@ public final class AssetDetailsUiSupport {
|
|||||||
|
|
||||||
public static String typeLabel(AssetFamilyCatalog assetFamily) {
|
public static String typeLabel(AssetFamilyCatalog assetFamily) {
|
||||||
return switch (assetFamily) {
|
return switch (assetFamily) {
|
||||||
case TILE_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_TILE_BANK);
|
case GLYPH_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_GLYPH_BANK);
|
||||||
case SOUND_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_SOUND_BANK);
|
case SOUND_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_SOUND_BANK);
|
||||||
case UNKNOWN -> Container.i18n().text(I18n.ASSETS_TYPE_UNKNOWN);
|
case UNKNOWN -> Container.i18n().text(I18n.ASSETS_TYPE_UNKNOWN);
|
||||||
};
|
};
|
||||||
@ -121,7 +121,7 @@ public final class AssetDetailsUiSupport {
|
|||||||
|
|
||||||
public static String typeChipTone(AssetFamilyCatalog assetFamily) {
|
public static String typeChipTone(AssetFamilyCatalog assetFamily) {
|
||||||
return switch (assetFamily) {
|
return switch (assetFamily) {
|
||||||
case TILE_BANK -> "assets-details-chip-image";
|
case GLYPH_BANK -> "assets-details-chip-image";
|
||||||
case SOUND_BANK -> "assets-details-chip-audio";
|
case SOUND_BANK -> "assets-details-chip-audio";
|
||||||
case UNKNOWN -> "assets-details-chip-generic";
|
case UNKNOWN -> "assets-details-chip-generic";
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,7 +20,7 @@ public final class AssetBankCapacityService {
|
|||||||
final Map<String, String> safeMetadata = Map.copyOf(Objects.requireNonNull(outputMetadata, "outputMetadata"));
|
final Map<String, String> safeMetadata = Map.copyOf(Objects.requireNonNull(outputMetadata, "outputMetadata"));
|
||||||
final Map<String, Object> safePipeline = Map.copyOf(Objects.requireNonNull(outputPipeline, "outputPipeline"));
|
final Map<String, Object> safePipeline = Map.copyOf(Objects.requireNonNull(outputPipeline, "outputPipeline"));
|
||||||
return switch (safeFamily) {
|
return switch (safeFamily) {
|
||||||
case TILE_BANK -> evaluateTileBank(artifactCount, safeMetadata);
|
case GLYPH_BANK -> evaluateGlyphBank(artifactCount, safeMetadata);
|
||||||
case SOUND_BANK -> evaluateSoundBank(resolveSoundBankUsedBytes(safePipeline, usedBytes));
|
case SOUND_BANK -> evaluateSoundBank(resolveSoundBankUsedBytes(safePipeline, usedBytes));
|
||||||
case UNKNOWN -> new AssetDetailsBankCompositionCapacityState(
|
case UNKNOWN -> new AssetDetailsBankCompositionCapacityState(
|
||||||
0.0d,
|
0.0d,
|
||||||
@ -31,7 +31,7 @@ public final class AssetBankCapacityService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int maxArtifactsForTileBank(Map<String, String> outputMetadata) {
|
public int maxArtifactsForGlyphBank(Map<String, String> outputMetadata) {
|
||||||
final String tileSizeValue = Objects.requireNonNull(outputMetadata, "outputMetadata")
|
final String tileSizeValue = Objects.requireNonNull(outputMetadata, "outputMetadata")
|
||||||
.getOrDefault("tile_size", "16x16");
|
.getOrDefault("tile_size", "16x16");
|
||||||
return switch (tileSizeValue) {
|
return switch (tileSizeValue) {
|
||||||
@ -41,10 +41,10 @@ public final class AssetBankCapacityService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssetDetailsBankCompositionCapacityState evaluateTileBank(
|
private AssetDetailsBankCompositionCapacityState evaluateGlyphBank(
|
||||||
int artifactCount,
|
int artifactCount,
|
||||||
Map<String, String> outputMetadata) {
|
Map<String, String> outputMetadata) {
|
||||||
final int maxSlots = maxArtifactsForTileBank(outputMetadata);
|
final int maxSlots = maxArtifactsForGlyphBank(outputMetadata);
|
||||||
final int safeArtifactCount = Math.max(0, artifactCount);
|
final int safeArtifactCount = Math.max(0, artifactCount);
|
||||||
final double progress = maxSlots <= 0 ? 0.0d : (double) safeArtifactCount / (double) maxSlots;
|
final double progress = maxSlots <= 0 ? 0.0d : (double) safeArtifactCount / (double) maxSlots;
|
||||||
final boolean blocked = safeArtifactCount >= maxSlots;
|
final boolean blocked = safeArtifactCount >= maxSlots;
|
||||||
@ -53,7 +53,7 @@ public final class AssetBankCapacityService {
|
|||||||
severityFor(progress),
|
severityFor(progress),
|
||||||
blocked,
|
blocked,
|
||||||
safeArtifactCount + " / " + maxSlots,
|
safeArtifactCount + " / " + maxSlots,
|
||||||
blocked ? "Tile bank slot capacity reached." : "");
|
blocked ? "Glyph bank slot capacity reached." : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssetDetailsBankCompositionCapacityState evaluateSoundBank(long usedBytes) {
|
private AssetDetailsBankCompositionCapacityState evaluateSoundBank(long usedBytes) {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public final class AssetDetailsBankCompositionCoordinator {
|
public final class AssetDetailsBankCompositionCoordinator {
|
||||||
private final List<AssetDetailsBankCompositionFamilySupport> familySupports = List.of(
|
private final List<AssetDetailsBankCompositionFamilySupport> familySupports = List.of(
|
||||||
new AssetDetailsTileBankCompositionFamilySupport(),
|
new AssetDetailsGlyphBankCompositionFamilySupport(),
|
||||||
new AssetDetailsSoundBankCompositionFamilySupport(),
|
new AssetDetailsSoundBankCompositionFamilySupport(),
|
||||||
new AssetDetailsFallbackBankCompositionFamilySupport());
|
new AssetDetailsFallbackBankCompositionFamilySupport());
|
||||||
|
|
||||||
|
|||||||
@ -7,21 +7,21 @@ import p.studio.workspaces.assets.messages.AssetWorkspaceBankCompositionFile;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
final class AssetDetailsTileBankCompositionFamilySupport extends AssetDetailsAbstractBankCompositionFamilySupport {
|
final class AssetDetailsGlyphBankCompositionFamilySupport extends AssetDetailsAbstractBankCompositionFamilySupport {
|
||||||
private final AssetBankCapacityService capacityService = new AssetBankCapacityService();
|
private final AssetBankCapacityService capacityService = new AssetBankCapacityService();
|
||||||
|
|
||||||
private int maxSlots = capacityService.maxArtifactsForTileBank(Map.of());
|
private int maxSlots = capacityService.maxArtifactsForGlyphBank(Map.of());
|
||||||
private Map<String, String> outputMetadata = Map.of();
|
private Map<String, String> outputMetadata = Map.of();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(AssetFamilyCatalog assetFamily) {
|
public boolean supports(AssetFamilyCatalog assetFamily) {
|
||||||
return assetFamily == AssetFamilyCatalog.TILE_BANK;
|
return assetFamily == AssetFamilyCatalog.GLYPH_BANK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssetDetailsBankCompositionDraft createDraft(AssetWorkspaceAssetDetails details) {
|
public AssetDetailsBankCompositionDraft createDraft(AssetWorkspaceAssetDetails details) {
|
||||||
outputMetadata = metadataMap(details);
|
outputMetadata = metadataMap(details);
|
||||||
maxSlots = capacityService.maxArtifactsForTileBank(outputMetadata);
|
maxSlots = capacityService.maxArtifactsForGlyphBank(outputMetadata);
|
||||||
return super.createDraft(details);
|
return super.createDraft(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ final class AssetDetailsTileBankCompositionFamilySupport extends AssetDetailsAbs
|
|||||||
@Override
|
@Override
|
||||||
public AssetDetailsBankCompositionCapacityState evaluate(AssetDetailsBankCompositionDraft draft) {
|
public AssetDetailsBankCompositionCapacityState evaluate(AssetDetailsBankCompositionDraft draft) {
|
||||||
return capacityService.evaluate(
|
return capacityService.evaluate(
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
draft.selectedFiles().size(),
|
draft.selectedFiles().size(),
|
||||||
outputMetadata,
|
outputMetadata,
|
||||||
Map.of(),
|
Map.of(),
|
||||||
@ -18,7 +18,7 @@ public final class AssetDetailsPaletteOverhaulingCoordinator {
|
|||||||
private StudioFormSession<AssetDetailsPaletteOverhaulingDraft> formSession;
|
private StudioFormSession<AssetDetailsPaletteOverhaulingDraft> formSession;
|
||||||
|
|
||||||
public void replaceDetails(AssetWorkspaceAssetDetails details) {
|
public void replaceDetails(AssetWorkspaceAssetDetails details) {
|
||||||
if (details == null || details.summary().assetFamily() != AssetFamilyCatalog.TILE_BANK) {
|
if (details == null || details.summary().assetFamily() != AssetFamilyCatalog.GLYPH_BANK) {
|
||||||
formSession = null;
|
formSession = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,7 +112,7 @@ public final class AssetListItemControl extends VBox {
|
|||||||
|
|
||||||
private String assetRowToneClass(AssetFamilyCatalog assetFamily) {
|
private String assetRowToneClass(AssetFamilyCatalog assetFamily) {
|
||||||
return switch (assetFamily) {
|
return switch (assetFamily) {
|
||||||
case TILE_BANK -> "assets-workspace-asset-row-tone-image";
|
case GLYPH_BANK -> "assets-workspace-asset-row-tone-image";
|
||||||
case SOUND_BANK -> "assets-workspace-asset-row-tone-audio";
|
case SOUND_BANK -> "assets-workspace-asset-row-tone-audio";
|
||||||
default -> "assets-workspace-asset-row-tone-generic";
|
default -> "assets-workspace-asset-row-tone-generic";
|
||||||
};
|
};
|
||||||
@ -120,7 +120,7 @@ public final class AssetListItemControl extends VBox {
|
|||||||
|
|
||||||
private String assetNameToneClass(AssetFamilyCatalog assetFamily) {
|
private String assetNameToneClass(AssetFamilyCatalog assetFamily) {
|
||||||
return switch (assetFamily) {
|
return switch (assetFamily) {
|
||||||
case TILE_BANK -> "assets-workspace-asset-name-tone-image";
|
case GLYPH_BANK -> "assets-workspace-asset-name-tone-image";
|
||||||
case SOUND_BANK -> "assets-workspace-asset-name-tone-audio";
|
case SOUND_BANK -> "assets-workspace-asset-name-tone-audio";
|
||||||
default -> "assets-workspace-asset-name-tone-generic";
|
default -> "assets-workspace-asset-name-tone-generic";
|
||||||
};
|
};
|
||||||
|
|||||||
@ -181,7 +181,7 @@ assets.label.registration=Registration
|
|||||||
assets.label.buildParticipation=Build Participation
|
assets.label.buildParticipation=Build Participation
|
||||||
assets.label.assetId=Asset ID
|
assets.label.assetId=Asset ID
|
||||||
assets.label.type=Type
|
assets.label.type=Type
|
||||||
assets.type.tileBank=Tile Bank
|
assets.type.glyphBank=Glyph Bank
|
||||||
assets.type.paletteBank=Palette Bank
|
assets.type.paletteBank=Palette Bank
|
||||||
assets.type.soundBank=Sound Bank
|
assets.type.soundBank=Sound Bank
|
||||||
assets.type.unknown=Unknown
|
assets.type.unknown=Unknown
|
||||||
|
|||||||
@ -101,9 +101,9 @@ final class AssetDetailsBankCompositionCoordinatorTest {
|
|||||||
|
|
||||||
private AssetWorkspaceAssetDetails tileDetails(String tileSize, int fileCount) {
|
private AssetWorkspaceAssetDetails tileDetails(String tileSize, int fileCount) {
|
||||||
return new AssetWorkspaceAssetDetails(
|
return new AssetWorkspaceAssetDetails(
|
||||||
summary(AssetFamilyCatalog.TILE_BANK),
|
summary(AssetFamilyCatalog.GLYPH_BANK),
|
||||||
List.of(),
|
List.of(),
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
List.of(OutputCodecCatalog.NONE),
|
List.of(OutputCodecCatalog.NONE),
|
||||||
Map.of(OutputCodecCatalog.NONE, List.of()),
|
Map.of(OutputCodecCatalog.NONE, List.of()),
|
||||||
|
|||||||
@ -80,12 +80,12 @@ final class AssetDetailsPaletteOverhaulingCoordinatorTest {
|
|||||||
AssetWorkspaceAssetState.REGISTERED,
|
AssetWorkspaceAssetState.REGISTERED,
|
||||||
AssetWorkspaceBuildParticipation.INCLUDED,
|
AssetWorkspaceBuildParticipation.INCLUDED,
|
||||||
1,
|
1,
|
||||||
AssetFamilyCatalog.TILE_BANK,
|
AssetFamilyCatalog.GLYPH_BANK,
|
||||||
Path.of("/tmp/bank"),
|
Path.of("/tmp/bank"),
|
||||||
false,
|
false,
|
||||||
false),
|
false),
|
||||||
List.of(),
|
List.of(),
|
||||||
OutputFormatCatalog.TILES_INDEXED_V1,
|
OutputFormatCatalog.GLYPH_INDEXED_V1,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
List.of(OutputCodecCatalog.NONE),
|
List.of(OutputCodecCatalog.NONE),
|
||||||
Map.of(OutputCodecCatalog.NONE, List.of()),
|
Map.of(OutputCodecCatalog.NONE, List.of()),
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
"relative_path" : "confirm.png",
|
"relative_path" : "confirm.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 137,
|
"size" : 137,
|
||||||
"last_modified" : 1774359768919,
|
"last_modified" : 1775797786944,
|
||||||
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
|
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
@ -1263,7 +1263,7 @@
|
|||||||
"relative_path" : "right-palette.png",
|
"relative_path" : "right-palette.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 327,
|
"size" : 327,
|
||||||
"last_modified" : 1774359773932,
|
"last_modified" : 1775797786950,
|
||||||
"fingerprint" : "0526996900bdeef23c72fe987fb45800f11895946dcd5f0f7f8390c879069a37",
|
"fingerprint" : "0526996900bdeef23c72fe987fb45800f11895946dcd5f0f7f8390c879069a37",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1281,7 +1281,7 @@
|
|||||||
"relative_path" : "wrong-palette.png",
|
"relative_path" : "wrong-palette.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 248,
|
"size" : 248,
|
||||||
"last_modified" : 1774359771814,
|
"last_modified" : 1775797786946,
|
||||||
"fingerprint" : "15850f68547775866b01a0fe0b0012bb0243dec303ce1f9c3e02220e05b593e6",
|
"fingerprint" : "15850f68547775866b01a0fe0b0012bb0243dec303ce1f9c3e02220e05b593e6",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
@ -1311,7 +1311,7 @@
|
|||||||
"relative_path" : "confirm.png",
|
"relative_path" : "confirm.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 137,
|
"size" : 137,
|
||||||
"last_modified" : 1774359768918,
|
"last_modified" : 1775797786770,
|
||||||
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
|
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1341,7 +1341,7 @@
|
|||||||
"relative_path" : "flag00.png",
|
"relative_path" : "flag00.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 507,
|
"size" : 507,
|
||||||
"last_modified" : 1774359777378,
|
"last_modified" : 1775797786709,
|
||||||
"fingerprint" : "6ca635a7906067b6a2a8460a8562718c445783e6df18b9f2c80c83c5ac569db6",
|
"fingerprint" : "6ca635a7906067b6a2a8460a8562718c445783e6df18b9f2c80c83c5ac569db6",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1365,7 +1365,7 @@
|
|||||||
"relative_path" : "flag01.png",
|
"relative_path" : "flag01.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 766,
|
"size" : 766,
|
||||||
"last_modified" : 1774359777379,
|
"last_modified" : 1775797786708,
|
||||||
"fingerprint" : "79257d8437747a68e9e8eb8f43fced7aa55940dc8eca98f95767994abbacdd81",
|
"fingerprint" : "79257d8437747a68e9e8eb8f43fced7aa55940dc8eca98f95767994abbacdd81",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
@ -1379,7 +1379,7 @@
|
|||||||
"relative_path" : "flag02.png",
|
"relative_path" : "flag02.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 684,
|
"size" : 684,
|
||||||
"last_modified" : 1774359777379,
|
"last_modified" : 1775797786703,
|
||||||
"fingerprint" : "5fd43c447cf6dd9b164458860239427d2f4544ff6e007814731b50c17ffe75bf",
|
"fingerprint" : "5fd43c447cf6dd9b164458860239427d2f4544ff6e007814731b50c17ffe75bf",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
@ -1393,7 +1393,7 @@
|
|||||||
"relative_path" : "flag03.png",
|
"relative_path" : "flag03.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 669,
|
"size" : 669,
|
||||||
"last_modified" : 1774359777380,
|
"last_modified" : 1775797786706,
|
||||||
"fingerprint" : "7feab8c868bb446afd3dd7250e70504fb0ca228f463650d2dd7c525144e0b321",
|
"fingerprint" : "7feab8c868bb446afd3dd7250e70504fb0ca228f463650d2dd7c525144e0b321",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1411,7 +1411,7 @@
|
|||||||
"relative_path" : "link00.png",
|
"relative_path" : "link00.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 497,
|
"size" : 497,
|
||||||
"last_modified" : 1774359777381,
|
"last_modified" : 1775797786710,
|
||||||
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
|
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1429,7 +1429,7 @@
|
|||||||
"relative_path" : "link01.png",
|
"relative_path" : "link01.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 500,
|
"size" : 500,
|
||||||
"last_modified" : 1774359777382,
|
"last_modified" : 1775797786711,
|
||||||
"fingerprint" : "e2130efbb9643b41a4fb62619f2713402f9622c7db040fe18d929609ef70b89a",
|
"fingerprint" : "e2130efbb9643b41a4fb62619f2713402f9622c7db040fe18d929609ef70b89a",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1447,7 +1447,7 @@
|
|||||||
"relative_path" : "link02.png",
|
"relative_path" : "link02.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 517,
|
"size" : 517,
|
||||||
"last_modified" : 1774359777383,
|
"last_modified" : 1775797786713,
|
||||||
"fingerprint" : "9216dfc6a6226fac398e9f781550d23fbfaa65bd377cdda69187149beca114ec",
|
"fingerprint" : "9216dfc6a6226fac398e9f781550d23fbfaa65bd377cdda69187149beca114ec",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1465,7 +1465,7 @@
|
|||||||
"relative_path" : "link03.png",
|
"relative_path" : "link03.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 507,
|
"size" : 507,
|
||||||
"last_modified" : 1774359777383,
|
"last_modified" : 1775797786712,
|
||||||
"fingerprint" : "ebc4b7ca7bb1455288681c5d71424f60f658a44cb343d0c3934329cec676c867",
|
"fingerprint" : "ebc4b7ca7bb1455288681c5d71424f60f658a44cb343d0c3934329cec676c867",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1483,7 +1483,7 @@
|
|||||||
"relative_path" : "link04.png",
|
"relative_path" : "link04.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 497,
|
"size" : 497,
|
||||||
"last_modified" : 1774359777384,
|
"last_modified" : 1775797786718,
|
||||||
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
|
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1501,7 +1501,7 @@
|
|||||||
"relative_path" : "link05.png",
|
"relative_path" : "link05.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 495,
|
"size" : 495,
|
||||||
"last_modified" : 1774359777384,
|
"last_modified" : 1775797786717,
|
||||||
"fingerprint" : "1ba8ce75c445396334737143e0cfa56c87a1fb64cca8ad0962192594849249eb",
|
"fingerprint" : "1ba8ce75c445396334737143e0cfa56c87a1fb64cca8ad0962192594849249eb",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1519,7 +1519,7 @@
|
|||||||
"relative_path" : "link06.png",
|
"relative_path" : "link06.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 518,
|
"size" : 518,
|
||||||
"last_modified" : 1774359777385,
|
"last_modified" : 1775797786714,
|
||||||
"fingerprint" : "5e0954447699c6d5eac7550f1a10cf520efcddad0b9fbd9a716434da9d9550d4",
|
"fingerprint" : "5e0954447699c6d5eac7550f1a10cf520efcddad0b9fbd9a716434da9d9550d4",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1537,7 +1537,7 @@
|
|||||||
"relative_path" : "link07.png",
|
"relative_path" : "link07.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 517,
|
"size" : 517,
|
||||||
"last_modified" : 1774359777385,
|
"last_modified" : 1775797786716,
|
||||||
"fingerprint" : "6104ba7f216a937994d478ed07766ec28f48ad72fdd6620508535a1f877b8ddb",
|
"fingerprint" : "6104ba7f216a937994d478ed07766ec28f48ad72fdd6620508535a1f877b8ddb",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"palette" : {
|
"palette" : {
|
||||||
@ -1555,7 +1555,7 @@
|
|||||||
"relative_path" : "t1381s1.png",
|
"relative_path" : "t1381s1.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 4970,
|
"size" : 4970,
|
||||||
"last_modified" : 1774359777386,
|
"last_modified" : 1775797786715,
|
||||||
"fingerprint" : "c8b667527b32436ab97fd57b3215917f7065d6d1b7f6d71be1827351bdc61fa6",
|
"fingerprint" : "c8b667527b32436ab97fd57b3215917f7065d6d1b7f6d71be1827351bdc61fa6",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
@ -1569,7 +1569,7 @@
|
|||||||
"relative_path" : "t1489s1.png",
|
"relative_path" : "t1489s1.png",
|
||||||
"mime_type" : "image/png",
|
"mime_type" : "image/png",
|
||||||
"size" : 6489,
|
"size" : 6489,
|
||||||
"last_modified" : 1774359777387,
|
"last_modified" : 1775797786719,
|
||||||
"fingerprint" : "678c6f48c6d1fcd1209c9d0ab1c46f20eea4871946135263b7363488cceb74f0",
|
"fingerprint" : "678c6f48c6d1fcd1209c9d0ab1c46f20eea4871946135263b7363488cceb74f0",
|
||||||
"metadata" : { },
|
"metadata" : { },
|
||||||
"diagnostics" : [ {
|
"diagnostics" : [ {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "87396aab-337e-479e-b1f4-ec296678389e",
|
"asset_uuid" : "87396aab-337e-479e-b1f4-ec296678389e",
|
||||||
"name" : "Zelda",
|
"name" : "Zelda",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"codec" : "NONE",
|
"codec" : "NONE",
|
||||||
"pipeline" : {
|
"pipeline" : {
|
||||||
@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
} ]
|
} ]
|
||||||
},
|
},
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec_configuration" : { },
|
"codec_configuration" : { },
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"tile_size" : "32x32"
|
"tile_size" : "32x32"
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "64147d33-e8bf-4272-bb5c-b4c07c0276b3",
|
"asset_uuid" : "64147d33-e8bf-4272-bb5c-b4c07c0276b3",
|
||||||
"name" : "Bigode",
|
"name" : "Bigode",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec" : "NONE",
|
"codec" : "NONE",
|
||||||
"codec_configuration" : { },
|
"codec_configuration" : { },
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "b15b319f-5cab-4254-93ea-d83f4742d204",
|
"asset_uuid" : "b15b319f-5cab-4254-93ea-d83f4742d204",
|
||||||
"name" : "ui_atlas",
|
"name" : "ui_atlas",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec" : "NONE",
|
"codec" : "NONE",
|
||||||
"codec_configuration" : { },
|
"codec_configuration" : { },
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "f64d3bfe-443d-4703-b62a-face19a32cac",
|
"asset_uuid" : "f64d3bfe-443d-4703-b62a-face19a32cac",
|
||||||
"name" : "bbb2",
|
"name" : "bbb2",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"codec" : "NONE",
|
"codec" : "NONE",
|
||||||
"format" : "TILES/indexed_v1"
|
"format" : "GLYPH/indexed_v1"
|
||||||
},
|
},
|
||||||
"preload" : {
|
"preload" : {
|
||||||
"enabled" : false
|
"enabled" : false
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "4d9847b0-5a23-421f-8b78-bf3909ca2281",
|
"asset_uuid" : "4d9847b0-5a23-421f-8b78-bf3909ca2281",
|
||||||
"name" : "one-more-atlas",
|
"name" : "one-more-atlas",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec" : "NONE"
|
"codec" : "NONE"
|
||||||
},
|
},
|
||||||
"preload" : {
|
"preload" : {
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "21953cb8-4101-4790-9e5e-d95f5fbc9b5a",
|
"asset_uuid" : "21953cb8-4101-4790-9e5e-d95f5fbc9b5a",
|
||||||
"name" : "ui_atlas",
|
"name" : "ui_atlas",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec" : "NONE",
|
"codec" : "NONE",
|
||||||
"codec_configuration" : { },
|
"codec_configuration" : { },
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
"schema_version" : 1,
|
"schema_version" : 1,
|
||||||
"asset_uuid" : "62a81570-8f47-4612-9288-6060e6c9a2e2",
|
"asset_uuid" : "62a81570-8f47-4612-9288-6060e6c9a2e2",
|
||||||
"name" : "one-more-atlas",
|
"name" : "one-more-atlas",
|
||||||
"type" : "tile_bank",
|
"type" : "glyph_bank",
|
||||||
"output" : {
|
"output" : {
|
||||||
"format" : "TILES/indexed_v1",
|
"format" : "GLYPH/indexed_v1",
|
||||||
"codec" : "NONE"
|
"codec" : "NONE"
|
||||||
},
|
},
|
||||||
"preload" : {
|
"preload" : {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user