Pote yon jwèt multijoueurs soti nan C++ sou entènèt la ak Cheerp, WebRTC ak Firebase

Entwodiksyon

konpayi nou an Teknoloji apiye bay solisyon pou pòte aplikasyon pou Desktop tradisyonèl sou entènèt la. Konpilateur C++ nou an cheerp jenere yon konbinezon de WebAssembly ak JavaScript, ki bay tou de senp entèraksyon navigatè, ak pèfòmans segondè.

Kòm yon egzanp aplikasyon li, nou deside pò yon jwèt multijoueurs sou entènèt la epi nou chwazi Teeworlds. Teeworlds se yon jwèt retro 2D multijoueurs ak yon kominote jwè piti men aktif (ki gen ladan mwen!). Li se ti tou de an tèm de resous telechaje ak CPU ak GPU kondisyon - yon kandida ideyal.

Pote yon jwèt multijoueurs soti nan C++ sou entènèt la ak Cheerp, WebRTC ak Firebase
Kouri nan navigatè a Teeworlds

Nou deside sèvi ak pwojè sa a pou fè eksperyans solisyon jeneral pou pòte kòd rezo a sou entènèt la. Sa a anjeneral fè nan fason sa yo:

  • XMLHttpRequest/chache, si pati rezo a konsiste sèlman de demann HTTP, oswa
  • priz entènèt.

Tou de solisyon mande pou òganize yon eleman sèvè sou bò sèvè a, epi ni pa pèmèt pou itilize kòm yon pwotokòl transpò udp. Sa a enpòtan pou aplikasyon an tan reyèl tankou lojisyèl konferans videyo ak jwèt, paske li garanti livrezon ak lòd nan pake pwotokòl. Tchp ka vin yon antrav pou ba latansi.

Gen yon twazyèm fason - sèvi ak rezo a nan navigatè a: WebRTC.

RTCDataChannel Li sipòte tou de transmisyon serye ak enfidèl (nan dènye ka a li eseye sèvi ak UDP kòm yon pwotokòl transpò chak fwa sa posib), epi li ka itilize tou de ak yon sèvè aleka ak ant navigatè. Sa vle di ke nou ka pò tout aplikasyon an nan navigatè a, ki gen ladan eleman sèvè a!

Sepandan, sa a vini ak yon lòt difikilte: anvan de WebRTC kamarad ka kominike, yo bezwen fè yon lanmen relativman konplèks pou konekte, ki mande plizyè antite twazyèm pati (yon sèvè siyal ak youn oswa plis sèvè. STUN/VIRE).

Idealman, nou ta renmen kreye yon API rezo ki sèvi ak WebRTC anndan, men ki pi pre ke posib nan yon koòdone UDP Sockets ki pa bezwen etabli yon koneksyon.

Sa a pral pèmèt nou pran avantaj de WebRTC san yo pa bezwen ekspoze detay konplèks nan kòd aplikasyon an (ki nou te vle chanje pi piti ke posib nan pwojè nou an).

Minimòm WebRTC

WebRTC se yon seri API ki disponib nan navigatè yo ki bay transmisyon kanmarad odyo, videyo ak done abitrè.

Koneksyon ant kamarad yo etabli (menm si gen NAT sou youn oswa toude bò) lè l sèvi avèk STUN ak/oswa TURN sèvè atravè yon mekanis ki rele ICE. Kanmarad yo echanje enfòmasyon ICE ak paramèt chanèl atravè òf ak repons pwotokòl SDP a.

Wow! Konbyen abrevyasyon nan yon sèl fwa? Ann eksplike yon ti tan sa tèm sa yo vle di:

  • Itilite Traversal Sesyon pou NAT (STUN) — yon pwotokòl pou kontoune NAT ak jwenn yon pè (IP, pò) pou fè echanj done dirèkteman ak lame a. Si li jere ranpli travay li, Lè sa a, kanmarad yo ka poukont yo fè echanj done youn ak lòt.
  • Travèse lè l sèvi avèk relè alantou NAT (VIRE) yo itilize tou pou NAT traversal, men li aplike sa a pa voye done atravè yon prokurasyon ki vizib pou tou de kamarad yo. Li ajoute latansi epi li pi chè pou aplike pase STUN (paske li aplike pandan tout sesyon kominikasyon an), men pafwa li se sèl opsyon.
  • Etablisman Koneksyon entèaktif (ICE) yo itilize pou chwazi pi bon metòd posib pou konekte de kanmarad ki baze sou enfòmasyon yo jwenn nan konekte kanmarad yo dirèkteman, ansanm ak enfòmasyon ki resevwa pa nenpòt kantite sèvè STUN ak TURN.
  • Pwotokòl Deskripsyon Sesyon (RDS) se yon fòma pou dekri paramèt kanal koneksyon, pou egzanp, kandida ICE, kodèk miltimedya (nan ka yon chanèl odyo/videyo), elatriye... Youn nan kanmarad yo voye yon òf SDP, epi dezyèm nan reponn ak yon repons SDP. . . Apre sa, yon kanal kreye.

Pou kreye yon koneksyon konsa, kanmarad yo bezwen kolekte enfòmasyon yo resevwa nan men sèvè STUN ak TURN yo epi fè echanj youn ak lòt.

Pwoblèm lan se ke yo poko gen kapasite nan kominike dirèkteman, kidonk yon mekanis andeyò band dwe egziste pou echanje done sa yo: yon sèvè siyal.

Yon sèvè siyal ka trè senp paske sèl travay li se voye done ant kamarad nan faz lanmen (jan yo montre nan dyagram ki anba a).

Pote yon jwèt multijoueurs soti nan C++ sou entènèt la ak Cheerp, WebRTC ak Firebase
Senplifye dyagram sekans lanmen WebRTC

Teeworlds Rezo Modèl Apèsi sou lekòl la

Achitekti rezo Teeworlds trè senp:

  • Kliyan ak sèvè eleman yo se de pwogram diferan.
  • Kliyan antre nan jwèt la lè yo konekte nan youn nan plizyè serveurs, chak nan ki gen tout pouvwa a sèlman yon jwèt nan yon moman.
  • Tout transfè done nan jwèt la te pote soti nan sèvè a.
  • Yo itilize yon sèvè espesyal espesyal pou kolekte yon lis tout sèvè piblik ki parèt nan kliyan jwèt la.

Mèsi a itilize nan WebRTC pou echanj done, nou ka transfere eleman nan sèvè nan jwèt la nan navigatè a kote kliyan an sitiye. Sa ban nou yon gwo opòtinite...

Debarase m de serveurs

Mank lojik sèvè a gen yon bèl avantaj: nou ka deplwaye tout aplikasyon an kòm kontni estatik sou Github Pages oswa sou pyès ki nan konpitè pwòp pa nou dèyè Cloudflare, konsa asire telechajman rapid ak gwo disponiblite gratis. An reyalite, nou ka bliye sou yo, epi si nou gen chans epi jwèt la vin popilè, Lè sa a, enfrastrikti a pa pral oblije modènize.

Sepandan, pou sistèm nan travay, nou toujou oblije itilize yon achitekti ekstèn:

  • Youn oswa plis sèvè STUN: Nou gen plizyè opsyon gratis pou chwazi nan.
  • Omwen yon sèvè TURN: pa gen okenn opsyon gratis isit la, kidonk nou ka swa mete pwòp pa nou oswa peye pou sèvis la. Erezman, pi fò nan tan koneksyon an ka etabli atravè sèvè STUN (epi bay vrè p2p), men TURN nesesè kòm yon opsyon sere.
  • Sèvè siyal: Kontrèman ak de lòt aspè yo, siyal pa ofisyèl. Ki sa ki sèvè siyal la pral aktyèlman responsab pou depann yon ti jan sou aplikasyon an. Nan ka nou an, anvan etabli yon koneksyon, li nesesè pou fè echanj yon ti kantite done.
  • Teeworlds Master Server: Lòt serveurs itilize li pou fè piblisite egzistans yo epi kliyan yo jwenn sèvè piblik yo. Pandan ke li pa obligatwa (kliyan yo ka toujou konekte nan yon sèvè yo konnen sou manyèlman), li ta bon yo genyen pou ke jwè yo ka patisipe nan jwèt ak moun o aza.

Nou deside sèvi ak sèvè STUN gratis Google yo, epi nou deplwaye yon sèl sèvè TURN pou nou.

Pou de dènye pwen yo nou te itilize Firebase:

  • Teeworlds sèvè mèt la aplike trè tou senpleman: kòm yon lis objè ki gen enfòmasyon (non, IP, kat jeyografik, mòd, ...) nan chak sèvè aktif. Sèvè yo pibliye ak mete ajou pwòp objè yo, ak kliyan pran lis la tout antye epi montre li bay jwè a. Nou montre tou lis la sou paj lakay la kòm HTML pou jwè yo ka senpleman klike sou sèvè a epi yo ka mennen yo tou dwat nan jwèt la.
  • Siyal se byen ki gen rapò ak aplikasyon sipò nou an, ki dekri nan pwochen seksyon an.

Pote yon jwèt multijoueurs soti nan C++ sou entènèt la ak Cheerp, WebRTC ak Firebase
Lis serveurs andedan jwèt la ak sou paj lakay ou

Aplikasyon nan priz

Nou vle kreye yon API ki pi pre Posix UDP Sockets ke posib pou minimize kantite chanjman ki nesesè yo.

Nou vle tou aplike minimòm ki nesesè pou echanj done ki pi senp sou rezo a.

Pa egzanp, nou pa bezwen routage reyèl: tout kanmarad yo sou menm "LAN vityèl" ki asosye ak yon egzanp espesifik baz done Firebase.

Se poutèt sa, nou pa bezwen adrès IP inik: valè inik Firebase kle (menm jan ak non domèn) yo ase pou idantifye inikman kanmarad, epi chak kanmarad lokalman bay "fo" adrès IP nan chak kle ki bezwen tradui. Sa a konplètman elimine nesesite pou plasman adrès IP mondyal, ki se yon travay ki pa trivial.

Men API minimòm nou bezwen aplike:

// Create and destroy a socket
int socket();
int close(int fd);
// Bind a socket to a port, and publish it on Firebase
int bind(int fd, AddrInfo* addr);
// Send a packet. This lazily create a WebRTC connection to the 
// peer when necessary
int sendto(int fd, uint8_t* buf, int len, const AddrInfo* addr);
// Receive the packets destined to this socket
int recvfrom(int fd, uint8_t* buf, int len, AddrInfo* addr);
// Be notified when new packets arrived
int recvCallback(Callback cb);
// Obtain a local ip address for this peer key
uint32_t resolve(client::String* key);
// Get the peer key for this ip
String* reverseResolve(uint32_t addr);
// Get the local peer key
String* local_key();
// Initialize the library with the given Firebase database and 
// WebRTc connection options
void init(client::FirebaseConfig* fb, client::RTCConfiguration* ice);

API a senp epi menm jan ak API Posix Sockets, men li gen kèk diferans enpòtan: anrejistreman apèl, asiyen IP lokal yo, ak koneksyon parese.

Anrejistre apèl yo

Menm si pwogram orijinal la sèvi ak I/O ki pa bloke, kòd la dwe refactorize pou li kouri nan yon navigatè entènèt.

Rezon ki fè sa a se ke bouk evènman an nan navigatè a kache nan pwogram nan (se pou li JavaScript oswa WebAssembly).

Nan anviwònman natif natal nou ka ekri kòd tankou sa a

while(running) {
  select(...); // wait for I/O events
  while(true) {
    int r = readfrom(...); // try to read
    if (r < 0 && errno == EWOULDBLOCK) // no more data available
      break;
    ...
  }
  ...
}

Si bouk evènman an kache pou nou, Lè sa a, nou bezwen vire l 'nan yon bagay tankou sa a:

auto cb = []() { // this will be called when new data is available
  while(true) {
    int r = readfrom(...); // try to read
    if (r < 0 && errno == EWOULDBLOCK) // no more data available
      break;
    ...
  }
  ...
};
recvCallback(cb); // register the callback

Plasman IP lokal yo

ID yo nan "rezo" nou an pa adrès IP, men kle Firebase (yo se fisèl ki sanble sa a: -LmEC50PYZLCiCP-vqde ).

Sa a se pratik paske nou pa bezwen yon mekanis pou plase IP yo ak tcheke inik yo (kòm byen ke jete yo apre kliyan an dekonekte), men li se souvan nesesè yo idantifye kanmarad pa yon valè nimerik.

Sa a se egzakteman sa fonksyon yo itilize pou. resolve и reverseResolve: Aplikasyon an yon jan kanmenm resevwa valè kòd kle a (atravè opinyon itilizatè a oswa atravè sèvè mèt la), epi li ka konvèti li nan yon adrès IP pou itilizasyon entèn. Rès API a tou resevwa valè sa a olye de yon fisèl pou senplisite.

Sa a se menm jan ak rechèch DNS, men fè lokalman sou kliyan an.

Sa vle di, adrès IP yo pa ka pataje ant kliyan diferan, epi si gen yon kalite idantifyan mondyal bezwen, li pral gen yo dwe pwodwi nan yon fason diferan.

Koneksyon parese

UDP pa bezwen yon koneksyon, men jan nou te wè, WebRTC mande pou yon pwosesis koneksyon long anvan li ka kòmanse transfere done ant de kanmarad.

Si nou vle bay menm nivo abstraksyon, (sendto/recvfrom ak kanmarad abitrè san koneksyon anvan), Lè sa a, yo dwe fè yon "parese" (reta) koneksyon andedan API a.

Sa a se sa k ap pase pandan kominikasyon nòmal ant "sèvè a" ak "kliyan an" lè w ap itilize UDP, ak sa bibliyotèk nou an ta dwe fè:

  • Sèvè apèl bind()pou di sistèm operasyon an ke li vle resevwa pakè sou pò espesifye a.

Olye de sa, nou pral pibliye yon pò louvri nan Firebase anba kle sèvè a epi koute evènman ki nan subtree li yo.

  • Sèvè apèl recvfrom(), aksepte pake ki soti nan nenpòt lame sou pò sa a.

Nan ka nou an, nou bezwen tcheke keu fèk ap rantre nan pake ki voye nan pò sa a.

Chak pò gen pwòp keu li, epi nou ajoute pò sous ak destinasyon yo nan kòmansman datagram WebRTC yo pou nou konnen ki keu pou voye lè yon nouvo pake rive.

Apèl la pa bloke, kidonk si pa gen okenn pake, nou tou senpleman retounen -1 epi mete errno=EWOULDBLOCK.

  • Kliyan an resevwa IP ak pò sèvè a pa kèk mwayen ekstèn, ak apèl sendto(). Sa a tou fè yon apèl entèn. bind(), Se poutèt sa ki vin apre recvfrom() pral resevwa repons lan san yo pa egzekite bind klèman.

Nan ka nou an, kliyan an deyò resevwa kle fisèl la epi sèvi ak fonksyon an resolve() pou jwenn yon adrès IP.

Nan pwen sa a, nou kòmanse yon lanmen WebRTC si de kanmarad yo poko konekte youn ak lòt. Koneksyon nan pò diferan nan menm kanmarad la itilize menm WebRTC DataChannel la.

Nou menm tou nou fè endirèk bind()pou sèvè a ka rekonekte nan pwochen an sendto() nan ka li fèmen pou kèk rezon.

Se sèvè a avize sou koneksyon kliyan an lè kliyan an ekri òf SDP li anba enfòmasyon pò sèvè a nan Firebase, epi sèvè a reponn ak repons li la.

Dyagram ki anba a montre yon egzanp koule mesaj pou yon konplo priz ak transmisyon premye mesaj la soti nan kliyan an nan sèvè a:

Pote yon jwèt multijoueurs soti nan C++ sou entènèt la ak Cheerp, WebRTC ak Firebase
Konplete dyagram faz koneksyon ant kliyan ak sèvè

Konklizyon

Si ou te li byen lwen, ou pwobableman enterese nan wè teyori a an aksyon. Jwèt la ka jwe sou teeworlds.leaningtech.com, eseye li!


Match amikal ant kòlèg yo

Kòd bibliyotèk rezo a disponib gratis nan Github. Antre nan konvèsasyon an sou chanèl nou an nan Gitter!

Sous: www.habr.com

Add nouvo kòmantè