العودة إلى المشاريع

كيف يعمل Galactic Games

موقع ألعاب على المتصفح تنشئ فيه حسابا، وترى من هو متصل، وتتحدى شخصا وتلعب معه مباشرة. كل ذلك يعمل على Cloudflare Worker واحد، دون أي خوادم خاصة بي أحتاج إلى صيانتها.

الدور
بمفردي، من التصميم إلى النشر
التقنيات المستخدمة
JavaScript, three.js, Cloudflare Workers, Durable Objects, SQLite
الحالة
متاح على games.galacticstudios.net
مركز Galactic Games، يظهر فيه شبكة الألعاب وتبويبا اللاعبين واللعب الجماعي

الهدف

أردت بيتا للألعاب الصغيرة التي أبنيها، حيث تكون اللعب مع صديق بنقرة واحدة لا بتنزيل. وهذا يعني حسابات حقيقية، وردهة تتحدث لحظيا، ومباريات عبر الإنترنت تبدو عادلة. كان لا بد أيضا أن يكلف تشغيله شيئا يقارب الصفر طالما هو صغير.

شكل النظام

يقدم Worker واحد الموقع الثابت وواجهة برمجة تطبيقات صغيرة. وكل ما يحتاج إلى تذكر حالته يعيش داخل Durable Object: نسخة واحدة من صنف تُبقيه Cloudflare قيد التشغيل، ولها تخزينها الخاص.

تتصل المتصفحات بـ Worker واحد، الذي يوجّه الطلبات إلى كائنات Hub وRoom وArena الدائمة المتصفحاتHTTP وWebSocket Workerالموقع ومسارات /api Hubالحسابات، الردهة، النتائج Roomواحدة لكل رمز، ولاعبان اثنان ArenaKnife Duels، حتى 4 ضد 4
  • Hub نسخة واحدة ولها قاعدة بيانات SQLite خاصة بها. تحفظ الحسابات، والجلسات، والردهة الحية، وسجلات المباريات والنتائج.
  • يُنشأ Room لكل رمز من 5 أحرف. وهو ينقل الرسائل بين مقبسين اثنين فقط، المضيف والضيف. وأي مقبس ثالث يُخبَر بأن الغرفة ممتلئة.
  • يشغّل Arena مباريات Knife Duels، من 1 ضد 1 حتى 4 ضد 4.

من التحدي إلى المباراة

  1. تفتح تبويب اللاعبين. يبقي متصفحك اتصال WebSocket واحدا مفتوحا مع Hub، الذي يُعلم الجميع بمن هو متصل.
  2. تتحدى شخصا. فيراه فورا ويقبل أو يرفض.
  3. عند القبول، ينشئ Hub رمز غرفة ويرسل الإشارة إلى كلا اللاعبين.
  4. تنضم كلتا اللعبتين إلى ذلك Room، الذي ينقل المدخلات بينهما.
  5. عند انتهاء المباراة، تُبلغ لعبتا اللاعبين بالنتيجة. ولا تُحتسب إلا إذا اتفقتا.

يستخدم مقبس الردهة واجهة إسبات WebSocket، بحيث لا تُبقي ردهة هادئة Hub مستيقظا وتُحتسب تكلفته بينما الناس يجلسون فقط على الصفحة.

الحفاظ على العدالة

تشغيل كل مباراة على الخادم مكلف جدا لموقع صغير، لذلك وزعت الثقة بدلا من ذلك. في Oathsteel، مبارزة السيوف، يقرر المضيف الضربات والجولات، ويملك كل لاعب حركته الخاصة، بينما يُحرَّك المقاتل الآخر بالمدخلات المنقولة. تبقى الحركة سريعة الاستجابة على الطرفين، ولطرف واحد الكلمة الفصل في أي شيء يحدد الفائز.

لا تصل النتائج إلى لوحة المتصدرين إلا للمباريات التي تتم عبر الردهة، وفقط عندما تُبلغ لعبتا اللاعبين بالنتيجة نفسها. ولأن Knife Duels تضم لاعبين أكثر في المباراة الواحدة، تُحتسب النتيجة مرة واحدة، عندما يتفق عليها معظم اللاعبين البشر.

مقاتلان يتواجهان في حلبة مبارزة Oathsteel
Oathsteel، مبارزة السيوف. تمر مباريات رمز الغرفة وتحديات الردهة كلتاهما عبر نفس Room.

حسابات مبنية بشكل صحيح

تُشفَّر كلمات المرور بخوارزمية PBKDF2-SHA256 بـ 100,000 تكرار. وتُخزَّن رموز الجلسات مشفَّرة أيضا، بحيث لا تكشف قاعدة بيانات مسرَّبة بيانات دخول أي أحد.

اختبار اللعب الجماعي

لدى Room وHub فحوص آلية تعمل مقابل Worker محلي: 8 فحوص لعملية النقل، و21 للحسابات والردهة والنتائج. تفصل Knife Duels منطق لعبتها عن three.js والصفحة، بحيث يمكن اختبارها بمعزل عن غيرها بواسطة 178 اختبار وحدة.

أما من أجل الاختبار الحقيقي، فسكربت يشغّل متصفحين بلا واجهة عبر مبارزة كاملة عبر الإنترنت. والمشكلة أن متصفحين يُرسمان بالبرمجيات على جهاز واحد يستنزف كل منهما موارد الآخر، فيعملان بسرعة أقل بكثير من الواقع، ويجب أن يكون كل انتظار في الاختبار سخيا.

ما تعلمته من ذلك

  • تجعل Durable Objects حالة اللعب الجماعي سهلة الفهم: كائن واحد، مكان واحد تعيش فيه الحقيقة.
  • إضافة لعبة جديدة تعني مجلدا وسطرا واحدا في قائمة، ولهذا يستمر المركز في النمو.
  • عدم وجود خطوة بناء واستضافة three.js ذاتيا يعنيان أن الموقع يُنشر في ثوان ولا شيء فيه قد يتعطل بين الإصدارات.