ما يميّز لعبة MMORPG عن لعبة فردية هو الخادم القائم خلف كل ما تراه. في هذا الجزء الأول من يوميات تطوير Ancient Online: Remastered نشرح كيف نبني لعبة MMORPG بمحرك Unreal Engine 5.8: كيف يُقسَّم العمل بين العميل والخادم، وكيف يُحاكى العالم، وكيف نستطيع تحرير عالم واحد موحّد مباشرةً وهو يعمل.
قطعتان: العميل والخادم
تتكون Ancient Online من برنامجين منفصلين:
- العميل مكتوب بلغة C++ على Unreal Engine 5.8. ومهمته العرض والصوت والواجهة والإدخال.
- الخادم مستقل عن Unreal: كتبناه من الصفر بلغة C++23. هنا تعمل كل قواعد اللعبة.
لماذا كتبنا الخادم منفصلًا لا داخل المحرك؟ لأن ما يحتاجه خادم MMORPG يختلف عما يحتاجه محرك ألعاب: لا رسوم فيه، لكن فيه آلاف الكيانات، وبيانات دائمة، ومدد تشغيل طويلة، وحاجة إلى أداء يمكن التنبؤ به. الخادم المستقل يتيح لنا أن نؤدي العمل المطلوب فقط وأن نتحكم في كل بايت.
الخادم صاحب السلطة: عدم الثقة بالعميل
قاعدتنا الأساسية هي: العميل يدّعي، والخادم يقرر.
- الحركة: يذهب إدخال اللاعب إلى الخادم، والخادم يحسب الموقع. يعرض العميل الموقع الذي يبلّغه به الخادم مستخدمًا استيفاءً سلسًا. فالعميل الذي «ينقل نفسه آنيًّا» أو يعبر جدارًا لا يصل إلى أي مكان في نظر الخادم.
- القتال: نتائج مثل الضرر والإصابات والدفع إلى الخلف تُحسب على الخادم. فمثلًا، الخادم هو من يقرر هل تُسقط ضربة الكومبو الخصم أرضًا، ويبثّ النتيجة إلى الجميع في اللحظة نفسها.
- الاقتصاد: العناصر والعملة وعمليات المتجر لا تتغير إلا على الخادم وفي قاعدة البيانات.
ثمن هذا النهج هو ضرورة إدارة تأخر الشبكة جيدًا؛ والمكسب عالم يكون الغش فيه أصعب بكثير وتسري فيه القواعد نفسها على الجميع.
حلقة عالم بتردد 25 Hz
يحدّث الخادم العالم 25 مرة في الثانية. وفي كل خطوة يتقدم ذكاء الوحوش الاصطناعي والحركة والقتال وتأثيرات المهارات والطقس. الخطوة الثابتة تُبقي المحاكاة قابلة للتنبؤ وتضمن أن يعطي الإدخال نفسه النتيجة نفسها دائمًا.
لا يحتاج كل لاعب إلى معرفة كل شيء. يقسّم الخادم العالم إلى شبكة ويرسل إلى كل لاعب تحديثات الكيانات الواقعة ضمن منطقة اهتمامه فقط (أي القريبة منه). وهذا يُبقي حركة الشبكة معقولة حتى في مدينة مزدحمة.
بروتوكول ثنائي خفيف
لا JSON ولا REST بين العميل والخادم؛ كل رسالة حزمة ثنائية ذات تخطيط ثابت. وهذا يوفّر عرض النطاق ووقت المعالج معًا. وحين نضيف نظامًا جديدًا (مثل الطقس أو الحركة أو خدمة الحساب داخل اللعبة) نكتب له عقد حزم مستقلًّا ذا إصدارات، ونستخدم ملفات ترويسة مشتركة لضمان أن يعمل العميل والخادم بالعقد نفسه.
الحفظ الدائم: الحفظ دون أن تنتظر اللعبة
بيانات اللاعبين محفوظة في قاعدة بيانات PostgreSQL. لكن أن تنتظر حلقة العالم قاعدة البيانات في كل خطوة أمر غير مقبول. لذلك يتم الحفظ في الخلفية بأسلوب الكتابة المؤجلة (write-behind): يضع خادم العالم التغييرات في طابور (Redis)، ويثبّتها كاتب يعمل في الخلفية في قاعدة البيانات على دفعات. فسير اللعبة لا يعتمد على سرعة قاعدة البيانات.
القنوات وخادم تسجيل الدخول
يتصل اللاعبون أولًا بخادم تسجيل الدخول الذي يتولى التحقق من الحساب واختيار الشخصية والجلسة. ثم ينتقلون إلى إحدى قنوات اللعب الأربع (CH1–CH4). الحالة المباشرة للقنوات معروضة في صفحة حالة الخوادم في موقع اللعبة.
عالم واحد موحّد يُحرَّر مباشرةً
صُمّم عالم Ancient Online ليكون عالمًا واحدًا موحّدًا لا خرائط منفصلة تفصل بينها شاشات تحميل؛ وهو مقسّم إلى خلايا ويُحمَّل بالتدفق.
محتوى العالم (التضاريس والأجسام ومواضع الوحوش) لا يُحفظ في الشيفرة بل في قاعدة البيانات، بإصدارات. ونستطيع تحرير هذا العالم بمحرر عالم داخل اللعبة: تُجرى التغييرات أولًا في مسودة، ثم تُفحص، ثم تُنشر. كل نشر ينشئ إصدارًا جديدًا، ويتحقق العميل من أن بيانات العالم التي لديه تطابق بيانات الخادم بمقارنة بصمة البيانات. فإن وُجد اختلاف انتظر تحديث البيانات قبل أن يكمل الدخول إلى اللعبة.
المهام: Lua لغةً للبرمجة النصية
تُكتب المهام وحوارات شخصيات NPC بلغة Lua 5.4 على الخادم. وهذا يتيح لنا تطوير المهام واختبارها دون إعادة بناء الخادم.
رسائل اللاعبين لا تغادر خوادمنا أبدًا
لا نستخدم خدمة ترجمة خارجية لترجمة الدردشة داخل اللعبة. نشغّل على خوادمنا نموذج ترجمة محليًّا يعمل على المعالج (CPU) وحده؛ ولا تُرسَل رسائل اللاعبين إلى أي API خارجي. بهذا يفهم اللاعبون الذين يتحدثون لغات مختلفة بعضهم بعضًا دون أن تغادر رسائلهم الاستوديو أبدًا.
ما التالي
الجزء الثاني من يوميات التطوير يتناول القرارات التي اتخذناها ونحن نجعل العالم نفسه قابلًا للعب بالفأرة وشاشة اللمس ويد التحكم. وللتعرف على الاستوديو اقرأ من هي Astronaut Entertainment؟؛ وللتعرف على اللعبة نفسها راجع صفحة الألعاب.


