126 lines
3.5 KiB
TypeScript
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 };
|
|
}
|
|
}
|