Архітэктура шматкарыстальніцкай гульні
Шматкарыстальніцкі рэжым En Parlant~ выкарыстоўвае WebSocket-рэле-сервер для злучэння двух гульцоў у рэальным часе. Ніякага peer-to-peer — уся камунікацыя ідзе праз рэле. Гэта спрашчае сеткавую архітэктуру і надзейна працуе праз файрволы і NAT.
Агляд архітэктуры
Section titled “Агляд архітэктуры”Player A (host) Relay Server Player B (joiner) | | | |--- create_game(name) ----------->| | |<-- game_created(code) -----------| | | |<--- join_game(code, name) -----| |<-- game_joined(name) ------------|--- game_joined(name) -------->| | | | |--- game_move(uci, times) ------->|--- game_move(uci, times) --->| |<-- game_move(uci, times) --------|<-- game_move(uci, times) ----| | | | |--- heartbeat ------------------>|--- peer_heartbeat ----------->|Рэле — гэта тонкі пераадрасавальны ўзровень. Яно захоўвае пакоі ў памяці, маршрутызуе падзеі паміж двума гульцамі ў кожным пакоі і апрацоўвае ачыстку. На серверы няма гульнявой логікі ці валідацыі хадоў — аўтарытэтнымі з’яўляюцца кліенты.
Тэхналагічны стэк
Section titled “Тэхналагічны стэк”- Франтэнд (кліент): socket.io-client — стандартны JavaScript-кліент Socket.IO
- Бэкенд (рэле): socketioxide — Socket.IO-сервер на Rust, пабудаваны на Axum
- Пратакол: Socket.IO праз WebSocket (з аўтаматычным пераключэннем на HTTP long-polling пры неабходнасці)
Socket.IO быў абраны замест звычайнага WebSocket, бо ён забяспечвае аўтаматычнае пераадключэнне, кіраванне пакоямі/прасторамі імёнаў і структураваную апрацоўку падзей з каробкі.
Працэс гульні
Section titled “Працэс гульні”1. Стварэнне гульні
Section titled “1. Стварэнне гульні”Гаспадар націскае Multiplayer і ўводзіць сваё імя для адлюстравання. Кліент адпраўляе падзею create_game з імем. Сервер:
- Генеруе ўнікальны 6-сімвальны код пакоя
- Стварае пакой і дадае гаспадара як першага гульца
- Адказвае
game_created(code), каб гаспадар мог падзяліцца кодам
2. Далучэнне да гульні
Section titled “2. Далучэнне да гульні”Удзельнік уводзіць код пакоя і сваё імя для адлюстравання. Кліент адпраўляе join_game(code, name). Сервер:
- Знаходзіць пакой па кодзе
- Дадае ўдзельніка як другога гульца
- Адпраўляе
game_joined(name)абодвум гульцам — кожны атрымлівае імя суперніка
3. Гульня
Section titled “3. Гульня”Калі абодва гульцы ў пакоі:
- Гаспадар заўсёды гуляе белымі, удзельнік — заўсёды чорнымі. Гэта вызначаецца парадкам далучэння, а не дамоўленасцю.
- Хады адпраўляюцца ў фармаце UCI (напрыклад,
e2e4) разам з часам на гадзінніках абодвух гульцоў. - Рэле пераадрасоўвае кожную падзею
game_moveсуперніку. Абодва гульцы таксама атрымліваюць свае ўласныя хады назад як пацвярджэнне.
4. Падзеі заканчэння гульні
Section titled “4. Падзеі заканчэння гульні”Некалькі падзей апрацоўваюць сцэнарыі заканчэння гульні:
- Здача — пераадрасоўваецца суперніку для выкліку дыялогу здачы
- Прапанова нічыі — пераадрасоўваецца суперніку, які можа прыняць ці праігнараваць
- Прыняцце нічыі — пераадрасоўваецца абодвум гульцам для завяршэння гульні нічыёй
5. Рэванш
Section titled “5. Рэванш”Пасля заканчэння гульні любы гулец можа адправіць падзею ready, каб паказаць гатоўнасць да рэваншу. Калі абодва гульцы адправілі ready, кліенты скідваюць дошку і мяняюць колеры (або пакідаюць іх — вызначаецца на баку кліента).
Коды пакояў
Section titled “Коды пакояў”Коды пакояў складаюцца з 6 сімвалаў і фарматуюцца як XX-XX-XX для зручнасці ўспрымання пры вусным абмене. Набор сімвалаў выключае візуальна неадназначныя літары:
- Няма
0ціO(нуль і літара O) - Няма
1,IціL(адзінка, вялікая I і вялікая L)
Гэта дазваляе пазбегнуць праблемы «гэта нуль ці O?», калі хтосьці дыктуе код у галасавым чаце ці набірае яго з паведамлення сябра.
Сістэма серцабіцця
Section titled “Сістэма серцабіцця”Шматкарыстальніцкія злучэнні патрабуюць выяўлення моманту адключэння гульца — ці то з-за абрыву сеткі, ці то з-за закрыцця праграмы, ці то з-за пераходу наўтбука ў рэжым сну. En Parlant~ выкарыстоўвае для гэтага сістэму серцабіцця:
- Кожны кліент адпраўляе падзею
heartbeatна сервер кожныя 5 секунд - Сервер пацвярджае серцабіццё і пераадрасоўвае яго суперніку як
peer_heartbeat - Кліент адсочвае, калі апошні раз атрымліваў
peer_heartbeatад суперніка - Функцыя
isPeerAlive(timeoutMs)правярае, ці знаходзіцца апошняе серцабіццё суперніка ў дапушчальным парозе
Гэта кіруе індыкатарам стану злучэння ў інтэрфейсе. Калі серцабіцці перастаюць паступаць, гулец бачыць, што суперніка, магчыма, адключана, і можа вырашыць чакаць або пакінуць гульню.
Ачыстка пакояў
Section titled “Ачыстка пакояў”Рэле-сервер аўтаматычна выдаляе неактыўныя пакоі для прадухілення ўцечак памяці:
- Пакой лічыцца неактыўным пасля 30 хвілін без актыўнасці
- Задача ачысткі запускаецца кожныя 60 секунд, выдаляючы пакоі, якія перавысілі парог неактыўнасці
- Пры ачыстцы пакоя ўсе злучэнні, што засталіся, разрываюцца
Пастаяннага сховішча няма. Калі сервер перазапускаецца, усе пакоі знікаюць. Гэта зроблена наўмысна — рэле з’яўляецца бяздзейным і эфемерным. Гульні, якія былі ў працэсе, прыйдзецца пачынаць нанова, але на практыцы гэта здараецца рэдка.
Разгортванне
Section titled “Разгортванне”Стандартнае рэле працуе на Fly.io, забяспечваючы нізкалатэнтныя WebSocket-злучэнні з аўтаматычным TLS. Глядзіце кіраўніцтва па наладцы шматкарыстальніцкага сервера для інструкцый па запуску ўласнага рэле.
Лакальнае тэсціраванне
Section titled “Лакальнае тэсціраванне”Каб пратэсціраваць шматкарыстальніцкі рэжым падчас распрацоўкі:
-
Кланіруйце і запусціце рэле:
Terminal window git clone https://github.com/DarrellThomas/en-parlant-relay.gitcd en-parlant-relaycargo runСервер запускаецца на порце 3210.
-
У En Parlant~ змяніце URL рэле-сервера на
ws://localhost:3210. -
Адкрыйце дзве асобнікі праграмы (або адну праграму і адну ў рэжыме распрацоўкі) для імітацыі абодвух гульцоў.
Хады, серцабіцці і ўсе падзеі працуюць ідэнтычна прадакшн-рэле — адзіная розніца ў URL злучэння.