feat: add anti-cheat awareness step to benchmark wizard
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
import { db } from "@/lib/db/index"
|
import { db } from "@/lib/db/index"
|
||||||
import { games, gameVersions, performanceEntries } from "@/lib/db/schema"
|
import { games, gameVersions, performanceEntries, gamePlatformSupport } from "@/lib/db/schema"
|
||||||
import { eq, sql } from "drizzle-orm"
|
import { eq, sql } from "drizzle-orm"
|
||||||
import { GameEntryWizard } from "@/components/wizard/game-entry-wizard"
|
import { GameEntryWizard } from "@/components/wizard/game-entry-wizard"
|
||||||
|
|
||||||
@@ -68,6 +68,17 @@ export default async function SubmitBenchmarkPage({
|
|||||||
.returning()
|
.returning()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch platform support for anti-cheat awareness
|
||||||
|
const platformSupport = await db
|
||||||
|
.select({
|
||||||
|
hardwareSlug: gamePlatformSupport.hardwareSlug,
|
||||||
|
antiCheatRelevant: gamePlatformSupport.antiCheatRelevant,
|
||||||
|
antiCheatName: gamePlatformSupport.antiCheatName,
|
||||||
|
antiCheatStatus: gamePlatformSupport.antiCheatStatus,
|
||||||
|
})
|
||||||
|
.from(gamePlatformSupport)
|
||||||
|
.where(eq(gamePlatformSupport.gameId, game.id))
|
||||||
|
|
||||||
// If editing, fetch the existing performance entry
|
// If editing, fetch the existing performance entry
|
||||||
let editEntry = null
|
let editEntry = null
|
||||||
if (edit) {
|
if (edit) {
|
||||||
@@ -95,6 +106,7 @@ export default async function SubmitBenchmarkPage({
|
|||||||
gameId={game.id}
|
gameId={game.id}
|
||||||
gameVersionId={version.id}
|
gameVersionId={version.id}
|
||||||
editEntry={editEntry}
|
editEntry={editEntry}
|
||||||
|
platformSupport={platformSupport}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"
|
|||||||
import { motion, AnimatePresence } from "motion/react"
|
import { motion, AnimatePresence } from "motion/react"
|
||||||
import { StepIndicator } from "@/components/wizard/step-indicator"
|
import { StepIndicator } from "@/components/wizard/step-indicator"
|
||||||
import { HardwareStep } from "@/components/wizard/steps/hardware-step"
|
import { HardwareStep } from "@/components/wizard/steps/hardware-step"
|
||||||
|
import { AntiCheatStep } from "@/components/wizard/steps/anti-cheat-step"
|
||||||
import { PerformanceStep, type PerformanceData } from "@/components/wizard/steps/performance-step"
|
import { PerformanceStep, type PerformanceData } from "@/components/wizard/steps/performance-step"
|
||||||
import { SettingsStep } from "@/components/wizard/steps/settings-step"
|
import { SettingsStep } from "@/components/wizard/steps/settings-step"
|
||||||
import { EnvironmentStep, type EnvironmentData } from "@/components/wizard/steps/environment-step"
|
import { EnvironmentStep, type EnvironmentData } from "@/components/wizard/steps/environment-step"
|
||||||
@@ -14,19 +15,28 @@ import { performanceEntries } from "@/lib/db/schema"
|
|||||||
|
|
||||||
const STEPS = [
|
const STEPS = [
|
||||||
{ label: "Hardware", tooltip: "Choose the hardware you tested this game on" },
|
{ label: "Hardware", tooltip: "Choose the hardware you tested this game on" },
|
||||||
|
{ label: "Anti-Cheat", tooltip: "Review anti-cheat compatibility for your selected hardware" },
|
||||||
{ label: "Performance", tooltip: "Enter the performance metrics you observed. FPS Average is required." },
|
{ label: "Performance", tooltip: "Enter the performance metrics you observed. FPS Average is required." },
|
||||||
{ label: "Settings", tooltip: "Configure the game settings you used. Add categories and settings to help others replicate your setup." },
|
{ label: "Settings", tooltip: "Configure the game settings you used. Add categories and settings to help others replicate your setup." },
|
||||||
{ label: "Environment", tooltip: "Specify the software environment and any launch options used" },
|
{ label: "Environment", tooltip: "Specify the software environment and any launch options used" },
|
||||||
{ label: "Review", tooltip: "Review your entry before submitting. Add any additional notes." },
|
{ label: "Review", tooltip: "Review your entry before submitting. Add any additional notes." },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
interface PlatformSupportEntry {
|
||||||
|
hardwareSlug: string
|
||||||
|
antiCheatRelevant: boolean
|
||||||
|
antiCheatStatus: "none" | "supported" | "unsupported" | "unknown"
|
||||||
|
antiCheatName: string | null
|
||||||
|
}
|
||||||
|
|
||||||
interface GameEntryWizardProps {
|
interface GameEntryWizardProps {
|
||||||
gameId: string
|
gameId: string
|
||||||
gameVersionId: string
|
gameVersionId: string
|
||||||
editEntry?: typeof performanceEntries.$inferSelect | null
|
editEntry?: typeof performanceEntries.$inferSelect | null
|
||||||
|
platformSupport: PlatformSupportEntry[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryWizardProps) {
|
export function GameEntryWizard({ gameId, gameVersionId, editEntry, platformSupport }: GameEntryWizardProps) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
const [currentStep, setCurrentStep] = useState(0)
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
@@ -37,7 +47,8 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
const [hardwareSlug, setHardwareSlug] = useState(editEntry?.hardwareSlug ?? "")
|
const [hardwareSlug, setHardwareSlug] = useState(editEntry?.hardwareSlug ?? "")
|
||||||
const [hardwareName, setHardwareName] = useState("")
|
const [hardwareName, setHardwareName] = useState("")
|
||||||
|
|
||||||
// Step 2: Performance
|
// Step 2: Anti-Cheat (informational)
|
||||||
|
// Step 3: Performance
|
||||||
const [performance, setPerformance] = useState<PerformanceData>(
|
const [performance, setPerformance] = useState<PerformanceData>(
|
||||||
editEntry
|
editEntry
|
||||||
? {
|
? {
|
||||||
@@ -51,12 +62,12 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
: {},
|
: {},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Step 3: Settings
|
// Step 4: Settings
|
||||||
const [settingsJson, setSettingsJson] = useState<SettingCategory[]>(
|
const [settingsJson, setSettingsJson] = useState<SettingCategory[]>(
|
||||||
editEntry?.settingsJson ?? [],
|
editEntry?.settingsJson ?? [],
|
||||||
)
|
)
|
||||||
|
|
||||||
// Step 4: Environment
|
// Step 5: Environment
|
||||||
const [environment, setEnvironment] = useState<EnvironmentData>(
|
const [environment, setEnvironment] = useState<EnvironmentData>(
|
||||||
editEntry
|
editEntry
|
||||||
? {
|
? {
|
||||||
@@ -75,7 +86,7 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Step 5: Notes
|
// Step 6: Notes
|
||||||
const [userNotes, setUserNotes] = useState(editEntry?.userNotes ?? "")
|
const [userNotes, setUserNotes] = useState(editEntry?.userNotes ?? "")
|
||||||
|
|
||||||
// Fetch hardware name when slug changes
|
// Fetch hardware name when slug changes
|
||||||
@@ -122,12 +133,14 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
case 0:
|
case 0:
|
||||||
return hardwareSlug !== ""
|
return hardwareSlug !== ""
|
||||||
case 1:
|
case 1:
|
||||||
return performance.fpsAvg !== undefined && performance.fpsAvg > 0
|
return true // Anti-cheat is informational
|
||||||
case 2:
|
case 2:
|
||||||
return true // Settings are optional
|
return performance.fpsAvg !== undefined && performance.fpsAvg > 0
|
||||||
case 3:
|
case 3:
|
||||||
return true // Environment is optional
|
return true // Settings are optional
|
||||||
case 4:
|
case 4:
|
||||||
|
return true // Environment is optional
|
||||||
|
case 5:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@@ -250,15 +263,18 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
<HardwareStep value={hardwareSlug} onChange={handleHardwareChange} />
|
<HardwareStep value={hardwareSlug} onChange={handleHardwareChange} />
|
||||||
)}
|
)}
|
||||||
{currentStep === 1 && (
|
{currentStep === 1 && (
|
||||||
<PerformanceStep value={performance} onChange={setPerformance} />
|
<AntiCheatStep hardwareSlug={hardwareSlug} platformSupport={platformSupport} />
|
||||||
)}
|
)}
|
||||||
{currentStep === 2 && (
|
{currentStep === 2 && (
|
||||||
<SettingsStep value={settingsJson} onChange={setSettingsJson} />
|
<PerformanceStep value={performance} onChange={setPerformance} />
|
||||||
)}
|
)}
|
||||||
{currentStep === 3 && (
|
{currentStep === 3 && (
|
||||||
<EnvironmentStep value={environment} onChange={setEnvironment} />
|
<SettingsStep value={settingsJson} onChange={setSettingsJson} />
|
||||||
)}
|
)}
|
||||||
{currentStep === 4 && (
|
{currentStep === 4 && (
|
||||||
|
<EnvironmentStep value={environment} onChange={setEnvironment} />
|
||||||
|
)}
|
||||||
|
{currentStep === 5 && (
|
||||||
<ReviewStep
|
<ReviewStep
|
||||||
data={{
|
data={{
|
||||||
hardwareSlug,
|
hardwareSlug,
|
||||||
@@ -278,7 +294,7 @@ export function GameEntryWizard({ gameId, gameVersionId, editEntry }: GameEntryW
|
|||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
{/* Navigation Buttons */}
|
{/* Navigation Buttons */}
|
||||||
{currentStep < 4 && (
|
{currentStep < 5 && (
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { Shield, ShieldCheck, ShieldX, ShieldQuestion } from "lucide-react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
interface PlatformSupportEntry {
|
||||||
|
hardwareSlug: string
|
||||||
|
antiCheatRelevant: boolean
|
||||||
|
antiCheatStatus: "none" | "supported" | "unsupported" | "unknown"
|
||||||
|
antiCheatName: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AntiCheatStepProps {
|
||||||
|
hardwareSlug: string
|
||||||
|
platformSupport: PlatformSupportEntry[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusConfig = {
|
||||||
|
supported: {
|
||||||
|
icon: ShieldCheck,
|
||||||
|
label: "Supported",
|
||||||
|
color: "border-green-500/30 bg-green-500/10",
|
||||||
|
textColor: "text-green-400",
|
||||||
|
message: "This game's anti-cheat supports Linux/SteamOS. Multiplayer should work.",
|
||||||
|
},
|
||||||
|
unsupported: {
|
||||||
|
icon: ShieldX,
|
||||||
|
label: "Unsupported",
|
||||||
|
color: "border-red-500/30 bg-red-500/10",
|
||||||
|
textColor: "text-red-400",
|
||||||
|
message: "This game's anti-cheat does not support Linux/SteamOS. Multiplayer may not work.",
|
||||||
|
},
|
||||||
|
unknown: {
|
||||||
|
icon: ShieldQuestion,
|
||||||
|
label: "Unknown",
|
||||||
|
color: "border-yellow-500/30 bg-yellow-500/10",
|
||||||
|
textColor: "text-yellow-400",
|
||||||
|
message: "Anti-cheat compatibility is unknown. Multiplayer may or may not work.",
|
||||||
|
},
|
||||||
|
none: {
|
||||||
|
icon: Shield,
|
||||||
|
label: "None",
|
||||||
|
color: "border-zinc-500/30 bg-zinc-500/10",
|
||||||
|
textColor: "text-zinc-400",
|
||||||
|
message: "No anti-cheat detected for this game.",
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export function AntiCheatStep({ hardwareSlug, platformSupport }: AntiCheatStepProps) {
|
||||||
|
const support = platformSupport.find((p) => p.hardwareSlug === hardwareSlug)
|
||||||
|
|
||||||
|
if (!hardwareSlug) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center py-16">
|
||||||
|
<Shield className="h-8 w-8 text-text/30 mb-4" />
|
||||||
|
<p className="text-sm text-text/60">Please select a hardware device first.</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!support || !support.antiCheatRelevant) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center py-16">
|
||||||
|
<Shield className="h-8 w-8 text-text/30 mb-4" />
|
||||||
|
<p className="text-sm text-text/60">No anti-cheat information for this hardware device.</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = statusConfig[support.antiCheatStatus]
|
||||||
|
const Icon = config.icon
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Shield className="h-4 w-4 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-semibold text-text">Anti-Cheat Status</h3>
|
||||||
|
<p className="text-xs text-text/60 mt-1">
|
||||||
|
Check the anti-cheat compatibility for your selected hardware before submitting.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={cn("rounded-lg border p-4", config.color)}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Icon className={cn("h-5 w-5", config.textColor)} />
|
||||||
|
<h4 className="font-medium">
|
||||||
|
Anti-Cheat: {support.antiCheatName || config.label}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<p className={cn("mt-2 text-sm", config.textColor)}>{config.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export { HardwareStep } from "./hardware-step"
|
export { HardwareStep } from "./hardware-step"
|
||||||
|
export { AntiCheatStep } from "./anti-cheat-step"
|
||||||
export { PerformanceStep, type PerformanceData } from "./performance-step"
|
export { PerformanceStep, type PerformanceData } from "./performance-step"
|
||||||
export { SettingsStep } from "./settings-step"
|
export { SettingsStep } from "./settings-step"
|
||||||
export { EnvironmentStep, type EnvironmentData } from "./environment-step"
|
export { EnvironmentStep, type EnvironmentData } from "./environment-step"
|
||||||
|
|||||||
Reference in New Issue
Block a user