في شهر مايو من هذا العام ، شاركت كلاعب في
حدث KatherineOfSky MMO . لقد لاحظت أنه عندما يصل عدد اللاعبين إلى عدد معين ، كل بضع دقائق "يسقط". لحسن الحظ بالنسبة لك (ولكن ليس بالنسبة لي) ، كنت أحد هؤلاء اللاعبين الذين انفصلوا في
كل مرة ، حتى مع وجود اتصال جيد. أخذت هذا كتحدي شخصي وبدأت في البحث عن أسباب المشكلة. بعد ثلاثة أسابيع من تصحيح الأخطاء والاختبار والإصلاح ، تم إصلاح الخطأ في النهاية ، لكن هذه الرحلة لم تكن بهذه البساطة.
من الصعب للغاية تعقب مشاكل الألعاب متعددة اللاعبين. عادة ما تنشأ في ظروف محددة للغاية من معلمات الشبكة وفي ظروف محددة للغاية للعبة (في هذه الحالة ، وجود أكثر من 200 لاعب). وحتى عندما يكون من الممكن إعادة إنتاج المشكلة ، لا يمكن تصحيحها بشكل صحيح ، لأن إدراج نقاط التحكم يوقف اللعبة ، ويخلط بين الموقتات ويؤدي عادة إلى إنهاء الاتصال بسبب تجاوز وقت الانتظار. ولكن بفضل العناد والأداة الرائعة المسماة
الخرقاء ، تمكنت من معرفة ما كان يحدث.
باختصار: نظرًا لحدوث خطأ وتنفيذ غير كامل لمحاكاة حالة التأخير ، يجد العميل أحيانًا نفسه في موقف يتعين عليه فيه إرسال حزمة شبكة في دورة واحدة على مدار الساعة ، تتكون من إجراءات اللاعب لاختيار حوالي 400 كيان لعبة (نسميها "حزمة ضخمة"). بعد ذلك ، لا ينبغي أن يتلقى الخادم جميع إجراءات الإدخال هذه بشكل صحيح فحسب ، بل يجب أيضًا إرسالها إلى جميع العملاء الآخرين. إذا كان لديك 200 عميل ، فسيصبح هذا مشكلة بسرعة. يتم انسداد القناة إلى الخادم بسرعة ، مما يؤدي إلى فقد الحزمة وتتابع الحزم التي تم إعادة طلبها. يؤدي تأجيل إجراءات الإدخال إلى حقيقة أن المزيد من العملاء يبدأون في إرسال مجموعات كبيرة الحجم ، ويصبح الانهيار أقوى. يتمكن العملاء الناجحون من التعافي ، وكل ما تبقى "يسقط".

