Arată la ce se joacă cineva
Lasă-ți jocul să-i spună lui mssgs ce face un jucător. Prietenii văd „Playing” sub numele lui, deschid detaliile și apasă Join now ca să intre în același joc. Jocul tău poate verifica și dacă un jucător e în comunitatea ta.
Ce poți face
- Publică un status de jocJocul, ce face jucătorul, rolul lui și cât de plin e grupul.
- Adaugă un buton Join nowPrietenii intră în același joc, server sau lobby dintr-o singură apăsare.
- Verifică apartenențaÎntreabă dacă un jucător e în comunitatea ta și cu ce roluri.
- Desktop, browser sau telefonJocurile native folosesc puntea locală; cele din browser și de pe telefon trec prin backend-ul tău.
În aplicație
Statusul de sub nume și detaliile pe care le deschide. Jocul a publicat un singur bloc JSON; restul îl face aplicația.
Prezentare generală
Aplicația desktop mssgs rulează o mică punte HTTP locală cu care vorbește un joc de pe același computer. Jocul tău nu vorbește niciodată cu serverele noastre, nu vede niciodată parola sau tokenul unui cont și nu poate posta niciodată în numele jucătorului. Vorbește cu instanța mssgs în care jucătorul e deja conectat, iar ea decide ce răspunde.
Ce poți face cu ea:
- Să detectezi că mssgs e instalat și că e cineva conectat.
- Să afli cine e jucătorul: user_guid, username, avatar.
- Să întrebi „e jucătorul acesta în comunitatea X?” și ce rol are acolo.
- Să publici un status „Playing …” cu un buton Join now pentru ceilalți.
- Să primești datele de alăturare când cineva apasă acel buton.
Două căi de intrare
Un joc desktop nativ vorbește cu puntea locală; despre asta sunt secțiunile următoare. Un joc în browser sau pe telefon nu poate ajunge la această punte. Pentru el publică propriul tău backend, pentru jucătorii care și-au conectat contul mssgs printr-un cod QR sau un cod din opt caractere: vezi Jocuri în browser și pe telefon, cu CozyCity ca prim exemplu. Statusul de joc în sine e același bloc în ambele cazuri.
Dezvăluire minimă, implicit
Scope-urile sunt inegale intenționat. Dacă tot ce îți trebuie e „e persoana asta în comunitatea noastră”, ceri membership.query și numești tu server_guid-ul: primești da/nu plus rolurile ei acolo și nu afli nimic despre restul comunităților ei. Lista completă stă în spatele unui scope distinct, de nivel mai înalt, pe care jucătorul trebuie să-l aprobe separat.
Găsirea clientului
Puntea ascultă doar pe 127.0.0.1, pe primul port liber dintr-un interval mic. Încearcă-le pe rând până răspunde unul: 7440, 7441, 7442, 7443. Versiunile de dezvoltare ale mssgs ascultă în schimb pe 7540–7543, așa că o versiune de test nu răspunde niciodată la apelurile unui joc real.
http://127.0.0.1:7440/mssgs/v1/hello
Nu e nevoie de token, iar răspunsul nu spune nimic despre jucător, doar că mssgs e aici și dacă e cineva conectat.
{
"product": "mssgs",
"api": 1,
"client": "desktop",
"version": "14.2.20015",
"platform": "darwin",
"signed_in": true,
"scopes": ["identity", "staff", "membership.query", "servers.list", "presence.write"]
}
Verifică product === "mssgs" și api înainte să mergi mai departe. Dacă niciunul dintre cele patru porturi nu răspunde, mssgs nu rulează. Oferă pur și simplu experiența obișnuită, în loc să-l pui pe jucător să aștepte.
Scope-uri și confidențialitate
Cele cinci scope-uri dezvăluie cantități foarte diferite de date. Nu e întâmplător; pe asta se bazează tot designul. Cere cât mai puțin, pornind de sus în acest tabel.
| Scope | Ce permite | La ce renunță jucătorul |
|---|---|---|
presence.write |
Arată la ce se joacă | Nimic. Acest scope doar scrie; nu citește deloc date din cont. |
identity |
Cine e jucătorul | user_guid, username, nume afișat, URL-ul avatarului. |
staff |
Indicatori de staff / moderator | Două valori booleene, pe lângă identity. Separat, pentru că un joc care afișează un nume n-are de ce să știe că jucătorul moderează comunități. |
membership.query |
Verifică o comunitate pe care o știi deja | Pentru un server_guid pe care îl numești: da/nu, numele ei și rolurile pe care le are jucătorul acolo. Nimic despre vreo altă comunitate. |
servers.list |
Toate comunitățile din care face parte | Lista completă: guid-uri, nume, pictograme și roluri. Acesta e cel scump: cere-l doar dacă chiar ai nevoie de el. |
Majorității jocurilor le ajung două
identity și presence.write acoperă „cine ești” și „arată la ce te joci”, adică aproape orice integrare. Adaugă membership.query dacă vrei să legi o recompensă de apartenența la comunitatea ta. Aproape niciodată nu ai nevoie de servers.list, iar jucătorul îl vede evidențiat cu roșu.
Verificarea apartenenței
Aceasta e alternativa la „dă-mi toată lista”. Numești server_guid-ul propriei comunități (pe care îl știi deja) și primești un răspuns doar despre ea.
curl -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:7440/mssgs/v1/membership?server_guid=ca94ecc…f4g02"
# membru:
# {"server_guid":"ca94ecc…","member":true,"name":"Acme Fans","is_owner":false,
# "roles":[{"guid":"0aa32…","name":"Pro"}]}
# nu e membru, și nimic altceva:
# {"server_guid":"…","member":false}
Un „nu” înseamnă exact atât și nimic mai mult. Poți trimite până la 10 guid-uri per apel (repetă server_guid sau separă-le prin virgulă), iar atunci primești un array results. Grupul @everyone nu apare niciodată în roles: e valabil pentru fiecare membru, deci nu-ți spune nimic.
Publicarea unui status de joc
Un singur PUT pune rândul „Playing …” sub numele jucătorului, oriunde îl văd comunitățile lui.
{
"name": "Space Raiders",
"details": "Sector 7",
"state": "In a raid",
"role": "Gunner",
"started_at": 1755859200000,
"party": { "size": 3, "max": 4, "kind": "party" },
"join": { "secret": "raid-42" }
}
Doar name e obligatoriu. Răspunsul îți spune cât trăiește statusul și cât de des să trimiți heartbeat:
{ "ok": true, "expires_in_ms": 90000, "heartbeat_every_ms": 30000 }
Heartbeat, altfel statusul dispare
Un status fără niciun semn de viață timp de 90 de secunde e șters automat. E intenționat: dacă jocul se blochează, jucătorul nu rămâne „în joc” ore întregi. Trimite un POST /mssgs/v1/activity/heartbeat la fiecare 30 de secunde și DELETE /mssgs/v1/activity la o închidere curată.
Număr de jucători și rol
party.kind decide ce propoziție se afișează, pentru că aceleași două numere nu înseamnă același lucru. O echipă de patru nu e un server cu patru jucători.
kind |
Se afișează ca | Pentru |
|---|---|---|
party (implicit) | 3 of 4 in the party | o echipă, un clan sau un grup |
server | 4/100 players | un server de joc (FiveM, un server de comunitate) |
lobby | 4/100 players | un lobby înainte să înceapă meciul |
match | 4/100 players | un meci sau o rundă în desfășurare |
role (până la 48 de caractere) spune în ce rol joacă jucătorul: o meserie, o clasă sau un personaj. Are propriul câmp în loc de încă o propoziție în state, pentru că apare ca etichetă lângă numărul de jucători.
details și state au maximum 128 de caractere fiecare, name 64. Trecerile la rând nou și caracterele de control sunt eliminate. Un URL de pictogramă nu e acceptat, intenționat: l-ar descărca fiecare client care afișează rândul, iar asta ar transforma statusul într-un far care raportează serverului tău fiecare membru din fiecare comunitate în care e jucătorul.
Butonul Join now
Pune un bloc join în activitate, iar ceilalți membri primesc un buton Join now lângă status. Există două variante și le poți combina.
1. Un secret (pentru jocuri native)
Setează {"join":{"secret":"raid-42"}}. Când cineva apasă Join now, secretul ajunge la propria lui copie a jocului tău, pe propriul lui computer, potrivită după același game_id. Nu se deschide niciun URL și nu e apelat niciun handler de schemă. Jocul tău îl preia cu:
{
"events": [
{ "seq": 1, "type": "join", "secret": "raid-42",
"from": { "user_guid": "62e377…", "username": "mssgs-test-1" } }
],
"cursor": 1
}
Interoghează cu ?since=<cursor> ca să vezi fiecare eveniment o singură dată. Dacă jocul celui care a apăsat nu rulează, nu se livrează nimic, ceea ce e un motiv bun să oferi și un URL.
2. Un URL https (pentru jocuri web și linkuri de lobby)
Setează {"join":{"url":"https://play.example.com/s/abc"}} și butonul deschide acel link. Se acceptă doar https. O schemă personalizată (steam://, mygame://, file://) e refuzată: blocul ajunge pe ecranul fiecărui membru, iar un astfel de URL e o cale de a face computerul altcuiva să apeleze un handler local cu argumente alese de tine.
Tot ce e în join e public
Blocul join e difuzat tuturor celor care pot vedea statusul jucătorului; asta e tot rostul unui buton Join now. Așa că tratează-l ca pe un cod de lobby, nu ca pe o credențială. Nu pune niciodată în el ceva ce trebuie să rămână secret și fă-ți codurile să expire.
FiveM
FiveM nu are HTTP în runtime-ul Lua de pe partea de client, așa că o resursă vorbește cu puntea prin NUI, o vizualizare CEF care trimite un Origin. Puntea acceptă explicit aceste origini: https://cfx-nui-<resource> și mai vechiul nui://<resource>. Paginile web obișnuite rămân refuzate, iar o pagină de pe internetul deschis nu poate pretinde acest origin; îl setează browserul însuși.
-- Pagina NUI face HTTP-ul; Lua doar îi trimite datele.
CreateThread(function()
while true do
SendNUIMessage({
action = 'mssgs:publish',
players = GetActivePlayers and #GetActivePlayers() or 0,
maxPlayers = GetConvarInt('sv_maxclients', 100),
job = exports['qb-core'] and 'Police' or nil
})
Wait(30000) -- heartbeat: statusul expiră după 90 s
end
end)
const BASE = 'http://127.0.0.1:7440/mssgs/v1'; // încearcă 7440-7443
let token = null;
async function authorize () {
const res = await fetch(`${BASE}/authorize`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
game_id: 'fivem.lossantos.rp',
name: 'Los Santos Roleplay',
scopes: ['presence.write'] // aici nu e nevoie de nimic altceva
})
});
const started = await res.json();
if (started.status === 'approved') { return started.token; }
// Jucătorul vede acum dialogul de permisiune în mssgs.
for (let i = 0; i < 180; i += 1) {
await new Promise((r) => { setTimeout(r, 1000); });
const poll = await (await fetch(`${BASE}/authorize/${started.request_id}`)).json();
if (poll.status === 'approved') { return poll.token; }
if (poll.status !== 'pending') { return null; }
}
return null;
}
window.addEventListener('message', async (event) => {
if (event.data.action !== 'mssgs:publish') { return; }
if (!token) { token = await authorize(); }
if (!token) { return; }
await fetch(`${BASE}/activity`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({
name: 'FiveM',
details: 'Los Santos Roleplay',
role: event.data.job, // "Police"
party: { size: event.data.players, max: event.data.maxPlayers, kind: 'server' },
join: { url: 'https://cfx.re/join/abc123' } // linkul tău cfx.re
})
});
});
Rezultatul: Playing FiveM · Los Santos Roleplay · 4/100 players · Police, cu un buton Join now care deschide linkul tău cfx.re.
Cere doar presence.write
Un status de joc nu are nevoie de nimic altceva: acest scope nu citește absolut nimic. Dacă vrei să legi o recompensă din joc de apartenența la comunitatea ta mssgs, adaugă membership.query și numește propriul server_guid; tot nu afli nimic despre celelalte comunități ale jucătorului.
Un server pe care joci nu e automat de încredere
Orice server FiveM poate rula resurse pe client, deci orice server pe care intră cineva poate cere permisiunea. Exact de aceea stă la mijloc un dialog care numește resursa: decide jucătorul, nu serverul.
Jocuri în browser și pe telefon: conectare prin backend-ul tău
Un joc dintr-un tab de browser sau de pe telefon nu poate ajunge la puntea de mai sus. Ea rulează pe desktopul jucătorului, iar între ele stau trei ziduri: puntea refuză orice cerere care poartă un Origin de browser, Chrome afișează o cerere de permisiune înainte ca o pagină publică să acceseze 127.0.0.1, Safari refuză din start, iar un telefon nu are nicio cale către loopback-ul unui desktop.
Așa că direcția se inversează. Backend-ul tău știe deja cine joacă și îi spune lui mssgs, pentru jucătorii care și-au conectat contul mssgs la jocul tău. Conectarea se aprobă în aplicația mssgs, niciodată în jocul tău, și creează o legătură, niciodată o sesiune: nimic din ce urmează nu poate autentifica pe cineva și nici nu poate acționa în numele jucătorului. Clientul jocului tău nu vede niciodată o cheie și nu vorbește niciodată cu mss.gs. Primul joc pe această cale este CozyCity, un city builder livrat ca pagină WebGL și ca aplicație de iPhone, fără versiune desktop; exemplele de mai jos sunt chiar ale lui.
1. Înregistrează-ți jocul
Înregistrează jocul pe pagina de înregistrare Game SDK: game_id (de exemplu com.deverence.cozycity), numele și pictograma pe care jucătorul le vede în fereastra de aprobare și hostname-urile backend-ului tău. Îl verificăm acolo, iar după aprobare cheia de backend te așteaptă pe aceeași pagină, afișată o singură dată; noi păstrăm doar un hash al ei. Cheia trebuie să stea pe serverul tău și nicăieri altundeva. O poți roti acolo oricând, iar cea veche rămâne valabilă 24 de ore, ca un deploy să se poată derula treptat.
Numele și pictograma din fereastră vin întotdeauna din înregistrare, niciodată din cerere. Altfel, un link de phishing ar putea deghiza o cerere de conectare în orice joc ar vrea. Hostname-urile limitează unde poate duce un join.url, vezi mai jos.
2. Conectează un jucător
Jucătorul alege Connect mssgs în jocul tău. Jocul îți întreabă backend-ul, iar backend-ul ne întreabă pe noi:
curl -X POST https://ams1-gateway.mss.gs/game-sdk/v1/link/start \
-H "Authorization: Bearer $BACKEND_KEY" \
-H "Content-Type: application/json" \
-d '{ "player_ref": "player-8812", "player_name": "René\u2019s city" }'
# {"link_code":"K7PQ2XM4","device_code":"…","qr_url":"https://mss.gs/gl/K7PQ2XM4",
# "deep_link":"mssgs://link-game/K7PQ2XM4","expires_in":600,"interval":5}
player_ref e propriul tău id stabil pentru acel jucător (până la 128 de caractere), nu pentru o sesiune sau un meci; player_name (până la 64) e ce afișează fereastra ca „Player: …”. Dă clientului jocului doar link_code, qr_url și deep_link. device_code e handle-ul tău de interogare și rămâne pe server.
Apoi jocul afișează trei lucruri deodată, pentru că jucătorul poate fi oriunde:
- Codul QR pentru
qr_url. Un telefon cu mssgs îl deschide direct în fereastra de aprobare din aplicație. Fără aplicație, ajunge pe o pagină de pe mss.gs care arată codul și oferă descărcarea. - Un buton „Open in mssgs” cu
deep_link, pentru un browser de desktop aflat pe același computer cu aplicația desktop. E singurul URL extern pe care jocul tău trebuie să-l deschidă vreodată. - Codul în sine, în două grupe de câte patru, de tastat în Settings → Game Activity → Link a game. Alfabetul nu are 0/O sau 1/I, așa că rareori se greșește la tastare.
Ce vede jucătorul în mssgs, în fereastra pe care aplicația o construiește din înregistrare:
Connect CozyCity to your mssgs account?
CozyCity will be able to show what you are playing as your mssgs status. It will not see your messages, your friends or your servers, and it cannot post as you.
Player: René's city · Connect / Not now
Între timp, backend-ul tău interoghează la fiecare interval secunde (dacă interoghează mai des, primește 429 SLOW_DOWN) până se schimbă statusul. Un cod funcționează o singură dată și expiră după zece minute:
curl -X POST https://ams1-gateway.mss.gs/game-sdk/v1/link/poll \
-H "Authorization: Bearer $BACKEND_KEY" \
-H "Content-Type: application/json" \
-d '{ "device_code": "…" }'
# {"status":"pending"}
# {"status":"denied"} # jucătorul a ales Not now
# {"status":"expired"}
# {"status":"linked","link_guid":"…","user":{"user_guid":"62e377…"}}
Salvează link_guid la jucătorul tău; de acum înainte e adresa pentru care publici. Răspunsul conține doar user_guid; un username se adaugă doar când înregistrarea ta are scope-ul identity.link, și nimic în plus. O a doua aprobare pentru același player_ref înlocuiește legătura anterioară, deci un jucător al jocului tău înseamnă un singur cont mssgs. Același cont mssgs se poate conecta la mai multe jocuri și la mai multe player_ref ale aceluiași joc (un iPad de familie).
3. Publică statusul de joc
Același bloc ca la punte, cu aceleași reguli și aceleași limite, doar că acum per legătură și cu cheia ta de backend:
{
"activity": {
"name": "CozyCity",
"details": "Lantern Hollow",
"state": "Day 12 · 34 residents",
"started_at": 1788901000000,
"party": { "size": 6, "max": 40, "kind": "server" },
"join": { "url": "https://cozycity.net/game/?share=…" }
}
}
200 {"published":true,"changed":true} # blocul s-a schimbat și a fost difuzat
200 {"published":true,"changed":false} # identic cu ce era salvat; s-a reîmprospătat doar TTL-ul
204 # salvat, dar jucătorul nu e online în mssgs acum
410 {"error":"LINK_REVOKED"} # jucătorul s-a deconectat: renunță la legătură
Tratează 200 și 204 la fel: salvat. { "activity": null } șterge blocul; trimite-l când jucătorul pleacă. O diferență față de punte: hostul din join.url trebuie să fie unul dintre backend-urile tale înregistrate (sau un subdomeniu al unuia), altfel primești 400 INVALID_PAYLOAD. Așa, un backend nu poate pune pe statusul unui jucător un buton Join now care duce undeva unde jucătorul acela n-a jucat niciodată.
Heartbeat la fiecare 60 de secunde, TTL 120
Un status publicat trăiește 120 de secunde fără un mesaj nou și apoi dispare singur. Așa că retrimite același bloc la fiecare 60 de secunde; un bloc neschimbat nu costă nimic și doar reîmprospătează TTL-ul. Dacă heartbeat-ul se oprește, se oprește și rândul „Playing …”, exact cum trebuie.
Cu sute de jucători online, trimite heartbeat-ul într-un singur apel, până la 100 de elemente odată. Fiecare element primește propriul status, așa că un jucător care s-a deconectat din mssgs nu-i oprește niciodată pe ceilalți nouăzeci și nouă:
{ "items": [ { "link_guid": "…", "activity": { "name": "CozyCity", "details": "Lantern Hollow" } },
{ "link_guid": "…", "activity": null } ] }
// → 200 { "results": [ { "link_guid": "…", "status": 200, "changed": false },
// { "link_guid": "…", "status": 410 } ] }
Cum se afișează statusul
- Identic cu un status de pe punte: Playing CozyCity · Lantern Hollow · 6/40 players, cu Join now când există un
join.url. Serverul marchează blocul cuvia: "backend", așa că un client poate adăuga „Shared by the game's server”. - Doar cât timp jucătorul e online în mssgs. Fără un client mssgs deschis, contul e offline și rămâne offline; backend-ul tău nu poate face pe cineva să pară prezent. Asta împiedică totodată ruta aceasta să devină un far de tipul „e René la calculator?”.
- Prioritate: un joc din aplicație > un joc pe punte > backend-ul tău. Dacă jucătorul se apucă de șah în mssgs în timp ce backend-ul tău continuă să trimită heartbeat, câștigă șahul, nu cine a scris ultimul.
Deconectarea
Jucătorul vede fiecare legătură în Settings → Game Activity → Linked games, cu pictograma și numele tău, numele jucătorului din jocul tău, data conectării și a ultimei publicări, plus un buton Disconnect. După asta, următoarea ta publicare primește 410 LINK_REVOKED; așa află jocul tău. Renunță la link_guid și oferă din nou „Connect mssgs”. Din partea ta, închei o legătură cu DELETE /game-sdk/v1/links/{link_guid}.
Limite
Per legătură, o schimbare contează cel mult o dată la 2 secunde; un heartbeat neschimbat e gratuit. Per cheie sunt 600 de cereri pe minut, iar elementele dintr-un batch se numără individual: heartbeat pentru 300 de jucători la fiecare 60 de secunde consumă 5 din cele 600.
Referință endpoint-uri: puntea
URL de bază http://127.0.0.1:<port>. Toate, în afară de primele trei, necesită Authorization: Bearer <token>.
| Metodă | Cale | Scope | Ce face |
|---|---|---|---|
| GET | /mssgs/v1/hello |
niciunul | E mssgs aici, ce API vorbește și e cineva conectat. Singura rută care nu cere token, iar ea nu spune nimic despre jucător. |
| POST | /mssgs/v1/authorize |
niciunul | Cere permisiunea jucătorului. Deschide un dialog în aplicație și returnează un request_id de interogat. |
| GET | /mssgs/v1/authorize/:request_id |
niciunul | pending, approved (cu tokenul), denied sau expired. |
| GET | /mssgs/v1/me |
identity |
Jucătorul conectat. Adaugă is_staff / is_moderator doar cu scope-ul staff. |
| GET | /mssgs/v1/membership |
membership.query |
Apartenența la valorile server_guid pe care le trimiți (până la 10, repetate sau separate prin virgulă). |
| GET | /mssgs/v1/servers |
servers.list |
Toate comunitățile din care face parte jucătorul, cu rolurile lui. Mesajele directe nu sunt incluse niciodată. |
| PUT | /mssgs/v1/activity |
presence.write |
Publică blocul „Playing …”. Returnează TTL-ul și cât de des să trimiți heartbeat. |
| POST | /mssgs/v1/activity/heartbeat |
presence.write |
Menține activitatea publicată fără s-o retrimiți. |
| DELETE | /mssgs/v1/activity |
presence.write |
O șterge imediat, la o închidere curată. |
| GET | /mssgs/v1/events |
presence.write |
Datele de alăturare destinate jocului tău. Interoghează cu ?since=<cursor>. |
| GET | /mssgs/v1/session |
niciunul | Ce conține acest token: game_id, scope-urile acordate, dacă e cineva conectat. |
| DELETE | /mssgs/v1/session |
niciunul | Renunță la permisiune. Același efect ca atunci când jucătorul o revocă din Settings. |
Referință endpoint-uri: backend-uri conectate
URL de bază https://ams1-gateway.mss.gs. Fiecare rută necesită Authorization: Bearer <backend key> și scope-ul activity.write în înregistrarea ta; răspunsurile pleacă cu Cache-Control: no-store. Apelează-le de pe serverul tău, niciodată din clientul jocului.
| Metodă | Cale | Ce face |
|---|---|---|
| POST | /game-sdk/v1/link/start |
Pornește o conectare pentru unul dintre jucătorii tăi ({ player_ref, player_name? }). Returnează link_code, device_code, qr_url, deep_link, expires_in și interval. |
| POST | /game-sdk/v1/link/poll |
{ device_code } → pending, denied, expired sau linked cu link_guid și user. |
| DELETE | /game-sdk/v1/links/{link_guid} |
Încheie o legătură din partea ta. Jucătorul poate face același lucru din Settings. |
| PUT | /game-sdk/v1/links/{link_guid}/activity |
Publică blocul „Playing …” pentru un jucător; { "activity": null } îl șterge. |
| POST | /game-sdk/v1/activity/batch |
Același lucru, pentru până la 100 de jucători într-un singur apel. Fiecare element primește propriul răspuns. |
Coduri de eroare
Erorile vin înapoi ca {"error":"CODE","message":"…"}, cu statusul HTTP corespunzător.
| Cod | Semnificație |
|---|---|
401 UNAUTHORIZED | Token lipsă sau necunoscut; autorizează-te mai întâi. |
403 MISSING_SCOPE | Jucătorul nu a acordat această permisiune. Poate a debifat-o. |
403 ORIGIN_NOT_ALLOWED | Cererea purta un Origin de browser. Vezi „Doar jocuri native” mai jos. |
409 NOT_SIGNED_IN | mssgs rulează, dar nu e nimeni conectat. |
429 RATE_LIMITED | Peste 120 de cereri pe minut de la un singur joc. |
400 INVALID_GAME_ID | game_id poate conține doar litere, cifre, punct, cratimă sau underscore. |
400 TOO_MANY_GUIDS | Cel mult 10 valori server_guid per apel membership. |
Backend-uri conectate
Rutele de backend folosesc același format. Într-un batch, statusul vine pentru fiecare element în parte în results, așa că o legătură încheiată nu face niciodată să eșueze tot apelul.
| Cod | Semnificație |
|---|---|
401 INVALID_BACKEND_KEY | Cheie necunoscută sau una rotită acum mai bine de 24 de ore. |
403 SCOPE_NOT_GRANTED | Înregistrarea ta nu are scope-ul de care are nevoie ruta. |
400 INVALID_PAYLOAD | Corp malformat, peste 100 de elemente în batch sau un join.url al cărui host nu e unul dintre backend-urile tale înregistrate. |
400 INVALID_ACTIVITY | După normalizare nu a mai rămas niciun nume utilizabil. |
410 LINK_REVOKED | Legătura s-a încheiat, de o parte sau de cealaltă. Renunță la ea și oferă din nou „Connect mssgs”. |
429 SLOW_DOWN | Ai interogat link/poll mai des decât interval. |
429 RATE_LIMITED | O schimbare la aceeași legătură la mai puțin de 2 secunde după ultima sau peste 600 de cereri pe minut pe cheia ta. |
503 LINK_STORE_UNAVAILABLE | Problemă temporară la noi. Reîncearcă la următorul heartbeat. |
Securitate
Doar jocuri native
Cererile care poartă un Origin de pagină web sunt refuzate cu 403 ORIGIN_NOT_ALLOWED. Dacă orice pagină web ar putea detecta că folosești mssgs și ar putea deschide un dialog de permisiune, asta ar fi o suprafață de atac pentru fingerprinting și phishing, nu o funcție. Un joc nativ nu trimite deloc Origin, deci nu e afectat, iar browserul încorporat al unui joc e permis explicit, pe nume, vezi FiveM. Dacă construiești un joc pentru browser sau telefon, nu vorbești cu puntea: propriul tău backend publică pentru jucătorii conectați, vezi Jocuri în browser și pe telefon.
Ce rămâne sub controlul jucătorului
- Jucătorul poate opri puntea în Settings → Game Activity, după care niciun joc nu mai poate vedea mssgs deloc.
- Fiecare joc aprobat apare acolo exact cu permisiunile pe care le are, cu momentul ultimei activități și cu un buton Remove. Eliminarea e imediată: tokenul moare pe loc.
- Un joc conectat din browser sau de pe telefon apare la Linked games cu un buton Disconnect. Și deconectarea e imediată: următoarea publicare a acelui backend primește un
410. - Puntea ascultă doar pe 127.0.0.1, niciodată în rețea.
- Mesajele directe nu sunt dezvăluite niciodată, nici măcar cu servers.list.
- Fiecare joc are un buget de 120 de cereri pe minut.
Bune practici
- Cere scope-urile atunci când ai nevoie de ele, nu pe toate deodată la prima pornire.
- Funcționează și fără mssgs: jucătorul nu e obligat să-l aibă.
- Șterge-ți statusul când se termină jocul, în loc să aștepți TTL-ul.
- Tratează un scope refuzat ca pe un rezultat normal, nu ca pe o eroare.