One Command Loads a Map
A djb2-hashed PK3 index cached in localStorage, and a loadMap pipeline that resolves every dependency a map needs before it draws anything.
The Index
A djb2 hash of `pk3name:size` pairs for cache invalidation, saved to localStorage. PK3Index answers findFile(path), findShader(name), findMap(name), findPK3sForTextures(paths), getMapNames() and getShaderNames().
Index build is ~2-5s for 20+ PK3s. Size is 100-500KB in localStorage.
Hashing name and size rather than modification time is a deliberate choice: file mtimes are not stable across a download, and an index that invalidates itself on every fresh copy of the same game is an index nobody trusts.
The Pipeline
loadMap(name)
-> findMap -> loadBsp -> resolveMapDependencies -> loadRequiredPK3s
-> loadShaders -> buildMesh -> applyTextures -> applySkybox -> applyLightmapsCommands: map <name>|list|current|reload|unload, pk3 index build|stats|clear, shader deps <path>.
The Fixes
Flare halos became transparent (GL_ONE GL_ONE_MINUS_SRC_COLOR), skybox paths stopped double-prefixing env/, filter/multiply decal shaders got depthWrite = false, and BSP command state stayed in sync with map-loaded maps.
Known Limitations
- Requires
pk3_manifest.jsonin the game folder for PK3 discovery, or falls back
to pattern matching.
- Local
.mapfile loading not yet integrated (BSP only). - Decal z-fighting —
polygonOffsetdecals still have z-fighting issues with
underlying geometry. "Needs proper decal rendering with depth sorting or stencil buffer."
That decal line survives all the way to v0.8.10 and is still, four years and thousands of commits later, the honest answer for textures/decals/plasterworn0030.