Skip to content

Commit

Permalink
fix(lobbies-regions): Use proper distance calculations for (long, lat…
Browse files Browse the repository at this point in the history
…) coords
  • Loading branch information
ABCxFF committed Sep 29, 2024
1 parent 411dc9c commit 05e2458
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 9 deletions.
8 changes: 4 additions & 4 deletions modules/lobbies/scripts/find_or_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface Request {
noWait?: boolean;

createConfig: {
region: string;
region: string;
tags?: Record<string, string>;
maxPlayers: number;
maxPlayersDirect: number;
Expand Down Expand Up @@ -60,19 +60,19 @@ export async function run(
{
query: {
version: req.version,
regions: req.regions,
regions: req.regions,
tags: req.tags,
},
lobby: {
lobbyId,
version: req.version,
region: req.createConfig.region,
region: req.createConfig.region,
tags: req.createConfig.tags,
maxPlayers: req.createConfig.maxPlayers,
maxPlayersDirect: req.createConfig.maxPlayersDirect,
},
players: req.players,
noWait: req.noWait ?? false,
noWait: req.noWait ?? false,
}
);

Expand Down
15 changes: 11 additions & 4 deletions modules/lobbies/scripts/list_regions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RuntimeError, ScriptContext } from "../module.gen.ts";
import { getLobbyConfig } from "../utils/lobby_config.ts";
import { Region, regionsForBackend } from "../utils/region.ts";
import { getSortedRegionsByProximity, Region, regionsForBackend } from "../utils/region.ts";
import { getRequestGeoCoords } from "../utils/rivet/geo_coord.ts";

export interface Request {
tags?: Record<string, string>,
Expand All @@ -16,8 +17,14 @@ export async function run(
): Promise<Response> {
const lobbyConfig = getLobbyConfig(ctx.config, req.tags ?? {});

const regions = regionsForBackend(lobbyConfig.backend)

return { regions };
const coords = getRequestGeoCoords(ctx);
const regions = regionsForBackend(lobbyConfig.backend);
if (!coords) {
return { regions };
}

return {
regions: getSortedRegionsByProximity(regions, coords)
}
}

51 changes: 50 additions & 1 deletion modules/lobbies/utils/region.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import { REGIONS as LOCAL_DEVELOPMENT_REGIONS } from "./lobby/backend/local_deve
import { UnreachableError } from "../module.gen.ts";
import { LobbyBackend } from "../config.ts";

export interface Region {
export interface RegionGeoCoords {
latitude: number;
longitude: number;
}


export interface Region extends RegionGeoCoords {
id: string;
name: string;
latitude: number;
Expand All @@ -22,3 +28,46 @@ export function regionsForBackend(backend: LobbyBackend): Region[] {
else throw new UnreachableError(backend);
}

// Using haversine formula to calculate approximate distance
function getDistance(a: RegionGeoCoords, b: RegionGeoCoords) {
const EARTH_RADIUS = 6371; // Radius of the earth in km
const DEG_2_RAD = (Math.PI / 180);

const deltaLatitude = DEG_2_RAD * (b.latitude - a.latitude);
const deltaLongitude = DEG_2_RAD * (b.longitude - a.longitude);

const aLatitude = DEG_2_RAD * a.latitude;
const bLatitude = DEG_2_RAD * b.latitude;

const sinOfDLat = Math.sin(deltaLatitude / 2);
const sinOfDLon = Math.sin(deltaLongitude / 2);
const x = sinOfDLat * sinOfDLat + sinOfDLon * sinOfDLon * Math.cos(aLatitude) * Math.cos(bLatitude);
const unitDistance = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));

return EARTH_RADIUS * unitDistance;
}

export function getClosestRegion(
region: Region[],
coords: RegionGeoCoords
) {
let closestRegion: Region | null = null;
let closestDistance = Infinity;
for (const r of region) {
const distance = getDistance(r, coords);
if (distance < closestDistance) {
closestRegion = r;
closestDistance = distance;
}
}
return closestRegion;
}

export function getSortedRegionsByProximity(
regions: Region[],
coords: RegionGeoCoords
) {
return [...regions].sort((a, b) => {
return getDistance(a, coords) - getDistance(b, coords);
});
}
44 changes: 44 additions & 0 deletions modules/lobbies/utils/rivet/geo_coord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ScriptContext } from "../../module.gen.ts";
import { RegionGeoCoords } from "../region.ts";

export function getRequestGeoCoords(
ctx: ScriptContext
): RegionGeoCoords | undefined {
// If they aren't real servers, we're probably not in managed
// So we just return
if (!("server" in ctx.config.lobbies.backend)) {
return undefined;
}

if (ctx.environment.get("RIVET_BACKEND_RUNTIME") !== "cloudflare_workers_platforms") {
return undefined;
}

const topLevelTrace = ctx.trace.entries[0];
if (!topLevelTrace || !("httpRequest" in topLevelTrace.type)) {
return undefined;
}

const httpReq = topLevelTrace.type.httpRequest
if (!httpReq) {
return undefined;
}

if (!httpReq.headers["x-backend-client-coords"]) {
throw new Error("Missing x-backend-client-coords header");
}

const [latitudeStr, longitudeStr] = httpReq.headers["x-backend-client-coords"].split(",") as [string, string];

const longitude = parseFloat(longitudeStr.trim());
const latitude = parseFloat(latitudeStr.trim());

if (!isFinite(longitude) || !isFinite(latitude)) {
throw new Error("Invalid x-backend-client-coords header (non-finite)");
}

return {
latitude,
longitude
}
}

0 comments on commit 05e2458

Please sign in to comment.