6.9 KiB
Prompt for Unity Cursor — hidden MMR winner report
Copy everything below the line into Unity Cursor. Do not change join/collect, rematch, or client UI.
You are working in the Kick Kings dedicated server Unity project.
The matchmaker API now computes hidden MMR on settle. Players must never see MMR. Do not add MMR to HUD, post-match screens, profile, or any client-bound packet.
Your only job: extend the existing PATCH /internal/match/{matchId}/winner JSON body so every settle includes scores and a forfeit flag. Keep the existing header X-Dedicated-Server-Secret. Call winner exactly once when the outcome is known (retries with the same winner are safe).
Endpoint (unchanged URL)
PATCH /internal/match/{matchId}/winner
New required JSON body
Always send all six fields. winner, red_connected, and blue_connected already exist — do not remove them.
{
"winner": "red",
"red_connected": true,
"blue_connected": true,
"red_score": 3,
"blue_score": 1,
"forfeit": false
}
| Field | Type | Rules |
|---|---|---|
winner |
"red" or "blue" |
Winning side. Unchanged. |
red_connected |
bool | Red still had a live connection at settle. Do not infer from winner. |
blue_connected |
bool | Blue still had a live connection at settle. |
red_score |
int | Rounds/sets red has won (first-to-3). Send on every settle, including forfeits. Use the score at the moment the match ended (0–3 typical). |
blue_score |
int | Same for blue. |
forfeit |
bool | true for leave, disconnect, last-disconnect-wins, and skip/auto-forfeit (two skipped turns). false only for a normal score win. |
JSON types must be real booleans and integers, not strings (true not "true", 3 not "3").
How the API uses this (do not reimplement)
The API applies hidden MMR. You only report facts.
| What you send | MMR % the API uses |
|---|---|
forfeit: true and loser *_connected: false, or both disconnected |
20% |
forfeit: true and both still connected (skip/auto-forfeit) |
score table (100% / 90% / 75%) |
| Normal finish, loser score 0 (3–0) | 100% |
| Normal finish, loser score 1 (3–1) | 90% |
| Normal finish, loser score 2+ (3–2) | 75% |
Skip-forfeit: both still connected → forfeit: true and send the actual score. API uses the score table, not 20%. The skipper (loser) does not get CC.
If you omit scores, the API treats the match as 3–0 (100%). That is wrong for 3–1 and 3–2. Always send scores.
Connected flags (unchanged meaning)
Set a side to false when:
- Mirror reports disconnect and reconnect grace expired
- That player pressed Leave (even if TCP is still up for a moment)
true = still in the match when you report the outcome (score win, opponent forfeit, or skip-forfeit while they stayed).
CC (100) is awarded only to connected finishers who did not forfeit. Last-disconnect winner can be disconnected: they get RC, not CC. Skip/auto-forfeit: skipper gets no CC even if still connected. Do not infer *_connected from winner.
What to send in each end condition
1. Normal score win (first to 3)
Both still in the match.
{ "winner": "red", "red_connected": true, "blue_connected": true, "red_score": 3, "blue_score": 1, "forfeit": false }
Use the real score: 3–0, 3–1, or 3–2. forfeit is false.
2. One player leaves or disconnects
Remaining player wins. Disconnected side false. forfeit: true. Scores = rounds already won when they left.
{ "winner": "red", "red_connected": true, "blue_connected": false, "red_score": 1, "blue_score": 0, "forfeit": true }
3. Both disconnect (last-disconnect-wins)
Last player who disconnected is winner. Both *_connected: false. forfeit: true. Keep disconnect-order tracking until the winner call is acknowledged.
{ "winner": "blue", "red_connected": false, "blue_connected": false, "red_score": 0, "blue_score": 2, "forfeit": true }
4. Skip-forfeit (two skipped turns)
Not a disconnect. If that player is still connected, keep *_connected: true. Send forfeit: true. They do not get CC. Send the actual score. Winner is whoever the game rules already pick. Hidden MMR uses the score table.
5. Process crash / forced shutdown after fees were collected
Same as remaining-player or last-disconnect. Send accurate *_connected, scores, forfeit: true if it was a disconnect path, and call winner before exit whenever possible.
Never skip the winner call after collect. Never invent a draw.
Success response (ignore MMR on clients)
{
"ok": true,
"id": 123,
"winner": "red",
"winner_id": 456,
"already_settled": false,
"economy": { "entry_fee_rc": 21, "rc_prize": 34, "participant_cc": 100, "cc_awarded_red": true, "cc_awarded_blue": false },
"mmr_delta": 27,
"forfeit": false
}
- Keep using
economy/cc_awarded_*as today. mmr_deltaandforfeitare for server logs only. Do not forward them to player clients. Do not show them in UI.- Honor response
winner/winner_id. Simultaneous Leave/skip: the secondforfeit: truePATCH is 200already_settledwith the first settle’s winner, not 409.
HTTP: 200 = settled, already settled same winner, or a second forfeit that lost the race. 409 = entries not collected, or winner already set to the other side on a non-forfeit conflict.
Suggested C# payload
Extend the existing winner DTO / anonymous object. Do not stringify bools/ints.
public sealed class WinnerReportBody
{
public string winner; // "red" | "blue"
public bool red_connected;
public bool blue_connected;
public int red_score;
public int blue_score;
public bool forfeit;
}
Serialize with standard JSON (true/false, numeric scores). Field names must match exactly (snake_case as above).
Find the dedicated-server method that currently PATCHes /internal/match/{id}/winner and add red_score, blue_score, forfeit there. Pass the live round scoreboard and whether this settle is a leave, disconnect, or skip/auto-forfeit.
Do not
- Show MMR,
mmr_delta, or rating of any kind to players - Change join PATCH (
red_joined_at/blue_joined_at) or rematch - Omit scores on forfeit (still send the score at leave)
- Set
forfeit: falsefor skip-forfeit / auto-forfeit (must betrueso the skipper gets no CC) - Infer
red_connected/blue_connectedfrom who won - Leave a collected match without a winner call
Done when
- Winner PATCH body always includes
red_score,blue_score,forfeit - Score wins send
forfeit: falseand the real 3–0 / 3–1 / 3–2 - Leave / disconnect / last-disconnect send
forfeit: trueand*_connected: falseon leavers - Skip-forfeit / auto-forfeit sends
forfeit: true(skipper gets no CC even if still connected) - No client UI or gameplay packet exposes MMR
- Winner is still always called after fees were collected