كانت المشكلة أساسية للغاية ، واستغرق الأمر أسبوعين لإصلاحها. إنها تقنية تمامًا ، وسأشرح أدناه التفاصيل الفنية المثيرة. ولكن عليك أولاً أن تعرف أنه منذ الإصدار 0.17.54 ، الذي تم إصداره في 4 يونيو ، في مواجهة مشكلات الاتصال المؤقت ، أصبح لاعبو الوسائط المتعددة أكثر استقرارًا ، كما أن إخفاء التأخيرات أقل بكثير من العربات التي تجرها الدواب (أقل الكبح والانتقال عن بُعد). بالإضافة إلى ذلك ، لقد غيرت طريقة إخفاء التأخير في القتال وآمل أن يكونوا أكثر سلاسة بفضل هذا.
متعدد المستخدمين Megapack - التفاصيل الفنية
بعبارات بسيطة ، يعمل اللاعبون المتعددين في اللعبة على النحو التالي: يحاكي جميع العملاء حالة اللعبة ، ويستقبلون ويرسلون فقط مدخلات اللاعب (تسمى "إجراءات الإدخال" ،
إجراءات الإدخال ). تتمثل المهمة الرئيسية للخادم في نقل
إجراءات الإدخال والتحكم في قيام جميع العملاء بنفس الإجراءات في دورة واحدة. اقرأ المزيد عن هذا في
المنشور FFF-149 .
نظرًا لأن الخادم يجب أن يتخذ قرارات بشأن الإجراءات التي يتعين القيام بها ، فإن إجراءات اللاعب تتحرك على هذا المسار: إجراء اللاعب -> عميل اللعبة -> الشبكة -> الخادم -> عميل اللعبة. هذا يعني أن إجراء كل لاعب يتم تنفيذه فقط بعد قيامه بمسار ذهابًا وإيابًا عبر الشبكة. لهذا السبب ، ستبدو اللعبة بطيئة بشكل رهيب ، لذا فور ظهور اللاعب المتعدد في اللعبة ، تم تقديم آلية لإخفاء التأخير. إخفاء التأخير يقلد مدخلات اللاعب دون مراعاة تصرفات اللاعبين الآخرين وقرارات الخادم.
Factorio لديه حالة
لعبة تسمى
Game State - هذه هي الحالة الكاملة للخريطة واللاعب والكيانات وكل شيء آخر. يتم محاكاته بشكل نهائي في جميع العملاء بناءً على الإجراءات التي تم تلقيها من الخادم. حالة اللعبة مقدسة ، وإذا بدأت في الاختلاف عن الخادم أو أي عميل آخر ، يحدث عدم التزامن.
بالإضافة إلى
Game State ، لدينا حالة
زمن انتقال Latency State . أنه يحتوي على مجموعة فرعية صغيرة من الدولة الأرض.
حالة زمن الانتقال ليست مقدسة وتقدم ببساطة صورة لكيفية ظهور حالة اللعبة في المستقبل بناءً على
إجراءات الإدخال التي قدمها اللاعب.
للقيام بذلك ، نقوم بتخزين نسخة من
إجراءات الإدخال التي تم إنشاؤها في قائمة انتظار التأخير.
وهذا هو ، في نهاية العملية على جانب العميل ، تبدو الصورة مثل هذا:
- قم بتطبيق إجراءات الإدخال الخاصة بجميع اللاعبين على حالة اللعبة حيث تم استلام إجراءات الإدخال هذه من الخادم.
- نزيل من قائمة انتظار التأخير جميع إجراءات الإدخال التي طبقًا للخادم ، تم تطبيقها بالفعل على Game State .
- احذف حالة Latency وأعد ضبطها بحيث تبدو تمامًا مثل حالة اللعبة .
- قم بتطبيق جميع الإجراءات من قائمة انتظار التأخير إلى حالة الاختفاء .
- استنادًا إلى البيانات الواردة من Game State و Latency State ، نوفر اللعبة للاعب.
كل هذا يتكرر في كل تدبير.
معقدة للغاية؟ لا تسترخي ، هذا ليس كل شيء. للتعويض عن اتصالات الإنترنت غير الموثوق بها ، أنشأنا آليتين:
- علامات التجزئة المفقودة: عندما يقرر الخادم أن إجراءات الإدخال سيتم تنفيذها في اللعبة ، فإذا لم يتلق إجراءات إدخال بعض اللاعبين (على سبيل المثال ، بسبب زيادة التأخير) ، فلن ينتظر ، لكنه سيخبر هذا العميل "لم أضع في الاعتبار إجراءات الإدخال الخاصة بك ، سأحاول إضافتها إلى الإجراء التالي. " يتم ذلك بحيث ، بسبب مشاكل في الاتصال (أو مع الكمبيوتر) من لاعب واحد ، لن يتباطأ تحديث الخريطة للجميع. تجدر الإشارة إلى أنه لا يتم تجاهل إجراءات الإدخال ، ولكن تم تأجيلها ببساطة.
- تأخير الرحلة ذهابًا وإيابًا: يحاول الخادم تخمين مدى تأخر الرحلة ذهابًا وإيابًا بين العميل والخادم لكل عميل. كل 5 ثوانٍ ، إذا لزم الأمر ، يناقش مع العميل تأخيرًا جديدًا (حسب كيفية تصرف الاتصال في الماضي) ، وبالتالي يزيد أو يقلل التأخير في نقل البيانات ذهابًا وإيابًا.
هذه الآليات هي في حد ذاتها بسيطة للغاية ، ولكن عندما يتم استخدامها معًا (والتي تحدث غالبًا مع مشكلات الاتصال) ، يصبح من الصعب إدارة منطق الكود ومعه مجموعة من الحالات الحدودية. بالإضافة إلى ذلك ، عندما تدخل هذه الآليات في الاعتبار ، يجب أن يقوم الخادم وقائمة انتظار التأخير بشكل صحيح بتنفيذ إجراء
إدخال خاص يسمى
StopMovementInTheNextTick . بسبب هذا ، مع وجود مشاكل في الاتصال ، لن يتم تشغيل الشخصية بنفسها (على سبيل المثال ، تحت القطار).
أنت الآن بحاجة إلى أن توضح لك كيف يعمل اختيار الكيان. أحد أنواع
إجراء الإدخال الذي تم تمريره هو التغيير في حالة اختيار الكيان. إنه يخبر الجميع بالكيان الذي يحوم عليه اللاعب. كما يمكنك أن تفهم ، يعد هذا أحد أكثر إجراءات الإدخال شيوعًا التي يرسلها العملاء ، لذلك ، لتوفير عرض النطاق الترددي ، قمنا بتحسينه بحيث يستغرق أقل مساحة ممكنة. يتم تطبيق ذلك على النحو التالي: عند اختيار كل كيان ، بدلاً من الحفاظ على الإحداثيات المطلقة وعالية الدقة للخريطة ، تحتفظ اللعبة بالإزاحة النسبية المنخفضة الحالية من الخيار السابق. هذا يعمل بشكل جيد لأن اختيار الماوس يحدث عادة بالقرب من التحديد السابق. لهذا السبب ، ينشأ شرطان مهمان: يجب ألا يتم تخطي
إجراءات الإدخال ويجب تنفيذها بالترتيب الصحيح. يتم استيفاء هذه المتطلبات لـ
Game State . ولكن نظرًا لأن مهمة
حالة Latency هي "أن تبدو جيدة بما يكفي" للاعب ، فهي غير راضية عن حالة التأخير. لا تأخذ
حالة الاختفاء في الاعتبار
العديد من حالات الحدود المرتبطة بتخطي الدورات وتغيير التأخيرات ذهابًا وإيابًا.
يمكنك بالفعل تخمين أين كل شيء يسير. أخيرًا ، نبدأ في رؤية أسباب مشكلة megapackage. جذر المشكلة هو أنه عند تحديد ما إذا كان سيتم تمرير إجراء تغيير التحديد ، يعتمد منطق اختيار الكيان على حالة
الكمون ، ولا تحتوي هذه الحالة دائمًا على المعلومات الصحيحة. لذلك ، يتم إنشاء megapackage مثل هذا:
- لاعب لديه مشكلة اتصال.
- تدخل آليات تخطي الساعات وتنظيم تأخير رحلة الذهاب والإياب.
- انتظار حالة التأخير لا يفسر هذه الآليات. يؤدي هذا إلى حذف بعض الإجراءات قبل الأوان أو تنفيذها بترتيب خاطئ ، مما يؤدي إلى حالة اختفاء غير صحيحة.
- يواجه اللاعب مشكلة في الاتصال وهو يحاكي ما يصل إلى 400 دورة على مدار الساعة.
- في كل دورة على مدار الساعة ، يتم إنشاء إجراء جديد ، وهو تغيير اختيار كيان ، ويتم إعداده للإرسال إلى الخادم.
- يرسل العميل إلى الخادم مجموعة كبيرة تضم أكثر من 400 تغيير في اختيار الكيانات (ومع إجراءات أخرى: حالة التصوير والمشي وما إلى ذلك ، والتي عانت أيضًا من هذه المشكلة).
- يستقبل الخادم 400 إجراء إدخال. نظرًا لأنه لا يُسمح له بتخطي إجراء إدخال واحد ، فإنه يطلب من جميع العملاء تنفيذ هذه الإجراءات وإرسالها عبر الشبكة.
المفارقة هي أن الآلية المصممة لحفظ عرض النطاق الترددي للقناة خلقت حزم شبكة ضخمة نتيجة لذلك.
لقد حللنا هذه المشكلة عن طريق تصحيح جميع حالات الخط الحدودي لتحديث قائمة انتظار التأخير ودعمها. على الرغم من أن الأمر استغرق بعض الوقت ، إلا أنه في النهاية كان يستحق تنفيذ كل شيء بشكل صحيح وعدم الاعتماد على الاختراقات السريعة.