meow (#1344)
This commit is contained in:
+40
-22
@@ -971,6 +971,42 @@ def _capture_tm_vectors(tm: list) -> tuple[np.ndarray, np.ndarray, np.ndarray, n
|
|||||||
return a0, a1, a2, c
|
return a0, a1, a2, c
|
||||||
|
|
||||||
|
|
||||||
|
def _halve_outlier_capture_area(areas: list[dict]) -> list[dict]:
|
||||||
|
"""Halve a single capture area whose radius is a strong outlier.
|
||||||
|
|
||||||
|
Some definitions report one capture point at roughly double its true radius
|
||||||
|
(a known datamine quirk that also rides along in the replay's own zone
|
||||||
|
geometry). When exactly one area among at least three exceeds 2x the median
|
||||||
|
sibling radius, halve it — radius plus its tm X/Z basis so the rendered
|
||||||
|
outline matches. Applied to every capture-area source so the correction is
|
||||||
|
independent of whether geometry came from the mission .blk or the replay
|
||||||
|
zone data fallback.
|
||||||
|
"""
|
||||||
|
if len(areas) < 3:
|
||||||
|
return areas
|
||||||
|
radii = sorted(float(c["radius"]) for c in areas if float(c.get("radius", 0.0)) > 0.0)
|
||||||
|
if len(radii) < 3:
|
||||||
|
return areas
|
||||||
|
median_r = radii[len(radii) // 2]
|
||||||
|
if median_r <= 0.0:
|
||||||
|
return areas
|
||||||
|
outlier = [
|
||||||
|
i for i, c in enumerate(areas)
|
||||||
|
if float(c.get("radius", 0.0)) > (2.0 * median_r)
|
||||||
|
]
|
||||||
|
if len(outlier) != 1:
|
||||||
|
return areas
|
||||||
|
oi = outlier[0]
|
||||||
|
areas[oi]["radius"] = float(areas[oi]["radius"]) * 0.5
|
||||||
|
tm = areas[oi].get("tm")
|
||||||
|
if isinstance(tm, dict):
|
||||||
|
for key in ("a0", "a2"):
|
||||||
|
vec = tm.get(key)
|
||||||
|
if isinstance(vec, list) and len(vec) >= 3:
|
||||||
|
tm[key] = [float(vec[0]) * 0.5, float(vec[1]) * 0.5, float(vec[2]) * 0.5]
|
||||||
|
return areas
|
||||||
|
|
||||||
|
|
||||||
def resolve_capture_areas(mission_def: dict | None, mission_def_path: Path | None,
|
def resolve_capture_areas(mission_def: dict | None, mission_def_path: Path | None,
|
||||||
battle_type: str) -> list[dict]:
|
battle_type: str) -> list[dict]:
|
||||||
"""Resolve gameplay capture areas from mission imports (mode-specific)."""
|
"""Resolve gameplay capture areas from mission imports (mode-specific)."""
|
||||||
@@ -1058,27 +1094,8 @@ def resolve_capture_areas(mission_def: dict | None, mission_def_path: Path | Non
|
|||||||
"radius": _capture_radius_from_tm(tm),
|
"radius": _capture_radius_from_tm(tm),
|
||||||
"tm": tm_data,
|
"tm": tm_data,
|
||||||
})
|
})
|
||||||
# If exactly one cap is a strong outlier (>2x median sibling radius),
|
# Correct a single oversized-outlier cap, regardless of geometry source.
|
||||||
# halve only that cap (including tm X/Z basis so rendered outline matches).
|
return _halve_outlier_capture_area(out)
|
||||||
if len(out) >= 3:
|
|
||||||
radii = sorted(float(c["radius"]) for c in out if float(c["radius"]) > 0.0)
|
|
||||||
if len(radii) >= 3:
|
|
||||||
median_r = radii[len(radii) // 2]
|
|
||||||
if median_r > 0.0:
|
|
||||||
outlier = [
|
|
||||||
i for i, c in enumerate(out)
|
|
||||||
if float(c.get("radius", 0.0)) > (2.0 * median_r)
|
|
||||||
]
|
|
||||||
if len(outlier) == 1:
|
|
||||||
oi = outlier[0]
|
|
||||||
out[oi]["radius"] = float(out[oi]["radius"]) * 0.5
|
|
||||||
tm = out[oi].get("tm")
|
|
||||||
if isinstance(tm, dict):
|
|
||||||
for key in ("a0", "a2"):
|
|
||||||
vec = tm.get(key)
|
|
||||||
if isinstance(vec, list) and len(vec) >= 3:
|
|
||||||
tm[key] = [float(vec[0]) * 0.5, float(vec[1]) * 0.5, float(vec[2]) * 0.5]
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def _capture_areas_from_zone_geometry(zone_geometry: dict | None) -> list[dict]:
|
def _capture_areas_from_zone_geometry(zone_geometry: dict | None) -> list[dict]:
|
||||||
@@ -1107,7 +1124,7 @@ def _capture_areas_from_zone_geometry(zone_geometry: dict | None) -> list[dict]:
|
|||||||
"radius": radius,
|
"radius": radius,
|
||||||
"tm": None,
|
"tm": None,
|
||||||
})
|
})
|
||||||
return out
|
return _halve_outlier_capture_area(out)
|
||||||
|
|
||||||
|
|
||||||
def _world_to_map_px(x: float, z: float, x0: float, z0: float, xr: float, zr: float, canvas: int) -> tuple[int, int]:
|
def _world_to_map_px(x: float, z: float, x0: float, z0: float, xr: float, zr: float, canvas: int) -> tuple[int, int]:
|
||||||
@@ -3727,6 +3744,7 @@ def export_replay_json(replay_path: Path) -> dict:
|
|||||||
|
|
||||||
map_coords = None
|
map_coords = None
|
||||||
full_map_level = None
|
full_map_level = None
|
||||||
|
mc0 = mc1 = None
|
||||||
if level_data:
|
if level_data:
|
||||||
try:
|
try:
|
||||||
mc0, mc1, _ = select_map_coords(level_data)
|
mc0, mc1, _ = select_map_coords(level_data)
|
||||||
|
|||||||
Reference in New Issue
Block a user