blanchon's picture
Nerfies-style home, paper-style match header, prettier setup, dataset README
95e3d2a
// CS2 map calibration. `pos_x`, `pos_y` are the world coords of the radar
// PNG's upper-left corner; `scale` is units-per-pixel. Multi-floor maps use
// `lower_level_max_units` as a Z threshold: any player at or below it is on
// the lower floor and should be drawn against the `_lower` radar.
//
// Source: awpy's map-data.json (https://awpycs.com/<patch>/maps.zip).
export type MapData = {
pos_x: number;
pos_y: number;
scale: number;
rotate: number | null;
zoom: number | null;
lower_level_max_units: number;
};
export const RADAR_PX = 1024;
let cache: Record<string, MapData> | null = null;
let inflight: Promise<Record<string, MapData>> | null = null;
export async function loadMapData(fetchFn: typeof fetch = fetch): Promise<Record<string, MapData>> {
if (cache) return cache;
if (!inflight) {
inflight = fetchFn('/maps/map-data.json')
.then((r) => {
if (!r.ok) throw new Error(`map-data.json ${r.status}`);
return r.json() as Promise<Record<string, MapData>>;
})
.then((d) => {
cache = d;
return d;
});
}
return inflight;
}
export type Floor = 'upper' | 'lower';
export function radarUrl(mapName: string, floor: Floor): string {
return floor === 'lower' ? `/maps/${mapName}_lower.webp` : `/maps/${mapName}.webp`;
}
export function hasLowerFloor(map: MapData): boolean {
// awpy uses -1_000_000 as the sentinel for "no lower floor".
return map.lower_level_max_units > -100_000;
}
export function floorForZ(map: MapData, z: number): Floor {
if (!hasLowerFloor(map)) return 'upper';
// de_vertigo is sky-high (lower_level_max_units = 11700 means below that =
// lower B site). de_nuke / de_train use a negative threshold. The
// inequality is the same in both cases.
return z <= map.lower_level_max_units ? 'lower' : 'upper';
}
export function worldToImage(map: MapData, x: number, y: number): { px: number; py: number } {
return {
px: (x - map.pos_x) / map.scale,
py: (map.pos_y - y) / map.scale
};
}
// CS yaw: 0° = +X (east), 90° = +Y (north), CCW positive. Image space has
// Y pointing down, so a screen-space rotation of `-yaw` makes an icon whose
// "forward" is +X point in the player's facing direction.
export function yawToScreenDeg(yaw: number): number {
return -yaw;
}