# JavaScript गेम का सोर्स कोड कैसे सुरक्षित करें: एक मल्टीप्लेयर केस स्टडी

JavaScript गेम का सोर्स कोड बचाने के लिए क्लाइंट बिल्ड ओबफस्केट करें। BIGBOARD.GAMES अपने मल्टीप्लेयर गेम AfterPack से सुरक्षित करके बिना फ़्रेम गिराए शिप करता है।

Source: https://www.afterpack.dev/hi/blog/protect-javascript-game-source-code

Published: 2026-10-08 · Author: Nikita Savchenko · Tags: guide, security, games

JavaScript गेम का सोर्स कोड सुरक्षित करने के लिए क्लाइंट बिल्ड को ओबफस्केट करें, थर्ड-पार्टी इंजन और string tables को ओबफस्केटर से बाहर रखें, और secrets तथा हर वह जाँच जो सर्वर कर सकता है, सर्वर पर ही रखें। AfterPack ([afterpack.dev](https://www.afterpack.dev/)), यानी JavaScript ओबफस्केटर, बिल्ड किए गए गेम को हर रिलीज़ पर ऐसे प्रोग्राम में बदल देता है जिसकी संरचना अलग होती है। इसका Free इंजन [`npx afterpack`](https://www.afterpack.dev/docs/cli) या [Vite](https://www.afterpack.dev/docs/frameworks/vite), [webpack](https://www.afterpack.dev/docs/frameworks/webpack) या [Rollup](https://www.afterpack.dev/docs/frameworks/rollup) plugin के ज़रिए लोकली चलता है। [BIGBOARD.GAMES](https://bigboard.games), एक peer-to-peer मल्टीप्लेयर गेम, इसी के साथ शिप होता है, उसी फ़्रेम रेट पर जिसकी ब्राउज़र इजाज़त देता है।

मैंने [BIGBOARD.GAMES](https://bigboard.games) 6 अक्टूबर को लॉन्च किया। यह मुफ़्त ब्राउज़र गेम्स का एक सेट है, जिसे मेज़ पर सटाकर रखे 2 से 4 फ़ोन और टैबलेट पर खेला जाता है: हर स्क्रीन एक ही बोर्ड का हिस्सा बन जाती है, और [Seam Hockey](https://bigboard.games/games/seam-hockey) में पक स्क्रीनों के जोड़ के पार एक डिवाइस से अगले पर फिसल जाता है। लॉन्च के समय इसमें Seam Hockey, [Spillover](https://bigboard.games/games/spillover), [Whack-a-Mole](https://bigboard.games/games/whack-a-mole) और [Islands](https://bigboard.games/games/islands) थे। गेमप्ले [WebRTC](https://en.wikipedia.org/wiki/WebRTC) के ज़रिए सीधे डिवाइस से डिवाइस चलता है, बीच में कोई गेम सर्वर नहीं होता; [गेम ख़ुद कैसे बना है](https://nikitaeverywhere.com/posts/bigboard-games/), यह मैंने अपने ब्लॉग पर लिखा है। रिपॉज़िटरी के पहले ही कमिट में `vite.config.ts` के अंदर AfterPack मौजूद था, इसलिए गेम कभी बिना सुरक्षा के शिप नहीं हुआ। यह पोस्ट बताती है कि इसके लिए गेम ने फ़्रेम, बाइट्स और बिल्ड टाइम में कितनी क़ीमत चुकाई, और इसका हर आँकड़ा असली बिल्ड से लिया गया है।

डेवलपर्स को सबसे ज़्यादा डर गेम्स में ही होता है कि [ओबफस्केशन](https://en.wikipedia.org/wiki/Obfuscation_(software)) उनका फ़्रेम रेट खा जाएगा, और शिप किया गया कोड सबसे पहले भी गेम्स का ही पढ़ा जाता है, क्योंकि नियम, फ़िज़िक्स और नेटवर्क प्रोटोकॉल, सब खिलाड़ी के डिवाइस पर चलते हैं। AI ने यह पढ़ना सस्ता कर दिया है: एक एजेंट ने दो लोकप्रिय ओबफस्केटरों के अपने ही डेमो [10 और 20 मिनट में वापस साफ़ सोर्स में बदल दिए](https://www.afterpack.dev/blog/ai-deobfuscates-javascript)। जिन टूल्स के सहारे मैंने BIGBOARD.GAMES लगभग दस दिन में बनाया, [वही टूल्स](https://claude.com/product/claude-code) किसी और को इसे उतनी ही तेज़ी से पढ़ने भी देते हैं।

## JavaScript गेम का कोड क्या-क्या उजागर करता है?

सब कुछ। नियम, फ़िज़िक्स, स्कोरिंग और वह नेटवर्क प्रोटोकॉल जिसमें किसी चीट को बात करनी होगी, सब बंडल में हैं, और [minification](https://developer.mozilla.org/en-US/docs/Glossary/Minification) सिर्फ़ लोकल नाम छोटे करता है: strings, constants और संरचना पढ़ने लायक बने रहते हैं, जैसा [minified बंडल की यह पड़ताल](https://www.afterpack.dev/blog/protect-javascript-source-code#what-does-minified-javascript-expose) लाइन-दर-लाइन दिखाती है।

[Peer-to-peer](https://en.wikipedia.org/wiki/Peer-to-peer) गेम में क्लाइंट ही रेफ़री भी होता है। [Seam Hockey](https://bigboard.games/games/seam-hockey) में पक जिस डिवाइस पर होता है, वही उसे सिमुलेट करता है और उसकी पोज़िशन बाक़ी डिवाइसों को स्ट्रीम करता है, और जोड़ पर पहुँचते ही ownership अगले डिवाइस के पास चली जाती है। [Spillover](https://bigboard.games/games/spillover) और [Shoal](https://bigboard.games/games/shoal) [deterministic lockstep](https://gafferongames.com/post/deterministic_lockstep/) में चलते हैं: हर डिवाइस एक जैसे इनपुट से वही सिमुलेशन चलाता है, और सभी को एक ही state पर पहुँचना होता है। दो [Durable Objects](https://developers.cloudflare.com/durable-objects/) वाला एक [Cloudflare Worker](https://developers.cloudflare.com/workers/) सिर्फ़ टेबल तैयार करता है, सीटें संभालता है और नतीजे दर्ज करता है।

| हर खिलाड़ी तक क्या पहुँचता है | उसे पढ़ने से क्या मिलता है |
| --- | --- |
| पक की फ़िज़िक्स और जोड़ों पर ownership का हैंड-ऑफ़ | गोल कहाँ तय होता है, और किस डिवाइस पर |
| Lockstep सिमुलेशन और उनकी deterministic त्रिकोणमिति | वह सटीक state जिस पर हर डिवाइस को सहमत होना है |
| [WebRTC data channels](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel) पर मैसेज codec | वह प्रोटोकॉल जिसमें किसी बदले हुए क्लाइंट को बात करनी होगी |
| असली मिलीमीटर में स्क्रीन कैलिब्रेशन (डिवाइस प्रोफ़ाइल, या स्क्रीन से सटाया गया [बैंक कार्ड](https://en.wikipedia.org/wiki/ISO/IEC_7810)) | वह हिस्सा जिसकी किसी क्लोन को सबसे ज़्यादा ज़रूरत होगी, और जिसे दोबारा बनाना सबसे मुश्किल है |

## क्या JavaScript ओबफस्केशन से गेम धीमा होता है?

BIGBOARD.GAMES में इतना नहीं कि दिखे। AfterPack के डिफ़ॉल्ट [`light` preset](https://www.afterpack.dev/docs/presets#the-default-is-light) पर Seam Hockey का फ़्रेम लूप उसी रफ़्तार से चलता है जो ब्राउज़र [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame) को देता है: [OnePlus Pad 3](https://www.oneplus.com/global/oneplus-pad-3) पर 60 से 144 fps के बीच, और iPad पर 60 fps, जहाँ हर ब्राउज़र [WebKit](https://webkit.org/) है और WebKit पेजों को 60 fps के आसपास रोके रखता है, जब तक खिलाड़ी Safari का "Prefer Page Rendering Updates near 60fps" feature flag बंद न कर दे। गेम के diagnostics यह रेट उसी ओबफस्केट किए हुए बिल्ड से पढ़ते हैं जो खिलाड़ियों को मिलता है।

फ़्रेम रेट एक मोटा पैमाना है, इसलिए मैंने सिमुलेशन कोड का समय भी अलग से नापा: वही फ़ंक्शन जो गेम्स शिप करते हैं, [esbuild](https://esbuild.github.io/) से बंडल किए हुए, सादे भी और `light` पर ओबफस्केट किए हुए भी, उस इंजन से जिस पर BIGBOARD लॉन्च हुआ था (0.2.1) और मौजूदा इंजन (0.2.3) से, [V8](https://v8.dev/) में भी और [JavaScriptCore](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html) में भी।

| गेम कोड (इकाई) | रनटाइम | सादा | इंजन 0.2.1 | इंजन 0.2.3 |
| --- | --- | ---: | ---: | ---: |
| Deterministic `sinCos` (ns प्रति कॉल) | V8 | 44.2 | 104.2 (2.36x) | 44.1 (1.00x) |
| Deterministic `sinCos` (ns प्रति कॉल) | JavaScriptCore | 9.5 | 57.4 (6.04x) | 20.6 (2.17x) |
| Shoal सिमुलेशन (µs प्रति टिक) | V8 | 26.5 | 58.2 (2.20x) | 49.7 (1.88x) |
| Shoal सिमुलेशन (µs प्रति टिक) | JavaScriptCore | 21.7 | 36.9 (1.71x) | 26.7 (1.23x) |
| Seam Hockey की पक फ़िज़िक्स (µs प्रति स्टेप) | V8 | 0.52 | 1.01 (1.94x) | 0.78 (1.50x) |
| Seam Hockey की पक फ़िज़िक्स (µs प्रति स्टेप) | JavaScriptCore | 0.39 | 0.66 (1.69x) | 0.64 (1.63x) |

2026-10-08 को Apple M2 Max पर [Node.js](https://nodejs.org/) 24.21.0 (V8) और [Playwright](https://playwright.dev/) के WebKit 26.6 (JavaScriptCore) के साथ मापा गया: हर वेरिएंट के लिए 4 से 8 नए प्रोसेस में 60 से 120 मापे गए रन का median, उसी seed के साथ जो शिप हुए बिल्ड ने इस्तेमाल किया था। V8 पर, इंजन 0.2.3 वाले आठ Shoal प्रोसेस में से एक 50 की जगह लगभग 67 µs पर जाकर टिका; यह इस पर निर्भर था कि V8 ने उस रन को किस तरह ऑप्टिमाइज़ किया।

तो हाँ, ओबफस्केट किया हुआ गेम कोड धीमा चलता है, मौजूदा इंजन पर सादे कोड के मुक़ाबले 1.0x से 2.2x, और फ़्रेम रेट फिर भी नहीं हिलता, क्योंकि सिमुलेशन फ़्रेम का एक छोटा-सा टुकड़ा भर है। टेबल का सबसे धीमा मामला, इंजन 0.2.1 के साथ V8 पर [Shoal](https://bigboard.games/games/shoal), प्रति टिक 58.2 µs लेता है: 60 Hz पर 16.7 ms के फ़्रेम का 0.35%, और 144 Hz पर 6.9 ms के फ़्रेम का 0.84%। टैबलेट M2 Max से धीमा होता है, लेकिन उस टिक से 144 Hz का पूरा फ़्रेम भरने के लिए CPU को 100 गुना से भी ज़्यादा धीमा होना पड़ेगा।

[`light`](https://www.afterpack.dev/docs/presets#the-default-is-light) identifiers के नाम बदलता है, string literals को एक runtime decoder से होकर गुज़ारता है और syntax दोबारा लिखता है, और कोई structural layer नहीं जोड़ता। इंजन 0.2.3 से यह loops को भी loops ही रहने देता है: पिछले इंजन उन्हें callback helpers में बदल देते थे, जिससे hot loops 2-5x धीमे हो जाते थे ([changelog](https://www.afterpack.dev/changelog))। Property और global नाम अब भी एनकोड किए गए constants से होकर जाते हैं, और [बहुत hot कोड में इसका कुछ ख़र्च होता है](https://www.afterpack.dev/docs/presets#the-default-is-light)। इसके [ऊपर वाले presets](https://www.afterpack.dev/docs/presets#the-ladder), `medium` से `extreme` तक, हर token पर structural काम जोड़ते हैं। जिस गेम को उनकी ज़रूरत हो, वह उन्हें [Pro directive](https://www.afterpack.dev/docs/directives) के ज़रिए सबसे क़ीमती कोड पर लगाए, जैसे netcode पर, और फ़्रेम लूप को `light` पर ही रहने दे।

## क्या ओबफस्केशन से deterministic मल्टीप्लेयर टूट जाता है?

टूटना नहीं चाहिए, और BIGBOARD.GAMES में नहीं टूटता: lockstep गेम्स को हर डिवाइस पर bit-identical state चाहिए, Safari के JavaScriptCore और Chrome के V8 दोनों में, और ओबफस्केट किए हुए बिल्ड से उन्हें यही मिलता है।

यह पैमाना "गेम अब भी चल रहा है" से ऊँचा है। [`Math.sin`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin) हर इंजन में एक जैसे bits लौटाए, इसकी कोई गारंटी नहीं है ([spec](https://tc39.es/ecma262/#sec-math.sin) उसके नतीजे को implementation-approximated कहता है), इसलिए [Spillover](https://bigboard.games/games/spillover) [Rapier](https://rapier.rs/) फ़िज़िक्स इंजन के [deterministic build](https://rapier.rs/docs/user_guides/javascript/determinism) के साथ अपना `sinCos` इस्तेमाल करता है, जो `Math.sin` से 5e-14 के भीतर है। वह `sinCos` और उसे कॉल करने वाले सिमुलेशन बाक़ी गेम कोड की तरह ही ओबफस्केट होते हैं। ऊपर के हर मापे गए रन में मैंने पूरी सिमुलेशन state का hash निकाला, हर float को उसके सटीक bits से, और हर ओबफस्केट किया हुआ वेरिएंट V8 और JavaScriptCore दोनों में सादे वेरिएंट से मेल खाया। Shoal की state और `sinCos` के आउटपुट दोनों इंजनों के बीच भी मेल खाए, और lockstep इसी गुण पर टिका है। हर रात Playwright का multi-device suite staging पर गेम्स खेलता है, जो वही ओबफस्केट किया हुआ बिल्ड सर्व करता है जो खिलाड़ियों को मिलता है; इसमें तीन डिवाइसों वाला एक [Shoal](https://bigboard.games/games/shoal) मैच भी है, जो खेल के बीच में एक खिलाड़ी को हटा देता है और बाक़ी दो में desync जाँचता है।

ओबफस्केट किया हुआ आउटपुट क्या-क्या वैसा ही रखता है, और कौन-से गिने-चुने अंतर जानबूझकर हैं, यह [semantic contract](https://www.afterpack.dev/docs/semantic-contract) पेज पर लिखा है।

## Vite गेम बिल्ड को कैसे ओबफस्केट करें

[`@afterpack/vite`](https://www.afterpack.dev/docs/frameworks/vite) इंस्टॉल करें, `plugins` में `afterpackVite()` जोड़ें, और जो chunks आपके नहीं हैं उन्हें exclude करें। `vite dev` पर कोई असर नहीं पड़ता; `vite build` ओबफस्केट किए हुए chunks बनाता है।

```bash
npm install -D @afterpack/vite
```

नीचे वाला कॉन्फ़िग BIGBOARD का ही है, बस दो excludes तक छोटा किया हुआ। मैंने इसे 2026-10-08 को एक साफ़ प्रोजेक्ट में [Vite](https://vite.dev/) 8.3.3, `@afterpack/vite` 0.2.2 (इंजन 0.2.3), Rapier के [`@dimforge/rapier2d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic-compat) 0.21.0 और Node.js 24.21.0 के साथ बिल्ड किया। Receipt ने Rapier और i18n chunks को अछूता और गेम chunk को ओबफस्केट किया हुआ दर्ज किया, और एक ही कमिट के दो बिल्ड byte-identical निकले।

```ts
// vite.config.ts (Vite 8)
import { afterpackVite } from "@afterpack/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    afterpackVite({
      // One program per commit; the same commit and input give the same bytes.
      seed: "git",
      // Output files to leave as they are.
      paths: { exclude: ["**/rapier-*.js", "**/i18n-*.js"] },
    }),
  ],
  build: {
    rolldownOptions: {
      output: {
        codeSplitting: {
          groups: [
            // Give each excluded part its own chunk, or Vite merges it into one of yours.
            { name: "rapier", test: /[\\/]node_modules[\\/]@dimforge[\\/]/ },
            { name: "i18n", test: /[\\/]locales[\\/]/ },
          ],
        },
      },
    },
  },
});
```

[`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude) के globs आउटपुट फ़ाइलों के नामों से मेल खाते हैं, इसलिए chunks कैसे बँटते हैं, यह उतना ही मायने रखता है जितना ख़ुद globs। अपने हाल पर छोड़ दें तो Vite किसी लाइब्रेरी को ऐसे chunk में मिला सकता है जिसमें आपका कोड भी हो, और फिर वह पूरा chunk ओबफस्केट हो जाता है। Vite 8 chunks को Rolldown के [`codeSplitting`](https://rolldown.rs/reference/OutputOptions.codeSplitting) से बाँटता है; Vite 7 और उससे पुराने वर्ज़न में यही बँटवारा Rollup का [`manualChunks`](https://rollupjs.org/configuration-options/#output-manualchunks) करता है।

BIGBOARD.GAMES ये chunks बाहर रखता है, यानी अपनी 140 JavaScript फ़ाइलों में से 21, और इनकी वजहें इंजन 0.2.1 पर मापी गई हैं:

| Chunk | यह क्या है | बाहर क्यों रहता है |
| --- | --- | --- |
| `rapier-*.js` | [Rapier](https://rapier.rs/) फ़िज़िक्स, deterministic build | थर्ड-पार्टी: 3.4 MB का [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) glue, जिसमें हमारा कुछ भी नहीं |
| `analytics-posthog-*.js`, `openapi-fetch-*.js`, `qr-*.js` | [PostHog](https://posthog.com/) analytics, [openapi-fetch](https://openapi-ts.dev/openapi-fetch/) REST क्लाइंट, QR encoder | थर्ड-पार्टी। ओबफस्केट करने पर अकेला QR encoder तीन गुना हो गया, gzip के बाद लगभग 25 KB |
| `i18n-*.js` | अंग्रेज़ी, यूक्रेनी और स्पेनिश strings | ओबफस्केट करने पर सादी strings लगभग 10x बढ़ गईं, और उनमें से कोई भी सीक्रेट नहीं है |
| `brand-marks-*.js`, `brand-glyphs-*.js` | लोगो की आउटलाइन और SVG markup | Path data strings की तरह बर्ताव करता है: ओबफस्केट करने पर इसने entry को दस गुना बढ़ा दिया |

`paths.exclude` एक [Free](https://www.afterpack.dev/docs/tiers) फ़ीचर है। पूरी फ़ाइल की जगह फ़ाइल के अंदर किसी एक फ़ंक्शन को छोड़ने के लिए [Pro directive](https://www.afterpack.dev/docs/directives) चाहिए; Free बिल्ड में directive error देता है।

## ओबफस्केशन से गेम का साइज़ कितना बढ़ता है?

मौजूदा इंजन के साथ पहले लोड पर gzip के बाद लगभग 1.65x, और जिस इंजन पर BIGBOARD लॉन्च हुआ था उसके साथ 2.2x। `/play`, यानी वह पेज जो खिलाड़ी खोलते हैं, 20 chunks लोड करता है:

| सर्व किया गया, gzip के बाद | सादा | इंजन 0.2.1 | इंजन 0.2.3 |
| --- | ---: | ---: | ---: |
| `/play` पहला लोड | 107.9 KB | 239.3 KB (2.22x) | 178.5 KB (1.65x) |
| [Seam Hockey](https://bigboard.games/games/seam-hockey) chunk | 20.5 KB | 36.8 KB (1.80x) | 29.5 KB (1.44x) |
| [Spillover](https://bigboard.games/games/spillover) chunk | 34.0 KB | 59.6 KB (1.75x) | 47.7 KB (1.40x) |

2026-10-08 को `light` पर मापा गया; ओबफस्केट किए गए कॉलम 7 बिल्ड का median हैं। अपग्रेड में बस वर्ज़न बढ़ाना पड़ा: वही कॉन्फ़िग, वही excludes, और gate, `afterpack verify` और multi-device end-to-end रन, तीनों उस पर पास हुए। ओबफस्केशन की असली क़ीमत यही है: यह बाइट्स जोड़ता है, और जो गेम एक-एक किलोबाइट गिनता है, उसे इनके लिए बजट रखना होगा। बिल्ड टाइम सस्ता हिस्सा है: पूरा बिल्ड, यानी ऐप, लैंडिंग और admin, M2 Max पर सादा 1.5 s और ओबफस्केट करके 3.6 s लेता है, दोनों में से किसी भी इंजन पर। इंजन के अपने माप AfterPack के [performance पेज](https://www.afterpack.dev/docs/performance) पर हैं।

साइज़ बजट से निकला एक सबक़ अपनाने लायक है। BIGBOARD का बिल्ड अपने entry chunk में बिल्ड का समय डाल देता है, इसलिए हर बिल्ड entry का और उसे import करने वाले हर chunk का नाम बदल देता है, और जो भी chunk बदला, वह AfterPack से पूरी तरह नए सिरे से फेंटा हुआ निकलता है। एक ही कमिट के अलग-अलग बिल्ड में पहला लोड 176 से 182 KB के बीच घटता-बढ़ता रहा, और सर्व की गई बाइट्स पर रखा बजट बेतरतीब ढंग से फ़ेल होता रहा। इसके बजाय BIGBOARD ओबफस्केशन से पहले मापे गए साइज़ पर बजट रखता है, और जो सर्व होता है उस पर 256 KB की ढीली सीमा। Timestamp को कमिट से लेने पर ([`git log -1 --format=%cI`](https://git-scm.com/docs/git-log)) असली वजह ही दूर हो जाएगी।

## हर रिलीज़ पर अलग प्रोग्राम क्यों शिप करें?

ताकि एक बिल्ड के ख़िलाफ़ लिखा गया चीट, patch या hook अगले बिल्ड से मेल न खाए। [`seed: "git"`](https://www.afterpack.dev/docs/config#seed) के साथ हर कमिट संरचना में अलग आउटपुट देता है, और एक ही seed और एक ही इनपुट से [एक जैसी बाइट्स मिलती हैं](https://www.afterpack.dev/docs/builds#random-seed-by-default-pin-for-reproducibility)। बिल्ड का timestamp पिन करने पर एक कमिट के दो BIGBOARD बिल्ड सभी 140 फ़ाइलों में मेल खाए। तब प्रोडक्शन के लिए दोबारा बिल्ड करने वाली pipeline ठीक वही बाइट्स शिप कर सकती है जिन्हें staging पर टेस्ट किया गया था।

AfterPack का [threat model](https://www.afterpack.dev/docs/threat-model#what-afterpack-does-not-replace) `hard` preset पर इसका असर बताता है: [चीट](https://en.wikipedia.org/wiki/Cheating_in_online_games) बनाने वाले को "किसी ज्ञात offset को एक बार patch करने के बजाय हर release पर असली analysis दोबारा करना पड़ता है"। `light` पर भी नाम, offsets और string decoders हर seed के साथ बदल जाते हैं; बस analysis का हर दौर सस्ता पड़ता है। दोनों ही सूरतों में, जो गेम अक्सर शिप होता है, वह हर रिलीज़ पर चीट बनाने वाले से फिर से क़ीमत वसूलता है। अगर किसी स्क्रिप्ट को आपके डिप्लॉय से भी ज़्यादा बार नया रूप चाहिए, तो उसे [Cloudflare Worker से हर रिक्वेस्ट पर](https://www.afterpack.dev/blog/obfuscate-javascript-cloudflare-workers) नया रूप मिल सकता है।

हर बिल्ड पर बदलने वाले आउटपुट में एक पेच है, जिसे जान लेना चाहिए। AfterPack तब चलता है जब Vite chunks के नाम रख चुका होता है, इसलिए किसी chunk की बाइट्स उसकी फ़ाइल का नाम बदले बिना बदल सकती हैं। तब कई बिल्ड के बीच साझा [service worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) cache किसी ताज़ा chunk के बगल में एक पुराना chunk सर्व कर सकता है। BIGBOARD का service worker अपने cache का नाम बिल्ड के नाम पर रखता है, और पुराना cache तभी हटाता है जब कोई भी खुला पेज वह बिल्ड न चला रहा हो।

## कैसे साबित करें कि शिप हुई हर फ़ाइल ओबफस्केट की गई थी?

डिप्लॉय से पहले आख़िरी क़दम के रूप में [`npx afterpack verify dist`](https://www.afterpack.dev/docs/cli#afterpack-verify-dir) चलाएँ। यह बिल्ड की protection receipt में दर्ज हर फ़ाइल का hash दोबारा निकालता है, और अगर कोई फ़ाइल बदल गई हो, receipt ग़ायब हो या किसी दूसरे बिल्ड की हो, तो फ़ेल हो जाता है।

BIGBOARD इसे हर pull request पर चलाता है, और फिर अपनी डिप्लॉय स्क्रिप्ट में बिल्ड के ठीक बाद, जैसा [CI गाइड](https://www.afterpack.dev/docs/builds#the-command-surface) सुझाती है। Receipt यह भी दर्ज करती है कि क्या जानबूझकर छोड़ा गया:

```json
{
  "tool": "afterpack-vite",
  "engine": "local",
  "engineVersion": "0.2.3",
  "seedOrigin": "git",
  "files": [
    { "path": "assets/field-hockey-CK8_TNd4.js", "sha256": "0e5bf72c…", "transformed": true },
    { "path": "assets/rapier-B0bbuRDd.js", "sha256": "0f45e3d1…", "transformed": false }
  ]
}
```

## मल्टीप्लेयर गेम में ओबफस्केशन क्या नहीं रोक पाता?

यह पक्के इरादे वाले चीटर को नहीं रोकता। यह क्लाइंट को पढ़ना और patch करना धीमा कर देता है, और हर रिलीज़ के साथ उस काम को फिर से शुरू करवाता है; यह तय नहीं करता कि स्कोर किसने किया। Peer-to-peer गेम में जाँचने के लिए कोई सर्वर नहीं होता, इसलिए जिसके पास पर्याप्त समय है, उसका बदला हुआ क्लाइंट अब भी पक की पोज़िशन के बारे में झूठ बोल सकता है।

BIGBOARD.GAMES में दाँव पर ज़्यादा कुछ नहीं है, और anti-cheat सामाजिक है: दूसरा खिलाड़ी मेज़ के उस पार बैठा उसी पक को देख रहा होता है। जिस गेम में रैंकिंग या पैसा दाँव पर हो, उसे क्लाइंट के पीछे hits, moves और नतीजों की [server-authoritative](https://www.gabrielgambetta.com/client-server-game-architecture.html) जाँच चाहिए, जैसा AfterPack का [threat model](https://www.afterpack.dev/docs/threat-model#not-a-substitute-for-server-authoritative-validation) भी कहता है। ओबफस्केशन उस कोड को पढ़ने की लागत बढ़ाता है जिसे ये जाँचें कवर नहीं कर सकतीं, और ब्राउज़र को भेजे गए सीक्रेट को कोई चीज़ नहीं बचाती: बंडल में रखी API key की जगह सर्वर पर है।

## अपने गेम पर आज़माकर देखें

अपने बिल्ड में plugin जोड़ें, या किसी भी bundler के आउटपुट पर `npx afterpack@latest dist/` चलाएँ ([quickstart](https://www.afterpack.dev/docs/quickstart)), फिर नतीजे को मूल फ़ाइल के बगल में [DevTools](https://developer.chrome.com/docs/devtools) में खोलें। मुफ़्त [security scanner](https://www.afterpack.dev/security-scanner) दिखाता है कि आपका लाइव गेम आज क्या-क्या उजागर कर रहा है। [BIGBOARD.GAMES](https://bigboard.games) मुफ़्त है, और दो टैबलेट और एक दोस्त के साथ इसमें सबसे ज़्यादा मज़ा आता है।

## अक्सर पूछे जाने वाले सवाल

### क्या मैं Phaser, PixiJS या Three.js गेम को ओबफस्केट कर सकता हूँ?

हाँ। AfterPack बिल्ड किए गए JavaScript पर काम करता है, चाहे उसे किसी भी इंजन या framework ने बनाया हो, [Phaser](https://phaser.io/), [PixiJS](https://pixijs.com/) और [Three.js](https://threejs.org/) समेत। इंजन लाइब्रेरी के साथ वही करें जो BIGBOARD, Rapier के साथ करता है: उसे उसके अपने chunk में रखें, [exclude करें](https://www.afterpack.dev/docs/config#paths-exclude), और अपने गेम कोड को ओबफस्केट करें।

### क्या AfterPack WebAssembly को ओबफस्केट करता है?

अभी नहीं। आज AfterPack JavaScript को बदलता है, और इसे [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) तक ले जाने का हमारा इरादा है। BIGBOARD की फ़िज़िक्स Rapier के WebAssembly में चलती है, जो थर्ड-पार्टी है और जैसी है वैसी ही शिप होती है; उसके आसपास का गेम लॉजिक JavaScript है, और ओबफस्केट वही होता है।

### क्या ओबफस्केशन PWA और service worker के साथ काम करता है?

हाँ। BIGBOARD.GAMES एक [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) के रूप में इंस्टॉल होता है और ऑफ़लाइन भी खुलता है। Service worker के cache का नाम बिल्ड के नाम पर रखें, क्योंकि ओबफस्केट किए हुए chunks की बाइट्स उनकी फ़ाइलों के नाम बदले बिना बदल सकती हैं।

### क्या AfterPack गेम डेवलपर्स के लिए मुफ़्त है?

[Free इंजन](https://www.afterpack.dev/docs/tiers) लोकली चलता है, बिना अकाउंट और बिना किसी लिमिट के, हर preset पर, और BIGBOARD.GAMES इसी से बिल्ड होता है। [Pro](https://www.afterpack.dev/docs/pro#what-pro-buys) हर हिस्से के लिए अलग [directives](https://www.afterpack.dev/docs/directives) जोड़ता है, जैसे सिर्फ़ आपके netcode पर भारी preset, और दो [hardening transforms](https://www.afterpack.dev/docs/config#transforms-kind-enabled) भी, $49 प्रति माह से, या एक बार के top-ups के रूप में ([pricing](https://www.afterpack.dev/docs/tiers#pricing))।

### गेम के लिए कौन-सा preset इस्तेमाल करें?

पूरे बंडल के लिए [`light`](https://www.afterpack.dev/docs/presets#the-default-is-light) से शुरू करें, जो डिफ़ॉल्ट है और जिसके साथ BIGBOARD.GAMES शिप होता है। [`medium`](https://www.afterpack.dev/docs/presets#the-ladder) को मैंने अभी तक फ़्रेम लूप के अंदर नहीं मापा है। अगला गेम, [Tilt Run](https://bigboard.games/games/tilt-run), एक साथ ज़्यादा से ज़्यादा चार डिवाइसों पर हर फ़्रेम में gyroscope पढ़ता है, इसलिए टेस्ट उसी पर होगा।
