mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-25 07:32:19 -05:00
map generation logic
This commit is contained in:
parent
63255cb290
commit
c7c340c768
|
|
@ -1,5 +1,5 @@
|
|||
import { GetAllLadderRegisteredTeamsData } from "prisma/queries/getAllLadderRegisteredTeams";
|
||||
import useSWR from "swr";
|
||||
|
||||
export const useLadderTeams = () =>
|
||||
useSWR<GetAllLadderRegisteredTeamsData>("/api/play/teams");
|
||||
export const useLadderTeams = (skip?: boolean) =>
|
||||
useSWR<GetAllLadderRegisteredTeamsData>(skip ? null : "/api/play/teams");
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
import { getMySession } from "lib/getMySession";
|
||||
import { getLadderRounds } from "lib/playFunctions";
|
||||
import { shuffleArray } from "lib/shuffleArray";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getAllLadderRegisteredTeamsForMatches } from "prisma/queries/getAllLadderRegisteredTeamsForMatches";
|
||||
|
||||
const matchesHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
switch (req.method) {
|
||||
case "POST":
|
||||
await postHandler(req, res);
|
||||
break;
|
||||
default:
|
||||
res.status(405).end();
|
||||
}
|
||||
};
|
||||
|
||||
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const user = await getMySession();
|
||||
|
||||
// if (user?.discordId !== ADMIN_DISCORD_ID) {
|
||||
// return res.status(401).end();
|
||||
// }
|
||||
|
||||
const teams = (await getAllLadderRegisteredTeamsForMatches()).filter(
|
||||
(team) => team.roster.length === 4
|
||||
);
|
||||
|
||||
if (teams.length < 4) return res.status(400).end();
|
||||
|
||||
const matches = getLadderRounds(teams);
|
||||
|
||||
// await Promise.all(
|
||||
// matches.flatMap((round, i) =>
|
||||
// round.map((match) =>
|
||||
// prisma.ladderMatch.create({
|
||||
// data: {
|
||||
// date: "",
|
||||
// maplist: {},
|
||||
// order: i + 1,
|
||||
// players: {
|
||||
// create: match.flatMap((team, teamI) =>
|
||||
// team.roster.map((user) => ({
|
||||
// userId: user.id,
|
||||
// team: teamI === 0 ? "ALPHA" : "BRAVO",
|
||||
// }))
|
||||
// ),
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
|
||||
const eighteenMaps = getMaplist();
|
||||
|
||||
res.status(200).json(
|
||||
matches.flatMap((round, i) =>
|
||||
round.map((match) => ({
|
||||
data: {
|
||||
date: "",
|
||||
maplist:
|
||||
i === 0 ? eighteenMaps.slice(0, 9) : eighteenMaps.slice(9, 18),
|
||||
order: i + 1,
|
||||
players: {
|
||||
create: match.flatMap((team, teamI) =>
|
||||
team.roster.map((user) => ({
|
||||
userId: user.id,
|
||||
team: teamI === 0 ? "ALPHA" : "BRAVO",
|
||||
}))
|
||||
),
|
||||
},
|
||||
},
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getMaplist() {
|
||||
const modes = shuffleArray(["SZ", "TC", "RM", "CB"]);
|
||||
const stages = shuffleArray([
|
||||
"The Reef",
|
||||
"Musselforge Fitness",
|
||||
"Starfish Mainstage",
|
||||
"Humpback Pump Track",
|
||||
"Inkblot Art Academy",
|
||||
"Sturgeon Shipyard",
|
||||
"Manta Maria",
|
||||
"Snapper Canal",
|
||||
"Blackbelly Skatepark",
|
||||
"MakoMart",
|
||||
"Shellendorf Institute",
|
||||
"Goby Arena",
|
||||
"Piranha Pit",
|
||||
"Camp Triggerfish",
|
||||
"Wahoo World",
|
||||
"New Albacore Hotel",
|
||||
"Ancho-V Games",
|
||||
"Skipper Pavilion",
|
||||
//"Moray Towers",
|
||||
//"Port Mackerel",
|
||||
//"Walleye Warehouse",
|
||||
//"Arowana Mall",
|
||||
//"Kelp Dome"
|
||||
]);
|
||||
|
||||
return stages.map((stage) => {
|
||||
const mode = modes.pop();
|
||||
modes.unshift(mode!);
|
||||
return { stage, mode };
|
||||
});
|
||||
}
|
||||
|
||||
export default matchesHandler;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Box, Flex, HStack } from "@chakra-ui/react";
|
||||
import { t } from "@lingui/macro";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import Breadcrumbs from "components/common/Breadcrumbs";
|
||||
import MyContainer from "components/common/MyContainer";
|
||||
import SubText from "components/common/SubText";
|
||||
|
|
@ -7,77 +7,214 @@ import TwitterAvatar from "components/common/TwitterAvatar";
|
|||
import UserAvatar from "components/common/UserAvatar";
|
||||
import RegisterHeader from "components/play/RegisterHeader";
|
||||
import { useLadderTeams } from "hooks/play";
|
||||
import { getLadderRounds } from "lib/playFunctions";
|
||||
import { shuffleArray } from "lib/shuffleArray";
|
||||
import { useMyTheme } from "lib/useMyTheme";
|
||||
import { GetStaticProps } from "next";
|
||||
import prisma from "prisma/client";
|
||||
import { getAllLadderRegisteredTeamsForMatches } from "prisma/queries/getAllLadderRegisteredTeamsForMatches";
|
||||
import { getLadderDay, GetLadderDayData } from "prisma/queries/getLadderDay";
|
||||
|
||||
const PlayPage = () => {
|
||||
interface Props {
|
||||
ladderDay: GetLadderDayData;
|
||||
}
|
||||
|
||||
const PlayPage: React.FC<Props> = ({ ladderDay }) => {
|
||||
const { gray } = useMyTheme();
|
||||
const { data } = useLadderTeams();
|
||||
const { data } = useLadderTeams(!ladderDay);
|
||||
|
||||
console.log({ ladderDay });
|
||||
|
||||
return (
|
||||
<MyContainer>
|
||||
<Breadcrumbs pages={[{ name: t`Play` }]} />
|
||||
<Box fontSize="lg" fontWeight="bold">
|
||||
Next event: testing
|
||||
{ladderDay ? (
|
||||
<>Next event: {new Date(ladderDay.date).toLocaleString()}</>
|
||||
) : (
|
||||
<>
|
||||
<Trans>
|
||||
Next ladder date is not confirmed. Follow this page for updates!
|
||||
</Trans>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<RegisterHeader />
|
||||
<Box mt={4}>
|
||||
{data
|
||||
?.sort((a, b) => b.roster.length - a.roster.length)
|
||||
.map((team) => {
|
||||
const teamTuple = team.roster
|
||||
.filter((member) => member.team)
|
||||
.map((member) => member.team)
|
||||
.reduce(
|
||||
(
|
||||
acc: [
|
||||
{ name: string; twitterName: string; nameForUrl: string },
|
||||
number
|
||||
][],
|
||||
cur
|
||||
) => {
|
||||
const tuple = acc.find(([{ name }]) => name === cur!.name);
|
||||
if (tuple) tuple[1]++;
|
||||
{ladderDay && ladderDay.matches.length === 0 && (
|
||||
<>
|
||||
<RegisterHeader />
|
||||
<Box mt={4}>
|
||||
{data
|
||||
?.sort((a, b) => b.roster.length - a.roster.length)
|
||||
.map((team) => {
|
||||
const teamTuple = team.roster
|
||||
.filter((member) => member.team)
|
||||
.map((member) => member.team)
|
||||
.reduce(
|
||||
(
|
||||
acc: [
|
||||
{
|
||||
name: string;
|
||||
twitterName: string;
|
||||
nameForUrl: string;
|
||||
},
|
||||
number
|
||||
][],
|
||||
cur
|
||||
) => {
|
||||
const tuple = acc.find(
|
||||
([{ name }]) => name === cur!.name
|
||||
);
|
||||
if (tuple) tuple[1]++;
|
||||
|
||||
acc.push([{ ...(cur as any) }, 1]);
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
)
|
||||
.find((tuple) => tuple[1] >= 3);
|
||||
return (
|
||||
<Box key={team.id} my={4}>
|
||||
{teamTuple && team.roster.length === 4 ? (
|
||||
<Flex fontWeight="bold" align="center">
|
||||
{teamTuple[0].twitterName && (
|
||||
<TwitterAvatar
|
||||
twitterName={teamTuple[0].twitterName}
|
||||
size="sm"
|
||||
mr={1}
|
||||
/>
|
||||
acc.push([{ ...(cur as any) }, 1]);
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
)
|
||||
.find((tuple) => tuple[1] >= 3);
|
||||
return (
|
||||
<Box key={team.id} my={4}>
|
||||
{teamTuple && team.roster.length === 4 ? (
|
||||
<Flex fontWeight="bold" align="center">
|
||||
{teamTuple[0].twitterName && (
|
||||
<TwitterAvatar
|
||||
twitterName={teamTuple[0].twitterName}
|
||||
size="sm"
|
||||
mr={1}
|
||||
/>
|
||||
)}
|
||||
{teamTuple[0].name}
|
||||
{teamTuple[1] === 3 && team.roster.length >= 4 && (
|
||||
<SubText ml={1}>+1</SubText>
|
||||
)}
|
||||
</Flex>
|
||||
) : (
|
||||
<HStack>
|
||||
{team.roster.map((member) => (
|
||||
<UserAvatar key={member.id} user={member} size="sm" />
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
{teamTuple[0].name}
|
||||
{teamTuple[1] === 3 && team.roster.length >= 4 && (
|
||||
<SubText ml={1}>+1</SubText>
|
||||
)}
|
||||
</Flex>
|
||||
) : (
|
||||
<HStack>
|
||||
{team.roster.map((member) => (
|
||||
<UserAvatar key={member.id} user={member} size="sm" />
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
<Box color={gray} fontSize="sm" mt={2}>
|
||||
{team.roster
|
||||
.map((user) => `${user.username}#${user.discriminator}`)
|
||||
.join(", ")}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
<Box color={gray} fontSize="sm" mt={2}>
|
||||
{team.roster
|
||||
.map((user) => `${user.username}#${user.discriminator}`)
|
||||
.join(", ")}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</MyContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const getStaticProps: GetStaticProps<Props> = async () => {
|
||||
const ladderDay = await getLadderDay();
|
||||
|
||||
let ladderDayAfterGeneration: GetLadderDayData | undefined;
|
||||
if (
|
||||
ladderDay &&
|
||||
!ladderDay.matches.length &&
|
||||
ladderDay.date.getTime() < new Date().getTime()
|
||||
) {
|
||||
const teams = (await getAllLadderRegisteredTeamsForMatches()).filter(
|
||||
(team) => team.roster.length === 4
|
||||
);
|
||||
|
||||
if (teams.length < 4) {
|
||||
return {
|
||||
props: { ladderDay: JSON.parse(JSON.stringify(ladderDay)) },
|
||||
revalidate: 30,
|
||||
}; // FIX
|
||||
}
|
||||
|
||||
const matches = getLadderRounds(teams);
|
||||
|
||||
const eighteenMaps = getMaplist();
|
||||
|
||||
const dateWeekFromNow = new Date(ladderDay.date);
|
||||
dateWeekFromNow.setHours(168);
|
||||
|
||||
const createPosts = matches.flatMap((round, i) =>
|
||||
round.map((match) =>
|
||||
prisma.ladderMatch.create({
|
||||
data: {
|
||||
dayId: ladderDay.id,
|
||||
maplist:
|
||||
i === 0 ? eighteenMaps.slice(0, 9) : eighteenMaps.slice(9, 18),
|
||||
order: i + 1,
|
||||
players: {
|
||||
create: match.flatMap((team, teamI) =>
|
||||
team.roster.map((user) => ({
|
||||
userId: user.id,
|
||||
team: teamI === 0 ? "ALPHA" : "BRAVO",
|
||||
}))
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
const createLadderDay = prisma.ladderDay.create({
|
||||
data: { date: dateWeekFromNow },
|
||||
});
|
||||
const deleteLadderRegisteredTeams = prisma.ladderRegisteredTeam.deleteMany();
|
||||
|
||||
// TODO: is this ok?
|
||||
await prisma.$transaction([
|
||||
...createPosts,
|
||||
createLadderDay,
|
||||
deleteLadderRegisteredTeams,
|
||||
] as any);
|
||||
|
||||
ladderDayAfterGeneration = await getLadderDay();
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
ladderDay: JSON.parse(
|
||||
JSON.stringify(ladderDayAfterGeneration ?? ladderDay)
|
||||
),
|
||||
},
|
||||
revalidate: 30,
|
||||
};
|
||||
};
|
||||
|
||||
function getMaplist() {
|
||||
const modes = shuffleArray(["SZ", "TC", "RM", "CB"]);
|
||||
const stages = shuffleArray([
|
||||
"The Reef",
|
||||
"Musselforge Fitness",
|
||||
"Starfish Mainstage",
|
||||
"Humpback Pump Track",
|
||||
"Inkblot Art Academy",
|
||||
"Sturgeon Shipyard",
|
||||
"Manta Maria",
|
||||
"Snapper Canal",
|
||||
"Blackbelly Skatepark",
|
||||
"MakoMart",
|
||||
"Shellendorf Institute",
|
||||
"Goby Arena",
|
||||
"Piranha Pit",
|
||||
"Camp Triggerfish",
|
||||
"Wahoo World",
|
||||
"New Albacore Hotel",
|
||||
"Ancho-V Games",
|
||||
"Skipper Pavilion",
|
||||
//"Moray Towers",
|
||||
//"Port Mackerel",
|
||||
//"Walleye Warehouse",
|
||||
//"Arowana Mall",
|
||||
//"Kelp Dome"
|
||||
]);
|
||||
|
||||
return stages.map((stage) => {
|
||||
const mode = modes.pop();
|
||||
modes.unshift(mode!);
|
||||
return { stage, mode };
|
||||
});
|
||||
}
|
||||
|
||||
export default PlayPage;
|
||||
|
|
|
|||
35
prisma/queries/getLadderDay.ts
Normal file
35
prisma/queries/getLadderDay.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
import prisma from "prisma/client";
|
||||
|
||||
export type GetLadderDayData = Prisma.PromiseReturnType<typeof getLadderDay>;
|
||||
|
||||
export const getLadderDay = async () => {
|
||||
const d = new Date();
|
||||
d.setHours(d.getHours() - 6);
|
||||
|
||||
return prisma.ladderDay.findFirst({
|
||||
where: { date: { gte: d } },
|
||||
include: {
|
||||
matches: {
|
||||
select: {
|
||||
order: true,
|
||||
maplist: true,
|
||||
teamAScore: true,
|
||||
teamBScore: true,
|
||||
players: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
username: true,
|
||||
discordAvatar: true,
|
||||
discriminator: true,
|
||||
discordId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user