feat: HellDrinx takeaways — conflict blocklist + vehicle path signal
Two narrow additions adopted from a review of HellDrinx Mod Manager (/tmp/helldrinx-modmanager-PZ-main.zip), per docs/plans/ (planning conversation, no spec checked in). A. _IGNORED_FILENAMES in api/diagnostics.py — skip filenames that are intended merge points (PZ engine-concatenated or framework hooks) from /api/conflicts output. Multiple distinct sha1s for these files is by-design, not a conflict. Live cache had 33 providers shipping sandbox-options.txt with 31 distinct hashes — those would have been 31 false-positive conflict rows on any sort spanning them. B. Path-based Vehicles signal in worker.build_manifest_and_types — extended the existing scripts/vehicles[/] check with models_x/vehicles/ and models/vehicles/. Catches vehicle mods that ship 3D assets without scripts (rare but real); still requires the user-build's manifest to be rebuilt before mod_types reflects it.
This commit is contained in:
@@ -14,6 +14,29 @@ from typing import Dict, List, Tuple
|
|||||||
from mlos_sort import ModInfo
|
from mlos_sort import ModInfo
|
||||||
|
|
||||||
|
|
||||||
|
# Filenames that legitimately appear across multiple mods because they're
|
||||||
|
# intended merge points — either PZ engine-merged at runtime, or framework
|
||||||
|
# extension hooks where multiple client mods coexist by design. Multiple
|
||||||
|
# distinct sha1s here is by-design, not a conflict, so we skip them in
|
||||||
|
# scan_file_conflicts. Sourced from HellDrinx Mod Manager's known false-
|
||||||
|
# positive list (backend/services/workshop.cjs); add more here as we
|
||||||
|
# encounter them.
|
||||||
|
_IGNORED_FILENAMES = {
|
||||||
|
# PZ engine-merged at load time
|
||||||
|
"sandbox-options.txt",
|
||||||
|
"fileguidtable.xml",
|
||||||
|
# Framework extension hooks (designed for many mods to override)
|
||||||
|
"mf_ismoodle.lua", # MoodleFramework hook
|
||||||
|
"kp_extrabodylocations.lua", # KP body-locations framework hook
|
||||||
|
"registries.lua", # damnlib-style registry framework
|
||||||
|
# Specific mod-side merge points
|
||||||
|
"hat_gasmask.xml",
|
||||||
|
"hat_gasmask_nofilter.xml",
|
||||||
|
"sounds_tmrremovemumble.txt",
|
||||||
|
"null.wav", # silent placeholder, deliberately shared
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FileConflict:
|
class FileConflict:
|
||||||
rel_path: str
|
rel_path: str
|
||||||
@@ -59,7 +82,14 @@ async def scan_file_conflicts(conn, mods: List[ModInfo]) -> List[FileConflict]:
|
|||||||
idx = order_index.get(mod_id)
|
idx = order_index.get(mod_id)
|
||||||
if idx is None:
|
if idx is None:
|
||||||
continue
|
continue
|
||||||
by_path[r["rel_path"]].append((idx, mod_id, r["sha1"]))
|
rel_path = r["rel_path"]
|
||||||
|
# Skip known intended-merge-point filenames (engine-concatenated or
|
||||||
|
# framework hooks). These produce noisy false positives because
|
||||||
|
# multiple mods adding sandbox vars / framework hooks is by design.
|
||||||
|
basename = rel_path.rsplit("/", 1)[-1]
|
||||||
|
if basename in _IGNORED_FILENAMES:
|
||||||
|
continue
|
||||||
|
by_path[rel_path].append((idx, mod_id, r["sha1"]))
|
||||||
|
|
||||||
conflicts: List[FileConflict] = []
|
conflicts: List[FileConflict] = []
|
||||||
for rel, entries in by_path.items():
|
for rel, entries in by_path.items():
|
||||||
|
|||||||
@@ -431,7 +431,13 @@ def build_manifest_and_types(
|
|||||||
or suffix in {".png", ".dds"}):
|
or suffix in {".png", ".dds"}):
|
||||||
if path.name.lower() != "poster.png":
|
if path.name.lower() != "poster.png":
|
||||||
tags.add("Textures")
|
tags.add("Textures")
|
||||||
if rel_below.startswith(("scripts/vehicles/", "scripts/vehicle")):
|
# Path-based vehicle detection. scripts/vehicles is the universal
|
||||||
|
# signal; models[_x]/vehicles/ catches mods that ship 3D assets
|
||||||
|
# without scripts (rarer, but real — borrowed from HellDrinx Mod
|
||||||
|
# Manager's heuristic). rel_below is already lowercased so the
|
||||||
|
# capital "X" in the original PZ "models_X" path lands as "models_x".
|
||||||
|
if rel_below.startswith(("scripts/vehicles/", "scripts/vehicle",
|
||||||
|
"models_x/vehicles/", "models/vehicles/")):
|
||||||
tags.add("Vehicles")
|
tags.add("Vehicles")
|
||||||
if rel_below.startswith(("clothing/", "scripts/clothing/")):
|
if rel_below.startswith(("clothing/", "scripts/clothing/")):
|
||||||
tags.add("Clothing")
|
tags.add("Clothing")
|
||||||
|
|||||||
Reference in New Issue
Block a user