import { eq } from "drizzle-orm"; import { db } from "./db/client"; import { servers } from "./db/schema"; import { redis } from "./redis"; export interface PlayerPosition { uuid: string; username: string; x: number; y: number; z: number; } export function playerChannel(serverId: string): string { return `mcmapper:players:${serverId}`; } function snapshotKey(serverId: string): string { return `mcmapper:players:snapshot:${serverId}`; } export async function arePlayerPositionsVisible(serverId: string): Promise { const [row] = await db .select({ playerPositionsVisible: servers.playerPositionsVisible }) .from(servers) .where(eq(servers.id, serverId)) .limit(1); return row?.playerPositionsVisible ?? false; } /** * Fans a player roster out to every browser subscribed to this server's channel, and stashes it * in Redis so a browser tab that connects between mod flushes gets the current roster immediately * instead of waiting up to `playerPositionIntervalTicks` for the next one — see * players-gateway.ts's `open()`. No history/persistence beyond the latest snapshot: unlike chat, * player positions have no meaningful "history" to keep. */ export async function publishPlayerPositions(serverId: string, dimension: number, players: PlayerPosition[]) { const payload = JSON.stringify({ dimension, players }); await redis.set(snapshotKey(serverId), payload); await redis.publish(playerChannel(serverId), payload); } export async function getPlayerSnapshot(serverId: string): Promise { return redis.get(snapshotKey(serverId)); }