mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-25 20:50:14 -05:00
Show groups closer to own skill tier first
This commit is contained in:
@@ -33,7 +33,7 @@ export function GroupCard({
|
||||
hideWeapons = false,
|
||||
hideNote: _hidenote = false,
|
||||
}: {
|
||||
group: LookingGroup;
|
||||
group: Omit<LookingGroup, "createdAt">;
|
||||
action?: "LIKE" | "UNLIKE" | "GROUP_UP" | "MATCH_UP";
|
||||
ownRole?: GroupMemberType["role"];
|
||||
ownGroup?: boolean;
|
||||
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
TieredSkill,
|
||||
} from "~/features/mmr/tiered.server";
|
||||
import type { RecentMatchPlayer } from "../queries/findRecentMatchPlayersByUserId.server";
|
||||
import { TIERS } from "~/features/mmr/mmr-constants";
|
||||
|
||||
export function divideGroups({
|
||||
groups,
|
||||
@@ -165,6 +166,66 @@ export function censorGroups({
|
||||
};
|
||||
}
|
||||
|
||||
export function sortGroupsBySkill({
|
||||
groups,
|
||||
userSkills,
|
||||
intervals,
|
||||
}: {
|
||||
groups: DividedGroups;
|
||||
userSkills: Record<string, TieredSkill>;
|
||||
intervals: SkillTierInterval[];
|
||||
}): DividedGroups {
|
||||
const ownGroupTier =
|
||||
groups.own.tier?.name ??
|
||||
resolveGroupSkill({
|
||||
group: groups.own as LookingGroupWithInviteCode,
|
||||
userSkills,
|
||||
intervals,
|
||||
})?.name;
|
||||
const ownGroupTierIndex = TIERS.findIndex((t) => t.name === ownGroupTier);
|
||||
|
||||
const tierDiff = (otherGroupTierName?: string) => {
|
||||
if (!otherGroupTierName) return 10;
|
||||
|
||||
const otherGroupTierIndex = TIERS.findIndex(
|
||||
(t) => t.name === otherGroupTierName,
|
||||
);
|
||||
|
||||
return Math.abs(ownGroupTierIndex - otherGroupTierIndex);
|
||||
};
|
||||
|
||||
return {
|
||||
...groups,
|
||||
neutral: groups.neutral.sort((a, b) => {
|
||||
const aTier =
|
||||
a.tier?.name ??
|
||||
resolveGroupSkill({
|
||||
group: a as LookingGroupWithInviteCode,
|
||||
userSkills,
|
||||
intervals,
|
||||
})?.name;
|
||||
const bTier =
|
||||
b.tier?.name ??
|
||||
resolveGroupSkill({
|
||||
group: b as LookingGroupWithInviteCode,
|
||||
userSkills,
|
||||
intervals,
|
||||
})?.name;
|
||||
|
||||
const aTierDiff = tierDiff(aTier);
|
||||
const bTierDiff = tierDiff(bTier);
|
||||
|
||||
// if same tier difference, show newer groups first
|
||||
if (aTierDiff === bTierDiff) {
|
||||
return b.createdAt - a.createdAt;
|
||||
}
|
||||
|
||||
// show groups with smaller tier difference first
|
||||
return aTierDiff - bTierDiff;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function addSkillsToGroups({
|
||||
groups,
|
||||
userSkills,
|
||||
@@ -174,33 +235,16 @@ export function addSkillsToGroups({
|
||||
userSkills: Record<string, TieredSkill>;
|
||||
intervals: SkillTierInterval[];
|
||||
}): DividedGroupsUncensored {
|
||||
const resolveGroupSkill = (
|
||||
group: LookingGroupWithInviteCode,
|
||||
): TieredSkill["tier"] | undefined => {
|
||||
if (group.members.length < FULL_GROUP_SIZE) return;
|
||||
|
||||
const skills = group.members
|
||||
.map((m) => userSkills[String(m.id)])
|
||||
.filter(Boolean);
|
||||
const averageOrdinal =
|
||||
skills.reduce((acc, s) => acc + s.ordinal, 0) / skills.length;
|
||||
|
||||
const tier = intervals.find(
|
||||
(i) => i.neededOrdinal && averageOrdinal > i.neededOrdinal,
|
||||
) ?? { isPlus: false, name: "IRON" };
|
||||
|
||||
// For Leviathan we don't specify if it's plus or not
|
||||
return tier.name === "LEVIATHAN"
|
||||
? { name: "LEVIATHAN", isPlus: false }
|
||||
: { name: tier.name, isPlus: tier.isPlus };
|
||||
};
|
||||
const addSkill = (group: LookingGroupWithInviteCode) => ({
|
||||
...group,
|
||||
members: group.members?.map((m) => ({
|
||||
...m,
|
||||
skill: userSkills[String(m.id)],
|
||||
})),
|
||||
tier: resolveGroupSkill(group),
|
||||
tier:
|
||||
group.members.length === FULL_GROUP_SIZE
|
||||
? resolveGroupSkill({ group, userSkills, intervals })
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -214,6 +258,31 @@ export function membersNeededForFull(currentSize: number) {
|
||||
return FULL_GROUP_SIZE - currentSize;
|
||||
}
|
||||
|
||||
function resolveGroupSkill({
|
||||
group,
|
||||
userSkills,
|
||||
intervals,
|
||||
}: {
|
||||
group: LookingGroupWithInviteCode;
|
||||
userSkills: Record<string, TieredSkill>;
|
||||
intervals: SkillTierInterval[];
|
||||
}): TieredSkill["tier"] | undefined {
|
||||
const skills = group.members
|
||||
.map((m) => userSkills[String(m.id)])
|
||||
.filter(Boolean);
|
||||
const averageOrdinal =
|
||||
skills.reduce((acc, s) => acc + s.ordinal, 0) / skills.length;
|
||||
|
||||
const tier = intervals.find(
|
||||
(i) => i.neededOrdinal && averageOrdinal > i.neededOrdinal,
|
||||
) ?? { isPlus: false, name: "IRON" };
|
||||
|
||||
// For Leviathan we don't specify if it's plus or not
|
||||
return tier.name === "LEVIATHAN"
|
||||
? { name: "LEVIATHAN", isPlus: false }
|
||||
: { name: tier.name, isPlus: tier.isPlus };
|
||||
}
|
||||
|
||||
export function groupExpiryStatus(
|
||||
group: Pick<Group, "latestActionAt">,
|
||||
): null | "EXPIRING_SOON" | "EXPIRED" {
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { GroupForMatch } from "./queries/groupForMatch.server";
|
||||
export type LookingGroup = {
|
||||
id: number;
|
||||
mapListPreference?: Group["mapListPreference"];
|
||||
createdAt: Group["createdAt"];
|
||||
tier?: TieredSkill["tier"];
|
||||
isReplay?: boolean;
|
||||
isLiked?: boolean;
|
||||
|
||||
@@ -34,6 +34,7 @@ const stm = sql.prepare(/* sql */ `
|
||||
"q1"."id",
|
||||
"q1"."mapListPreference",
|
||||
"q1"."inviteCode",
|
||||
"q1"."createdAt",
|
||||
json_group_array(
|
||||
json_object(
|
||||
'id', "q1"."userId",
|
||||
@@ -57,6 +58,7 @@ export function findPreparingGroup(
|
||||
|
||||
return {
|
||||
id: row.id,
|
||||
createdAt: row.createdAt,
|
||||
mapListPreference: row.mapListPreference,
|
||||
inviteCode: row.inviteCode,
|
||||
members: parseDBJsonArray(row.members).map((member: any) => {
|
||||
|
||||
@@ -46,6 +46,7 @@ const stm = sql.prepare(/* sql */ `
|
||||
"q1"."id",
|
||||
"q1"."mapListPreference",
|
||||
"q1"."inviteCode",
|
||||
"q1"."createdAt",
|
||||
json_group_array(
|
||||
json_object(
|
||||
'id', "q1"."userId",
|
||||
@@ -64,7 +65,6 @@ const stm = sql.prepare(/* sql */ `
|
||||
) as "members"
|
||||
from "q1"
|
||||
group by "q1"."id"
|
||||
order by "q1"."createdAt" desc
|
||||
`);
|
||||
|
||||
export function findLookingGroups({
|
||||
@@ -83,6 +83,7 @@ export function findLookingGroups({
|
||||
id: row.id,
|
||||
mapListPreference: row.mapListPreference,
|
||||
inviteCode: row.inviteCode,
|
||||
createdAt: row.createdAt,
|
||||
members: parseDBJsonArray(row.members).map((member: any) => {
|
||||
const weapons = parseDBArray(member.weapons);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
filterOutGroupsWithIncompatibleMapListPreference,
|
||||
groupExpiryStatus,
|
||||
membersNeededForFull,
|
||||
sortGroupsBySkill,
|
||||
} from "../core/groups.server";
|
||||
import { createMatchMemento, matchMapList } from "../core/match.server";
|
||||
import { FULL_GROUP_SIZE } from "../q-constants";
|
||||
@@ -324,9 +325,13 @@ export const loader = async ({ request }: LoaderArgs) => {
|
||||
|
||||
const season = currentOrPreviousSeason(new Date());
|
||||
|
||||
const { intervals, userSkills: calculatedUserSkills } = await userSkills(
|
||||
season!.nth,
|
||||
);
|
||||
const groupsWithSkills = addSkillsToGroups({
|
||||
groups: dividedGroups,
|
||||
...(await userSkills(season!.nth)),
|
||||
intervals,
|
||||
userSkills: calculatedUserSkills,
|
||||
});
|
||||
|
||||
const compatibleGroups = groupIsFull
|
||||
@@ -347,12 +352,18 @@ export const loader = async ({ request }: LoaderArgs) => {
|
||||
showInviteCode: hasGroupManagerPerms(currentGroup.role) && !groupIsFull,
|
||||
});
|
||||
|
||||
return {
|
||||
const sortedGroups = sortGroupsBySkill({
|
||||
groups: censoredGroups,
|
||||
intervals,
|
||||
userSkills: calculatedUserSkills,
|
||||
});
|
||||
|
||||
return {
|
||||
groups: sortedGroups,
|
||||
role: currentGroup.role,
|
||||
chatCode:
|
||||
// don't chat with yourself...
|
||||
censoredGroups.own.members!.length > 1 ? currentGroup.chatCode : null,
|
||||
sortedGroups.own.members!.length > 1 ? currentGroup.chatCode : null,
|
||||
lastUpdated: new Date().getTime(),
|
||||
expiryStatus: groupExpiryStatus(currentGroup),
|
||||
trustedPlayers: hasGroupManagerPerms(currentGroup.role)
|
||||
|
||||
Reference in New Issue
Block a user