{"id":38370,"date":"2019-10-31T22:23:18","date_gmt":"2019-10-31T19:23:18","guid":{"rendered":"https:\/\/prohoster.info\/blog\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\/"},"modified":"2019-10-31T22:23:18","modified_gmt":"2019-10-31T19:23:18","slug":"portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","title":{"rendered":"Pohojm\u00eb nj\u00eb loj\u00eb multiplayer nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2>Hyrje<\/h2>\n<p>\nKompania jon\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/leaningtech.com\">Leaning Technologies<\/a><\/noindex> ofron zgjidhje p\u00ebr portimin e aplikacioneve tradicionale desktop n\u00eb web. Kompileri yn\u00eb C++ <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\">Cheerp<\/a><\/noindex> gjeneron nj\u00eb kombinim t\u00eb WebAssembly dhe JavaScript, q\u00eb siguron <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\/wiki\/Cheerp-Tutorial%3A-Mixed-mode-C++-to-WebAssembly-and-JavaScript\">interaksion t\u00eb thjesht\u00eb me shfletuesin<\/a><\/noindex>, dhe nj\u00eb performanc\u00eb t\u00eb lart\u00eb.<\/p>\n<p>Si nj\u00eb shembull t\u00eb aplikimit t\u00eb tij, vendos\u00ebm t\u00eb portojm\u00eb p\u00ebr web nj\u00eb loj\u00eb multiplayer dhe zgjodh\u00ebm <noindex><a rel=\"nofollow\" href=\"https:\/\/www.teeworlds.com\/\"><strong>Teeworlds<\/strong><\/a><\/noindex>. Teeworlds \u00ebsht\u00eb nj\u00eb loj\u00eb retro dy-dimensionale multiplayer me nj\u00eb komunitet t\u00eb vog\u00ebl, por aktiv lojtar\u00ebsh (p\u00ebrfshir\u00eb edhe mua!). Ajo \u00ebsht\u00eb e vog\u00ebl sa i p\u00ebrket burimeve q\u00eb shkarkohet dhe k\u00ebrkesave p\u00ebr CPU dhe GPU \u2014 nj\u00eb kandidat ideal.<\/p>\n<p><img decoding=\"async\" alt=\"Pohojm\u00eb nj\u00eb loj\u00eb multiplayer nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/30bff36ee1158ddea2e76d8b11e48d2b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Teeworlds q\u00eb funksionon n\u00eb shfletues<\/i><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nVendos\u00ebm ta p\u00ebrdorim k\u00ebt\u00eb projekt p\u00ebr t\u00eb eksperimentuar me <strong>zgjidhje t\u00eb p\u00ebrgjithshme p\u00ebr portimin e kodit rrjetor n\u00eb web<\/strong>. Zakonisht, kjo kryhet n\u00ebp\u00ebrmjet m\u00ebnyrave t\u00eb m\u00ebposhtme:<\/p>\n<ul>\n<li><strong>XMLHttpRequest\/fetch<\/strong>, n\u00ebse pjesa rrjetore p\u00ebrb\u00ebhet vet\u00ebm nga k\u00ebrkesa HTTP, ose<\/li>\n<li><strong>WebSockets<\/strong>.<\/li>\n<\/ul>\n<p>\nT\u00eb dyja zgjidhjet k\u00ebrkojn\u00eb t\u00eb hospedosh komponentin server n\u00eb an\u00ebn e serverit, dhe asnj\u00ebra prej tyre nuk lejon p\u00ebrdorimin si protokoll transporti <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/User_Datagram_Protocol\">UDP<\/a><\/noindex>. Kjo \u00ebsht\u00eb e r\u00ebnd\u00ebsishme p\u00ebr aplikacione n\u00eb koh\u00eb reale, si softi p\u00ebr videokonferenca dhe lojra, p\u00ebr shkak se garancit\u00eb e dor\u00ebzimit dhe rendit t\u00eb paketave t\u00eb protokollit. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Transmission_Control_Protocol\">TCP<\/a><\/noindex> mund t\u00eb krijojn\u00eb pengesa p\u00ebr vonesa t\u00eb ul\u00ebta.<\/p>\n<p>Ka nj\u00eb rrug\u00eb t\u00eb tret\u00eb \u2014 t\u00eb p\u00ebrdor\u00ebsh nj\u00eb rrjet nga shfletuesi: <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/WebRTC\"><strong>WebRTC<\/strong><\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/RTCDataChannel\"><strong>RTCDataChannel<\/strong><\/a><\/noindex> mb\u00ebshtet si transmetim t\u00eb besuesh\u00ebm ashtu edhe t\u00eb pabesuesh\u00ebm (n\u00eb rastin e dyt\u00eb, ai p\u00ebrpiqet t\u00eb p\u00ebrdor\u00eb UDP si protokoll transporti kur \u00ebsht\u00eb e mundur) dhe mund t\u00eb p\u00ebrdoret si me nj\u00eb server t\u00eb shfletuesit, ashtu edhe mes shfletuesve. <strong>Kjo do t\u00eb thot\u00eb se mund t\u00eb portojm\u00eb gjith\u00eb aplikacionin n\u00eb shfletues, p\u00ebrfshir\u00eb edhe komponentin server!<\/strong><\/p>\n<p>Megjithat\u00eb, kjo ka nj\u00eb v\u00ebshtir\u00ebsi shtes\u00eb: para se dy peer t\u00eb WebRTC t\u00eb mund t\u00eb shk\u00ebmbejn\u00eb t\u00eb dh\u00ebna, ata duhet t\u00eb kryejn\u00eb nj\u00eb procedur\u00eb relativisht t\u00eb nd\u00ebrlikuar t\u00eb \"duarve\" (handshake) p\u00ebr t\u00eb lidhur, p\u00ebr t\u00eb cilin k\u00ebrkohen disa entitete t\u00eb jashtme (serveri i sinjalizimit dhe nj\u00eb ose m\u00eb shum\u00eb servera, <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\">STUN<\/a><\/noindex>\/<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Traversal_Using_Relays_around_NAT\">TURN<\/a><\/noindex>).<\/p>\n<p>Idealisht do t\u00eb donim t\u00eb krijonim nj\u00eb API rrjeti, brenda t\u00eb cilit t\u00eb p\u00ebrdorej WebRTC, por sa m\u00eb af\u00ebr q\u00eb t\u00eb ishte me nd\u00ebrfaqen e UDP Sockets, e cila nuk k\u00ebrkon lidhje.<\/p>\n<p>Kjo do t'u lejoj\u00eb t\u00eb shfryt\u00ebzojm\u00eb p\u00ebrfitimet e WebRTC pa nevoj\u00ebn p\u00ebr t\u00eb zbuluar detaje t\u00eb komplikuara n\u00eb kodin e aplikacionit (t\u00eb cilin n\u00eb projektin ton\u00eb donim ta ndryshonim sa m\u00eb pak).<\/p>\n<h1>WebRTC Minimal<\/h1>\n<p>\nWebRTC \u00ebsht\u00eb nj\u00eb grup API-sh q\u00eb ekziston n\u00eb shfletues, i cili siguron transmetimin peer-to-peer t\u00eb z\u00ebrit, videos dhe t\u00eb dh\u00ebnave t\u00eb p\u00ebrgjithshme.<\/p>\n<p>Lidhja midis peer-ve vendoset (edhe n\u00ebse ka NAT nga nj\u00ebra ose t\u00eb dyja an\u00ebt) p\u00ebrmes server\u00ebve STUN dhe\/ose TURN p\u00ebrmes nj\u00eb mekanizmi t\u00eb quajtur ICE. Peer-t shk\u00ebmbejn\u00eb informacionin ICE dhe parametrat e kanaleve p\u00ebrmes ofertave dhe p\u00ebrgjigjeve t\u00eb protokollit SDP.<\/p>\n<p>Wow! Sa shum\u00eb akronime n\u00eb nj\u00eb her\u00eb. Le t\u00eb shpjegojm\u00eb shkurtimisht se \u00e7far\u00eb do t\u00eb thon\u00eb k\u00ebto koncepte:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\"><strong>Session Traversal Utilities for NAT<\/strong> (<strong>STUN<\/strong>)<\/a><\/noindex> \u2014 nj\u00eb protokoll p\u00ebr t\u00eb anashkaluar NAT dhe p\u00ebr t\u00eb marr\u00eb nj\u00eb \u00e7ift (IP, port) p\u00ebr shk\u00ebmbimin e t\u00eb dh\u00ebnave direkt me host-in. N\u00ebse ia del t\u00eb kryej\u00eb detyr\u00ebn e tij, at\u00ebher\u00eb peer-t mund t\u00eb shk\u00ebmbejn\u00eb t\u00eb dh\u00ebna me nj\u00ebri-tjetrin n\u00eb m\u00ebnyr\u00eb t\u00eb pavarur.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Traversal_Using_Relays_around_NAT\"><strong>Traversal Using Relays around NAT<\/strong> (<strong>TURN<\/strong>)<\/a><\/noindex> p\u00ebrdoret gjithashtu p\u00ebr t\u00eb anashkaluar NAT, por e realizon k\u00ebt\u00eb duke drejtuar t\u00eb dh\u00ebnat p\u00ebrmes nj\u00eb proksi, i cili \u00ebsht\u00eb i duksh\u00ebm p\u00ebr t\u00eb dy pal\u00ebt. Kjo shton vones\u00eb dhe \u00ebsht\u00eb m\u00eb e kushtueshme p\u00ebr t'u zbatuar se STUN (sepse aplikohet gjat\u00eb gjith\u00eb sesionit t\u00eb komunikimit), por ndonj\u00ebher\u00eb ky \u00ebsht\u00eb opsioni i vet\u00ebm i mundsh\u00ebm.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Interactive_Connectivity_Establishment\"><strong>Krijimi Interaktiv i Lidhjeve<\/strong> (<strong>ICE<\/strong>)<\/a><\/noindex> p\u00ebrdoret p\u00ebr t\u00eb zgjedhur m\u00ebnyr\u00ebn m\u00eb t\u00eb mir\u00eb t\u00eb mundshme p\u00ebr lidhjen e dy pal\u00ebve bazuar n\u00eb informacionin e marr\u00eb gjat\u00eb lidhjes direkte t\u00eb pal\u00ebve, si dhe informacionin e marr\u00eb nga \u00e7do num\u00ebr serverash STUN dhe TURN.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Session_Description_Protocol\"><strong>Protokolli i P\u00ebrshkrimit t\u00eb Sesionit<\/strong> (<strong>SDP<\/strong>)<\/a><\/noindex> \u00ebsht\u00eb nj\u00eb format p\u00ebrshkrimi i parametrave t\u00eb kanalit t\u00eb lidhjes, p\u00ebr shembull, kandidat\u00ebt ICE, kodek\u00ebt multimedia (n\u00eb rastin e kanaleve audio\/video), etj... Nj\u00ebra pal\u00eb d\u00ebrgon nj\u00eb ofert\u00eb SDP (\u00aboferta\u00bb), dhe tjetra p\u00ebrgjigjet me nj\u00eb p\u00ebrgjigje SDP (\u00abp\u00ebrgjigja\u00bb). Pas k\u00ebsaj krijohet kanali.<\/li>\n<\/ul>\n<p>\nP\u00ebr t\u00eb krijuar nj\u00eb lidhje t\u00eb till\u00eb, pal\u00ebt duhet t\u00eb grumbullojn\u00eb informacionin e marr\u00eb nga serverat STUN dhe TURN dhe ta ndajn\u00eb at\u00eb me nj\u00ebra-tjetr\u00ebn.<\/p>\n<p>Problemi \u00ebsht\u00eb se ato p\u00ebr momentin nuk kan\u00eb mund\u00ebsin\u00eb p\u00ebr t\u00eb ndar\u00eb t\u00eb dh\u00ebna direkt, prandaj p\u00ebr ndarjen e k\u00ebtyre t\u00eb dh\u00ebnave duhet t\u00eb ekzistoj\u00eb nj\u00eb mekaniz\u00ebm jasht\u00eb-banda: serveri i sinjalizimit.<\/p>\n<p>Serveri sinjalizimi mund t\u00eb jet\u00eb shum\u00eb i thjesht\u00eb, sepse detyra e tij e vetme \u00ebsht\u00eb t\u00eb drejtosh t\u00eb dh\u00ebnat midis pirat n\u00eb faz\u00ebn e \"shtr\u00ebngimit t\u00eb duarve\" (si\u00e7 \u00ebsht\u00eb treguar n\u00eb diagramin m\u00eb posht\u00eb).<\/p>\n<p><img decoding=\"async\" alt=\"Pohojm\u00eb nj\u00eb loj\u00eb multiplayer nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/0fc39ba5e0942bc19183e8cf06c60868.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Diagrami i thjeshtuar i sekuenc\u00ebs s\u00eb \"shtr\u00ebngimit t\u00eb duarve\" WebRTC<\/i><\/p>\n<h1>P\u00ebrmbledhje e modelit rrjetor Teeworlds<\/h1>\n<p>\nArkitektura e rrjetit Teeworlds \u00ebsht\u00eb shum\u00eb e thjesht\u00eb:<\/p>\n<ul>\n<li>Komponent\u00ebt e klientit dhe serverit jan\u00eb dy programe t\u00eb ndryshme.<\/li>\n<li>Klient\u00ebt hyjn\u00eb n\u00eb loj\u00eb duke u lidhur me nj\u00eb nga disa server\u00eb, secili prej t\u00eb cil\u00ebve ndan nj\u00eb loj\u00eb n\u00eb nj\u00eb koh\u00eb.<\/li>\n<li>T\u00eb gjitha transferimet e t\u00eb dh\u00ebnave n\u00eb loj\u00eb b\u00ebhen p\u00ebrmes serverit.<\/li>\n<li>Nj\u00eb server i ve\u00e7ant\u00eb master p\u00ebrdoret p\u00ebr t\u00eb mbledhur list\u00ebn e t\u00eb gjith\u00eb server\u00ebve publik\u00eb, t\u00eb cil\u00ebt shfaqen n\u00eb klientin e loj\u00ebs.<\/li>\n<\/ul>\n<p>\nFal\u00eb p\u00ebrdorimit t\u00eb WebRTC p\u00ebr shk\u00ebmbimin e t\u00eb dh\u00ebnave, ne mund ta transferojm\u00eb komponentin server t\u00eb loj\u00ebs n\u00eb shfletues, ku ndodhet klienti. Kjo na ofron nj\u00eb mund\u00ebsi t\u00eb shk\u00eblqyer\u2026<\/p>\n<h1>T\u00eb heqim qafe server\u00ebt<\/h1>\n<p>\nMungesa e logjik\u00ebs s\u00eb server\u00ebve ka nj\u00eb avantaj t\u00eb k\u00ebndsh\u00ebm: mund t\u00eb zhvillojm\u00eb t\u00ebr\u00eb aplikacionin si p\u00ebrmbajtje statike n\u00eb Github Pages ose n\u00eb pajisjet tona pas Cloudflare, duke siguruar k\u00ebshtu ngarkime t\u00eb shpejta dhe nj\u00eb koh\u00ebzurri t\u00eb lart\u00eb falas. N\u00eb thelb, mund t\u00eb harrohet p\u00ebr to, dhe n\u00ebse na fat, dhe loja b\u00ebhet popullore, at\u00ebher\u00eb infrastruktura nuk do t\u00eb k\u00ebrkoj\u00eb modernizim.<\/p>\n<p>Megjithat\u00eb, p\u00ebr t\u00eb funksionuar sistemi, gjithsesi do t\u00eb na duhen struktura e jashtme:<\/p>\n<ul>\n<li>Nj\u00eb ose disa server\u00eb STUN: kemi mund\u00ebsin\u00eb t\u00eb zgjedhim nga disa mund\u00ebsi falas.<\/li>\n<li>T\u00eb pakt\u00ebn nj\u00eb server TURN: k\u00ebtu nuk ka mund\u00ebsi falas, prandaj mund t\u00eb konfiguroni nj\u00eb ton\u00eb ose t\u00eb paguani p\u00ebr sh\u00ebrbimin. Fatmir\u00ebsisht, pjes\u00ebn m\u00eb t\u00eb madhe t\u00eb koh\u00ebs lidhja do t\u00eb mund t\u00eb vendoset p\u00ebrmes server\u00ebve STUN (dhe t\u00eb siguroj\u00eb v\u00ebrtet p2p), por TURN \u00ebsht\u00eb e nevojshme si nj\u00eb mund\u00ebsi rezerv\u00eb.<\/li>\n<li>Serveri i sinjalit: ndryshe nga dy aspektet e tjera, sinjalizimi nuk \u00ebsht\u00eb standardizuar. Ajo p\u00ebr t\u00eb cil\u00ebn n\u00eb t\u00eb v\u00ebrtet\u00eb do t\u00eb p\u00ebrgjigjet serveri i sinjalit, n\u00eb nj\u00eb far\u00eb m\u00ebnyre varet nga aplikacioni. N\u00eb rastin ton\u00eb, para se t\u00eb vendoset lidhja, \u00ebsht\u00eb e nevojshme t\u00eb shk\u00ebmbehen disa t\u00eb dh\u00ebna t\u00eb vogla.<\/li>\n<li>Serveri kryesor i Teeworlds: ai p\u00ebrdoret nga server\u00ebt e tjer\u00eb p\u00ebr t\u00eb njoftuar ekzistenc\u00ebn e tij dhe nga klient\u00ebt p\u00ebr t\u00eb k\u00ebrkuar server\u00eb publik\u00eb. Nd\u00ebrsa ai nuk \u00ebsht\u00eb i detyruesh\u00ebm (klient\u00ebt gjithmon\u00eb mund t\u00eb lidhen manualisht me nj\u00eb server t\u00eb njohur), do t\u00eb ishte mir\u00eb t\u00eb kishte nj\u00eb t\u00eb till\u00eb, n\u00eb m\u00ebnyr\u00eb q\u00eb lojtar\u00ebt t\u00eb mund t\u00eb merrnin pjes\u00eb n\u00eb loj\u00ebra me njer\u00ebz t\u00eb rast\u00ebsish\u00ebm.<\/li>\n<\/ul>\n<p>\nNe vendos\u00ebm t\u00eb p\u00ebrdorim server\u00ebt falas STUN nga Google, dhe nj\u00eb server TURN e ngrit\u00ebm n\u00eb vetvete.<\/p>\n<p>P\u00ebr dy pika t\u00eb fundit, ne p\u00ebrdor\u00ebm <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Firebase\">Firebase<\/a><\/noindex>:<\/p>\n<ul>\n<li>Serveri master Teeworlds \u00ebsht\u00eb implementuar shum\u00eb leht\u00eb: si nj\u00eb list\u00eb objektesh q\u00eb p\u00ebrmbajn\u00eb informacion (emri, IP, harta, mode, \u2026) p\u00ebr \u00e7do server aktiv. Server\u00ebt publikojn\u00eb dhe p\u00ebrdit\u00ebsojn\u00eb objektin e tyre, nd\u00ebrsa klient\u00ebt e marrin t\u00eb gjith\u00eb list\u00ebn dhe e shfaqin at\u00eb p\u00ebr lojtarin. Ne gjithashtu shfaqim list\u00ebn n\u00eb faqen kryesore si HTML, n\u00eb m\u00ebnyr\u00eb q\u00eb lojtar\u00ebt t\u00eb mund t\u00eb klikojn\u00eb direkt n\u00eb server dhe t\u00eb hyjn\u00eb n\u00eb loj\u00eb.<\/li>\n<li>Sinjalizimi \u00ebsht\u00eb ngusht\u00ebsisht i lidhur me realizimin ton\u00eb t\u00eb socket-eve, t\u00eb p\u00ebrshkruar n\u00eb seksionin n\u00eb vijim.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Pohojm\u00eb nj\u00eb loj\u00eb multiplayer nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/5e30bc22643f8baecf850053bf69e130.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Lista e server\u00ebve brenda loj\u00ebs dhe n\u00eb faqen kryesore<\/i><\/p>\n<h1>Realizimi i socket-eve<\/h1>\n<p>\nD\u00ebshirojm\u00eb t\u00eb krijojm\u00eb nj\u00eb API sa m\u00eb af\u00ebr socket-eve UDP Posix, p\u00ebr t\u00eb minimizuar numrin e ndryshimeve t\u00eb nevojshme.<\/p>\n<p>Po ashtu, duam t\u00eb zbatojm\u00eb minimumin e nevojsh\u00ebm q\u00eb k\u00ebrkohet p\u00ebr shk\u00ebmbimin m\u00eb t\u00eb thjesht\u00eb t\u00eb t\u00eb dh\u00ebnave n\u00eb rrjet.<\/p>\n<p>P\u00ebr shembull, nuk na nevojitet nj\u00eb ruter i v\u00ebrtet\u00eb: t\u00eb gjith\u00eb peer-t jan\u00eb n\u00eb nj\u00eb 'LAN virtuale', e lidhur me nj\u00eb instanc\u00eb specifike t\u00eb baz\u00ebs s\u00eb t\u00eb dh\u00ebnave Firebase.<\/p>\n<p>Prandaj, nuk na duhen adresa IP unike: p\u00ebr identifikimin unik t\u00eb peer-eve mjafton t\u00eb p\u00ebrdoren vlera unike \u00e7elash Firebase (si emrat e domain-eve), dhe \u00e7do peer cakton lokalisht adresa IP \"fiktive\" p\u00ebr \u00e7do \u00e7el\u00ebs q\u00eb duhet t\u00eb konvertohet. Kjo na liron plot\u00ebsisht nga nevoja p\u00ebr caktimin global t\u00eb adresave IP, q\u00eb \u00ebsht\u00eb nj\u00eb detyr\u00eb e nd\u00ebrlikuar.<\/p>\n<p>Ja minimalja API q\u00eb na nevojitet t\u00eb realizojm\u00eb:<\/p>\n<pre><code class=\"cpp\">\/\/ Create and destroy a socket\nint socket();\nint close(int fd);\n\/\/ Bind a socket to a port, and publish it on Firebase\nint bind(int fd, AddrInfo* addr);\n\/\/ Send a packet. This lazily create a WebRTC connection to the \n\/\/ peer when necessary\nint sendto(int fd, uint8_t* buf, int len, const AddrInfo* addr);\n\/\/ Receive the packets destined to this socket\nint recvfrom(int fd, uint8_t* buf, int len, AddrInfo* addr);\n\/\/ Be notified when new packets arrived\nint recvCallback(Callback cb);\n\/\/ Obtain a local ip address for this peer key\nuint32_t resolve(client::String* key);\n\/\/ Get the peer key for this ip\nString* reverseResolve(uint32_t addr);\n\/\/ Get the local peer key\nString* local_key();\n\/\/ Initialize the library with the given Firebase database and \n\/\/ WebRTc connection options\nvoid init(client::FirebaseConfig* fb, client::RTCConfiguration* ice);<\/code><\/pre>\n<p>\nAPI \u00ebsht\u00eb e thjesht\u00eb dhe e ngjashme me API-n\u00eb Posix Sockets, por ka disa karakteristika t\u00eb r\u00ebnd\u00ebsishme: <strong>regjistrimi i thirrjeve t\u00eb prapme, caktimi i IP-ve lokale dhe lidhja \"lenive\"<\/strong>.<\/p>\n<h2>Regjistrimi i thirrjeve t\u00eb prapme<\/h2>\n<p>\nMadje edhe n\u00ebse programi fillestar p\u00ebrdor hyrje-dalje jo bllokuese, p\u00ebr ta ekzekutuar n\u00eb nj\u00eb shfletues interneti, kodi duhet t\u00eb ristrukturohet.<\/p>\n<p>Arsyeja p\u00ebr k\u00ebt\u00eb \u00ebsht\u00eb se cikli i ngjarjeve n\u00eb shfletues \u00ebsht\u00eb i fshehur nga programi (qoft\u00eb JavaScript ose WebAssembly).<\/p>\n<p>N\u00eb mjedisin natyror mund t\u00eb shkruajm\u00eb kodin n\u00eb k\u00ebt\u00eb m\u00ebnyr\u00eb<\/p>\n<pre><code class=\"cpp\">while(running) {\n  select(...); \/\/ prit p\u00ebr ngjarje I\/O\n  while(true) {\n    int r = readfrom(...); \/\/ provo t\u00eb lexosh\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ s\u2019ka m\u00eb t\u00eb dh\u00ebna t\u00eb disponueshme\n      break;\n    ...\n  }\n  ...\n}<\/code><\/pre>\n<p>\nN\u00ebse cikli i ngjarjeve \u00ebsht\u00eb i fshehur p\u00ebr ne, at\u00ebher\u00eb duhet ta shnd\u00ebrrojm\u00eb n\u00eb di\u00e7ka t\u00eb ngjashme:<\/p>\n<pre><code class=\"cpp\">auto cb = []() { \/\/ kjo do t\u00eb th\u00ebrritet kur jan\u00eb t\u00eb dh\u00ebna t\u00eb reja n\u00eb dispozicion\n  while(true) {\n    int r = readfrom(...); \/\/ p\u00ebrpiquni t\u00eb lexoni\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ nuk ka m\u00eb t\u00eb dh\u00ebna t\u00eb disponueshme\n      break;\n    ...\n  }\n  ...\n};\nrecvCallback(cb); \/\/ regjistrojini thirrjen e prapambetjes<\/code><\/pre>\n<p><\/p>\n<h2>Caktoni IP lokale<\/h2>\n<p>\nIdentifikuesit e nyjave n\u00eb 'rrjetin' ton\u00eb nuk jan\u00eb adresa IP, por \u00e7el\u00ebsa Firebase (k\u00ebto jan\u00eb vargje q\u00eb duken si: <code>-LmEC50PYZLCiCP-vqde<\/code> ).<\/p>\n<p>Kjo \u00ebsht\u00eb e p\u00ebrshtatshme, sepse nuk kemi nevoj\u00eb p\u00ebr nj\u00eb mekaniz\u00ebm p\u00ebr caktimin e IP-ve dhe kontrollimin e unik\u00ebsis\u00eb s\u00eb tyre (si dhe t\u00eb heqim ato pas \u00e7aktivizimit t\u00eb klientit), por shpesh \u00ebsht\u00eb e nevojshme t\u00eb identifikoni peers me nj\u00eb vler\u00eb numerike.<\/p>\n<p>Pik\u00ebrisht p\u00ebr k\u00ebt\u00eb p\u00ebrdoren funksionet <code>resolve<\/code> dhe <code>reverseResolve<\/code>: aplikacioni n\u00eb nj\u00ebfar\u00eb m\u00ebnyre merr vler\u00ebn e vargut t\u00eb \u00e7el\u00ebsit (n\u00ebp\u00ebrmjet hyrjes s\u00eb p\u00ebrdoruesit ose p\u00ebrmes serverit kryesor), dhe mund ta konvertoj\u00eb at\u00eb n\u00eb nj\u00eb adres\u00eb IP p\u00ebr p\u00ebrdorim t\u00eb brendsh\u00ebm. Pjesa tjet\u00ebr e API-s\u00eb gjithashtu p\u00ebr thjesht\u00ebsi merr k\u00ebt\u00eb vler\u00eb n\u00eb vend t\u00eb vargut.<\/p>\n<p>Kjo \u00ebsht\u00eb si nj\u00eb k\u00ebrkes\u00eb DNS, vet\u00ebm se realizohet lokalisht tek klienti.<\/p>\n<p>Pra, adresat IP nuk mund t\u00eb jen\u00eb t\u00eb zakonshme p\u00ebr klient\u00eb t\u00eb ndrysh\u00ebm, dhe n\u00ebse nevojitet nj\u00eb identifikues global, duhet ta gjeneroni ndryshe.<\/p>\n<h2>Lidhje e len\u00eb<\/h2>\n<p>\nUDP nuk k\u00ebrkon lidhje, por, si\u00e7 e pam\u00eb, p\u00ebrpara se t\u00eb fillojm\u00eb transferimin e t\u00eb dh\u00ebnave midis dy pirat, WebRTC k\u00ebrkon nj\u00eb proces t\u00eb gjat\u00eb lidhjeje.<\/p>\n<p>N\u00ebse duam t\u00eb sigurojm\u00eb t\u00eb nj\u00ebjtin nivel abstraksioni, (<code>sendto<\/code>\/<code>recvfrom<\/code> me pira t\u00eb rast\u00ebsishme pa lidhje paraprake), at\u00ebher\u00eb duhet t\u00eb kryejm\u00eb lidhje \"t\u00eb ngadalshme\" (t\u00eb vonuar) brenda API-s\u00eb.<\/p>\n<p>K\u00ebtu \u00ebsht\u00eb se \u00e7far\u00eb ndodh gjat\u00eb shk\u00ebmbimit t\u00eb zakonsh\u00ebm t\u00eb t\u00eb dh\u00ebnave midis \"serverit\" dhe \"klientit\" kur p\u00ebrdoret UDP, dhe \u00e7far\u00eb duhet t\u00eb b\u00ebj\u00eb biblioteka jon\u00eb:<\/p>\n<ul>\n<li>Serveri th\u00ebrret <code>bind()<\/code>, p\u00ebr t'i njoftuar sistemit operativ q\u00eb d\u00ebshiron t\u00eb marr paketa n\u00eb portin e caktuar.<\/li>\n<\/ul>\n<p>\nN\u00eb vend t\u00eb k\u00ebsaj, do t\u00eb publikojm\u00eb nj\u00eb port t\u00eb hapur n\u00eb Firebase n\u00ebn \u00e7el\u00ebsin e serverit dhe do t\u00eb d\u00ebgjojm\u00eb ngjarjet n\u00eb n\u00ebnstruktur\u00ebn e tij.<\/p>\n<ul>\n<li>Serveri th\u00ebrret <code>recvfrom()<\/code>, duke pranuar n\u00eb k\u00ebt\u00eb port paketa q\u00eb vijn\u00eb nga \u00e7do host.<\/li>\n<\/ul>\n<p>\nN\u00eb rastin ton\u00eb, duhet t\u00eb kontrollojm\u00eb radh\u00ebn hyr\u00ebse t\u00eb paketimeve t\u00eb d\u00ebrguara n\u00eb k\u00ebt\u00eb port.<\/p>\n<p>\u00c7do port ka radh\u00ebn e vet, dhe ne shtojm\u00eb n\u00eb fillim t\u00eb datagrameve WebRTC portet e origjin\u00ebs dhe atyre p\u00ebrfundimtare, p\u00ebr t\u00eb ditur se n\u00eb cil\u00ebn radh\u00eb t\u00eb drejtojm\u00eb paket\u00ebn e re kur arrin.<\/p>\n<p>Thirrja \u00ebsht\u00eb jo-bllokuese, prandaj n\u00ebse nuk ka paketa, ne thjesht kthejm\u00eb -1 dhe vendosim <code>errno=EWOULDBLOCK<\/code>.<\/p>\n<ul>\n<li>Klienti merr n\u00ebp\u00ebrmjet mjeteve t\u00eb jashtme IP-n\u00eb dhe portin e serverit dhe b\u00ebn thirrjen <code>sendto()<\/code>. Po ashtu, k\u00ebt\u00eb realizojm\u00eb me nj\u00eb thirrje t\u00eb brendshme <code>bind()<\/code>, prandaj e m\u00ebposhtmja <code>recvfrom()<\/code> do t\u00eb marr\u00eb p\u00ebrgjigje pa realizimin e qart\u00eb t\u00eb bind.<\/li>\n<\/ul>\n<p>\nN\u00eb rastin ton\u00eb, klienti n\u00eb m\u00ebnyr\u00eb t\u00eb jashtme merr nj\u00eb \u00e7el\u00ebs n\u00eb form\u00eb stringu dhe p\u00ebrdor funksionin <code>resolve()<\/code> p\u00ebr t\u00eb marr\u00eb IP-n\u00eb.<\/p>\n<p>N\u00eb k\u00ebt\u00eb faz\u00eb, fillojm\u00eb \"dor\u00ebzimin\" WebRTC, n\u00ebse dy peer-a ende nuk jan\u00eb lidhur me nj\u00ebri-tjetrin. Lidhjet n\u00eb porte t\u00eb ndryshme t\u00eb nj\u00eb peer-i p\u00ebrdorin t\u00eb nj\u00ebjtin DataChannel WebRTC.<\/p>\n<p>Po ashtu, ne realizojm\u00eb nj\u00eb lidhje t\u00eb dyt\u00eb <code>bind()<\/code>, n\u00eb m\u00ebnyr\u00eb q\u00eb serveri t\u00eb mund t\u00eb rikthej\u00eb lidhjen n\u00eb <code>sendto()<\/code> rast se ajo \u00ebsht\u00eb mbyllur p\u00ebr arsye t\u00eb caktuara.<\/p>\n<p>Serveri njoftohet p\u00ebr lidhjen e klientit, kur klienti regjistron ofert\u00ebn e tij SDP n\u00eb informacionin e portit t\u00eb serverit n\u00eb Firebase, dhe serveri i p\u00ebrgjigjet atje po ashtu.<\/p>\n<p>\nN\u00eb diagramin e m\u00ebposht\u00ebm ilustrohet shembulli i l\u00ebvizjes s\u00eb mesazheve p\u00ebr skem\u00ebn e soketeve dhe d\u00ebrgimin e mesazhit t\u00eb par\u00eb nga klienti te serveri:<\/p>\n<p><img decoding=\"async\" alt=\"Pohojm\u00eb nj\u00eb loj\u00eb multiplayer nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/7dc48e816c09e33daf28c307cad0c258.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Skema e plot\u00eb e faz\u00ebs s\u00eb lidhjes nd\u00ebrmjet klientit dhe serverit<\/i><\/p>\n<h1>P\u00ebrfundimi<\/h1>\n<p>\nN\u00ebse e keni lexuar deri n\u00eb fund, ndoshta ju intereson t\u00eb shihni teorin\u00eb n\u00eb veprim. Mund t\u00eb luani n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/teeworlds.leaningtech.com\">teeworlds.leaningtech.com<\/a><\/noindex>, provoni!<\/p>\n<p><center><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/gfycat.com\/ifr\/newjaggedcoyote\" frameborder=\"0\" allowfullscreen><\/iframe><\/center><br \/>\n<i>Nj\u00eb ndeshje miq\u00ebsore mes koleg\u00ebsh<\/i><\/p>\n<p>Kodi i bibliotek\u00ebs n\u00eb rrjet \u00ebsht\u00eb i disponuesh\u00ebm falas n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerpnet\">Github<\/a><\/noindex>. Bashkohuni n\u00eb diskutimin ton\u00eb n\u00eb kanalin ton\u00eb n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/gitter.im\/leaningtech\/cheerp\">Gitter<\/a><\/noindex>!<br \/>\n<br \/>Burimi: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/468031\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 C++ Cheerp \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 WebAssembly \u0438 JavaScript, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0435\u0431\u0430 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Teeworlds. Teeworlds \u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0442\u0440\u043e-\u0438\u0433\u0440\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28801,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38370","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 C++ Cheerp \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 WebAssembly \u0438 JavaScript, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0435\u0431\u0430 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Teeworlds. Teeworlds \u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0442\u0440\u043e-\u0438\u0433\u0440\u0430\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"sq_AL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0441 \u0421++ \u043d\u0430 \u0432\u0435\u0431 c Cheerp, WebRTC \u0438 Firebase | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 C++ Cheerp \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 WebAssembly \u0438 JavaScript, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0435\u0431\u0430 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Teeworlds. Teeworlds \u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0442\u0440\u043e-\u0438\u0433\u0440\u0430\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:23:18+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:23:18+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Portimi i loj\u00ebs shum\u00ebp\u00ebrdorueshe nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase | ProHoster","description":"Hyrje Komania jon\u00eb Leaning Technologies ofron zgjidhje p\u00ebr portimin e aplikacioneve tradicionale desktop n\u00eb web. Kompilatori yn\u00eb C++ Cheerp gjeneron nj\u00eb kombinim t\u00eb WebAssembly dhe JavaScript, duke siguruar k\u00ebshtu nj\u00eb nd\u00ebrveprim t\u00eb thjesht\u00eb me shfletuesin dhe performanc\u00eb t\u00eb lart\u00eb. Si nj\u00eb shembull i p\u00ebrdorimit t\u00eb tij, vendos\u00ebm t\u00eb portojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdorueshe p\u00ebr web dhe zgjodh\u00ebm Teeworlds p\u00ebr k\u00ebt\u00eb. Teeworlds \u00ebsht\u00eb nj\u00eb loj\u00eb retro dy-dimensional\u00eb shum\u00ebp\u00ebrdorueshe","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sq_AL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0441 \u0421++ \u043d\u0430 \u0432\u0435\u0431 c Cheerp, WebRTC \u0438 Firebase | ProHoster","og:description":"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 C++ Cheerp \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 WebAssembly \u0438 JavaScript, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0435\u0431\u0430 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Teeworlds. Teeworlds \u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0442\u0440\u043e-\u0438\u0433\u0440\u0430","og:url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:23:18+00:00","article:modified_time":"2019-10-31T19:23:18+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38370","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 21:44:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:10:24","updated":"2026-01-23 21:44:19"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/38370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/comments?post=38370"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/38370\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media\/28801"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=38370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=38370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=38370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}