mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 21:27:46 +00:00
feat: get dating prefs, birthday, voice, personality
This commit is contained in:
parent
5b498430c8
commit
1ff3823209
5 changed files with 79 additions and 6 deletions
|
|
@ -48,7 +48,7 @@ const submitSchema = z.object({
|
||||||
// Save data way
|
// Save data way
|
||||||
miiDataFile: z
|
miiDataFile: z
|
||||||
.instanceof(File)
|
.instanceof(File)
|
||||||
.refine((blob) => blob.size < 1024 * 30, "File too large") // TODO: actual size
|
.refine((blob) => blob.size < 1024 * 1024 * 1.5, "File too large") // TODO: actual size
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|
||||||
// Manual way
|
// Manual way
|
||||||
|
|
@ -207,7 +207,16 @@ export async function POST(request: NextRequest) {
|
||||||
const miiData = miiDataFileBuffer ? CharInfoEx.FromShareMiiFileArrayBuffer(miiDataFileBuffer) : undefined;
|
const miiData = miiDataFileBuffer ? CharInfoEx.FromShareMiiFileArrayBuffer(miiDataFileBuffer) : undefined;
|
||||||
|
|
||||||
if (way === "savedata") {
|
if (way === "savedata") {
|
||||||
if (!miiData) return rateLimit.sendResponse({ error: "No mii data provided" }, 400);
|
if (!miiData || !miiDataFileBuffer || !miiDataFileArray) return rateLimit.sendResponse({ error: "No valid Mii data provided" }, 400);
|
||||||
|
|
||||||
|
const view = new DataView(miiDataFileBuffer);
|
||||||
|
|
||||||
|
const parse = (index: number): number => view.getUint8(161 + index * 4);
|
||||||
|
|
||||||
|
const age = view.getUint32(0x00e1, true);
|
||||||
|
const year = view.getUint32(0x00d9, true);
|
||||||
|
|
||||||
|
const dontAge = age !== 0xffffffff;
|
||||||
|
|
||||||
const instructions: Partial<SwitchMiiInstructions> = {
|
const instructions: Partial<SwitchMiiInstructions> = {
|
||||||
head: {
|
head: {
|
||||||
|
|
@ -375,7 +384,28 @@ export async function POST(request: NextRequest) {
|
||||||
},
|
},
|
||||||
height: miiData.height,
|
height: miiData.height,
|
||||||
weight: miiData.build,
|
weight: miiData.build,
|
||||||
// uh oh, no dating prefs, birthday, voice, personality
|
datingPreferences: ([MiiGender.MALE, MiiGender.FEMALE, MiiGender.NONBINARY] as const).filter((_, i) => miiDataFileArray[0x01a9 + i] === 1),
|
||||||
|
birthday: {
|
||||||
|
month: parse(17),
|
||||||
|
day: parse(15),
|
||||||
|
age: dontAge ? age : new Date().getFullYear() - year,
|
||||||
|
dontAge,
|
||||||
|
},
|
||||||
|
voice: {
|
||||||
|
speed: parse(6),
|
||||||
|
pitch: parse(8),
|
||||||
|
depth: parse(5),
|
||||||
|
delivery: Math.max(0, view.getInt8(0xc5)), // why is this an integer??
|
||||||
|
tone: parse(7) + 1,
|
||||||
|
// preset type?
|
||||||
|
},
|
||||||
|
personality: {
|
||||||
|
movement: parse(4) - 1,
|
||||||
|
speech: parse(2) - 1,
|
||||||
|
energy: parse(1) - 1,
|
||||||
|
thinking: parse(0) - 1,
|
||||||
|
overall: parse(3) - 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
minifiedInstructions = minifyInstructions(instructions);
|
minifiedInstructions = minifyInstructions(instructions);
|
||||||
|
|
|
||||||
32
src/app/mii/[id]/download/route.ts
Normal file
32
src/app/mii/[id]/download/route.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { RateLimit } from "@/lib/rate-limit";
|
||||||
|
import { idSchema } from "@/lib/schemas";
|
||||||
|
|
||||||
|
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
|
||||||
|
const rateLimit = new RateLimit(request, 200, "/mii/image");
|
||||||
|
const check = await rateLimit.handle();
|
||||||
|
if (check) return check;
|
||||||
|
|
||||||
|
const { id: slugId } = await params;
|
||||||
|
const parsed = idSchema.safeParse(slugId);
|
||||||
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
|
const miiId = parsed.data;
|
||||||
|
|
||||||
|
const mii = await prisma.mii.findUnique({
|
||||||
|
where: { id: miiId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!mii || !mii.miiData) {
|
||||||
|
return new NextResponse("Not found", { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = `${mii.name}.ltd`;
|
||||||
|
|
||||||
|
return new NextResponse(mii.miiData, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/octet-stream",
|
||||||
|
"Content-Disposition": `attachment; filename="${fileName}"`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -371,9 +371,15 @@ export default async function MiiPage({ params }: Props) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Buttons */}
|
{/* Buttons */}
|
||||||
<div className="flex gap-3 w-fit bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 text-3xl text-orange-400 max-md:place-self-center *:size-12 *:flex *:flex-col *:items-center *:gap-1 **:transition-discrete **:duration-150 *:hover:brightness-75 *:hover:scale-[1.08] *:[&_span]:text-xs">
|
<div className="flex gap-4 w-fit bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-4 text-3xl text-orange-400 max-md:place-self-center *:size-12 *:flex *:flex-col *:items-center *:gap-1 **:transition-discrete **:duration-150 *:hover:brightness-75 *:hover:scale-[1.08] *:[&_span]:text-xs">
|
||||||
<AuthorButtons mii={mii} />
|
<AuthorButtons mii={mii} />
|
||||||
|
|
||||||
|
{mii.miiData && (
|
||||||
|
<Link aria-label="Download Mii" href={`/mii/${mii.id}/download`} download>
|
||||||
|
<Icon icon="material-symbols:download" />
|
||||||
|
<span>Download</span>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
<ShareMiiButton miiId={mii.id} />
|
<ShareMiiButton miiId={mii.id} />
|
||||||
<Link aria-label="Report Mii" href={`/report/mii/${mii.id}`}>
|
<Link aria-label="Report Mii" href={`/report/mii/${mii.id}`}>
|
||||||
<Icon icon="material-symbols:flag-rounded" />
|
<Icon icon="material-symbols:flag-rounded" />
|
||||||
|
|
@ -391,7 +397,11 @@ export default async function MiiPage({ params }: Props) {
|
||||||
Instructions
|
Instructions
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="text-xs text-amber-800">All instructions are based off of the default Male Mii.</p>
|
<p className="text-xs text-amber-800">
|
||||||
|
All instructions are based off of the default Male Mii.
|
||||||
|
<br />
|
||||||
|
{mii.miiData && "If you're on modded/emulator, you can download the .ltd file above."}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{mii.youtubeId && (
|
{mii.youtubeId && (
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@ export default function MiiInstructions({ instructions, isUsingSaveFile }: Props
|
||||||
{(height || weight || datingPreferences || voice || personality) && (
|
{(height || weight || datingPreferences || voice || personality) && (
|
||||||
<div className="p-3 border-l-4 border-amber-400 bg-amber-100/50 rounded-r-lg py-2.5 text-amber-950 w-max mb-4">
|
<div className="p-3 border-l-4 border-amber-400 bg-amber-100/50 rounded-r-lg py-2.5 text-amber-950 w-max mb-4">
|
||||||
<h3 className="font-semibold text-xl text-amber-800 mb-1">Misc</h3>
|
<h3 className="font-semibold text-xl text-amber-800 mb-1">Misc</h3>
|
||||||
|
<p className="text-xs text-amber-800 mb-4">These contain sliders: 0 is middle, positive is to the right, negative is to the left</p>
|
||||||
|
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,7 @@ export default function SubmitForm({ inQueueMiisCount }: Props) {
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex flex-col justify-center items-center rounded-xl p-4 shadow-md border-2 cursor-pointer text-center text-sm transition hover:scale-[1.03] ${way === "savedata" ? "bg-cyan-100 border-cyan-600" : "bg-zinc-50 border-zinc-300 hover:bg-cyan-100 hover:border-cyan-600"}`}
|
className={`flex flex-col justify-center items-center rounded-xl p-4 shadow-md border-2 cursor-pointer text-center text-sm transition hover:scale-[1.03] ${way === "savedata" ? "bg-cyan-100 border-cyan-600" : "bg-zinc-50 border-zinc-300 hover:bg-cyan-100 hover:border-cyan-600"}`}
|
||||||
>
|
>
|
||||||
.ltd file
|
.ltd file (Modded)
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue