maybeeee fix more stuff for gob videos (#1262)
This commit is contained in:
+108
-2
@@ -710,13 +710,18 @@ def _battle_type_candidates(battle_type: str) -> list[str]:
|
||||
mode = bt.split("_")[-1]
|
||||
out: list[str] = []
|
||||
if mode:
|
||||
out.append(f"{mode}_battle_area_realistic")
|
||||
out.append(f"{mode}_battle_area_arcade")
|
||||
out.append(f"{mode}_battle_area_hardcore")
|
||||
out.append(f"{mode}_battle_area")
|
||||
if "dom" in bt:
|
||||
out.append("dom_battle_area_realistic")
|
||||
out.append("dom_battle_area_arcade")
|
||||
out.append("dom_battle_area_hardcore")
|
||||
if "conq" in bt:
|
||||
out.append("conq_battle_area_realistic")
|
||||
out.append("conq_battle_area_arcade")
|
||||
out.append("conq_battle_area_hardcore")
|
||||
dedup: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for name in out:
|
||||
@@ -726,6 +731,19 @@ def _battle_type_candidates(battle_type: str) -> list[str]:
|
||||
return dedup
|
||||
|
||||
|
||||
def _battle_area_variant_priority(name: str) -> int:
|
||||
ln = name.lower()
|
||||
if "realistic" in ln:
|
||||
return 0
|
||||
if "hardcore" in ln:
|
||||
return 1
|
||||
if "arcade" in ln:
|
||||
return 2
|
||||
if "briefing" in ln or "brief_" in ln:
|
||||
return 3
|
||||
return 4
|
||||
|
||||
|
||||
def _select_battle_area_name(mission_def: dict | None,
|
||||
areas: dict[str, dict],
|
||||
battle_type: str) -> str:
|
||||
@@ -795,6 +813,80 @@ def resolve_world_bounds(level_def: dict,
|
||||
return c0, c1, f"battleArea:{battle_name}"
|
||||
|
||||
|
||||
def _ground_points_for_bounds_fit(ground_entities: list[dict]) -> list[tuple[float, float]]:
|
||||
pts: list[tuple[float, float]] = []
|
||||
for ent in ground_entities:
|
||||
for sample in ent.get("Path", []):
|
||||
try:
|
||||
pts.append((float(sample["X"]), float(sample["Z"])))
|
||||
except Exception:
|
||||
continue
|
||||
return pts
|
||||
|
||||
|
||||
def _bounds_coverage(points: list[tuple[float, float]], c0: list[float], c1: list[float]) -> float:
|
||||
if not points:
|
||||
return 0.0
|
||||
x_lo = min(float(c0[0]), float(c1[0]))
|
||||
x_hi = max(float(c0[0]), float(c1[0]))
|
||||
z_lo = min(float(c0[1]), float(c1[1]))
|
||||
z_hi = max(float(c0[1]), float(c1[1]))
|
||||
inside = 0
|
||||
for x, z in points:
|
||||
if x_lo <= x <= x_hi and z_lo <= z <= z_hi:
|
||||
inside += 1
|
||||
return inside / float(len(points))
|
||||
|
||||
|
||||
def _fit_world_bounds_to_ground_activity(c0: list[float], c1: list[float], coord_src: str,
|
||||
mission_def: dict | None, mission_def_path: Path | None,
|
||||
battle_type: str, ground_entities: list[dict],
|
||||
) -> tuple[list[float], list[float], str]:
|
||||
pts = _ground_points_for_bounds_fit(ground_entities)
|
||||
if not pts:
|
||||
return c0, c1, coord_src
|
||||
areas = _collect_mission_areas(mission_def, mission_def_path)
|
||||
if not areas:
|
||||
return c0, c1, coord_src
|
||||
|
||||
names: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for name in _mission_battle_area_targets(mission_def):
|
||||
if name in areas and name not in seen:
|
||||
seen.add(name)
|
||||
names.append(name)
|
||||
for name in _battle_type_candidates(battle_type):
|
||||
if name in areas and name not in seen:
|
||||
seen.add(name)
|
||||
names.append(name)
|
||||
if not names:
|
||||
return c0, c1, coord_src
|
||||
|
||||
candidates: list[tuple[str, list[float], list[float], float, float]] = []
|
||||
for name in names:
|
||||
area = areas.get(name)
|
||||
if not isinstance(area, dict):
|
||||
continue
|
||||
bounds = _box_bounds_from_tm(area)
|
||||
if bounds is None:
|
||||
continue
|
||||
bc0, bc1 = bounds
|
||||
cov = _bounds_coverage(pts, bc0, bc1)
|
||||
area_sz = abs((float(bc1[0]) - float(bc0[0])) * (float(bc1[1]) - float(bc0[1])))
|
||||
candidates.append((name, bc0, bc1, cov, area_sz))
|
||||
if not candidates:
|
||||
return c0, c1, coord_src
|
||||
|
||||
cur_cov = _bounds_coverage(pts, c0, c1)
|
||||
best_name, best_c0, best_c1, best_cov, _ = sorted(
|
||||
candidates, key=lambda t: (-t[3], _battle_area_variant_priority(t[0]), t[4])
|
||||
)[0]
|
||||
# Switch when current bounds miss noticeable movement.
|
||||
if best_cov > cur_cov + 0.02:
|
||||
return best_c0, best_c1, f"battleArea:{best_name}|fit={best_cov:.3f}"
|
||||
return c0, c1, coord_src
|
||||
|
||||
|
||||
def _capture_mode_prefixes(battle_type: str) -> list[str]:
|
||||
bt = _clean_map_key(battle_type).lower()
|
||||
if "conq" in bt:
|
||||
@@ -1201,7 +1293,7 @@ def _draw_capture_areas(img: Image.Image, capture_areas: list[dict],
|
||||
icon_size = 18
|
||||
rp = 8
|
||||
if len(outline_points) >= 3:
|
||||
outline = _pick_contrast_outline_color(out, outline_points)
|
||||
outline = (255, 255, 255)
|
||||
draw.line(outline_points + [outline_points[0]], fill=outline, width=stroke_w)
|
||||
# Keep icon area at ~1/4 of cap area (diamond area ~= s^2/2).
|
||||
area2 = 0.0
|
||||
@@ -1226,7 +1318,7 @@ def _draw_capture_areas(img: Image.Image, capture_areas: list[dict],
|
||||
(px + int(rp * 0.707), py - int(rp * 0.707)),
|
||||
(px - int(rp * 0.707), py - int(rp * 0.707)),
|
||||
]
|
||||
outline = _pick_contrast_outline_color(out, ring_samples)
|
||||
outline = (255, 255, 255)
|
||||
draw.ellipse((px - rp, py - rp, px + rp, py + rp), outline=outline, width=stroke_w)
|
||||
cap_area = math.pi * float(rp * rp)
|
||||
icon_size = max(10, min(canvas, int(round(math.sqrt(cap_area / 2.0)))))
|
||||
@@ -2532,6 +2624,11 @@ def render_gob(
|
||||
mission_def_path,
|
||||
battle_type,
|
||||
)
|
||||
tc0, tc1, coord_src = _fit_world_bounds_to_ground_activity(
|
||||
tc0, tc1, coord_src,
|
||||
mission_def, mission_def_path, battle_type,
|
||||
ground_ents,
|
||||
)
|
||||
tc0, tc1 = _expand_bounds_by_pixels(tc0, tc1, canvas=canvas, pad_px=MAP_PAD_PX)
|
||||
tc0, tc1 = _clamp_bounds_to_base(tc0, tc1, base_tc0, base_tc1)
|
||||
print(f"ok ({coord_src}) X=[{tc0[0]}, {tc1[0]}] Z=[{tc0[1]}, {tc1[1]}]")
|
||||
@@ -2988,6 +3085,10 @@ def export_replay_json(gob_path: Path) -> dict:
|
||||
level_path = level_override
|
||||
session_id = d.get("SessionID", 0)
|
||||
level_data = load_level_coords(level_path, session_id=session_id)
|
||||
ground_entities_for_bounds = [e for e in d.get("Entities", [])
|
||||
if e.get("PlayerID", 0) != 0
|
||||
and e.get("ModelName", "").startswith("tankModels/")
|
||||
and e.get("Path")]
|
||||
capture_areas = resolve_capture_areas(mission_def, mission_def_path, battle_type)
|
||||
if level_data:
|
||||
c0, c1, _ = resolve_world_bounds(
|
||||
@@ -2997,6 +3098,11 @@ def export_replay_json(gob_path: Path) -> dict:
|
||||
mission_def_path,
|
||||
battle_type,
|
||||
)
|
||||
c0, c1, _ = _fit_world_bounds_to_ground_activity(
|
||||
c0, c1, "json",
|
||||
mission_def, mission_def_path, battle_type,
|
||||
ground_entities_for_bounds,
|
||||
)
|
||||
c0, c1 = _expand_bounds_by_pixels(c0, c1, canvas=CANVAS_MIN, pad_px=MAP_PAD_PX)
|
||||
base_c0, base_c1, _ = select_tank_coords(level_data, use_alt_map_coord)
|
||||
c0, c1 = _clamp_bounds_to_base(c0, c1, base_c0, base_c1)
|
||||
|
||||
@@ -818,7 +818,7 @@ async def _process_squadron_points(
|
||||
# SAFE CHUNK BUILDER
|
||||
max_len = 1024
|
||||
chunks = []
|
||||
buf = "```\nName Change Now KDR KPS\n"
|
||||
buf = "```\nName Change Now KDR\n"
|
||||
|
||||
for uid, (delta, now) in sorted_changes:
|
||||
name_raw = (
|
||||
@@ -837,7 +837,7 @@ async def _process_squadron_points(
|
||||
current_points_str = f"{now:>6}"
|
||||
# DO NOT CHANGE
|
||||
|
||||
line = f"{member_str}{change_str}{current_points_str} {kdr_str:>5} {kps_str:>5}\n"
|
||||
line = f"{member_str}{change_str}{current_points_str} {kdr_str:>5}\n"
|
||||
|
||||
# Width-safe check
|
||||
if discord_len(buf) + discord_len(line) > max_len:
|
||||
|
||||
@@ -556,8 +556,7 @@ class ReplayCanvas {
|
||||
|
||||
let iconSize = 18;
|
||||
if (outlinePoints.length >= 3) {
|
||||
const outline = this._pickContrastOutlineColor(outlinePoints);
|
||||
this.mapCtx.strokeStyle = outline;
|
||||
this.mapCtx.strokeStyle = '#fff';
|
||||
this.mapCtx.lineWidth = RC_CAP_STROKE_PX;
|
||||
this.mapCtx.beginPath();
|
||||
this.mapCtx.moveTo(outlinePoints[0][0], outlinePoints[0][1]);
|
||||
@@ -591,8 +590,7 @@ class ReplayCanvas {
|
||||
[px + Math.round(rp * 0.707), py - Math.round(rp * 0.707)],
|
||||
[px - Math.round(rp * 0.707), py - Math.round(rp * 0.707)],
|
||||
];
|
||||
const outline = this._pickContrastOutlineColor(ringSamples);
|
||||
this.mapCtx.strokeStyle = outline;
|
||||
this.mapCtx.strokeStyle = '#fff';
|
||||
this.mapCtx.lineWidth = RC_CAP_STROKE_PX;
|
||||
this.mapCtx.beginPath();
|
||||
this.mapCtx.arc(px, py, rp, 0, Math.PI * 2);
|
||||
|
||||
Reference in New Issue
Block a user