feature: basic matchmaking (#2227)

## Description:

Implement a basic matchmaking modal that connects to the api service and
waits for a game id. It then waits until the game starts and connects to
it.

Workers use long polling to check in with the matchmaking server and
receive player assignments.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Evan
2025-10-21 14:08:07 -07:00
committed by GitHub
co-authored by coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
parent dddf54be0b
commit 4ada4c7375
10 changed files with 320 additions and 9 deletions
+15 -1
View File
@@ -22,6 +22,8 @@ import { JoinPrivateLobbyModal } from "./JoinPrivateLobbyModal";
import "./LangSelector";
import { LangSelector } from "./LangSelector";
import { LanguageModal } from "./LanguageModal";
import "./Matchmaking";
import { MatchmakingModal } from "./Matchmaking";
import { NewsModal } from "./NewsModal";
import "./PublicLobby";
import { PublicLobby } from "./PublicLobby";
@@ -100,6 +102,7 @@ class Client {
private userSettings: UserSettings = new UserSettings();
private patternsModal: TerritoryPatternsModal;
private tokenLoginModal: TokenLoginModal;
private matchmakingModal: MatchmakingModal;
private gutterAds: GutterAds;
@@ -256,6 +259,16 @@ class Client {
console.warn("Token login modal element not found");
}
this.matchmakingModal = document.querySelector(
"matchmaking-modal",
) as MatchmakingModal;
if (
!this.matchmakingModal ||
!(this.matchmakingModal instanceof MatchmakingModal)
) {
console.warn("Matchmaking modal element not found");
}
const onUserMe = async (userMeResponse: UserMeResponse | false) => {
document.dispatchEvent(
new CustomEvent("userMeResponse", {
@@ -598,6 +611,7 @@ class Client {
"flag-input-modal",
"account-button",
"token-login",
"matchmaking-modal",
].forEach((tag) => {
const modal = document.querySelector(tag) as HTMLElement & {
close?: () => void;
@@ -697,7 +711,7 @@ document.addEventListener("DOMContentLoaded", () => {
});
// WARNING: DO NOT EXPOSE THIS ID
function getPlayToken(): string {
export function getPlayToken(): string {
const result = isLoggedIn();
if (result !== false) return result.token;
return getPersistentIDFromCookie();