Skip to content

Commit 05371d1

Browse files
authored
Merge pull request #59 from Balatro-Multiplayer/mmr-role-fixes
fix: fix MMR roles and leaderboard roles
2 parents 8ae172b + 9273222 commit 05371d1

File tree

3 files changed

+88
-19
lines changed

3 files changed

+88
-19
lines changed

src/utils/algorithms/calculateMMR.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import {
22
getQueueSettings,
33
getUsersNeedingRoleUpdates,
44
updatePlayerMmrAll,
5+
countPlayerGames,
6+
getLeaderboardPosition,
57
} from '../queryDB'
6-
import type { Matches, Queues, teamResults } from 'psqlDB'
8+
import type { Queues, teamResults } from 'psqlDB'
79
import { setUserQueueRole } from 'utils/queueHelpers'
810
import { clamp } from 'lodash-es'
911

@@ -130,7 +132,6 @@ export async function calculatePredictedMMR(
130132

131133
export async function calculateNewMMR(
132134
queueId: number,
133-
matchData: Matches,
134135
queueSettings: Queues,
135136
teamResults: teamResults,
136137
winningTeamId: number,
@@ -143,50 +144,68 @@ export async function calculateNewMMR(
143144
queueSettings.default_elo,
144145
)
145146

146-
const playerMMRChanges: Array<{ user_id: string; oldMMR: number; newMMR: number }> = []
147+
const playerMMRChanges: Array<{
148+
user_id: string
149+
oldMMR: number
150+
newMMR: number
151+
oldRank: number | null
152+
newRank: number | null
153+
}> = []
147154
const updatePromises: Promise<void>[] = []
155+
let roleUpdateUsers: string[] = []
148156

149157
for (const ts of teamStats) {
150158
const isWinner = ts.isWinner
151159
const mmrChange = isWinner ? ratingChange : -ratingChange / loserCount
152160

153161
for (const player of ts.team.players) {
154162
const oldMMR = player.elo ?? queueSettings.default_elo
163+
const oldRank = await getLeaderboardPosition(queueId, player.user_id)
155164
const oldVolatility = player.volatility ?? 0
156165

157166
const newMMR = parseFloat((oldMMR + mmrChange).toFixed(1))
158167
const newVolatility = Math.min(oldVolatility + 1, 10)
159168

160-
playerMMRChanges.push({
161-
user_id: player.user_id,
162-
oldMMR,
163-
newMMR,
164-
})
165-
166169
player.elo = clamp(newMMR, 0, 9999)
167170
player.elo_change = parseFloat(mmrChange.toFixed(1))
168171
player.volatility = newVolatility
169172

170173
updatePromises.push(
171174
updatePlayerMmrAll(queueId, player.user_id, newMMR, newVolatility),
172175
)
176+
177+
const newRank = await getLeaderboardPosition(queueId, player.user_id)
178+
179+
playerMMRChanges.push({
180+
user_id: player.user_id,
181+
oldMMR,
182+
newMMR,
183+
oldRank,
184+
newRank,
185+
})
186+
187+
const gamesPlayed = await countPlayerGames(queueId, player.user_id)
188+
if (gamesPlayed === 1) {
189+
roleUpdateUsers.push(player.user_id)
190+
}
173191
}
174192

175193
ts.team.score = isWinner ? 1 : 0
176194
}
177195

178196
await Promise.all(updatePromises)
179197

180-
const usersNeedingRoleUpdate = await getUsersNeedingRoleUpdates(
198+
// Get users who need role updates due to MMR threshold changes
199+
let usersNeedingRoleUpdate = await getUsersNeedingRoleUpdates(
181200
queueId,
182201
playerMMRChanges,
183202
)
184203

185-
if (usersNeedingRoleUpdate.length > 0) {
204+
roleUpdateUsers = roleUpdateUsers.concat(usersNeedingRoleUpdate).flat()
205+
206+
if (roleUpdateUsers.length > 0) {
186207
await Promise.all(
187-
usersNeedingRoleUpdate.map((userId) =>
188-
setUserQueueRole(queueId, userId),
189-
),
208+
roleUpdateUsers.map((userId) => setUserQueueRole(queueId, userId)),
190209
)
191210
}
192211

src/utils/matchHelpers.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,6 @@ export async function endMatch(
760760

761761
teamResults = await calculateNewMMR(
762762
queueId,
763-
matchData,
764763
queueSettings,
765764
teamResultsData,
766765
winningTeamId,

src/utils/queryDB.ts

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
} from 'psqlDB'
1414
import { client, getGuild } from '../client'
1515
import { QueryResult } from 'pg'
16-
import { setUserQueueRole } from './queueHelpers'
1716
import { endMatch } from './matchHelpers'
1817

1918
// Get the helper role
@@ -281,6 +280,23 @@ export async function getAllQueueRoles(
281280
return res.rows
282281
}
283282

283+
// Count completed games for a user in a queue
284+
export async function countPlayerGames(
285+
queueId: number,
286+
userId: string,
287+
): Promise<number> {
288+
const res = await pool.query(
289+
`
290+
SELECT COUNT(CASE WHEN m.winning_team IS NOT NULL THEN 1 END)::integer as games_played
291+
FROM match_users mu
292+
JOIN matches m ON m.id = mu.match_id
293+
WHERE mu.user_id = $1 AND m.queue_id = $2
294+
`,
295+
[userId, queueId],
296+
)
297+
return res.rows[0]?.games_played ?? 0
298+
}
299+
284300
// get a users highest queue role
285301
export async function getUserQueueRole(
286302
queueId: number,
@@ -306,7 +322,13 @@ export async function getUserQueueRole(
306322

307323
export async function getUsersNeedingRoleUpdates(
308324
queueId: number,
309-
players: Array<{ user_id: string; oldMMR: number; newMMR: number }>,
325+
players: Array<{
326+
user_id: string
327+
oldMMR: number
328+
newMMR: number
329+
oldRank: number | null
330+
newRank: number | null
331+
}>,
310332
): Promise<string[]> {
311333
if (players.length === 0) return []
312334

@@ -317,6 +339,13 @@ export async function getUsersNeedingRoleUpdates(
317339
[queueId],
318340
)
319341

342+
const leaderboardRoles = await pool.query(
343+
`SELECT leaderboard_min, leaderboard_max FROM queue_roles
344+
WHERE queue_id = $1 AND mmr_threshold IS NULL
345+
ORDER BY leaderboard_min DESC`,
346+
[queueId],
347+
)
348+
320349
const thresholds = roles.rows.map((r) => r.mmr_threshold)
321350
const usersToUpdate: string[] = []
322351

@@ -327,6 +356,26 @@ export async function getUsersNeedingRoleUpdates(
327356
if (oldRole !== newRole) {
328357
usersToUpdate.push(player.user_id)
329358
}
359+
360+
// Also handle leaderboard positions
361+
if (
362+
player.oldRank !== null &&
363+
player.newRank !== null &&
364+
leaderboardRoles &&
365+
leaderboardRoles.rowCount !== 0
366+
) {
367+
const oldLeaderboardRole = leaderboardRoles.rows.find(
368+
(r) => r.leaderboard_min <= player.oldRank!,
369+
)
370+
const newLeaderboardRole = leaderboardRoles.rows.find(
371+
(r) => r.leaderboard_min <= player.newRank!,
372+
)
373+
374+
// Update leaderboard role if its not the same
375+
if (oldLeaderboardRole !== newLeaderboardRole) {
376+
usersToUpdate.push(player.user_id)
377+
}
378+
}
330379
}
331380

332381
return usersToUpdate
@@ -363,13 +412,15 @@ export async function getLeaderboardQueueRole(
363412
SELECT *
364413
FROM queue_roles
365414
WHERE queue_id = $1
366-
AND leaderboard_min >= $2
367-
AND leaderboard_max <= $2
415+
AND leaderboard_min <= $2
416+
AND leaderboard_max >= $2
368417
LIMIT 1
369418
`,
370419
[queueId, rank],
371420
)
372421

422+
console.log(roleRes.rowCount)
423+
373424
if (roleRes.rowCount === 0) return null
374425
return roleRes.rows[0]
375426
}

0 commit comments

Comments
 (0)