diff --git a/src/components/Hack/HackSubmitForm.tsx b/src/components/Hack/HackSubmitForm.tsx index 877889f..aa7307a 100644 --- a/src/components/Hack/HackSubmitForm.tsx +++ b/src/components/Hack/HackSubmitForm.tsx @@ -113,6 +113,8 @@ export default function HackSubmitForm({ const [patchFile, setPatchFile] = React.useState(null); const [patchMode, setPatchMode] = React.useState<"bps" | "rom">(() => (initialDraftRef.current?.patchMode === "rom" ? "rom" : "bps")); const [genStatus, setGenStatus] = React.useState<"idle" | "generating" | "ready" | "error">("idle"); + const [checksumStatus, setChecksumStatus] = React.useState<"idle" | "validating" | "valid" | "invalid" | "unknown">("idle"); + const [checksumError, setChecksumError] = React.useState(""); const [genError, setGenError] = React.useState(""); const [submitting, setSubmitting] = React.useState(false); const maxSteps = isArchive ? 3 : 4; @@ -546,6 +548,52 @@ export default function HackSubmitForm({ } } + async function onUploadPatch(e: React.ChangeEvent) { + try { + setChecksumStatus("validating"); + setChecksumError(""); + + const patch = e.target.files?.[0] || null; + if (!patch) { + setChecksumStatus("idle"); + setChecksumError(""); + setPatchFile(null); + return; + } + + if (!baseRomEntry) { + setChecksumStatus("unknown"); + setChecksumError("A checksum is not available to validate this patch file. Proceed at your own risk, or upload your modified ROM instead."); + return; + } + + // Verify that the patch is a valid BPS file for the selected base ROM + const bps = BPS.fromFile(new BinFile(await patch.arrayBuffer())); + if (bps.sourceChecksum === 0 || bps.sourceChecksum === undefined) { + setChecksumStatus("unknown"); + setChecksumError("A checksum is not available to validate this patch file. Proceed at your own risk, or upload your modified ROM instead."); + return; + } + + const baseRomChecksum = parseInt(baseRomEntry.crc32, 16); + if (bps.sourceChecksum !== baseRomChecksum) { + setChecksumStatus("invalid"); + setChecksumError("Checksum validation failed. The patch file is not compatible with the selected base ROM."); + return; + } + + // All checks passed, set the checksum status to valid + setChecksumStatus("valid"); + setChecksumError(""); + + setPatchFile(patch); + } + catch (err: any) { + setChecksumStatus("unknown"); + setChecksumError(err?.message || "Failed to validate patch file."); + } + } + const preview = { slug: slug || "preview", title: title || "Your hack title", @@ -1005,12 +1053,16 @@ export default function HackSubmitForm({
setPatchFile(e.target.files?.[0] || null)} + onChange={onUploadPatch} type="file" accept=".bps" className="rounded-md bg-[var(--surface-2)] px-3 py-2 text-sm italic text-foreground/50 ring-1 ring-inset ring-[var(--border)] file:bg-black/10 dark:file:bg-[var(--surface-2)] file:text-foreground/80 file:text-sm file:font-medium file:not-italic file:rounded-md file:border-0 file:px-3 file:py-2 file:mr-2 file:cursor-pointer" />

Upload a BPS patch file.

+ {checksumStatus === "validating" &&
Validating checksum…
} + {checksumStatus === "valid" &&
Checksum valid.
} + {checksumStatus === "invalid" && !!checksumError &&
{checksumError}
} + {checksumStatus === "unknown" && !!checksumError &&
{checksumError}
}
)}