<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Faizullah</title>
    <description>The latest articles on DEV Community by Faizullah (@faizullahpk).</description>
    <link>https://dev.to/faizullahpk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3978324%2F61cd9b2b-b98f-4612-a912-29d048760cca.png</url>
      <title>DEV Community: Faizullah</title>
      <link>https://dev.to/faizullahpk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faizullahpk"/>
    <language>en</language>
    <item>
      <title>How I Built a Real-Time Multiplayer Game with Socket.IO, Firebase &amp; Pakistani Payment Gateways</title>
      <dc:creator>Faizullah</dc:creator>
      <pubDate>Wed, 10 Jun 2026 20:03:49 +0000</pubDate>
      <link>https://dev.to/faizullahpk/how-i-built-a-real-time-multiplayer-game-with-socketio-firebase-pakistani-payment-gateways-426b</link>
      <guid>https://dev.to/faizullahpk/how-i-built-a-real-time-multiplayer-game-with-socketio-firebase-pakistani-payment-gateways-426b</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Real-Time Multiplayer Game with Socket.IO, Firebase &amp;amp; Pakistani Payment Gateways
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Faiz Ullah — Full-Stack Developer &amp;amp; Founder of DG Technology&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;When people think of multiplayer games, they imagine big studios and huge teams. But a real-time, money-handling, cheat-proof multiplayer platform can be built by one engineer who understands the architecture deeply. This is the story of &lt;strong&gt;Ludo Battle&lt;/strong&gt; — a real-time multiplayer Ludo tournament platform I built end-to-end, from the WebSocket game engine to the Android APK to the payment integration.&lt;/p&gt;

&lt;p&gt;I'll walk through the hard parts, the decisions that mattered, and the lessons that apply to &lt;em&gt;any&lt;/em&gt; real-time application — not just games.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;Build a platform where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 to 4 players play live Ludo matches with sub-second synchronization&lt;/li&gt;
&lt;li&gt;Players deposit and withdraw real money through local payment gateways&lt;/li&gt;
&lt;li&gt;Nobody can cheat — not the dice, not the moves, not the outcomes&lt;/li&gt;
&lt;li&gt;It runs on the web &lt;strong&gt;and&lt;/strong&gt; as a native Android app&lt;/li&gt;
&lt;li&gt;It works on Pakistani mobile networks, where strict NATs and unstable connections are the norm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last constraint shaped a lot of decisions. Building for ideal conditions is easy. Building for real-world 4G in Pakistan is the actual engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Decision #1: The Server Owns Everything
&lt;/h2&gt;

&lt;p&gt;The single most important principle in any real-money game: &lt;strong&gt;the client is a renderer, never a decision-maker.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the browser decides what the dice rolled, a cheater opens DevTools and rolls a six every time. So in Ludo Battle, the &lt;strong&gt;server is the source of truth&lt;/strong&gt; for every piece of game state. The client sends &lt;em&gt;intentions&lt;/em&gt; ("I want to roll", "I want to move this token"), and the server decides what actually happens.&lt;/p&gt;

&lt;p&gt;Here's the dice roll — it lives on the server and uses Node's cryptographically secure random generator, not &lt;code&gt;Math.random()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;randomInt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rollDice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 1–6, cryptographically secure&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Math.random()&lt;/code&gt; is predictable and can be exploited. &lt;code&gt;crypto.randomInt&lt;/code&gt; cannot. For real money, this difference matters.&lt;/p&gt;

&lt;p&gt;Every move is validated the same way: when a player sends &lt;code&gt;game:move&lt;/code&gt;, the server computes the &lt;strong&gt;legal moves&lt;/strong&gt; from the current board state and rejects anything illegal before applying it. The client literally cannot make an illegal or impossible move stick.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Decision #2: A Clean Real-Time Event Model
&lt;/h2&gt;

&lt;p&gt;The entire live experience runs over &lt;strong&gt;Socket.IO&lt;/strong&gt;. I designed the events around clear namespaces so the codebase stays readable as it grows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;room:create   room:join   room:leave   room:spectate
game:roll     game:move
chat:send     chat:msg
voice:join    voice:signal   voice:leave
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rooms map directly to Socket.IO rooms, so broadcasting game state or chat to exactly the right players is a one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`room:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chat:msg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure means game logic, chat, and voice are cleanly separated but share the same connection — no extra sockets, no wasted overhead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Decision #3: Voice Chat That Survives Real Networks
&lt;/h2&gt;

&lt;p&gt;I wanted players to talk during games. The naive approach — routing audio through the server — is expensive and laggy. Instead I used &lt;strong&gt;peer-to-peer WebRTC&lt;/strong&gt;, where the audio flows directly between players and the server only helps them find each other (signaling).&lt;/p&gt;

&lt;p&gt;The catch: most Pakistani mobile users are behind &lt;strong&gt;strict NATs&lt;/strong&gt; that block direct P2P connections. The fix is a &lt;strong&gt;TURN server&lt;/strong&gt; that relays audio when a direct connection isn't possible. The app fetches TURN credentials per session and falls back gracefully:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try direct connection (STUN)&lt;/li&gt;
&lt;li&gt;If blocked → relay through TURN&lt;/li&gt;
&lt;li&gt;Either way → players can talk&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the difference between voice chat that "works on my machine" and voice chat that works for a farmer on a 4G connection in South Punjab.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Decision #4: Payments Without the Liability
&lt;/h2&gt;

&lt;p&gt;Handling money means handling risk. I deliberately chose a &lt;strong&gt;hosted-redirect&lt;/strong&gt; payment flow for JazzCash and EasyPaisa so that &lt;strong&gt;no card or wallet credentials ever touch my server.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User taps "Deposit"&lt;/li&gt;
&lt;li&gt;My backend builds a &lt;strong&gt;signed&lt;/strong&gt; payload and returns it&lt;/li&gt;
&lt;li&gt;The user is redirected to JazzCash/EasyPaisa's own secure page to approve&lt;/li&gt;
&lt;li&gt;The gateway sends a &lt;strong&gt;callback&lt;/strong&gt; to my server&lt;/li&gt;
&lt;li&gt;My server &lt;strong&gt;verifies the HMAC signature&lt;/strong&gt; before crediting a single rupee&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That HMAC verification step is critical — it's how the server knows a callback genuinely came from the gateway and wasn't forged by someone trying to fake a deposit. Skipping it is how platforms get drained.&lt;/p&gt;

&lt;p&gt;I also built a &lt;strong&gt;test mode&lt;/strong&gt;: when no gateway credentials are configured, deposits credit instantly. This let me build and test the entire economy locally without touching real money or waiting on merchant approval.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Decision #5: One Codebase, Two Platforms
&lt;/h2&gt;

&lt;p&gt;The frontend is &lt;strong&gt;React + TypeScript + Vite&lt;/strong&gt;. To ship it as a native Android app without rewriting everything, I used &lt;strong&gt;Capacitor&lt;/strong&gt;, which wraps the web build into a real APK that I can distribute directly — no Play Store gatekeeping required.&lt;/p&gt;

&lt;p&gt;One important real-world gotcha: &lt;strong&gt;Android blocks insecure WebSocket connections.&lt;/strong&gt; The app &lt;em&gt;must&lt;/em&gt; talk to an HTTPS backend or the sockets silently fail in the APK. Discovering and solving that kind of platform-specific issue is where real shipping experience comes from.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust nothing from the client.&lt;/strong&gt; This one principle prevents an entire category of exploits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for the worst network, not the best.&lt;/strong&gt; Building for Pakistani 4G made the app rock-solid everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security isn't a feature you add later&lt;/strong&gt; — &lt;code&gt;crypto.randomInt&lt;/code&gt;, HMAC verification, and server-authoritative logic had to be in the foundation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of concerns scales.&lt;/strong&gt; Clean event namespaces and layered logic kept a complex real-time system maintainable.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Stack, Summarized
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React, TypeScript, Vite, Tailwind, Zustand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Node.js, Express, Socket.IO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Firebase Phone OTP + JWT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;JazzCash, EasyPaisa (HMAC-verified)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice&lt;/td&gt;
&lt;td&gt;WebRTC + TURN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;Capacitor → Android APK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Ludo Battle taught me that the gap between a "demo" and a "product" is almost entirely in the parts users never see: the anti-cheat, the payment verification, the network resilience. Anyone can render a game board. Making it fair, secure, and reliable on real-world networks is the actual work.&lt;/p&gt;

&lt;p&gt;If you're building something real-time, money-handling, or mobile — or you just want to talk architecture — I'd love to connect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faiz Ullah&lt;/strong&gt;&lt;br&gt;
Full-Stack Developer · Cybersecurity Engineer · Founder of &lt;a href="https://dgtechnology.ae" rel="noopener noreferrer"&gt;DG Technology&lt;/a&gt;&lt;br&gt;
🌐 &lt;a href="https://faizullah.pk" rel="noopener noreferrer"&gt;faizullah.pk&lt;/a&gt; · 📧 &lt;a href="mailto:work@faizullah.pk"&gt;work@faizullah.pk&lt;/a&gt; · 💻 &lt;a href="https://github.com/faizullahpk" rel="noopener noreferrer"&gt;github.com/faizullahpk&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this useful, follow me here and on GitHub — I write about real-world full-stack engineering, building for emerging markets, and shipping products solo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
