1
0
Fork 0
polaris-task-force/src/lib/arma-bridge/processSyncEvents.ts

112 lines
3.5 KiB
TypeScript

import type { Payload } from "payload";
import { emitGameEvent } from "@/utils/event-log/emit";
import { EventTypes } from "@/utils/event-log/eventTypes";
import { broadcastToUser } from "@/lib/realtime/bus";
type ScoreboardField = "infantryKills" | "vehicleKills" | "armorKills" | "airKills" | "deaths";
const VEHICLE_CLASS_AIR = /(^|[_])(Heli|Plane|VTOL|UAV)(_|$)/i;
const VEHICLE_CLASS_ARMOR = /(^|[_])(MBT|APC|IFV|Tank|LT[_]?)(_|$)/i;
const VEHICLE_CLASS_INFANTRY = /(^|[_])(Soldier|Crew|Officer|Sniper|Spotter|Medic|Engineer|Rifleman|Grenadier|MachineGunner)(_|$)/i;
export function classifyKillCategory(victimVehicle: string | null | undefined): ScoreboardField {
if (!victimVehicle) return "infantryKills";
if (VEHICLE_CLASS_AIR.test(victimVehicle)) return "airKills";
if (VEHICLE_CLASS_ARMOR.test(victimVehicle)) return "armorKills";
if (VEHICLE_CLASS_INFANTRY.test(victimVehicle)) return "infantryKills";
return "vehicleKills";
}
interface KillPayload {
victimName: string;
killerName: string;
killerSteamId: string;
victimVehicle: string | null;
killerVehicle: string | null;
}
export function parseKillPayload(payload: unknown): KillPayload | null {
if (!Array.isArray(payload) || payload.length < 6) return null;
const victimName = String(payload[0] ?? "");
const killerName = String(payload[2] ?? "");
const killerSteamId = String(payload[3] ?? "");
const victimVehicle = payload[6] ? String(payload[6]) : null;
const killerVehicle = payload[7] ? String(payload[7]) : null;
if (!killerSteamId) return null;
return { victimName, killerName, killerSteamId, victimVehicle, killerVehicle };
}
export async function processPlayerKill(
payload: Payload,
eventDoc: { id: number; payload: unknown; occurredAt: string },
): Promise<void> {
const kill = parseKillPayload(eventDoc.payload);
if (!kill) return;
const users = await payload.find({
collection: "users",
where: { steamId: { equals: kill.killerSteamId } },
limit: 1,
depth: 0,
overrideAccess: true,
});
const user = users.docs[0];
if (!user) {
payload.logger.warn(
`[KillTracker] No user found for Steam ID ${kill.killerSteamId}; kill not recorded.`,
);
return;
}
const profiles = await payload.find({
collection: "profiles",
where: { user: { equals: user.id } },
limit: 1,
depth: 0,
overrideAccess: true,
});
const profile = profiles.docs[0];
if (!profile) {
payload.logger.warn(
`[KillTracker] No profile found for user ${user.id} (${user.username}); kill not recorded.`,
);
return;
}
const field = classifyKillCategory(kill.victimVehicle);
const current = (profile.progression?.scoreboard as Record<string, number | undefined>)?.[field] ?? 0;
await payload.update({
collection: "profiles",
id: profile.id,
data: {
progression: {
scoreboard: {
...((profile.progression?.scoreboard as Record<string, number>) ?? {}),
[field]: current + 1,
},
},
},
depth: 0,
overrideAccess: true,
});
await emitGameEvent(payload, {
type: EventTypes.PlayerKill,
actor: user.id,
message: `${kill.killerName} eliminated ${kill.victimName} (${field.replace("Kills", "")})`,
targetCollection: "users",
targetId: user.id,
data: {
victim: kill.victimName,
category: field,
victimVehicle: kill.victimVehicle,
killerVehicle: kill.killerVehicle,
},
});
broadcastToUser("profile-update", user.id, { profileId: profile.id });
}