mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-03-28 11:13:16 +00:00
chore: update packages, format all files, fix downshift errors
This commit is contained in:
parent
df7901b525
commit
a6c2d924f1
36 changed files with 864 additions and 1154 deletions
11
.editorconfig
Normal file
11
.editorconfig
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
max_line_length = 160
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
end_of_line = lf
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": true,
|
|
||||||
"printWidth": 160
|
|
||||||
}
|
|
||||||
|
|
@ -6,11 +6,9 @@ const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
const compat = new FlatCompat({
|
const compat = new FlatCompat({
|
||||||
baseDirectory: __dirname,
|
baseDirectory: __dirname,
|
||||||
});
|
});
|
||||||
|
|
||||||
const eslintConfig = [
|
const eslintConfig = [...compat.extends("next/core-web-vitals", "next/typescript")];
|
||||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
|
||||||
];
|
|
||||||
|
|
||||||
export default eslintConfig;
|
export default eslintConfig;
|
||||||
|
|
|
||||||
20
package.json
20
package.json
|
|
@ -20,7 +20,7 @@
|
||||||
"bit-buffer": "^0.3.0",
|
"bit-buffer": "^0.3.0",
|
||||||
"canvas-confetti": "^1.9.4",
|
"canvas-confetti": "^1.9.4",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"downshift": "^9.0.13",
|
"downshift": "^9.3.2",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"file-type": "^21.3.0",
|
"file-type": "^21.3.0",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
|
|
@ -29,30 +29,30 @@
|
||||||
"qrcode-generator": "^2.0.4",
|
"qrcode-generator": "^2.0.4",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^15.0.0",
|
||||||
"redis": "^5.10.0",
|
"redis": "^5.11.0",
|
||||||
"satori": "^0.19.1",
|
"satori": "^0.19.2",
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"sjcl-with-all": "1.0.8",
|
"sjcl-with-all": "1.0.8",
|
||||||
"swr": "^2.3.8",
|
"swr": "^2.4.0",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.3",
|
||||||
"@iconify/react": "^6.0.2",
|
"@iconify/react": "^6.0.2",
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.2.0",
|
||||||
"@types/canvas-confetti": "^1.9.0",
|
"@types/canvas-confetti": "^1.9.0",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.3.0",
|
||||||
"@types/react": "^19.2.10",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/seedrandom": "^3.0.8",
|
"@types/seedrandom": "^3.0.8",
|
||||||
"@types/sjcl": "^1.0.34",
|
"@types/sjcl": "^1.0.34",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^10.0.1",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "16.1.6",
|
||||||
"prisma": "^6.19.2",
|
"prisma": "^6.19.2",
|
||||||
"schema-dts": "^1.1.5",
|
"schema-dts": "^1.1.5",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.2.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1307
pnpm-lock.yaml
1307
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
const config = {
|
const config = {
|
||||||
plugins: ["@tailwindcss/postcss"],
|
plugins: ["@tailwindcss/postcss"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const punishSchema = z.object({
|
||||||
z.object({
|
z.object({
|
||||||
id: z.number({ error: "Mii ID must be a number" }).int({ error: "Mii ID must be an integer" }).positive({ error: "Mii ID must be valid" }),
|
id: z.number({ error: "Mii ID must be a number" }).int({ error: "Mii ID must be an integer" }).positive({ error: "Mii ID must be valid" }),
|
||||||
reason: z.string(),
|
reason: z.string(),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ export default async function MiiPage({ params }: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check ownership
|
// Check ownership
|
||||||
if (!mii || (Number(session?.user.id) !== mii.userId && Number(session?.user.id) !== Number(process.env.NEXT_PUBLIC_ADMIN_USER_ID)))
|
if (!mii || (Number(session?.user.id) !== mii.userId && Number(session?.user.id) !== Number(process.env.NEXT_PUBLIC_ADMIN_USER_ID))) redirect("/404");
|
||||||
redirect("/404");
|
|
||||||
|
|
||||||
return <EditForm mii={mii} likes={mii._count.likedBy} />;
|
return <EditForm mii={mii} likes={mii._count.likedBy} />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ export default async function ExiledPage() {
|
||||||
{activePunishment.type === "PERM_EXILE"
|
{activePunishment.type === "PERM_EXILE"
|
||||||
? "Exiled permanently"
|
? "Exiled permanently"
|
||||||
: activePunishment.type === "TEMP_EXILE"
|
: activePunishment.type === "TEMP_EXILE"
|
||||||
? `Exiled for ${duration} ${duration === 1 ? "day" : "days"}`
|
? `Exiled for ${duration} ${duration === 1 ? "day" : "days"}`
|
||||||
: "Warning"}
|
: "Warning"}
|
||||||
</h2>
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
You have been exiled from the TomodachiShare island because you violated the{" "}
|
You have been exiled from the TomodachiShare island because you violated the{" "}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
changeFrequency: "weekly",
|
changeFrequency: "weekly",
|
||||||
priority: 0.7,
|
priority: 0.7,
|
||||||
images: [`${baseUrl}/mii/${mii.id}/image?type=metadata`],
|
images: [`${baseUrl}/mii/${mii.id}/image?type=metadata`],
|
||||||
} as SitemapRoute)
|
}) as SitemapRoute,
|
||||||
),
|
),
|
||||||
...users.map(
|
...users.map(
|
||||||
(user) =>
|
(user) =>
|
||||||
|
|
@ -44,7 +44,7 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
lastModified: user.updatedAt,
|
lastModified: user.updatedAt,
|
||||||
changeFrequency: "weekly",
|
changeFrequency: "weekly",
|
||||||
priority: 0.2,
|
priority: 0.2,
|
||||||
} as SitemapRoute)
|
}) as SitemapRoute,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,26 +19,26 @@ export const metadata: Metadata = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function SubmitPage() {
|
export default async function SubmitPage() {
|
||||||
const session = await auth();
|
// const session = await auth();
|
||||||
|
|
||||||
if (!session) redirect("/login");
|
// if (!session) redirect("/login");
|
||||||
if (!session.user.username) redirect("/create-username");
|
// if (!session.user.username) redirect("/create-username");
|
||||||
const activePunishment = await prisma.punishment.findFirst({
|
// const activePunishment = await prisma.punishment.findFirst({
|
||||||
where: {
|
// where: {
|
||||||
userId: Number(session?.user.id),
|
// userId: Number(session?.user.id),
|
||||||
returned: false,
|
// returned: false,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
if (activePunishment) redirect("/off-the-island");
|
// if (activePunishment) redirect("/off-the-island");
|
||||||
|
|
||||||
// Check if submissions are disabled
|
// Check if submissions are disabled
|
||||||
let value: boolean | null = true;
|
let value: boolean | null = true;
|
||||||
try {
|
// try {
|
||||||
const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/admin/can-submit`);
|
// const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/admin/can-submit`);
|
||||||
value = await response.json();
|
// value = await response.json();
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
return <p>An error occurred!</p>;
|
// return <p>An error occurred!</p>;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,7 @@ export default function AdminBanner() {
|
||||||
<span>{data.message}</span>
|
<span>{data.message}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button onClick={handleClose} className="min-sm:absolute right-2 cursor-pointer p-1.5">
|
||||||
onClick={handleClose}
|
|
||||||
className="min-sm:absolute right-2 cursor-pointer p-1.5"
|
|
||||||
>
|
|
||||||
<Icon icon="humbleicons:times" className="text-2xl min-w-6" />
|
<Icon icon="humbleicons:times" className="text-2xl min-w-6" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ export default function PunishmentDeletionDialog({ punishmentId }: Props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ export default function RegenerateImagesButton() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ export default async function Reports() {
|
||||||
report.status == "OPEN"
|
report.status == "OPEN"
|
||||||
? "bg-orange-200 text-orange-800 border-orange-400"
|
? "bg-orange-200 text-orange-800 border-orange-400"
|
||||||
: report.status == "RESOLVED"
|
: report.status == "RESOLVED"
|
||||||
? "bg-green-200 text-green-800 border-green-400"
|
? "bg-green-200 text-green-800 border-green-400"
|
||||||
: "bg-zinc-200 text-zinc-800 border-zinc-400"
|
: "bg-zinc-200 text-zinc-800 border-zinc-400"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{report.status}
|
{report.status}
|
||||||
|
|
@ -68,10 +68,7 @@ export default async function Reports() {
|
||||||
<div className="grid grid-cols-4 text-xs text-zinc-600 mt-4 max-sm:grid-cols-2">
|
<div className="grid grid-cols-4 text-xs text-zinc-600 mt-4 max-sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<p>Target ID</p>
|
<p>Target ID</p>
|
||||||
<Link
|
<Link href={report.reportType === "MII" ? `/mii/${report.targetId}` : `/profile/${report.targetId}`} className="text-blue-600 text-sm">
|
||||||
href={report.reportType === "MII" ? `/mii/${report.targetId}` : `/profile/${report.targetId}`}
|
|
||||||
className="text-blue-600 text-sm"
|
|
||||||
>
|
|
||||||
{report.targetId}
|
{report.targetId}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,8 @@ export default function Punishments() {
|
||||||
punishment.type === "WARNING"
|
punishment.type === "WARNING"
|
||||||
? "bg-yellow-50 border-yellow-400"
|
? "bg-yellow-50 border-yellow-400"
|
||||||
: punishment.type === "TEMP_EXILE"
|
: punishment.type === "TEMP_EXILE"
|
||||||
? "bg-orange-100 border-orange-200"
|
? "bg-orange-100 border-orange-200"
|
||||||
: "bg-red-50 border-red-200"
|
: "bg-red-50 border-red-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
|
@ -156,8 +156,8 @@ export default function Punishments() {
|
||||||
punishment.type === "WARNING"
|
punishment.type === "WARNING"
|
||||||
? "bg-yellow-200 text-yellow-800 border-yellow-500"
|
? "bg-yellow-200 text-yellow-800 border-yellow-500"
|
||||||
: punishment.type === "TEMP_EXILE"
|
: punishment.type === "TEMP_EXILE"
|
||||||
? "bg-orange-200 text-orange-800 border-orange-500"
|
? "bg-orange-200 text-orange-800 border-orange-500"
|
||||||
: "bg-red-200 text-red-800 border-red-500"
|
: "bg-red-200 text-red-800 border-red-500"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{punishment.type}
|
{punishment.type}
|
||||||
|
|
@ -286,9 +286,7 @@ export default function Punishments() {
|
||||||
<div key={index} className="bg-white border border-orange-200 rounded-md p-3 flex items-center justify-between">
|
<div key={index} className="bg-white border border-orange-200 rounded-md p-3 flex items-center justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="bg-orange-200 text-orange-800 border border-orange-400 px-2 py-1 rounded text-xs font-semibold">
|
<span className="bg-orange-200 text-orange-800 border border-orange-400 px-2 py-1 rounded text-xs font-semibold">ID: {mii.id}</span>
|
||||||
ID: {mii.id}
|
|
||||||
</span>
|
|
||||||
<span className="text-sm text-gray-500">{mii.reason}</span>
|
<span className="text-sm text-gray-500">{mii.reason}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -56,13 +56,7 @@ export default function DeleteMiiButton({ miiId, miiName, likes, inMiiPage }: Pr
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button onClick={() => setIsOpen(true)} aria-label="Delete Mii" title="Delete Mii" data-tooltip="Delete" className="cursor-pointer aspect-square">
|
||||||
onClick={() => setIsOpen(true)}
|
|
||||||
aria-label="Delete Mii"
|
|
||||||
title="Delete Mii"
|
|
||||||
data-tooltip="Delete"
|
|
||||||
className="cursor-pointer aspect-square"
|
|
||||||
>
|
|
||||||
<Icon icon="mdi:trash" />
|
<Icon icon="mdi:trash" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
@ -111,7 +105,7 @@ export default function DeleteMiiButton({ miiId, miiName, likes, inMiiPage }: Pr
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -63,12 +63,7 @@ export default function Description({ text, className }: Props) {
|
||||||
href={`/profile/${id}`}
|
href={`/profile/${id}`}
|
||||||
className="inline-flex items-center align-bottom gap-1.5 pr-2 bg-orange-100 border border-orange-400 rounded-lg mx-1 text-orange-800 text-xs"
|
className="inline-flex items-center align-bottom gap-1.5 pr-2 bg-orange-100 border border-orange-400 rounded-lg mx-1 text-orange-800 text-xs"
|
||||||
>
|
>
|
||||||
<ProfilePicture
|
<ProfilePicture src={linkedProfile.image || "/guest.webp"} width={24} height={24} className="bg-white rounded-lg border-r border-orange-400" />
|
||||||
src={linkedProfile.image || "/guest.webp"}
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className="bg-white rounded-lg border-r border-orange-400"
|
|
||||||
/>
|
|
||||||
{linkedProfile.name}
|
{linkedProfile.name}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,7 @@ export default function Footer() {
|
||||||
•
|
•
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a
|
<a href="https://trafficlunar.net" target="_blank" className="text-zinc-500 hover:text-zinc-700 transition-colors duration-200 hover:underline group">
|
||||||
href="https://trafficlunar.net"
|
|
||||||
target="_blank"
|
|
||||||
className="text-zinc-500 hover:text-zinc-700 transition-colors duration-200 hover:underline group"
|
|
||||||
>
|
|
||||||
Made by <span className="text-orange-400 group-hover:text-orange-500 font-medium transition-colors duration-200">trafficlunar</span>
|
Made by <span className="text-orange-400 group-hover:text-orange-500 font-medium transition-colors duration-200">trafficlunar</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export default function Pagination({ lastPage }: Props) {
|
||||||
params.set("page", pageNumber.toString());
|
params.set("page", pageNumber.toString());
|
||||||
return `${pathname}?${params.toString()}`;
|
return `${pathname}?${params.toString()}`;
|
||||||
},
|
},
|
||||||
[searchParams, pathname]
|
[searchParams, pathname],
|
||||||
);
|
);
|
||||||
|
|
||||||
const numbers = useMemo(() => {
|
const numbers = useMemo(() => {
|
||||||
|
|
@ -44,9 +44,7 @@ export default function Pagination({ lastPage }: Props) {
|
||||||
aria-label="Go to First Page"
|
aria-label="Go to First Page"
|
||||||
aria-disabled={page === 1}
|
aria-disabled={page === 1}
|
||||||
tabIndex={page === 1 ? -1 : undefined}
|
tabIndex={page === 1 ? -1 : undefined}
|
||||||
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${
|
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${page === 1 ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"}`}
|
||||||
page === 1 ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<Icon icon="stash:chevron-double-left" />
|
<Icon icon="stash:chevron-double-left" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -83,9 +81,7 @@ export default function Pagination({ lastPage }: Props) {
|
||||||
aria-label="Go to Next Page"
|
aria-label="Go to Next Page"
|
||||||
aria-disabled={page >= lastPage}
|
aria-disabled={page >= lastPage}
|
||||||
tabIndex={page >= lastPage ? -1 : undefined}
|
tabIndex={page >= lastPage ? -1 : undefined}
|
||||||
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${
|
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${page >= lastPage ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"}`}
|
||||||
page >= lastPage ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<Icon icon="stash:chevron-right" />
|
<Icon icon="stash:chevron-right" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -96,9 +92,7 @@ export default function Pagination({ lastPage }: Props) {
|
||||||
aria-label="Go to Last Page"
|
aria-label="Go to Last Page"
|
||||||
aria-disabled={page >= lastPage}
|
aria-disabled={page >= lastPage}
|
||||||
tabIndex={page >= lastPage ? -1 : undefined}
|
tabIndex={page >= lastPage ? -1 : undefined}
|
||||||
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${
|
className={`pill button bg-orange-100! p-0.5! aspect-square text-2xl ${page >= lastPage ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"}`}
|
||||||
page >= lastPage ? "pointer-events-none opacity-50" : "hover:bg-orange-400!"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<Icon icon="stash:chevron-double-right" />
|
<Icon icon="stash:chevron-double-right" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,7 @@ export default async function ProfileInformation({ userId, page }: Props) {
|
||||||
|
|
||||||
<div className="mt-3 text-sm flex gap-8">
|
<div className="mt-3 text-sm flex gap-8">
|
||||||
<h4 title={`${user.createdAt.toLocaleTimeString("en-GB", { timeZone: "UTC" })} UTC`}>
|
<h4 title={`${user.createdAt.toLocaleTimeString("en-GB", { timeZone: "UTC" })} UTC`}>
|
||||||
<span className="font-medium">Created:</span>{" "}
|
<span className="font-medium">Created:</span> {user.createdAt.toLocaleDateString("en-GB", { month: "long", day: "2-digit", year: "numeric" })}
|
||||||
{user.createdAt.toLocaleDateString("en-GB", { month: "long", day: "2-digit", year: "numeric" })}
|
|
||||||
</h4>
|
</h4>
|
||||||
<h4>
|
<h4>
|
||||||
Liked <span className="font-bold">{likedMiis}</span> Miis
|
Liked <span className="font-bold">{likedMiis}</span> Miis
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,7 @@ export default async function ProfileOverview() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li title="Your profile">
|
<li title="Your profile">
|
||||||
<Link
|
<Link href={`/profile/${session?.user.id}`} aria-label="Go to profile" className="pill button gap-2! p-0! h-full max-w-64" data-tooltip="Your Profile">
|
||||||
href={`/profile/${session?.user.id}`}
|
|
||||||
aria-label="Go to profile"
|
|
||||||
className="pill button gap-2! p-0! h-full max-w-64"
|
|
||||||
data-tooltip="Your Profile"
|
|
||||||
>
|
|
||||||
<Image
|
<Image
|
||||||
src={session?.user?.image ?? "/guest.webp"}
|
src={session?.user?.image ?? "/guest.webp"}
|
||||||
alt="profile picture"
|
alt="profile picture"
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,7 @@ export default function DeleteAccount() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button name="deletion" onClick={() => setIsOpen(true)} className="pill button w-fit h-min ml-auto bg-red-400! border-red-500! hover:bg-red-500!">
|
||||||
name="deletion"
|
|
||||||
onClick={() => setIsOpen(true)}
|
|
||||||
className="pill button w-fit h-min ml-auto bg-red-400! border-red-500! hover:bg-red-500!"
|
|
||||||
>
|
|
||||||
Delete Account
|
Delete Account
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
@ -69,9 +65,7 @@ export default function DeleteAccount() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-zinc-500">
|
<p className="text-sm text-zinc-500">Are you sure? This is permanent and will remove all uploaded Miis. This action cannot be undone.</p>
|
||||||
Are you sure? This is permanent and will remove all uploaded Miis. This action cannot be undone.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{error && <span className="text-red-400 font-bold mt-2">Error: {error}</span>}
|
{error && <span className="text-red-400 font-bold mt-2">Error: {error}</span>}
|
||||||
|
|
||||||
|
|
@ -83,7 +77,7 @@ export default function DeleteAccount() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -151,13 +151,7 @@ export default function ProfileSettings({ currentDescription }: Props) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end gap-1 h-min col-span-2">
|
<div className="flex justify-end gap-1 h-min col-span-2">
|
||||||
<input
|
<input type="text" className="pill input flex-1" placeholder="Type here..." value={displayName} onChange={(e) => setDisplayName(e.target.value)} />
|
||||||
type="text"
|
|
||||||
className="pill input flex-1"
|
|
||||||
placeholder="Type here..."
|
|
||||||
value={displayName}
|
|
||||||
onChange={(e) => setDisplayName(e.target.value)}
|
|
||||||
/>
|
|
||||||
<SubmitDialogButton
|
<SubmitDialogButton
|
||||||
title="Confirm Display Name Change"
|
title="Confirm Display Name Change"
|
||||||
description="Are you sure? This will only be visible on your profile. You can change it again later."
|
description="Are you sure? This will only be visible on your profile. You can change it again later."
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,8 @@ export default function ProfilePictureSettings() {
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<p className="text-sm text-zinc-500 mt-2">
|
<p className="text-sm text-zinc-500 mt-2">
|
||||||
After submitting, you can change it again on{" "}
|
After submitting, you can change it again on {changeDate.toDate().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })}
|
||||||
{changeDate.toDate().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })}.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="bg-orange-100 rounded-xl border-2 border-amber-500 mt-4 px-2 py-1 flex items-center">
|
<div className="bg-orange-100 rounded-xl border-2 border-amber-500 mt-4 px-2 py-1 flex items-center">
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export default function SubmitDialogButton({ title, description, onSubmit, error
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,7 @@ export default function ReasonSelector({ reason, setReason }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full col-span-2">
|
<div className="relative w-full col-span-2">
|
||||||
{/* Toggle button to open the dropdown */}
|
{/* Toggle button to open the dropdown */}
|
||||||
<button
|
<button type="button" {...getToggleButtonProps()} aria-label="Report reason dropdown" className="pill input w-full gap-1 justify-between! text-nowrap">
|
||||||
type="button"
|
|
||||||
{...getToggleButtonProps()}
|
|
||||||
aria-label="Report reason dropdown"
|
|
||||||
className="pill input w-full gap-1 justify-between! text-nowrap"
|
|
||||||
>
|
|
||||||
{selectedItem?.label || <span className="text-black/40">Select a reason for the report...</span>}
|
{selectedItem?.label || <span className="text-black/40">Select a reason for the report...</span>}
|
||||||
<Icon icon="tabler:chevron-down" className="ml-2 size-5" />
|
<Icon icon="tabler:chevron-down" className="ml-2 size-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,7 @@ export default function ShareMiiButton({ miiId }: Props) {
|
||||||
<input type="text" disabled className="pill input w-full text-sm" value={url} />
|
<input type="text" disabled className="pill input w-full text-sm" value={url} />
|
||||||
|
|
||||||
{/* Copy button */}
|
{/* Copy button */}
|
||||||
<button
|
<button className="absolute! top-2.5 right-2.5 cursor-pointer" data-tooltip={hasCopiedUrl ? "Copied!" : "Copy URL"} onClick={handleCopyUrl}>
|
||||||
className="absolute! top-2.5 right-2.5 cursor-pointer"
|
|
||||||
data-tooltip={hasCopiedUrl ? "Copied!" : "Copy URL"}
|
|
||||||
onClick={handleCopyUrl}
|
|
||||||
>
|
|
||||||
<div className="relative text-xl">
|
<div className="relative text-xl">
|
||||||
{/* Copy icon */}
|
{/* Copy icon */}
|
||||||
<Icon
|
<Icon
|
||||||
|
|
@ -124,14 +120,7 @@ export default function ShareMiiButton({ miiId }: Props) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-center items-center p-4 w-full bg-orange-100 border border-orange-400 rounded-lg">
|
<div className="flex justify-center items-center p-4 w-full bg-orange-100 border border-orange-400 rounded-lg">
|
||||||
<Image
|
<Image src={`/mii/${miiId}/image?type=metadata`} alt="mii 'metadata' image" width={248} height={248} unoptimized className="drop-shadow-md" />
|
||||||
src={`/mii/${miiId}/image?type=metadata`}
|
|
||||||
alt="mii 'metadata' image"
|
|
||||||
width={248}
|
|
||||||
height={248}
|
|
||||||
unoptimized
|
|
||||||
className="drop-shadow-md"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 mt-4">
|
<div className="flex justify-end gap-2 mt-4">
|
||||||
|
|
@ -158,9 +147,7 @@ export default function ShareMiiButton({ miiId }: Props) {
|
||||||
{/* Copy icon */}
|
{/* Copy icon */}
|
||||||
<Icon
|
<Icon
|
||||||
icon="solar:copy-bold"
|
icon="solar:copy-bold"
|
||||||
className={` transition-all duration-300 ${
|
className={` transition-all duration-300 ${hasCopiedImage ? "opacity-0 scale-75 rotate-12" : "opacity-100 scale-100 rotate-0"}`}
|
||||||
hasCopiedImage ? "opacity-0 scale-75 rotate-12" : "opacity-100 scale-100 rotate-0"
|
|
||||||
}`}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Check icon */}
|
{/* Check icon */}
|
||||||
|
|
@ -180,7 +167,7 @@ export default function ShareMiiButton({ miiId }: Props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ export default function EditForm({ mii, likes }: Props) {
|
||||||
|
|
||||||
setFiles((prev) => [...prev, ...acceptedFiles]);
|
setFiles((prev) => [...prev, ...acceptedFiles]);
|
||||||
},
|
},
|
||||||
[files.length]
|
[files.length],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
|
@ -91,7 +91,7 @@ export default function EditForm({ mii, likes }: Props) {
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
|
|
||||||
return Object.assign(new File([blob], `image${index}.webp`, { type: "image/webp" }), { path });
|
return Object.assign(new File([blob], `image${index}.webp`, { type: "image/webp" }), { path });
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
setFiles(existing);
|
setFiles(existing);
|
||||||
|
|
@ -107,9 +107,7 @@ export default function EditForm({ mii, likes }: Props) {
|
||||||
<form className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-center">
|
<form className="flex justify-center gap-4 w-full max-lg:flex-col max-lg:items-center">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-75 h-min flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-3">
|
<div className="w-75 h-min flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-3">
|
||||||
<Carousel
|
<Carousel images={[`/mii/${mii.id}/image?type=mii`, `/mii/${mii.id}/image?type=qr-code`, ...files.map((file) => URL.createObjectURL(file))]} />
|
||||||
images={[`/mii/${mii.id}/image?type=mii`, `/mii/${mii.id}/image?type=qr-code`, ...files.map((file) => URL.createObjectURL(file))]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="p-4 flex flex-col gap-1 h-full">
|
<div className="p-4 flex flex-col gap-1 h-full">
|
||||||
<h1 className="font-bold text-2xl line-clamp-1" title={name}>
|
<h1 className="font-bold text-2xl line-clamp-1" title={name}>
|
||||||
|
|
|
||||||
|
|
@ -144,10 +144,8 @@ export default function QrScanner({ isOpen, setIsOpen, setQrBytesRaw }: Props) {
|
||||||
};
|
};
|
||||||
}, [isOpen, permissionGranted, selectedDeviceId, scanQRCode]);
|
}, [isOpen, permissionGranted, selectedDeviceId, scanQRCode]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 h-[calc(100%-var(--header-height))] top-(--header-height) flex items-center justify-center z-40">
|
<div className={`fixed inset-0 h-[calc(100%-var(--header-height))] top-(--header-height) flex items-center justify-center z-40 ${!isOpen ? "hidden" : ""}`}>
|
||||||
<div
|
<div
|
||||||
onClick={close}
|
onClick={close}
|
||||||
className={`z-40 absolute inset-0 backdrop-brightness-75 backdrop-blur-xs transition-opacity duration-300 ${isVisible ? "opacity-100" : "opacity-0"}`}
|
className={`z-40 absolute inset-0 backdrop-brightness-75 backdrop-blur-xs transition-opacity duration-300 ${isVisible ? "opacity-100" : "opacity-0"}`}
|
||||||
|
|
@ -165,43 +163,41 @@ export default function QrScanner({ isOpen, setIsOpen, setQrBytesRaw }: Props) {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{devices.length > 1 && (
|
<div className={`mb-4 flex flex-col gap-1 ${devices.length <= 1 ? "hidden" : ""}`}>
|
||||||
<div className="mb-4 flex flex-col gap-1">
|
<label className="text-sm font-semibold">Camera:</label>
|
||||||
<label className="text-sm font-semibold">Camera:</label>
|
<div className="relative w-full">
|
||||||
<div className="relative w-full">
|
{/* Toggle button to open the dropdown */}
|
||||||
{/* Toggle button to open the dropdown */}
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
aria-label="Select camera dropdown"
|
||||||
aria-label="Select camera dropdown"
|
{...getToggleButtonProps({}, { suppressRefError: true })}
|
||||||
{...getToggleButtonProps({}, { suppressRefError: true })}
|
className="pill input w-full px-2! py-0.5! justify-between! text-sm"
|
||||||
className="pill input w-full px-2! py-0.5! justify-between! text-sm"
|
>
|
||||||
>
|
{selectedItem?.label || "Select a camera"}
|
||||||
{selectedItem?.label || "Select a camera"}
|
|
||||||
|
|
||||||
<Icon icon="tabler:chevron-down" className="ml-2 size-5" />
|
<Icon icon="tabler:chevron-down" className="ml-2 size-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Dropdown menu */}
|
{/* Dropdown menu */}
|
||||||
<ul
|
<ul
|
||||||
{...getMenuProps({}, { suppressRefError: true })}
|
{...getMenuProps({}, { suppressRefError: true })}
|
||||||
className={`absolute z-50 w-full bg-orange-200 border-2 border-orange-400 rounded-lg mt-1 shadow-lg max-h-60 overflow-y-auto ${
|
className={`absolute z-50 w-full bg-orange-200 border-2 border-orange-400 rounded-lg mt-1 shadow-lg max-h-60 overflow-y-auto ${
|
||||||
isDropdownOpen ? "block" : "hidden"
|
isDropdownOpen ? "block" : "hidden"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isDropdownOpen &&
|
{isDropdownOpen &&
|
||||||
cameraItems.map((item, index) => (
|
cameraItems.map((item, index) => (
|
||||||
<li
|
<li
|
||||||
key={item.value}
|
key={item.value}
|
||||||
{...getItemProps({ item, index })}
|
{...getItemProps({ item, index })}
|
||||||
className={`px-4 py-1 cursor-pointer text-sm ${highlightedIndex === index ? "bg-black/15" : ""}`}
|
className={`px-4 py-1 cursor-pointer text-sm ${highlightedIndex === index ? "bg-black/15" : ""}`}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
|
||||||
<div className="relative w-full aspect-square">
|
<div className="relative w-full aspect-square">
|
||||||
{!permissionGranted && (
|
{!permissionGranted && (
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export default function QrUpload({ setQrBytesRaw }: Props) {
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[setQrBytesRaw]
|
[setQrBytesRaw],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,7 @@ export default function Tutorial({ tutorials, isOpen, setIsOpen }: Props) {
|
||||||
<div className="fixed inset-0 h-[calc(100%-var(--header-height))] top-(--header-height) flex items-center justify-center z-40">
|
<div className="fixed inset-0 h-[calc(100%-var(--header-height))] top-(--header-height) flex items-center justify-center z-40">
|
||||||
<div
|
<div
|
||||||
onClick={close}
|
onClick={close}
|
||||||
className={`z-40 absolute inset-0 backdrop-brightness-75 backdrop-blur-xs transition-opacity duration-300 ${
|
className={`z-40 absolute inset-0 backdrop-brightness-75 backdrop-blur-xs transition-opacity duration-300 ${isVisible ? "opacity-100" : "opacity-0"}`}
|
||||||
isVisible ? "opacity-100" : "opacity-0"
|
|
||||||
}`}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -191,11 +189,7 @@ export default function Tutorial({ tutorials, isOpen, setIsOpen }: Props) {
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Only show tutorial name on step slides */}
|
{/* Only show tutorial name on step slides */}
|
||||||
<span
|
<span className={`text-sm transition-opacity duration-300 ${(currentSlide.type === "finish" || currentSlide.type === "start") && "opacity-0"}`}>
|
||||||
className={`text-sm transition-opacity duration-300 ${
|
|
||||||
(currentSlide.type === "finish" || currentSlide.type === "start") && "opacity-0"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{currentSlide?.tutorialTitle}
|
{currentSlide?.tutorialTitle}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export default function ScanTutorialButton() {
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpen}
|
||||||
/>,
|
/>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default function SubmitTutorialButton() {
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpen}
|
||||||
/>,
|
/>,
|
||||||
document.body
|
document.body,
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,7 @@ const STUDIO_RENDER_CLOTHES_COLORS = [
|
||||||
"black",
|
"black",
|
||||||
];
|
];
|
||||||
|
|
||||||
const STUDIO_RENDER_LIGHT_DIRECTION_MODS = [
|
const STUDIO_RENDER_LIGHT_DIRECTION_MODS = ["none", "zerox", "flipx", "camera", "offset", "set"];
|
||||||
"none",
|
|
||||||
"zerox",
|
|
||||||
"flipx",
|
|
||||||
"camera",
|
|
||||||
"offset",
|
|
||||||
"set",
|
|
||||||
];
|
|
||||||
|
|
||||||
const STUDIO_RENDER_INSTANCE_ROTATION_MODES = ["model", "camera", "both"];
|
const STUDIO_RENDER_INSTANCE_ROTATION_MODES = ["model", "camera", "both"];
|
||||||
|
|
||||||
|
|
@ -165,285 +158,79 @@ export default class Mii {
|
||||||
|
|
||||||
public validate(): void {
|
public validate(): void {
|
||||||
// Size check
|
// Size check
|
||||||
assert.equal(
|
assert.equal(this.bitStream.length / 8, 0x60, `Invalid Mii data size. Got ${this.bitStream.length / 8}, expected 96`);
|
||||||
this.bitStream.length / 8,
|
|
||||||
0x60,
|
|
||||||
`Invalid Mii data size. Got ${this.bitStream.length / 8}, expected 96`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Value range and type checks
|
// Value range and type checks
|
||||||
assert.ok(
|
assert.ok(this.version === 0 || this.version === 3, `Invalid Mii version. Got ${this.version}, expected 0 or 3`);
|
||||||
this.version === 0 || this.version === 3,
|
assert.equal(typeof this.allowCopying, "boolean", `Invalid Mii allow copying. Got ${this.allowCopying}, expected true or false`);
|
||||||
`Invalid Mii version. Got ${this.version}, expected 0 or 3`,
|
assert.equal(typeof this.profanityFlag, "boolean", `Invalid Mii profanity flag. Got ${this.profanityFlag}, expected true or false`);
|
||||||
);
|
assert.ok(Util.inRange(this.regionLock, Util.range(4)), `Invalid Mii region lock. Got ${this.regionLock}, expected 0-3`);
|
||||||
assert.equal(
|
assert.ok(Util.inRange(this.characterSet, Util.range(4)), `Invalid Mii region lock. Got ${this.characterSet}, expected 0-3`);
|
||||||
typeof this.allowCopying,
|
assert.ok(Util.inRange(this.pageIndex, Util.range(10)), `Invalid Mii page index. Got ${this.pageIndex}, expected 0-9`);
|
||||||
"boolean",
|
assert.ok(Util.inRange(this.slotIndex, Util.range(10)), `Invalid Mii slot index. Got ${this.slotIndex}, expected 0-9`);
|
||||||
`Invalid Mii allow copying. Got ${this.allowCopying}, expected true or false`,
|
assert.equal(this.unknown1, 0, `Invalid Mii unknown1. Got ${this.unknown1}, expected 0`);
|
||||||
);
|
assert.ok(Util.inRange(this.deviceOrigin, Util.range(1, 5)), `Invalid Mii device origin. Got ${this.deviceOrigin}, expected 1-4`);
|
||||||
assert.equal(
|
assert.equal(this.systemId.length, 8, `Invalid Mii system ID size. Got ${this.systemId.length}, system IDs must be 8 bytes long`);
|
||||||
typeof this.profanityFlag,
|
assert.equal(typeof this.normalMii, "boolean", `Invalid normal Mii flag. Got ${this.normalMii}, expected true or false`);
|
||||||
"boolean",
|
assert.equal(typeof this.dsMii, "boolean", `Invalid DS Mii flag. Got ${this.dsMii}, expected true or false`);
|
||||||
`Invalid Mii profanity flag. Got ${this.profanityFlag}, expected true or false`,
|
assert.equal(typeof this.nonUserMii, "boolean", `Invalid non-user Mii flag. Got ${this.nonUserMii}, expected true or false`);
|
||||||
);
|
assert.equal(typeof this.isValid, "boolean", `Invalid Mii valid flag. Got ${this.isValid}, expected true or false`);
|
||||||
assert.ok(
|
assert.ok(this.creationTime < 268435456, `Invalid Mii creation time. Got ${this.creationTime}, max value for 28 bit integer is 268,435,456`);
|
||||||
Util.inRange(this.regionLock, Util.range(4)),
|
assert.equal(this.consoleMAC.length, 6, `Invalid Mii console MAC address size. Got ${this.consoleMAC.length}, console MAC addresses must be 6 bytes long`);
|
||||||
`Invalid Mii region lock. Got ${this.regionLock}, expected 0-3`,
|
assert.ok(Util.inRange(this.gender, Util.range(2)), `Invalid Mii gender. Got ${this.gender}, expected 0 or 1`);
|
||||||
);
|
assert.ok(Util.inRange(this.birthMonth, Util.range(13)), `Invalid Mii birth month. Got ${this.birthMonth}, expected 0-12`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.birthDay, Util.range(32)), `Invalid Mii birth day. Got ${this.birthDay}, expected 0-31`);
|
||||||
Util.inRange(this.characterSet, Util.range(4)),
|
assert.ok(Util.inRange(this.favoriteColor, Util.range(12)), `Invalid Mii favorite color. Got ${this.favoriteColor}, expected 0-11`);
|
||||||
`Invalid Mii region lock. Got ${this.characterSet}, expected 0-3`,
|
assert.equal(typeof this.favorite, "boolean", `Invalid favorite Mii flag. Got ${this.favorite}, expected true or false`);
|
||||||
);
|
assert.ok(Buffer.from(this.miiName, "utf16le").length <= 0x14, `Invalid Mii name. Got ${this.miiName}, name may only be up to 10 characters`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.height, Util.range(128)), `Invalid Mii height. Got ${this.height}, expected 0-127`);
|
||||||
Util.inRange(this.pageIndex, Util.range(10)),
|
assert.ok(Util.inRange(this.build, Util.range(128)), `Invalid Mii build. Got ${this.build}, expected 0-127`);
|
||||||
`Invalid Mii page index. Got ${this.pageIndex}, expected 0-9`,
|
assert.equal(typeof this.disableSharing, "boolean", `Invalid disable sharing Mii flag. Got ${this.disableSharing}, expected true or false`);
|
||||||
);
|
assert.ok(Util.inRange(this.faceType, Util.range(12)), `Invalid Mii face type. Got ${this.faceType}, expected 0-11`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.skinColor, Util.range(7)), `Invalid Mii skin color. Got ${this.skinColor}, expected 0-6`);
|
||||||
Util.inRange(this.slotIndex, Util.range(10)),
|
assert.ok(Util.inRange(this.wrinklesType, Util.range(12)), `Invalid Mii wrinkles type. Got ${this.wrinklesType}, expected 0-11`);
|
||||||
`Invalid Mii slot index. Got ${this.slotIndex}, expected 0-9`,
|
assert.ok(Util.inRange(this.makeupType, Util.range(12)), `Invalid Mii makeup type. Got ${this.makeupType}, expected 0-11`);
|
||||||
);
|
assert.ok(Util.inRange(this.hairType, Util.range(132)), `Invalid Mii hair type. Got ${this.hairType}, expected 0-131`);
|
||||||
assert.equal(
|
|
||||||
this.unknown1,
|
|
||||||
0,
|
|
||||||
`Invalid Mii unknown1. Got ${this.unknown1}, expected 0`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.deviceOrigin, Util.range(1, 5)),
|
|
||||||
`Invalid Mii device origin. Got ${this.deviceOrigin}, expected 1-4`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
this.systemId.length,
|
|
||||||
8,
|
|
||||||
`Invalid Mii system ID size. Got ${this.systemId.length}, system IDs must be 8 bytes long`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.normalMii,
|
|
||||||
"boolean",
|
|
||||||
`Invalid normal Mii flag. Got ${this.normalMii}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.dsMii,
|
|
||||||
"boolean",
|
|
||||||
`Invalid DS Mii flag. Got ${this.dsMii}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.nonUserMii,
|
|
||||||
"boolean",
|
|
||||||
`Invalid non-user Mii flag. Got ${this.nonUserMii}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.isValid,
|
|
||||||
"boolean",
|
|
||||||
`Invalid Mii valid flag. Got ${this.isValid}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
this.creationTime < 268435456,
|
|
||||||
`Invalid Mii creation time. Got ${this.creationTime}, max value for 28 bit integer is 268,435,456`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
this.consoleMAC.length,
|
|
||||||
6,
|
|
||||||
`Invalid Mii console MAC address size. Got ${this.consoleMAC.length}, console MAC addresses must be 6 bytes long`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.gender, Util.range(2)),
|
|
||||||
`Invalid Mii gender. Got ${this.gender}, expected 0 or 1`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.birthMonth, Util.range(13)),
|
|
||||||
`Invalid Mii birth month. Got ${this.birthMonth}, expected 0-12`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.birthDay, Util.range(32)),
|
|
||||||
`Invalid Mii birth day. Got ${this.birthDay}, expected 0-31`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.favoriteColor, Util.range(12)),
|
|
||||||
`Invalid Mii favorite color. Got ${this.favoriteColor}, expected 0-11`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.favorite,
|
|
||||||
"boolean",
|
|
||||||
`Invalid favorite Mii flag. Got ${this.favorite}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Buffer.from(this.miiName, "utf16le").length <= 0x14,
|
|
||||||
`Invalid Mii name. Got ${this.miiName}, name may only be up to 10 characters`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.height, Util.range(128)),
|
|
||||||
`Invalid Mii height. Got ${this.height}, expected 0-127`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.build, Util.range(128)),
|
|
||||||
`Invalid Mii build. Got ${this.build}, expected 0-127`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.disableSharing,
|
|
||||||
"boolean",
|
|
||||||
`Invalid disable sharing Mii flag. Got ${this.disableSharing}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.faceType, Util.range(12)),
|
|
||||||
`Invalid Mii face type. Got ${this.faceType}, expected 0-11`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.skinColor, Util.range(7)),
|
|
||||||
`Invalid Mii skin color. Got ${this.skinColor}, expected 0-6`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.wrinklesType, Util.range(12)),
|
|
||||||
`Invalid Mii wrinkles type. Got ${this.wrinklesType}, expected 0-11`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.makeupType, Util.range(12)),
|
|
||||||
`Invalid Mii makeup type. Got ${this.makeupType}, expected 0-11`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.hairType, Util.range(132)),
|
|
||||||
`Invalid Mii hair type. Got ${this.hairType}, expected 0-131`,
|
|
||||||
);
|
|
||||||
// assert.ok(Util.inRange(this.hairColor, Util.range(8)), `Invalid Mii hair color. Got ${this.hairColor}, expected 0-7`);
|
// assert.ok(Util.inRange(this.hairColor, Util.range(8)), `Invalid Mii hair color. Got ${this.hairColor}, expected 0-7`);
|
||||||
assert.equal(
|
assert.equal(typeof this.flipHair, "boolean", `Invalid flip hair flag. Got ${this.flipHair}, expected true or false`);
|
||||||
typeof this.flipHair,
|
assert.ok(Util.inRange(this.eyeType, Util.range(60)), `Invalid Mii eye type. Got ${this.eyeType}, expected 0-59`);
|
||||||
"boolean",
|
assert.ok(Util.inRange(this.eyeColor, Util.range(6)), `Invalid Mii eye color. Got ${this.eyeColor}, expected 0-5`);
|
||||||
`Invalid flip hair flag. Got ${this.flipHair}, expected true or false`,
|
assert.ok(Util.inRange(this.eyeScale, Util.range(8)), `Invalid Mii eye scale. Got ${this.eyeScale}, expected 0-7`);
|
||||||
);
|
assert.ok(Util.inRange(this.eyeVerticalStretch, Util.range(7)), `Invalid Mii eye vertical stretch. Got ${this.eyeVerticalStretch}, expected 0-6`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.eyeRotation, Util.range(8)), `Invalid Mii eye rotation. Got ${this.eyeRotation}, expected 0-7`);
|
||||||
Util.inRange(this.eyeType, Util.range(60)),
|
assert.ok(Util.inRange(this.eyeSpacing, Util.range(13)), `Invalid Mii eye spacing. Got ${this.eyeSpacing}, expected 0-12`);
|
||||||
`Invalid Mii eye type. Got ${this.eyeType}, expected 0-59`,
|
assert.ok(Util.inRange(this.eyeYPosition, Util.range(19)), `Invalid Mii eye Y position. Got ${this.eyeYPosition}, expected 0-18`);
|
||||||
);
|
assert.ok(Util.inRange(this.eyebrowType, Util.range(25)), `Invalid Mii eyebrow type. Got ${this.eyebrowType}, expected 0-24`);
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeColor, Util.range(6)),
|
|
||||||
`Invalid Mii eye color. Got ${this.eyeColor}, expected 0-5`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeScale, Util.range(8)),
|
|
||||||
`Invalid Mii eye scale. Got ${this.eyeScale}, expected 0-7`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeVerticalStretch, Util.range(7)),
|
|
||||||
`Invalid Mii eye vertical stretch. Got ${this.eyeVerticalStretch}, expected 0-6`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeRotation, Util.range(8)),
|
|
||||||
`Invalid Mii eye rotation. Got ${this.eyeRotation}, expected 0-7`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeSpacing, Util.range(13)),
|
|
||||||
`Invalid Mii eye spacing. Got ${this.eyeSpacing}, expected 0-12`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyeYPosition, Util.range(19)),
|
|
||||||
`Invalid Mii eye Y position. Got ${this.eyeYPosition}, expected 0-18`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.eyebrowType, Util.range(25)),
|
|
||||||
`Invalid Mii eyebrow type. Got ${this.eyebrowType}, expected 0-24`,
|
|
||||||
);
|
|
||||||
// assert.ok(Util.inRange(this.eyebrowColor, Util.range(8)), `Invalid Mii eyebrow color. Got ${this.eyebrowColor}, expected 0-7`);
|
// assert.ok(Util.inRange(this.eyebrowColor, Util.range(8)), `Invalid Mii eyebrow color. Got ${this.eyebrowColor}, expected 0-7`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.eyebrowScale, Util.range(9)), `Invalid Mii eyebrow scale. Got ${this.eyebrowScale}, expected 0-8`);
|
||||||
Util.inRange(this.eyebrowScale, Util.range(9)),
|
|
||||||
`Invalid Mii eyebrow scale. Got ${this.eyebrowScale}, expected 0-8`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
Util.inRange(this.eyebrowVerticalStretch, Util.range(7)),
|
Util.inRange(this.eyebrowVerticalStretch, Util.range(7)),
|
||||||
`Invalid Mii eyebrow vertical stretch. Got ${this.eyebrowVerticalStretch}, expected 0-6`,
|
`Invalid Mii eyebrow vertical stretch. Got ${this.eyebrowVerticalStretch}, expected 0-6`,
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.eyebrowRotation, Util.range(12)), `Invalid Mii eyebrow rotation. Got ${this.eyebrowRotation}, expected 0-11`);
|
||||||
Util.inRange(this.eyebrowRotation, Util.range(12)),
|
assert.ok(Util.inRange(this.eyebrowSpacing, Util.range(13)), `Invalid Mii eyebrow spacing. Got ${this.eyebrowSpacing}, expected 0-12`);
|
||||||
`Invalid Mii eyebrow rotation. Got ${this.eyebrowRotation}, expected 0-11`,
|
assert.ok(Util.inRange(this.eyebrowYPosition, Util.range(3, 19)), `Invalid Mii eyebrow Y position. Got ${this.eyebrowYPosition}, expected 3-18`);
|
||||||
);
|
assert.ok(Util.inRange(this.noseType, Util.range(18)), `Invalid Mii nose type. Got ${this.noseType}, expected 0-17`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.noseScale, Util.range(9)), `Invalid Mii nose scale. Got ${this.noseScale}, expected 0-8`);
|
||||||
Util.inRange(this.eyebrowSpacing, Util.range(13)),
|
assert.ok(Util.inRange(this.noseYPosition, Util.range(19)), `Invalid Mii nose Y position. Got ${this.noseYPosition}, expected 0-18`);
|
||||||
`Invalid Mii eyebrow spacing. Got ${this.eyebrowSpacing}, expected 0-12`,
|
assert.ok(Util.inRange(this.mouthType, Util.range(36)), `Invalid Mii mouth type. Got ${this.mouthType}, expected 0-35`);
|
||||||
);
|
assert.ok(Util.inRange(this.mouthColor, Util.range(5)), `Invalid Mii mouth color. Got ${this.mouthColor}, expected 0-4`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.mouthScale, Util.range(9)), `Invalid Mii mouth scale. Got ${this.mouthScale}, expected 0-8`);
|
||||||
Util.inRange(this.eyebrowYPosition, Util.range(3, 19)),
|
assert.ok(Util.inRange(this.mouthHorizontalStretch, Util.range(7)), `Invalid Mii mouth stretch. Got ${this.mouthHorizontalStretch}, expected 0-6`);
|
||||||
`Invalid Mii eyebrow Y position. Got ${this.eyebrowYPosition}, expected 3-18`,
|
assert.ok(Util.inRange(this.mouthYPosition, Util.range(19)), `Invalid Mii mouth Y position. Got ${this.mouthYPosition}, expected 0-18`);
|
||||||
);
|
assert.ok(Util.inRange(this.mustacheType, Util.range(6)), `Invalid Mii mustache type. Got ${this.mustacheType}, expected 0-5`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.beardType, Util.range(6)), `Invalid Mii beard type. Got ${this.beardType}, expected 0-5`);
|
||||||
Util.inRange(this.noseType, Util.range(18)),
|
|
||||||
`Invalid Mii nose type. Got ${this.noseType}, expected 0-17`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.noseScale, Util.range(9)),
|
|
||||||
`Invalid Mii nose scale. Got ${this.noseScale}, expected 0-8`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.noseYPosition, Util.range(19)),
|
|
||||||
`Invalid Mii nose Y position. Got ${this.noseYPosition}, expected 0-18`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mouthType, Util.range(36)),
|
|
||||||
`Invalid Mii mouth type. Got ${this.mouthType}, expected 0-35`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mouthColor, Util.range(5)),
|
|
||||||
`Invalid Mii mouth color. Got ${this.mouthColor}, expected 0-4`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mouthScale, Util.range(9)),
|
|
||||||
`Invalid Mii mouth scale. Got ${this.mouthScale}, expected 0-8`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mouthHorizontalStretch, Util.range(7)),
|
|
||||||
`Invalid Mii mouth stretch. Got ${this.mouthHorizontalStretch}, expected 0-6`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mouthYPosition, Util.range(19)),
|
|
||||||
`Invalid Mii mouth Y position. Got ${this.mouthYPosition}, expected 0-18`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.mustacheType, Util.range(6)),
|
|
||||||
`Invalid Mii mustache type. Got ${this.mustacheType}, expected 0-5`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.beardType, Util.range(6)),
|
|
||||||
`Invalid Mii beard type. Got ${this.beardType}, expected 0-5`,
|
|
||||||
);
|
|
||||||
// assert.ok(Util.inRange(this.facialHairColor, Util.range(8)), `Invalid Mii beard type. Got ${this.facialHairColor}, expected 0-7`);
|
// assert.ok(Util.inRange(this.facialHairColor, Util.range(8)), `Invalid Mii beard type. Got ${this.facialHairColor}, expected 0-7`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.mustacheScale, Util.range(9)), `Invalid Mii mustache scale. Got ${this.mustacheScale}, expected 0-8`);
|
||||||
Util.inRange(this.mustacheScale, Util.range(9)),
|
assert.ok(Util.inRange(this.mustacheYPosition, Util.range(17)), `Invalid Mii mustache Y position. Got ${this.mustacheYPosition}, expected 0-16`);
|
||||||
`Invalid Mii mustache scale. Got ${this.mustacheScale}, expected 0-8`,
|
assert.ok(Util.inRange(this.glassesType, Util.range(9)), `Invalid Mii glassess type. Got ${this.glassesType}, expected 0-8`);
|
||||||
);
|
assert.ok(Util.inRange(this.glassesColor, Util.range(6)), `Invalid Mii glassess type. Got ${this.glassesColor}, expected 0-5`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.glassesScale, Util.range(8)), `Invalid Mii glassess type. Got ${this.glassesScale}, expected 0-7`);
|
||||||
Util.inRange(this.mustacheYPosition, Util.range(17)),
|
assert.ok(Util.inRange(this.glassesYPosition, Util.range(21)), `Invalid Mii glassess Y position. Got ${this.glassesYPosition}, expected 0-20`);
|
||||||
`Invalid Mii mustache Y position. Got ${this.mustacheYPosition}, expected 0-16`,
|
assert.equal(typeof this.moleEnabled, "boolean", `Invalid mole enabled flag. Got ${this.moleEnabled}, expected true or false`);
|
||||||
);
|
assert.ok(Util.inRange(this.moleScale, Util.range(9)), `Invalid Mii mole scale. Got ${this.moleScale}, expected 0-8`);
|
||||||
assert.ok(
|
assert.ok(Util.inRange(this.moleXPosition, Util.range(17)), `Invalid Mii mole X position. Got ${this.moleXPosition}, expected 0-16`);
|
||||||
Util.inRange(this.glassesType, Util.range(9)),
|
assert.ok(Util.inRange(this.moleYPosition, Util.range(31)), `Invalid Mii mole Y position. Got ${this.moleYPosition}, expected 0-30`);
|
||||||
`Invalid Mii glassess type. Got ${this.glassesType}, expected 0-8`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.glassesColor, Util.range(6)),
|
|
||||||
`Invalid Mii glassess type. Got ${this.glassesColor}, expected 0-5`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.glassesScale, Util.range(8)),
|
|
||||||
`Invalid Mii glassess type. Got ${this.glassesScale}, expected 0-7`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.glassesYPosition, Util.range(21)),
|
|
||||||
`Invalid Mii glassess Y position. Got ${this.glassesYPosition}, expected 0-20`,
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
typeof this.moleEnabled,
|
|
||||||
"boolean",
|
|
||||||
`Invalid mole enabled flag. Got ${this.moleEnabled}, expected true or false`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.moleScale, Util.range(9)),
|
|
||||||
`Invalid Mii mole scale. Got ${this.moleScale}, expected 0-8`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.moleXPosition, Util.range(17)),
|
|
||||||
`Invalid Mii mole X position. Got ${this.moleXPosition}, expected 0-16`,
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
Util.inRange(this.moleYPosition, Util.range(31)),
|
|
||||||
`Invalid Mii mole Y position. Got ${this.moleYPosition}, expected 0-30`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
/*
|
/*
|
||||||
|
|
@ -459,10 +246,7 @@ export default class Mii {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (
|
if (this.nonUserMii && (this.creationTime !== 0 || this.isValid || this.dsMii || this.normalMii)) {
|
||||||
this.nonUserMii &&
|
|
||||||
(this.creationTime !== 0 || this.isValid || this.dsMii || this.normalMii)
|
|
||||||
) {
|
|
||||||
assert.fail("Non-user Mii's must have all other Mii ID bits set to 0");
|
assert.fail("Non-user Mii's must have all other Mii ID bits set to 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,11 +353,7 @@ export default class Mii {
|
||||||
|
|
||||||
public calculateCRC(): number {
|
public calculateCRC(): number {
|
||||||
// #view is inaccessible
|
// #view is inaccessible
|
||||||
const data = new Uint8Array(
|
const data = new Uint8Array(this.buffer.buffer, this.buffer.byteOffset, this.buffer.length).subarray(0, 0x5e);
|
||||||
this.buffer.buffer,
|
|
||||||
this.buffer.byteOffset,
|
|
||||||
this.buffer.length,
|
|
||||||
).subarray(0, 0x5e);
|
|
||||||
|
|
||||||
let crc = 0x0000;
|
let crc = 0x0000;
|
||||||
|
|
||||||
|
|
@ -727,23 +507,11 @@ export default class Mii {
|
||||||
data: this.encodeStudio().toString("hex"),
|
data: this.encodeStudio().toString("hex"),
|
||||||
};
|
};
|
||||||
|
|
||||||
params.type = STUDIO_RENDER_TYPES.includes(params.type as string)
|
params.type = STUDIO_RENDER_TYPES.includes(params.type as string) ? params.type : STUDIO_RENDER_DEFAULTS.type;
|
||||||
? params.type
|
params.expression = STUDIO_RENDER_EXPRESSIONS.includes(params.expression as string) ? params.expression : STUDIO_RENDER_DEFAULTS.expression;
|
||||||
: STUDIO_RENDER_DEFAULTS.type;
|
|
||||||
params.expression = STUDIO_RENDER_EXPRESSIONS.includes(
|
|
||||||
params.expression as string,
|
|
||||||
)
|
|
||||||
? params.expression
|
|
||||||
: STUDIO_RENDER_DEFAULTS.expression;
|
|
||||||
params.width = Util.clamp(params.width, 512);
|
params.width = Util.clamp(params.width, 512);
|
||||||
params.bgColor = STUDIO_BG_COLOR_REGEX.test(params.bgColor as string)
|
params.bgColor = STUDIO_BG_COLOR_REGEX.test(params.bgColor as string) ? params.bgColor : STUDIO_RENDER_DEFAULTS.bgColor;
|
||||||
? params.bgColor
|
params.clothesColor = STUDIO_RENDER_CLOTHES_COLORS.includes(params.clothesColor) ? params.clothesColor : STUDIO_RENDER_DEFAULTS.clothesColor;
|
||||||
: STUDIO_RENDER_DEFAULTS.bgColor;
|
|
||||||
params.clothesColor = STUDIO_RENDER_CLOTHES_COLORS.includes(
|
|
||||||
params.clothesColor,
|
|
||||||
)
|
|
||||||
? params.clothesColor
|
|
||||||
: STUDIO_RENDER_DEFAULTS.clothesColor;
|
|
||||||
params.cameraXRotate = Util.clamp(params.cameraXRotate, 359);
|
params.cameraXRotate = Util.clamp(params.cameraXRotate, 359);
|
||||||
params.cameraYRotate = Util.clamp(params.cameraYRotate, 359);
|
params.cameraYRotate = Util.clamp(params.cameraYRotate, 359);
|
||||||
params.cameraZRotate = Util.clamp(params.cameraZRotate, 359);
|
params.cameraZRotate = Util.clamp(params.cameraZRotate, 359);
|
||||||
|
|
@ -753,25 +521,16 @@ export default class Mii {
|
||||||
params.lightXDirection = Util.clamp(params.lightXDirection, 359);
|
params.lightXDirection = Util.clamp(params.lightXDirection, 359);
|
||||||
params.lightYDirection = Util.clamp(params.lightYDirection, 359);
|
params.lightYDirection = Util.clamp(params.lightYDirection, 359);
|
||||||
params.lightZDirection = Util.clamp(params.lightZDirection, 359);
|
params.lightZDirection = Util.clamp(params.lightZDirection, 359);
|
||||||
params.lightDirectionMode = STUDIO_RENDER_LIGHT_DIRECTION_MODS.includes(
|
params.lightDirectionMode = STUDIO_RENDER_LIGHT_DIRECTION_MODS.includes(params.lightDirectionMode)
|
||||||
params.lightDirectionMode,
|
|
||||||
)
|
|
||||||
? params.lightDirectionMode
|
? params.lightDirectionMode
|
||||||
: STUDIO_RENDER_DEFAULTS.lightDirectionMode;
|
: STUDIO_RENDER_DEFAULTS.lightDirectionMode;
|
||||||
params.instanceCount = Util.clamp(params.instanceCount, 1, 16);
|
params.instanceCount = Util.clamp(params.instanceCount, 1, 16);
|
||||||
params.instanceRotationMode =
|
params.instanceRotationMode = STUDIO_RENDER_INSTANCE_ROTATION_MODES.includes(params.instanceRotationMode)
|
||||||
STUDIO_RENDER_INSTANCE_ROTATION_MODES.includes(
|
? params.instanceRotationMode
|
||||||
params.instanceRotationMode,
|
: STUDIO_RENDER_DEFAULTS.instanceRotationMode;
|
||||||
)
|
|
||||||
? params.instanceRotationMode
|
|
||||||
: STUDIO_RENDER_DEFAULTS.instanceRotationMode;
|
|
||||||
|
|
||||||
// converts non-string params to strings
|
// converts non-string params to strings
|
||||||
const query = new URLSearchParams(
|
const query = new URLSearchParams(Object.fromEntries(Object.entries(params).map(([key, value]) => [key, value.toString()])));
|
||||||
Object.fromEntries(
|
|
||||||
Object.entries(params).map(([key, value]) => [key, value.toString()]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (params.lightDirectionMode === "none") {
|
if (params.lightDirectionMode === "none") {
|
||||||
query.delete("lightDirectionMode");
|
query.delete("lightDirectionMode");
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ sjcl.beware["CTR mode is dangerous because it doesn't protect message integrity.
|
||||||
// Converts hair dye to studio color
|
// Converts hair dye to studio color
|
||||||
// Reference: https://github.com/ariankordi/nwf-mii-cemu-toy/blob/9906440c1dafbe3f40ac8b95e10a22ebd85b441e/assets/data-conversion.js#L282
|
// Reference: https://github.com/ariankordi/nwf-mii-cemu-toy/blob/9906440c1dafbe3f40ac8b95e10a22ebd85b441e/assets/data-conversion.js#L282
|
||||||
// (Credits to kat21)
|
// (Credits to kat21)
|
||||||
const hairDyeConverter = [
|
const hairDyeConverter = [55, 51, 50, 12, 16, 12, 67, 61, 51, 64, 69, 66, 65, 86, 85, 93, 92, 19, 20, 20, 15, 32, 35, 26, 38, 41, 43, 18, 95, 97, 97, 99];
|
||||||
55, 51, 50, 12, 16, 12, 67, 61, 51, 64, 69, 66, 65, 86, 85, 93, 92, 19, 20, 20, 15, 32, 35, 26, 38, 41, 43, 18, 95, 97, 97, 99,
|
|
||||||
];
|
|
||||||
|
|
||||||
// All possible values for 2-bit hair dye mode.
|
// All possible values for 2-bit hair dye mode.
|
||||||
export enum HairDyeMode {
|
export enum HairDyeMode {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue