Pag-port ug multiplayer nga dula gikan sa C++ ngadto sa web gamit ang Cheerp, WebRTC ug Firebase

Pasiuna

among kompanya Mga Teknolohiya nga Nagsandig naghatag og mga solusyon alang sa pag-port sa tradisyonal nga mga aplikasyon sa desktop ngadto sa web. Ang among C++ compiler cheerp nagmugna og kombinasyon sa WebAssembly ug JavaScript, nga naghatag ug simple nga interaksyon sa browser, ug taas nga performance.

Isip usa ka pananglitan sa aplikasyon niini, nakahukom kami nga i-port ang usa ka multiplayer nga dula sa web ug mipili Teeworlds. Ang Teeworlds usa ka multiplayer nga XNUMXD retro game nga adunay gamay apan aktibong komunidad sa mga magdudula (lakip ako!). Gamay ra kini sa mga termino sa na-download nga mga kapanguhaan ug mga kinahanglanon sa CPU ug GPU - usa ka sulundon nga kandidato.

Pag-port ug multiplayer nga dula gikan sa C++ ngadto sa web gamit ang Cheerp, WebRTC ug Firebase
Nagdagan sa Teeworlds browser

Nakahukom kami nga gamiton kini nga proyekto aron mag-eksperimento kinatibuk-ang mga solusyon alang sa pag-port sa network code ngadto sa web. Kasagaran kini gihimo sa mosunod nga mga paagi:

  • XMLHttpRequest/fetch, kung ang bahin sa network naglangkob lamang sa mga hangyo sa HTTP, o
  • Mga WebSocket.

Ang duha nga mga solusyon nanginahanglan pag-host sa usa ka sangkap sa server sa kilid sa server, ug wala usab gitugotan nga magamit ingon usa ka protocol sa transportasyon UDP. Importante kini alang sa real-time nga mga aplikasyon sama sa video conferencing software ug mga dula, tungod kay kini naggarantiya sa paghatod ug han-ay sa mga protocol packet. TCP mahimong babag sa ubos nga latency.

Adunay ikatulo nga paagi - gamita ang network gikan sa browser: WebRTC.

RTCDataChannel Gisuportahan niini ang kasaligan ug dili kasaligan nga transmission (sa ulahi nga kaso gisulayan niini nga gamiton ang UDP ingon usa ka protocol sa transportasyon kung mahimo), ug mahimong magamit sa usa ka hilit nga server ug taliwala sa mga browser. Kini nagpasabot nga mahimo natong i-port ang tibuok nga aplikasyon ngadto sa browser, lakip ang sangkap sa server!

Bisan pa, kini adunay dugang nga kalisud: sa dili pa ang duha ka WebRTC nga mga kaedad makakomunikar, kinahanglan nila nga maghimo usa ka medyo komplikado nga paglamano aron makonektar, nga nanginahanglan daghang mga third-party nga entidad (usa ka server sa pagsenyas ug usa o daghang mga server. STUN/PAGLIKOD).

Sa tinuud, gusto namon nga maghimo usa ka network API nga naggamit sa WebRTC sa sulod, apan ingon ka duol sa mahimo sa usa ka interface sa UDP Sockets nga dili kinahanglan nga magtukod usa ka koneksyon.

Magtugot kini kanamo nga mapahimuslan ang WebRTC nga dili kinahanglan nga ibutyag ang mga komplikado nga detalye sa code sa aplikasyon (nga gusto namon usbon ingon gamay nga mahimo sa among proyekto).

Minimum nga WebRTC

Ang WebRTC usa ka hugpong sa mga API nga anaa sa mga browser nga naghatag sa peer-to-peer nga transmission sa audio, video ug arbitraryong datos.

Ang koneksyon tali sa mga kauban naestablisar (bisan kung adunay NAT sa usa o duha ka kilid) gamit ang STUN ug/o TURN server pinaagi sa mekanismo nga gitawag ug ICE. Ang mga kaedad nagbayloay og impormasyon sa ICE ug mga parameter sa channel pinaagi sa tanyag ug tubag sa SDP protocol.

Wow! Pila ka abbreviation sa usa ka higayon? Atong ipasabut sa daklit kung unsa ang gipasabut niini nga mga termino:

  • Session Traversal Utilities para sa NAT (STUN) β€” usa ka protocol alang sa pag-bypass sa NAT ug pagkuha sa usa ka pares (IP, port) alang sa pagbayloay og data direkta sa host. Kung nakahimo siya sa pagkompleto sa iyang buluhaton, ang mga kaedad mahimo nga independente nga magbinayloay sa datos sa usag usa.
  • Traversal Gamit ang mga Relay sa palibot sa NAT (PAGLIKOD) gigamit usab alang sa NAT traversal, apan kini nagpatuman niini pinaagi sa pagpasa sa datos pinaagi sa usa ka proxy nga makita sa duha ka mga kaedad. Nagdugang kini og latency ug mas mahal ang pagpatuman kay sa STUN (tungod kay gipadapat kini sa tibuok sesyon sa komunikasyon), apan usahay kini ra ang kapilian.
  • Interactive Connectivity Establishment (ICE) gigamit sa pagpili sa pinakamaayong paagi sa pagkonektar sa duha ka kaedad base sa impormasyon nga nakuha gikan sa direktang pagkonektar sa mga kaedad, ingon man sa impormasyon nga nadawat sa bisan unsang gidaghanon sa STUN ug TURN server.
  • Protokol sa Deskripsyon sa Sesyon (SDP) mao ang usa ka format alang sa paghulagway sa koneksyon channel parameters, alang sa panig-ingnan, ICE kandidato, multimedia codecs (sa kaso sa usa ka audio/video channel), ug uban pa... Usa sa mga kaedad nagpadala sa usa ka SDP Offer, ug ang ikaduha mitubag sa usa ka SDP Tubag .. Pagkahuman niini, gihimo ang usa ka channel.

Aron makahimo sa ingon nga koneksyon, ang mga kaedad kinahanglan nga kolektahon ang kasayuran nga ilang nadawat gikan sa mga server sa STUN ug TURN ug ibaylo kini sa usag usa.

Ang problema kay wala pa silay abilidad sa direktang pagkomunikar, mao nga kinahanglan nga adunay out-of-band nga mekanismo aron ibaylo kini nga datos: usa ka signaling server.

Ang usa ka server sa pagsenyas mahimong yano kaayo tungod kay ang bugtong trabaho niini mao ang pagpasa sa datos tali sa mga kauban sa hugna sa handshake (sama sa gipakita sa diagram sa ubos).

Pag-port ug multiplayer nga dula gikan sa C++ ngadto sa web gamit ang Cheerp, WebRTC ug Firebase
Gipasimple nga WebRTC handshake sequence diagram

Overview sa Modelo sa Teeworlds Network

Ang arkitektura sa network sa Teeworlds yano ra kaayo:

  • Ang mga sangkap sa kliyente ug server duha ka lainlaing mga programa.
  • Ang mga kliyente mosulod sa dula pinaagi sa pagkonektar sa usa sa daghang mga server, nga ang matag usa nag-host lamang sa usa ka dula matag higayon.
  • Ang tanan nga pagbalhin sa data sa dula gihimo pinaagi sa server.
  • Ang usa ka espesyal nga master server gigamit aron mangolekta usa ka lista sa tanan nga mga publiko nga server nga gipakita sa kliyente sa dula.

Salamat sa paggamit sa WebRTC alang sa pagbayloay sa datos, mahimo namong ibalhin ang sangkap sa server sa dula ngadto sa browser diin nahimutang ang kliyente. Naghatag kini kanamo usa ka dako nga oportunidad ...

Kuhaa ang mga server

Ang kakulang sa lohika sa server adunay nindot nga bentaha: mahimo natong i-deploy ang tibuok nga aplikasyon isip static nga sulod sa Github Pages o sa atong kaugalingong hardware luyo sa Cloudflare, sa ingon masiguro ang paspas nga pag-download ug taas nga uptime nga libre. Sa tinuud, mahimo natong kalimtan ang bahin kanila, ug kung swerte kita ug ang dula nahimong popular, nan ang imprastraktura dili kinahanglan nga ma-moderno.

