Skip to content

Commit

Permalink
feat(lobbies.list_regions): return regions sorted by proximity to client
Browse files Browse the repository at this point in the history
  • Loading branch information
ABCxFF committed Sep 27, 2024
1 parent b86f5b1 commit 2eb8ffa
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 7 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 @@ -56,19 +56,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
8 changes: 6 additions & 2 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,7 +17,10 @@ export async function run(
): Promise<Response> {
const lobbyConfig = getLobbyConfig(ctx.config, req.tags ?? {});

const regions = regionsForBackend(lobbyConfig.backend)
const regions = getSortedRegionsByProximity(
regionsForBackend(lobbyConfig.backend),
getRequestGeoCoords(ctx),
);

return { regions };
}
Expand Down
45 changes: 44 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,40 @@ export function regionsForBackend(backend: LobbyBackend): Region[] {
else throw new UnreachableError(backend);
}

export const EMPTY_GEO_COORDS: RegionGeoCoords = Object.freeze({
latitude: 0,
longitude: 0
});

const getDistSq = (a: RegionGeoCoords, b: RegionGeoCoords) => {
const dlat = a.latitude - b.latitude;
const dlong = a.longitude - b.longitude;
return dlat * dlat + dlong * dlong;
}

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

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

type TraceEntry = ScriptContext["trace"]["entries"][0];
type TraceEntryTypeHttpRequest = Extract<TraceEntry["type"], { httpRequest: any }>["httpRequest"];
export const getRequestGeoCoords = (
ctx: ScriptContext
): RegionGeoCoords => {
// If they aren't real servers, we're probably not in managed
// So we just return
if (!("server" in ctx.config.lobbies.backend)) return EMPTY_GEO_COORDS;

// Check if env flag is set for managed
// TODO(Nathan): Set this flag to 1 for managed
if (ctx.environment.get("MANAGED") !== "1") return EMPTY_GEO_COORDS;

// TODO: Only check the first/last entry
let httpReq: TraceEntryTypeHttpRequest | null = null;
for (const entry of ctx.trace.entries) {
if ("httpRequest" in entry.type) {
httpReq = entry.type.httpRequest;
break;
}
}

if (!httpReq) return EMPTY_GEO_COORDS;

// TODO(Nathan):
// Add header to worker
if (!httpReq.headers["x-backend-client-coords"]) return EMPTY_GEO_COORDS;

// TODO: Optimize this
// Even add some checks for nan and infinities to be extra safe
const coords = httpReq.headers["x-backend-client-coords"].split(",").map(e => parseFloat(e.trim()));
if (coords.length !== 2) return EMPTY_GEO_COORDS;

return {
latitude: coords[0]!,
longitude: coords[1]!
}
}

0 comments on commit 2eb8ffa

Please sign in to comment.