This commit is contained in:
NotSoToothless
2026-05-19 18:06:30 -07:00
committed by GitHub
parent f511cdc083
commit b36886425b
2 changed files with 55 additions and 2 deletions
+5 -1
View File
@@ -3085,12 +3085,15 @@ def export_replay_json(gob_path: Path) -> dict:
level_path = level_override level_path = level_override
session_id = d.get("SessionID", 0) session_id = d.get("SessionID", 0)
level_data = load_level_coords(level_path, session_id=session_id) level_data = load_level_coords(level_path, session_id=session_id)
tank_map_coords = None
ground_entities_for_bounds = [e for e in d.get("Entities", []) ground_entities_for_bounds = [e for e in d.get("Entities", [])
if e.get("PlayerID", 0) != 0 if e.get("PlayerID", 0) != 0
and e.get("ModelName", "").startswith("tankModels/") and e.get("ModelName", "").startswith("tankModels/")
and e.get("Path")] and e.get("Path")]
capture_areas = resolve_capture_areas(mission_def, mission_def_path, battle_type) capture_areas = resolve_capture_areas(mission_def, mission_def_path, battle_type)
if level_data: if level_data:
base_c0, base_c1, _ = select_tank_coords(level_data, use_alt_map_coord)
tank_map_coords = {"x0": base_c0[0], "z0": base_c0[1], "x1": base_c1[0], "z1": base_c1[1]}
c0, c1, _ = resolve_world_bounds( c0, c1, _ = resolve_world_bounds(
level_data, level_data,
use_alt_map_coord, use_alt_map_coord,
@@ -3104,7 +3107,6 @@ def export_replay_json(gob_path: Path) -> dict:
ground_entities_for_bounds, ground_entities_for_bounds,
) )
c0, c1 = _expand_bounds_by_pixels(c0, c1, canvas=CANVAS_MIN, pad_px=MAP_PAD_PX) 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) c0, c1 = _clamp_bounds_to_base(c0, c1, base_c0, base_c1)
level_coords = {"x0": c0[0], "z0": c0[1], "x1": c1[0], "z1": c1[1]} level_coords = {"x0": c0[0], "z0": c0[1], "x1": c1[0], "z1": c1[1]}
else: else:
@@ -3231,6 +3233,8 @@ def export_replay_json(gob_path: Path) -> dict:
"kills": kills_out, "kills": kills_out,
"damages": damages_out, "damages": damages_out,
} }
if tank_map_coords:
out["tankMapCoords"] = tank_map_coords
if map_coords and full_map_level: if map_coords and full_map_level:
out["mapCoords"] = map_coords out["mapCoords"] = map_coords
out["fullMapLevel"] = full_map_level out["fullMapLevel"] = full_map_level
+50 -1
View File
@@ -40,6 +40,7 @@ class ReplayCanvas {
// Store both coordinate sets // Store both coordinate sets
this._groundCoords = data.levelCoords; this._groundCoords = data.levelCoords;
this._tankMapCoords = data.tankMapCoords || data.levelCoords;
this._airCoords = data.mapCoords || null; this._airCoords = data.mapCoords || null;
this._fullMapLevel = data.fullMapLevel || null; this._fullMapLevel = data.fullMapLevel || null;
this.captureAreas = Array.isArray(data.captureAreas) ? data.captureAreas : []; this.captureAreas = Array.isArray(data.captureAreas) ? data.captureAreas : [];
@@ -53,6 +54,7 @@ class ReplayCanvas {
this.zRange = data.levelCoords.z1 - data.levelCoords.z0; this.zRange = data.levelCoords.z1 - data.levelCoords.z0;
// Source rect for minimap image (full image by default) // Source rect for minimap image (full image by default)
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 }; this._mapSrc = { u: 0, v: 0, w: 1, h: 1 };
this._updateMapSourceRect();
this.players = {}; this.players = {};
for (const p of data.players) this.players[p.id] = p; for (const p of data.players) this.players[p.id] = p;
@@ -470,6 +472,53 @@ class ReplayCanvas {
ctx.drawImage(img, x - size / 2 + dx, y - size / 2 + dy, dw, dh); ctx.drawImage(img, x - size / 2 + dx, y - size / 2 + dy, dw, dh);
} }
_updateMapSourceRect() {
// Air/full-map mode always uses the full source image.
if (this._mode !== 'ground') {
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 };
return;
}
const base = this._tankMapCoords || this._groundCoords;
const render = this._groundCoords;
if (!base || !render) {
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 };
return;
}
const bx0 = Number(base.x0), bz0 = Number(base.z0);
const bx1 = Number(base.x1), bz1 = Number(base.z1);
const rx0 = Number(render.x0), rz0 = Number(render.z0);
const rx1 = Number(render.x1), rz1 = Number(render.z1);
const dx = bx1 - bx0;
const dz = bz1 - bz0;
if (!Number.isFinite(dx) || !Number.isFinite(dz) || dx === 0 || dz === 0) {
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 };
return;
}
const xLo = Math.min(rx0, rx1), xHi = Math.max(rx0, rx1);
const zLo = Math.min(rz0, rz1), zHi = Math.max(rz0, rz1);
const u0 = (xLo - bx0) / dx;
const u1 = (xHi - bx0) / dx;
const v0 = (zLo - bz0) / dz;
const v1 = (zHi - bz0) / dz;
const uMin = Math.max(0, Math.min(1, Math.min(u0, u1)));
const uMax = Math.max(0, Math.min(1, Math.max(u0, u1)));
const vMin = Math.max(0, Math.min(1, Math.min(v0, v1)));
const vMax = Math.max(0, Math.min(1, Math.max(v0, v1)));
const w = uMax - uMin;
const h = vMax - vMin;
if (!(w > 0 && h > 0)) {
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 };
return;
}
// Source top-left in image space: X -> uMin, Z -> (1 - vMax)
this._mapSrc = { u: uMin, v: 1 - vMax, w, h };
}
_capOutlinePoints(cap) { _capOutlinePoints(cap) {
const tm = cap?.tm; const tm = cap?.tm;
if (!tm || !Array.isArray(tm.a0) || !Array.isArray(tm.a2) || !Array.isArray(tm.center)) return []; if (!tm || !Array.isArray(tm.a0) || !Array.isArray(tm.a2) || !Array.isArray(tm.center)) return [];
@@ -694,7 +743,7 @@ class ReplayCanvas {
this.z0 = coords.z0; this.z0 = coords.z0;
this.xRange = coords.x1 - coords.x0; this.xRange = coords.x1 - coords.x0;
this.zRange = coords.z1 - coords.z0; this.zRange = coords.z1 - coords.z0;
this._mapSrc = { u: 0, v: 0, w: 1, h: 1 }; this._updateMapSourceRect();
// Redraw map background with new crop region // Redraw map background with new crop region
this._drawMapToCanvas(); this._drawMapToCanvas();