Bisan pa, aron molihok ang sistema, kinahanglan pa namon nga mogamit usa ka eksternal nga arkitektura:

  • Usa o daghan pa nga mga server sa STUN: Adunay kami daghang mga libre nga kapilian nga mapilian.
  • Labing menos usa ka TURN server: wala’y libre nga kapilian dinhi, aron mahimo namon nga i-set up ang among kaugalingon o magbayad alang sa serbisyo. Maayo na lang, kadaghanan sa mga oras ang koneksyon mahimong ma-establisar pinaagi sa mga server sa STUN (ug maghatag tinuod nga p2p), apan ang TURN gikinahanglan ingon usa ka kapilian sa pag-fallback.
  • Server sa Pagsenyas: Dili sama sa ubang duha ka aspeto, ang pagsenyas dili standardized. Unsa ang tinuod nga responsable sa signaling server depende sa aplikasyon. Sa among kaso, sa wala pa magtukod og koneksyon, gikinahanglan ang pagbayloay og gamay nga datos.
  • Teeworlds Master Server: Gigamit kini sa ubang mga server aron i-anunsyo ang ilang pagkaanaa ug sa mga kliyente aron makit-an ang mga pampublikong server. Samtang wala kini kinahanglana (ang mga kliyente kanunay nga makakonekta sa usa ka server nga ilang nahibal-an nga mano-mano), maayo nga adunay aron ang mga magdudula makaapil sa mga dula nga adunay mga random nga tawo.

Nakahukom kami nga gamiton ang libre nga mga server sa STUN sa Google, ug kami mismo ang nag-deploy ug usa ka TURN server.

Alang sa katapusang duha ka punto nga among gigamit Firebase:

  • Ang Teeworlds master server kay simple ra kaayo nga gipatuman: isip listahan sa mga butang nga adunay impormasyon (ngalan, IP, mapa, mode, ...) sa matag aktibong server. Ang mga server nagmantala ug nag-update sa ilang kaugalingong butang, ug ang mga kliyente nagkuha sa tibuok listahan ug nagpakita niini ngadto sa magdudula. Gipakita usab namo ang listahan sa home page isip HTML aron ang mga magdudula maka-klik lang sa server ug madala diretso sa dula.
  • Ang pagsenyas suod nga may kalabutan sa pagpatuman sa among mga socket, nga gihulagway sa sunod nga seksyon.

Pag-port ug multiplayer nga dula gikan sa C++ ngadto sa web gamit ang Cheerp, WebRTC ug Firebase
Listahan sa mga server sulod sa dula ug sa home page

Pagpatuman sa mga socket

Gusto namon nga maghimo usa ka API nga hapit sa Posix UDP Sockets kutob sa mahimo aron maminusan ang gidaghanon sa mga pagbag-o nga gikinahanglan.

Gusto usab namon nga ipatuman ang gikinahanglan nga minimum nga gikinahanglan alang sa pinakasimple nga pagbayloay sa datos sa network.

Pananglitan, wala namo kinahanglana ang tinuod nga pag-ruta: ang tanang mga kaedad anaa sa samang "virtual LAN" nga nalangkit sa usa ka piho nga pananglitan sa database sa Firebase.

Busa, wala namo kinahanglana ang talagsaon nga mga IP adres: ang talagsaon nga Firebase key values ​​(susama sa mga domain name) igo na aron sa talagsaon nga pag-ila sa mga kaedad, ug ang matag peer lokal nga mag-assign sa "peke" nga mga IP address sa matag yawe nga kinahanglang hubaron. Kini hingpit nga nagwagtang sa panginahanglan alang sa global IP address assignment, nga usa ka non-trivial nga buluhaton.

Ania ang minimum nga API nga kinahanglan natong ipatuman:

// 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);

Ang API yano ug susama sa Posix Sockets API, apan adunay pipila ka importante nga mga kalainan: pag-log callback, pag-assign sa mga lokal nga IP, ug tapolan nga koneksyon.

Pagparehistro sa mga Callback

Bisan kung ang orihinal nga programa naggamit sa dili pag-block sa I/O, ang code kinahanglan nga i-refactor aron modagan sa usa ka web browser.

Ang hinungdan niini mao nga ang panghitabo loop sa browser gitago gikan sa programa (mahimo nga JavaScript o WebAssembly).

Sa lumad nga palibot makasulat kita og code nga sama niini

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;
    ...
  }
  ...
}

Kung ang panghitabo loop gitago kanamo, nan kinahanglan namon nga himuon kini nga sama niini:

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

Lokal nga IP assignment

Ang mga node ID sa among "network" dili mga IP address, apan ang mga yawe sa Firebase (mga kuwerdas sila nga ingon niini: -LmEC50PYZLCiCP-vqde ).

Kombenyente kini tungod kay wala kami magkinahanglan og mekanismo sa pag-assign sa mga IP ug pagsusi sa ilang pagkatalagsaon (ingon man usab sa paglabay niini human madiskonekta ang kliyente), apan kasagaran gikinahanglan ang pag-ila sa mga kaedad pinaagi sa numeric nga kantidad.

Mao gyud kini ang gigamit sa mga gimbuhaton. resolve ΠΈ reverseResolve: Ang aplikasyon sa usa ka paagi makadawat sa string value sa yawe (pinaagi sa user input o pinaagi sa master server), ug mahimo kining i-convert ngadto sa IP address alang sa internal nga paggamit. Ang nahabilin sa API nakadawat usab niini nga kantidad imbes usa ka hilo alang sa kayano.

Kini susama sa DNS lookup, apan gihimo sa lokal sa kliyente.

Kana mao, ang mga adres sa IP dili mahimong ipaambit tali sa lainlaing mga kliyente, ug kung kinahanglan ang usa ka matang sa pangkalibutanon nga identifier, kinahanglan kini nga himuon sa lahi nga paagi.

Lay nga koneksyon

Ang UDP wala magkinahanglan og koneksyon, apan sama sa atong nakita, ang WebRTC nagkinahanglan og taas nga proseso sa koneksyon sa dili pa kini makasugod sa pagbalhin sa datos tali sa duha ka mga kaedad.

Kung gusto namon maghatag parehas nga lebel sa abstraction, (sendto/recvfrom nga adunay arbitraryong mga kaedad nga wala’y una nga koneksyon), nan kinahanglan sila maghimo usa ka "tapulan" (nalangan) nga koneksyon sa sulod sa API.

Mao kini ang mahitabo sa panahon sa normal nga komunikasyon tali sa "server" ug sa "kliyente" kung mogamit sa UDP, ug kung unsa ang kinahanglan buhaton sa among librarya:

  • Mga tawag sa server bind()aron isulti sa operating system nga gusto niini nga makadawat mga pakete sa piho nga pantalan.

Hinuon, mag-publish kami og bukas nga pantalan sa Firebase ubos sa yawe sa server ug maminaw sa mga panghitabo sa subtree niini.

  • Mga tawag sa server recvfrom(), pagdawat sa mga pakete gikan sa bisan unsang host niini nga pantalan.

Sa among kaso, kinahanglan namon nga susihon ang umaabot nga pila sa mga pakete nga gipadala sa kini nga pantalan.

Ang matag pantalan adunay kaugalingon nga pila, ug among gidugang ang gigikanan ug destinasyon nga mga pantalan sa sinugdanan sa mga datagram sa WebRTC aron mahibal-an namon kung unsang pila ang ipasa kung moabut ang bag-ong pakete.

Ang tawag dili blocking, mao nga kung walay mga pakete, ibalik lang namo ang -1 ug itakda errno=EWOULDBLOCK.

  • Ang kliyente makadawat sa IP ug pantalan sa server pinaagi sa pipila ka paagi sa gawas, ug mga tawag sendto(). Naghimo usab kini usa ka internal nga tawag. bind(), busa misunod recvfrom() makadawat sa tubag nga walay klarong pagpatuman sa bind.

Sa among kaso, ang kliyente sa gawas nakadawat sa string key ug gigamit ang function resolve() para makakuha ug IP address.

Niini nga punto, magsugod kami og WebRTC handshake kung ang duha ka mga kaedad wala pa konektado sa usag usa. Ang mga koneksyon sa lainlaing mga pantalan sa parehas nga kaedad naggamit sa parehas nga WebRTC DataChannel.

Naghimo usab kami dili direkta bind()aron ang server makakonektar pag-usab sa sunod sendto() sa kaso nga kini nagsira sa pipila ka rason.

Ang server gipahibalo sa koneksyon sa kliyente sa dihang ang kliyente nagsulat sa iyang SDP nga tanyag ubos sa server port nga impormasyon sa Firebase, ug ang server mitubag uban sa iyang tubag didto.

Ang dayagram sa ubos nagpakita sa usa ka pananglitan sa dagan sa mensahe alang sa usa ka socket scheme ug ang pagpasa sa unang mensahe gikan sa kliyente ngadto sa server:

Pag-port ug multiplayer nga dula gikan sa C++ ngadto sa web gamit ang Cheerp, WebRTC ug Firebase
Kompleto nga diagram sa hugna sa koneksyon tali sa kliyente ug server

konklusyon

Kung nabasa na nimo kini, lagmit interesado ka nga makita ang aksyon nga teorya. Ang dula mahimong dulaon sa teeworlds.leaningtech.com, sulayi kini!


Mahigalaon nga duwa tali sa mga kauban

Ang network library code kay libre nga magamit sa Github. Apil sa panag-istoryahanay sa among channel sa Gitugot!

Source: www.habr.com

Idugang sa usa ka comment