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 running ACE server for connected play; the examples use
|
||||
`127.0.0.1:9000`
|
||||
- For the graphical client, a driver exposing the mandatory modern OpenGL
|
||||
capabilities
|
||||
- For the graphical client, a driver exposing the mandatory Vulkan
|
||||
capabilities validated at startup
|
||||
|
||||
The project does not distribute Microsoft/Turbine DAT files or derived
|
||||
prepared packages.
|
||||
|
|
@ -111,10 +111,9 @@ dotnet build AcDream.slnx -c Release
|
|||
dotnet test AcDream.slnx -c Release --no-build
|
||||
```
|
||||
|
||||
The current baseline is a successful Release build with **8,826 passing tests
|
||||
and 5 intentional skips**. The build currently reports 17 test-project
|
||||
warnings tracked by [`#228`](docs/ISSUES.md#228--clean-release-build-emits-17-test-project-warnings);
|
||||
production compilation has zero errors.
|
||||
The current CI-filtered Windows baseline is a successful Release build with
|
||||
**16,151 passing tests and zero failures**; opt-in live, installed-DAT,
|
||||
prepared-package, manual, timing, and platform-specific lanes run separately.
|
||||
|
||||
## 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"
|
||||
```
|
||||
|
||||
A complete package is approximately 30 GB. It is machine-local and must not be
|
||||
committed. `ACDREAM_PAK_PATH` overrides the default
|
||||
A complete format-2 package from the standard installed DAT set is about
|
||||
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`.
|
||||
|
||||
## Run the graphical client
|
||||
|
|
|
|||
|
|
@ -450,6 +450,15 @@ src/
|
|||
|
||||
Prepared-content launch contract
|
||||
-> `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
|
||||
base SHA; there is never an unbounded overlay chain
|
||||
-> `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):
|
||||
- `src/AcDream.Core/Rendering/Wb/` — pure helpers (no GL): `TerrainUtils`,
|
||||
`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,
|
||||
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`.**
|
||||
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/`
|
||||
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
|
||||
|
|
@ -84,7 +84,7 @@ behavior change, no divergence-register row.
|
|||
survive, as they always did). The MP1b bake tool passes its own
|
||||
collector.
|
||||
- **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`),
|
||||
`ObjectRenderData`/`ObjectRenderBatch`
|
||||
(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
|
||||
`IPreparedAssetSource`; typed GfxObj and EnvCell requests deserialize immutable
|
||||
`ObjectMeshData` while retaining the existing App worker, staging, render-thread
|
||||
upload, cache, ownership, and shutdown contracts. The original
|
||||
format-1/bake-tool-3 render payload persists exact batch translucency so App
|
||||
does not reconstruct a
|
||||
upload, cache, ownership, and shutdown contracts. The prepared render payload
|
||||
persists exact batch translucency so App does not reconstruct a
|
||||
`GfxObjMesh` for metadata. Setup activation uses the package TOC as an explicit
|
||||
type-presence index before reading valid Setup records through the bounded DAT
|
||||
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:
|
||||
`docs/plans/2026-08-25-launcher-content-stabilization.md`.
|
||||
|
||||
**Slice I3 prepared collision extension (2026-07-25).** The package remains
|
||||
format 1 and retains mesh type values 1–3; bake-tool 4 appends typed GfxObj,
|
||||
**PAK v2 resource closeout (2026-08-27).** Format 2 / bake recipe 6 retains
|
||||
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
|
||||
immutable flat records and deterministic raw-DAT flattener. Content owns the
|
||||
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
|
||||
baking, corruption isolation, and random-access loading;
|
||||
- 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
|
||||
permits it, without changing the rendered result;
|
||||
- reduces offline bake time and live client CPU/GPU memory where the data
|
||||
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
|
||||
retaining the last verified package until the replacement is validated;
|
||||
- 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,
|
||||
translucency, culling, and index data.
|
||||
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
|
||||
bake, making even a truncated-hash collision a loud bake failure rather
|
||||
than silent substitution.
|
||||
namespace. The writer retains the full SHA-256 digest and length for every
|
||||
unique texture, making even a truncated-key collision a loud bake failure
|
||||
rather than silent substitution without pinning another copy of all bytes.
|
||||
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
|
||||
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.
|
||||
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
|
||||
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.
|
||||
5. Whole-file compression is forbidden. It would destroy random access and
|
||||
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
|
||||
|
||||
|
|
@ -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
|
||||
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,
|
||||
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
|
||||
`78886DFA28A3EDF9368A1E25C9B02A3B69ADC5DFCC01358D64A073B549B5B532`.
|
||||
|
||||
This sample is a checkpoint only. The size and performance release gates are
|
||||
decided by the complete installed-DAT package and connected world-loading
|
||||
measurements.
|
||||
The final complete four-worker and nine-worker bakes are byte-identical:
|
||||
|
||||
- 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
|
||||
|
||||
|
|
@ -100,10 +139,11 @@ measurements.
|
|||
determinism.
|
||||
- [x] Integrate format-2 accounting and strict validation into the bake.
|
||||
- [x] Publish the recipe-6 mandatory full-rebuild launcher migration.
|
||||
- [ ] Add launcher disk-space preflight and explicit long-work detail.
|
||||
- [ ] Complete installed-DAT equivalence and dual-worker full bakes.
|
||||
- [ ] Measure/tune package size, bake CPU/memory, read CPU/allocations, cold
|
||||
- [x] Add launcher disk-space preflight and explicit long-work detail.
|
||||
- [x] Complete installed-DAT equivalence and dual-worker full bakes.
|
||||
- [x] Measure/tune package size, bake time, read CPU/allocations, cold
|
||||
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.
|
||||
- [ ] 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
|
||||
/// binary format remains version 1. Version 6 introduces pak format 2:
|
||||
/// 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>
|
||||
public const uint CurrentBakeToolVersion = 6;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue