1
0
Fork 0
polaris-task-force/src/app/(frontend)/flappy/actions.ts

126 lines
3.5 KiB
TypeScript

"use server";
import config from "@payload-config";
import { getPayload } from "payload";
import { emitGameEvent } from "@/utils/event-log/emit";
import { EventTypes } from "@/utils/event-log/eventTypes";
interface ActionResult<T = undefined> {
success: boolean;
error?: string;
data?: T;
}
export interface FlappyStats {
gamesPlayed: number;
totalPasses: number;
bestScore: number;
flappyXp: number;
xpEarned: number;
}
const PASSES_PER_XP = 15;
const MAX_PASSES_PER_GAME = 5000;
async function authenticate() {
const payloadConfig = await config;
const payload = await getPayload({ config: payloadConfig });
const { headers } = await import("next/headers");
const hdrs = await headers();
const { user } = await payload.auth({
headers: hdrs,
canSetHeaders: false,
});
if (!user) {
throw new Error("Unauthorized");
}
return { payload, user };
}
export async function submitFlappyScore(input: {
passes: number;
}): Promise<ActionResult<FlappyStats>> {
try {
const { payload, user } = await authenticate();
const passes = Math.floor(input.passes);
if (!Number.isFinite(passes) || passes < 0) {
return { success: false, error: "Invalid score." };
}
if (passes > MAX_PASSES_PER_GAME) {
return { success: false, error: "Score too large." };
}
const profileRes = await payload.find({
collection: "profiles",
where: { user: { equals: user.id as number } },
limit: 1,
depth: 0,
overrideAccess: true,
});
const profile = profileRes.docs[0];
if (!profile) {
return { success: false, error: "No profile found for this user." };
}
const progression = (profile.progression ?? {}) as {
xp?: unknown;
minigames?: {
flappyBird?: {
gamesPlayed?: number;
totalPasses?: number;
bestScore?: number;
xpEarned?: number;
};
};
};
const current = progression.minigames?.flappyBird ?? {};
const gamesPlayed = (current.gamesPlayed ?? 0) + 1;
const totalPasses = (current.totalPasses ?? 0) + passes;
const bestScore = Math.max(current.bestScore ?? 0, passes);
const runXp = Math.floor(passes / PASSES_PER_XP);
const flappyXp = (current.xpEarned ?? 0) + runXp;
const { xp: _xp, ...progressionRest } = progression;
await payload.update({
collection: "profiles",
id: profile.id,
data: {
progression: {
...progressionRest,
minigames: {
...(progressionRest.minigames ?? {}),
flappyBird: { gamesPlayed, totalPasses, bestScore, xpEarned: flappyXp },
},
},
},
overrideAccess: true,
depth: 0,
});
if (passes > 0) {
await emitGameEvent(payload, {
type: EventTypes.MinigameFlappy,
message: `Completed a flight simulator run passing ${passes} obstacle${passes === 1 ? "" : "s"} (+${runXp} XP)`,
actor: user.id as number,
targetCollection: "users",
targetId: user.id as number,
data: { passes, xpEarned: runXp, bestScore, totalPasses, flappyXp },
});
}
return {
success: true,
data: { gamesPlayed, totalPasses, bestScore, flappyXp, xpEarned: runXp },
};
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
if (message === "Unauthorized") {
return { success: false, error: "You must be logged in." };
}
return { success: false, error: message };
}
}