maxpayne: stop the decal lift cracking surfaces, and spell the game's name - #38
Merged
Conversation
A quad split into two triangles gives two faces with the same bounding box, so each read as covering the other and the second rose eight millimetres off the plane. The gap shows as a hairline down the middle of every table top, wardrobe and picture frame at a grazing angle. Faces now stack only when they belong to different surfaces, keyed by the mesh and the material. Two pieces of one wardrobe top share both and stay put; a tag on a wall, a lit sign over a dark one, and two copies of the same prop differ in one or the other and still separate. Exact depth ties on `Part1_Level1` are 238, against 3882 when the key was the material alone.
The module went in as `maxpane`, which is not a word and not the game. Renames the package, the tests, the docs page and the `dade` subcommand.
There was a problem hiding this comment.
🔵 Needs a closer look
The change set is large (module rename plus substantial moved/added logic), and it’s safer to have a final human review confirm packaging/CLI compatibility and behavior across real data.
Pull request overview
This pull request follows up on the Max Payne importer/converter by (1) fixing decal “lift” behavior that was splitting coplanar surfaces (e.g., diagonally split quads) and (2) renaming the module/CLI/docs from maxpane to maxpayne to match the game name and package intent.
Changes:
- Adjust decal layering so faces only stack (lift) when they belong to different “surfaces” (now keyed by mesh + material), preventing visible cracks on flat geometry.
- Rename the Max Payne package, CLI command, docs API page, and test imports from
maxpanetomaxpayne. - Update/extend tests to reflect the new layering key and ensure decal lifting still resolves true depth ties.
File summaries
| File | Description |
|---|---|
| tests/test_cli.py | Updates expected CLI subcommand list to maxpayne. |
| tests/maxpayne/test_ras.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_models_command.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_model.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_memoryfile.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_ldb.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_gltf.py | Renames imports and updates decal-lift test expectations for new stacking key. |
| tests/maxpayne/test_decals.py | Updates layer_faces test inputs to include a surface key and adds regression coverage for split-surface triangles. |
| tests/maxpayne/test_crypto.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/test_commands.py | Renames command/module references and patched import paths to dade.maxpayne.*. |
| tests/maxpayne/test_blocks.py | Renames imports to dade.maxpayne.*. |
| tests/maxpayne/conftest.py | Updates docstring reference to dade.maxpayne.crypto.decrypt. |
| README.md | Updates CLI examples and references from maxpane to maxpayne. |
| docs/api/maxpayne.rst | Adds new API docs page for dade.maxpayne.*. |
| docs/api/maxpane.rst | Removes old API docs page for dade.maxpane.*. |
| docs/api/index.rst | Updates API index to reference maxpayne. |
| dade/maxpayne/typing.py | Updates module references in docstrings to dade.maxpayne. |
| dade/maxpayne/ras.py | Adds/renames RAS archive reader under dade.maxpayne. |
| dade/maxpayne/model.py | Adds/renames model reader under dade.maxpayne. |
| dade/maxpayne/memoryfile.py | Adds/renames tagged stream decoder under dade.maxpayne. |
| dade/maxpayne/main.py | Renames Click group from maxpane to maxpayne. |
| dade/maxpayne/ldb.py | Adds/renames level database reader under dade.maxpayne. |
| dade/maxpayne/gltf.py | Updates generator string and refines decal lifting inputs to include a surface key. |
| dade/maxpayne/decals.py | Changes layer_faces signature to accept a surface key and prevents stacking within the same surface. |
| dade/maxpayne/crypto.py | Adds/renames seeded stream cipher under dade.maxpayne. |
| dade/maxpayne/commands/utils.py | Updates debug logger routing to dade.maxpayne. |
| dade/maxpayne/commands/sources.py | Renames RAS magic import to dade.maxpayne.ras. |
| dade/maxpayne/commands/ras_list.py | Updates help text and imports to dade.maxpayne. |
| dade/maxpayne/commands/ras_extract.py | Updates help text and imports to dade.maxpayne. |
| dade/maxpayne/commands/models.py | Renames imports/types to dade.maxpayne. |
| dade/maxpayne/commands/ldb2glb.py | Updates help text and imports to dade.maxpayne. |
| dade/maxpayne/commands/ldb_textures.py | Updates help text and imports to dade.maxpayne. |
| dade/maxpayne/commands/inspect_tags.py | Updates help text and imports to dade.maxpayne. |
| dade/maxpayne/commands/init.py | Adds package init for dade.maxpayne.commands. |
| dade/maxpayne/blocks.py | Adds/renames block wrapper utilities under dade.maxpayne. |
| dade/maxpayne/init.py | Adds package-level documentation for dade.maxpayne. |
| dade/main.py | Switches main CLI wiring from maxpane to maxpayne. |
| .vscode/dictionary.txt | Removes maxpane and keeps maxpayne in the spellcheck dictionary. |
Review details
- Files reviewed: 30/38 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two follow-ups to #37.
The decal lift was cracking flat surfaces
A quad split into two triangles gives two faces with the same bounding box, so each read as
covering the other and the second rose
DECAL_STEPoff the plane. At a grazing angle the gapshows as a hairline down the middle of every table top, wardrobe and picture frame.
Faces now stack only when they belong to different surfaces, keyed by the mesh and the material.
Two pieces of one wardrobe top share both and stay put; a tag on a wall, a lit sign over a dark
one, and two copies of the same prop differ in one or the other and still separate.
Keying on the material alone was not enough — it also stopped separating duplicated props, which
share a material across two meshes, and took
Part1_Level1from 139 exact depth ties to 3882. Withthe mesh in the key it is 238.
Spelling
The module went in as
maxpane, which is not a word and not the game. The package, the tests, thedocs page and the
dadesubcommand are renamed tomaxpayne.Checks
uv run pytest tests/maxpayne --cov=dade.maxpayne— 239 passed, 100% statement and branchyarn gen-docs— builds; the only warning is the missing localgraphvizbinaryruff,mypy,cspell— cleandade maxpayne ldb2glbover the shipped data — 29/29 levels