Document PAK v2 resource closeout
This commit is contained in:
parent
d8c794a478
commit
cccae4169a
5 changed files with 98 additions and 32 deletions
16
README.md
16
README.md
|
|
@ -97,8 +97,8 @@ missing.
|
||||||
- A machine-local `acdream.pak` built from those DATs
|
- A machine-local `acdream.pak` built from those DATs
|
||||||
- A running ACE server for connected play; the examples use
|
- A running ACE server for connected play; the examples use
|
||||||
`127.0.0.1:9000`
|
`127.0.0.1:9000`
|
||||||
- For the graphical client, a driver exposing the mandatory modern OpenGL
|
- For the graphical client, a driver exposing the mandatory Vulkan
|
||||||
capabilities
|
capabilities validated at startup
|
||||||
|
|
||||||
The project does not distribute Microsoft/Turbine DAT files or derived
|
The project does not distribute Microsoft/Turbine DAT files or derived
|
||||||
prepared packages.
|
prepared packages.
|
||||||
|
|
@ -111,10 +111,9 @@ dotnet build AcDream.slnx -c Release
|
||||||
dotnet test AcDream.slnx -c Release --no-build
|
dotnet test AcDream.slnx -c Release --no-build
|
||||||
```
|
```
|
||||||
|
|
||||||
The current baseline is a successful Release build with **8,826 passing tests
|
The current CI-filtered Windows baseline is a successful Release build with
|
||||||
and 5 intentional skips**. The build currently reports 17 test-project
|
**16,151 passing tests and zero failures**; opt-in live, installed-DAT,
|
||||||
warnings tracked by [`#228`](docs/ISSUES.md#228--clean-release-build-emits-17-test-project-warnings);
|
prepared-package, manual, timing, and platform-specific lanes run separately.
|
||||||
production compilation has zero errors.
|
|
||||||
|
|
||||||
## Prepare content
|
## Prepare content
|
||||||
|
|
||||||
|
|
@ -127,8 +126,9 @@ dotnet run --project src\AcDream.Bake\AcDream.Bake.csproj -c Release -- `
|
||||||
--out "C:\Games\Asheron's Call\acdream.pak"
|
--out "C:\Games\Asheron's Call\acdream.pak"
|
||||||
```
|
```
|
||||||
|
|
||||||
A complete package is approximately 30 GB. It is machine-local and must not be
|
A complete format-2 package from the standard installed DAT set is about
|
||||||
committed. `ACDREAM_PAK_PATH` overrides the default
|
570 MiB (the former format-1 package was about 30 GB). It is machine-local and
|
||||||
|
must not be committed. `ACDREAM_PAK_PATH` overrides the default
|
||||||
`<DAT directory>\acdream.pak`.
|
`<DAT directory>\acdream.pak`.
|
||||||
|
|
||||||
## Run the graphical client
|
## Run the graphical client
|
||||||
|
|
|
||||||
|
|
@ -450,6 +450,15 @@ src/
|
||||||
|
|
||||||
Prepared-content launch contract
|
Prepared-content launch contract
|
||||||
-> `install.json` remains the strict backward-compatible base-pak authority
|
-> `install.json` remains the strict backward-compatible base-pak authority
|
||||||
|
-> format 2 / recipe 6 is the current full-package contract: globally
|
||||||
|
shared texture payloads, independent adaptive blob compression, and
|
||||||
|
source-native BC1/2/3 for surfaces that require no pixel-local edit
|
||||||
|
-> format changes always use an explicit confirmed full rebuild; the
|
||||||
|
launcher preflights 2 GiB free space, shows long-work progress, validates
|
||||||
|
the candidate beside the active package, and promotes atomically
|
||||||
|
-> the prepared texture LRU is bounded to 64 MiB / 1,024 entries; GPU atlas
|
||||||
|
ownership remains in App and the whole-file mmap is virtual, not a
|
||||||
|
committed-copy cache
|
||||||
-> optional `pak/content.current.json` binds one cumulative overlay to the
|
-> optional `pak/content.current.json` binds one cumulative overlay to the
|
||||||
base SHA; there is never an unbounded overlay chain
|
base SHA; there is never an unbounded overlay chain
|
||||||
-> `pak/content.client-pending` prevents newly migrated content from
|
-> `pak/content.client-pending` prevents newly migrated content from
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ particles), and uses the same Silk.NET + .NET stack we target.
|
||||||
our tree (see CLAUDE.md for the full breakdown):
|
our tree (see CLAUDE.md for the full breakdown):
|
||||||
- `src/AcDream.Core/Rendering/Wb/` — pure helpers (no GL): `TerrainUtils`,
|
- `src/AcDream.Core/Rendering/Wb/` — pure helpers (no GL): `TerrainUtils`,
|
||||||
`TerrainEntry`, `RegionInfo`, `SceneryHelpers`, `TextureHelpers`.
|
`TerrainEntry`, `RegionInfo`, `SceneryHelpers`, `TextureHelpers`.
|
||||||
- `src/AcDream.App/Rendering/Wb/` — GL infrastructure + mesh pipeline:
|
- `src/AcDream.App/Rendering/Wb/` — Vulkan/RHI infrastructure + mesh pipeline:
|
||||||
`ObjectMeshManager`, `WbMeshAdapter`, `WbDrawDispatcher`, texture cache,
|
`ObjectMeshManager`, `WbMeshAdapter`, `WbDrawDispatcher`, texture cache,
|
||||||
shader infra, EnvCell/portal/scenery/terrain-blending pipeline classes.
|
shader infra, EnvCell/portal/scenery/terrain-blending pipeline classes.
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ non-render content plus explicit bake/equivalence tooling.
|
||||||
|
|
||||||
**MP1a (2026-07-05): CPU mesh-extraction half moved to `AcDream.Content`.**
|
**MP1a (2026-07-05): CPU mesh-extraction half moved to `AcDream.Content`.**
|
||||||
The GL-free portion of the former `ObjectMeshManager` — dat read → polygon
|
The GL-free portion of the former `ObjectMeshManager` — dat read → polygon
|
||||||
walk → vertex/index build → inline BCn/palette texture decode →
|
walk → vertex/index build → palette/conditional BCn texture decode →
|
||||||
`ObjectMeshData` — is now `MeshExtractor` in a new `src/AcDream.Content/`
|
`ObjectMeshData` — is now `MeshExtractor` in a new `src/AcDream.Content/`
|
||||||
assembly (no Silk.NET dependency), so the MP1b bake tool can run the exact
|
assembly (no Silk.NET dependency), so the MP1b bake tool can run the exact
|
||||||
same extraction code offline without an OpenGL context. This was a
|
same extraction code offline without an OpenGL context. This was a
|
||||||
|
|
@ -84,7 +84,7 @@ behavior change, no divergence-register row.
|
||||||
survive, as they always did). The MP1b bake tool passes its own
|
survive, as they always did). The MP1b bake tool passes its own
|
||||||
collector.
|
collector.
|
||||||
- **Stays in `src/AcDream.App/Rendering/Wb/`:** `ObjectMeshManager` (the
|
- **Stays in `src/AcDream.App/Rendering/Wb/`:** `ObjectMeshManager` (the
|
||||||
staged-queue/worker-pool/Dispose-quiesce lifecycle and all GL upload;
|
staged-queue/worker-pool/Dispose-quiesce lifecycle and all Vulkan/RHI upload;
|
||||||
production workers now consume `IPreparedAssetSource`),
|
production workers now consume `IPreparedAssetSource`),
|
||||||
`ObjectRenderData`/`ObjectRenderBatch`
|
`ObjectRenderData`/`ObjectRenderBatch`
|
||||||
(hold a GL `TextureAtlasManager` field), `TextureAtlasManager`,
|
(hold a GL `TextureAtlasManager` field), `TextureAtlasManager`,
|
||||||
|
|
@ -120,9 +120,8 @@ EnvCell, Surface, palette, and texture graphs during portals. The validated
|
||||||
machine-local `acdream.pak` is opened through Content's
|
machine-local `acdream.pak` is opened through Content's
|
||||||
`IPreparedAssetSource`; typed GfxObj and EnvCell requests deserialize immutable
|
`IPreparedAssetSource`; typed GfxObj and EnvCell requests deserialize immutable
|
||||||
`ObjectMeshData` while retaining the existing App worker, staging, render-thread
|
`ObjectMeshData` while retaining the existing App worker, staging, render-thread
|
||||||
upload, cache, ownership, and shutdown contracts. The original
|
upload, cache, ownership, and shutdown contracts. The prepared render payload
|
||||||
format-1/bake-tool-3 render payload persists exact batch translucency so App
|
persists exact batch translucency so App does not reconstruct a
|
||||||
does not reconstruct a
|
|
||||||
`GfxObjMesh` for metadata. Setup activation uses the package TOC as an explicit
|
`GfxObjMesh` for metadata. Setup activation uses the package TOC as an explicit
|
||||||
type-presence index before reading valid Setup records through the bounded DAT
|
type-presence index before reading valid Setup records through the bounded DAT
|
||||||
cache. `DatPreparedAssetSource` and `MeshExtractor` remain explicit
|
cache. `DatPreparedAssetSource` and `MeshExtractor` remain explicit
|
||||||
|
|
@ -146,8 +145,25 @@ keeps either result non-launchable until the matching client is confirmed,
|
||||||
including across a crash/restart. Design and gates:
|
including across a crash/restart. Design and gates:
|
||||||
`docs/plans/2026-08-25-launcher-content-stabilization.md`.
|
`docs/plans/2026-08-25-launcher-content-stabilization.md`.
|
||||||
|
|
||||||
**Slice I3 prepared collision extension (2026-07-25).** The package remains
|
**PAK v2 resource closeout (2026-08-27).** Format 2 / bake recipe 6 retains
|
||||||
format 1 and retains mesh type values 1–3; bake-tool 4 appends typed GfxObj,
|
the fixed header and sorted random-access TOC while moving texture arrays into
|
||||||
|
one globally shared type-8 payload partition and independently applying
|
||||||
|
adaptive Brotli compression with raw fallback. Unedited DXT1/3/5 surfaces
|
||||||
|
retain exact DAT BC blocks through Vulkan upload; clip maps and authored
|
||||||
|
translucency continue through the RGBA edit path. The reader bounds decoded
|
||||||
|
blobs and retains shared texture arrays in a 64 MiB / 1,024-entry LRU. The
|
||||||
|
complete installed package is 597,229,424 bytes versus 29,908,271,024 bytes
|
||||||
|
for format 1; four- and nine-worker bakes have identical SHA-256. The
|
||||||
|
authoritative connected before/after route reduced heavy-route working set by
|
||||||
|
48.0%, private bytes by 26.1%, and prepared-mesh GPU bytes by 25.9% with equal
|
||||||
|
or faster matching reveal/frame percentiles. Format changes remain mandatory
|
||||||
|
launcher-confirmed full rebuilds with beside-active validation and atomic
|
||||||
|
promotion; overlays never cross a format boundary. Design and evidence:
|
||||||
|
`docs/plans/2026-08-27-pak-v2-resource-campaign.md`.
|
||||||
|
|
||||||
|
**Slice I3 prepared collision extension (2026-07-25).** At its introduction,
|
||||||
|
the package remained format 1 and retained mesh type values 1–3; bake-tool 4
|
||||||
|
appended typed GfxObj,
|
||||||
Setup, CellStruct, and EnvCell-topology collision payloads. Core owns the
|
Setup, CellStruct, and EnvCell-topology collision payloads. Core owns the
|
||||||
immutable flat records and deterministic raw-DAT flattener. Content owns the
|
immutable flat records and deterministic raw-DAT flattener. Content owns the
|
||||||
strict little-endian codec and `IPreparedCollisionSource`.
|
strict little-endian codec and `IPreparedCollisionSource`.
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ Ship one crash-safe prepared-asset format migration that:
|
||||||
- preserves decoded geometry, material metadata, texture bytes, deterministic
|
- preserves decoded geometry, material metadata, texture bytes, deterministic
|
||||||
baking, corruption isolation, and random-access loading;
|
baking, corruption isolation, and random-access loading;
|
||||||
- does not regress cold or warm world-reveal latency or frame-time percentiles;
|
- does not regress cold or warm world-reveal latency or frame-time percentiles;
|
||||||
- reduces bake CPU/memory and client retained texture memory where the data
|
- reduces offline bake time and live client CPU/GPU memory where the data
|
||||||
permits it, without changing the rendered result;
|
permits it, without changing the rendered result; the one-time bake remains
|
||||||
|
bounded for the user-confirmed 16-32 GiB target machines;
|
||||||
- gives launcher users a clear one-time update message and progress, while
|
- gives launcher users a clear one-time update message and progress, while
|
||||||
retaining the last verified package until the replacement is validated;
|
retaining the last verified package until the replacement is validated;
|
||||||
- passes two different worker-count bakes with identical SHA-256, the complete
|
- passes two different worker-count bakes with identical SHA-256, the complete
|
||||||
|
|
@ -51,9 +52,9 @@ The 64-byte header and 24-byte sorted TOC row remain fixed. Format version is
|
||||||
their own exact dimensions, format, upload metadata, surface identity,
|
their own exact dimensions, format, upload metadata, surface identity,
|
||||||
translucency, culling, and index data.
|
translucency, culling, and index data.
|
||||||
2. Texture payload keys are the first 56 bits of SHA-256 under the type-8
|
2. Texture payload keys are the first 56 bits of SHA-256 under the type-8
|
||||||
namespace. The writer retains and compares the full bytes for the complete
|
namespace. The writer retains the full SHA-256 digest and length for every
|
||||||
bake, making even a truncated-hash collision a loud bake failure rather
|
unique texture, making even a truncated-key collision a loud bake failure
|
||||||
than silent substitution.
|
rather than silent substitution without pinning another copy of all bytes.
|
||||||
3. Every physical blob is independently encoded. The high bit of the TOC
|
3. Every physical blob is independently encoded. The high bit of the TOC
|
||||||
length marks compression; the low 31 bits are the stored length. A
|
length marks compression; the low 31 bits are the stored length. A
|
||||||
compressed blob contains a four-byte decoded-length prefix followed by
|
compressed blob contains a four-byte decoded-length prefix followed by
|
||||||
|
|
@ -61,10 +62,15 @@ The 64-byte header and 24-byte sorted TOC row remain fixed. Format version is
|
||||||
CRC-32 covers stored bytes, then decompression is independently validated.
|
CRC-32 covers stored bytes, then decompression is independently validated.
|
||||||
4. Random access remains one binary search plus one mmap copy for raw blobs.
|
4. Random access remains one binary search plus one mmap copy for raw blobs.
|
||||||
Compressed blobs add decompression only when the writer proved a material
|
Compressed blobs add decompression only when the writer proved a material
|
||||||
size win. Texture payloads use a bounded, thread-safe 256 MiB / 2,048-entry
|
size win. Texture payloads use a bounded, thread-safe 64 MiB / 1,024-entry
|
||||||
LRU; concurrently decoded meshes converge on one shared array instance.
|
LRU; concurrently decoded meshes converge on one shared array instance.
|
||||||
5. Whole-file compression is forbidden. It would destroy random access and
|
5. Whole-file compression is forbidden. It would destroy random access and
|
||||||
make a small world reveal depend on unrelated content.
|
make a small world reveal depend on unrelated content.
|
||||||
|
6. Unedited DAT DXT1/3/5 surfaces retain their exact BC1/2/3 source blocks
|
||||||
|
through bake, mmap, and Vulkan upload. Clip maps and surfaces with authored
|
||||||
|
translucency still decode to RGBA8 because their per-surface alpha edits
|
||||||
|
require pixels. This is smaller and closer to retail's hardware DXT path
|
||||||
|
than the former unconditional software decode.
|
||||||
|
|
||||||
## Determinism and publication
|
## Determinism and publication
|
||||||
|
|
||||||
|
|
@ -79,7 +85,7 @@ DAT iterations, TOC counts, size, completion protocol, and SHA-256, then uses
|
||||||
the existing atomic promotion/backup transaction. Cancellation or failure
|
the existing atomic promotion/backup transaction. Cancellation or failure
|
||||||
keeps the verified format-1 package. No overlay may cross this format change.
|
keeps the verified format-1 package. No overlay may cross this format change.
|
||||||
|
|
||||||
## Checkpoint evidence
|
## Complete installed-DAT evidence
|
||||||
|
|
||||||
The first installed-DAT mixed sample (four GfxObj, three Setup, three EnvCell,
|
The first installed-DAT mixed sample (four GfxObj, three Setup, three EnvCell,
|
||||||
all corresponding collision/topology payloads) produced 58 keys, 29 globally
|
all corresponding collision/topology payloads) produced 58 keys, 29 globally
|
||||||
|
|
@ -88,9 +94,42 @@ deduplicated texture payloads, and 57 physical blobs. Decoded payload was
|
||||||
and three-worker bakes had the identical SHA-256
|
and three-worker bakes had the identical SHA-256
|
||||||
`78886DFA28A3EDF9368A1E25C9B02A3B69ADC5DFCC01358D64A073B549B5B532`.
|
`78886DFA28A3EDF9368A1E25C9B02A3B69ADC5DFCC01358D64A073B549B5B532`.
|
||||||
|
|
||||||
This sample is a checkpoint only. The size and performance release gates are
|
The final complete four-worker and nine-worker bakes are byte-identical:
|
||||||
decided by the complete installed-DAT package and connected world-loading
|
|
||||||
measurements.
|
- 2,237,866 logical keys and 786,892 physical blobs;
|
||||||
|
- 5,696 globally shared texture payloads;
|
||||||
|
- zero extraction/validation failures;
|
||||||
|
- 597,229,424 bytes (569.6 MiB), down 98.0% from 29,908,271,024 bytes;
|
||||||
|
- SHA-256
|
||||||
|
`37BC0EA1778F899AF9E3B2397937D373F69D615B15D3E32041BF389D93B624BF`;
|
||||||
|
- 28.7 seconds for the final four-worker bake versus 79.1 seconds for the
|
||||||
|
same-machine recipe-5 format-1 baseline (63.7% faster).
|
||||||
|
|
||||||
|
The exact before/after connected lifecycle route used the same machine,
|
||||||
|
server, 1280x720 Vulkan presentation, retail render pack, and matching client
|
||||||
|
code. Both runs passed fresh login, multi-world portal travel, same-location
|
||||||
|
revisit, fresh-process reconnect, and graceful teardown.
|
||||||
|
|
||||||
|
| Matching live measurement | Format 1 | Format 2 | Change |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| Heavy-route final working set | 2,621.9 MiB | 1,363.9 MiB | -48.0% |
|
||||||
|
| Heavy-route final private bytes | 2,470.5 MiB | 1,825.6 MiB | -26.1% |
|
||||||
|
| Holtburg prepared-mesh GPU bytes | 229.6 MiB | 170.1 MiB | -25.9% |
|
||||||
|
| Fresh reconnect working set | 974.1 MiB | 869.0 MiB | -10.8% |
|
||||||
|
| Fresh reconnect private bytes | 1,253.8 MiB | 1,166.6 MiB | -7.0% |
|
||||||
|
| Fresh reconnect to checkpoint | 59.3 s | 59.3 s | equal |
|
||||||
|
|
||||||
|
Rynthid and Facility transition times were equal; Holtburg completed 2.9 s
|
||||||
|
faster; Aerlinthe revisit differed by 0.1 s. Matching stable CPU p50/p95 rows
|
||||||
|
were equal or slightly faster and GPU time remained within 0.1 ms. The first
|
||||||
|
raw login samples were excluded from comparison because the server started
|
||||||
|
them in different cells with 6,671 versus 11,799 world entities. Matching
|
||||||
|
screenshots preserve geometry, materials, lighting, transparency, texture
|
||||||
|
detail, and mip behavior.
|
||||||
|
|
||||||
|
Automated gates at this checkpoint: 181/181 installed-DAT Content tests,
|
||||||
|
16,151/16,151 CI-filtered Windows tests, Release build with zero warnings, and
|
||||||
|
the authoritative connected lifecycle/reconnect gate all pass.
|
||||||
|
|
||||||
## Work ledger
|
## Work ledger
|
||||||
|
|
||||||
|
|
@ -100,10 +139,11 @@ measurements.
|
||||||
determinism.
|
determinism.
|
||||||
- [x] Integrate format-2 accounting and strict validation into the bake.
|
- [x] Integrate format-2 accounting and strict validation into the bake.
|
||||||
- [x] Publish the recipe-6 mandatory full-rebuild launcher migration.
|
- [x] Publish the recipe-6 mandatory full-rebuild launcher migration.
|
||||||
- [ ] Add launcher disk-space preflight and explicit long-work detail.
|
- [x] Add launcher disk-space preflight and explicit long-work detail.
|
||||||
- [ ] Complete installed-DAT equivalence and dual-worker full bakes.
|
- [x] Complete installed-DAT equivalence and dual-worker full bakes.
|
||||||
- [ ] Measure/tune package size, bake CPU/memory, read CPU/allocations, cold
|
- [x] Measure/tune package size, bake time, read CPU/allocations, cold
|
||||||
and warm reveal latency, and frame-time percentiles.
|
and warm reveal latency, and frame-time percentiles.
|
||||||
- [ ] Evaluate source-native BC texture retention only if it remains visually
|
- [x] Evaluate source-native BC texture retention only if it remains visually
|
||||||
exact and does not shift mip-generation work into the reveal frame.
|
exact and does not shift mip-generation work into the reveal frame.
|
||||||
- [ ] Pass complete tests, Windows CI, merge, push, and release gates.
|
- [x] Pass complete local tests and authoritative connected gates.
|
||||||
|
- [ ] Pass Gitea Windows CI, merge, push, and release gates.
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ public static class PakFormat {
|
||||||
/// 8 polygons all NoPos + Base1Solid, extracted to a 0-vertex mesh). The
|
/// 8 polygons all NoPos + Base1Solid, extracted to a 0-vertex mesh). The
|
||||||
/// binary format remains version 1. Version 6 introduces pak format 2:
|
/// binary format remains version 1. Version 6 introduces pak format 2:
|
||||||
/// globally shared texture payloads plus independently Brotli-compressed
|
/// globally shared texture payloads plus independently Brotli-compressed
|
||||||
/// blobs with raw fallback. Mesh geometry and decoded pixels remain exact.
|
/// blobs with raw fallback. Mesh geometry and source texture bytes remain
|
||||||
|
/// exact; unedited DXT surfaces now retain their native BC blocks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const uint CurrentBakeToolVersion = 6;
|
public const uint CurrentBakeToolVersion = 6;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue