Megapack: چگونه فاکتوریو مشکل چند نفره 200 نفره را حل کرد

Megapack: چگونه فاکتوریو مشکل چند نفره 200 نفره را حل کرد
در اردیبهشت امسال به عنوان بازیکن در رویدادهای MMO KatherineOfSky. من متوجه شدم که وقتی تعداد بازیکنان به یک عدد خاص می رسد، هر چند دقیقه یکبار تعدادی از آنها "میافتند". خوشبختانه برای شما (اما نه برای من)، من یکی از آن بازیکنانی بودم که ارتباط را قطع کردم هر زمان، حتی با یک اتصال خوب. من این را به عنوان یک چالش شخصی در نظر گرفتم و شروع به جستجوی دلایل مشکل کردم. پس از سه هفته اشکال‌زدایی، آزمایش و رفع اشکال، سرانجام این باگ برطرف شد، اما سفر به این سادگی‌ها نبود.

ردیابی مشکلات بازی های چند نفره بسیار دشوار است. آنها معمولاً تحت پارامترهای شبکه بسیار خاص و شرایط بازی بسیار خاص (در این مورد، داشتن بیش از 200 بازیکن) رخ می دهند. و حتی زمانی که مشکل قابل بازتولید باشد، نمی توان آن را به درستی اشکال زدایی کرد زیرا درج نقاط شکست بازی را متوقف می کند، تایمرها را گیج می کند و معمولاً باعث می شود اتصال به پایان برسد. اما به لطف پشتکار و ابزار فوق العاده ای به نام زمخت من موفق شدم بفهمم چه خبر است.

به طور خلاصه، به دلیل وجود اشکال و اجرای ناقص شبیه‌سازی حالت تأخیر، مشتری گاهی اوقات در موقعیتی قرار می‌گیرد که مجبور می‌شود یک بسته شبکه متشکل از اقدامات انتخاب ورودی بازیکن از تقریباً 400 موجودیت بازی در یک چرخه ساعت ارسال کند. ما این را "مگا بسته" می نامیم). سرور نه تنها باید تمام این اقدامات ورودی را به درستی دریافت کند، بلکه باید آنها را برای همه مشتریان دیگر ارسال کند. اگر 200 مشتری دارید، این به سرعت تبدیل به یک مشکل می شود. پیوند به سرور به سرعت مسدود می شود و منجر به از دست رفتن بسته ها و مجموعه ای از بسته های درخواستی مجدد می شود. به تعویق انداختن اقدام ورودی باعث می شود مشتریان حتی بیشتر مگاپکت ارسال کنند و بهمن بزرگتر شود. مشتریان خوش شانس موفق به بهبودی می شوند؛ بقیه از بین می روند.

Megapack: چگونه فاکتوریو مشکل چند نفره 200 نفره را حل کرد
مشکل کاملا اساسی بود و 2 هفته طول کشید تا آن را برطرف کنم. این بسیار فنی است، بنابراین من جزئیات فنی آبدار را در زیر توضیح خواهم داد. اما ابتدا باید بدانید که از نسخه 0.17.54 که در 4 ژوئن منتشر شد، در مواجهه با مشکلات اتصال موقت، چند نفره پایدارتر شده است و مخفی کردن تاخیرها بسیار کمتر باگ شده است (کاهش سرعت و تله پورت کمتر). من همچنین نحوه پنهان کردن لگ مبارزه را تغییر داده ام و امیدوارم این کار کمی هموارتر شود.

مگا پک چند نفره - جزئیات فنی

به بیان ساده، چند نفره در یک بازی به این صورت عمل می‌کند: همه کلاینت‌ها وضعیت بازی را شبیه‌سازی می‌کنند و فقط ورودی بازیکن را دریافت و ارسال می‌کنند (به نام «عملکردهای ورودی»، اقدامات ورودی). وظیفه اصلی سرور انتقال است اقدامات ورودی و کنترل کنید که همه مشتریان اقدامات مشابهی را در یک چرخه ساعت انجام دهند. می توانید در این پست بیشتر بخوانید FFF-149.

از آنجایی که سرور باید درباره اقداماتی که باید انجام دهد تصمیم بگیرد، اقدامات بازیکن تقریباً در این مسیر حرکت می کند: اقدام بازیکن -> کلاینت بازی -> شبکه -> سرور -> شبکه -> مشتری بازی. این بدان معنی است که عمل هر بازیکن تنها پس از انجام یک سفر رفت و برگشت در سراسر شبکه انجام می شود. به همین دلیل، بازی به طرز وحشتناکی کند به نظر می رسید، بنابراین تقریباً بلافاصله پس از معرفی چند نفره در بازی، مکانیزمی برای پنهان کردن تاخیرها معرفی شد. پنهان کردن تاخیر ورودی بازیکن را بدون در نظر گرفتن اقدامات سایر بازیکنان و تصمیمات سرور شبیه سازی می کند.

Megapack: چگونه فاکتوریو مشکل چند نفره 200 نفره را حل کرد
فاکتوریو حالت بازی دارد حالت بازی وضعیت کامل کارت، بازیکن، موجودیت ها و هر چیز دیگری است. این به طور قطعی در همه مشتریان بر اساس اقدامات دریافت شده از سرور شبیه سازی می شود. حالت بازی مقدس است و اگر زمانی شروع به تفاوت با سرور یا هر کلاینت دیگری کرد، پس همگام سازی اتفاق می افتد.

اما حالت بازی ما یک حالت تاخیر داریم وضعیت تأخیر. این شامل یک زیر مجموعه کوچک از حالت پایه است. وضعیت تأخیر مقدس نیست و به سادگی تصویری از وضعیت بازی در آینده بر اساس ورودی های بازیکن را نشان می دهد اقدامات ورودی.

برای این منظور، ما یک کپی از ایجاد شده را ذخیره می کنیم اقدامات ورودی در صف تاخیر

Megapack: چگونه فاکتوریو مشکل چند نفره 200 نفره را حل کرد
یعنی در پایان فرآیند در سمت مشتری، تصویر چیزی شبیه به این است:

  1. درخواست می کنیم اقدامات ورودی همه بازیکنان به حالت بازی نحوه دریافت این اقدامات ورودی از سرور.
  2. ما همه چیز را از صف تاخیر حذف می کنیم اقدامات ورودی، که طبق گفته سرور قبلاً روی آنها اعمال شده است حالت بازی.
  3. حذف کنید وضعیت تأخیر و آن را بازنشانی کنید تا دقیقاً شبیه به آن به نظر برسد حالت بازی.
  4. ما همه اقدامات را از صف تاخیر تا وضعیت تأخیر.
  5. بر اساس داده ها حالت بازی и وضعیت تأخیر ما بازی را به بازیکن ارائه می کنیم.

همه اینها در هر اندازه تکرار می شود.

خیلی سخت؟ آرام نشو، این همه ماجرا نیست. برای جبران اتصالات اینترنتی نامطمئن، دو مکانیسم ایجاد کرده ایم:

  • تیک های از دست رفته: زمانی که سرور تصمیم می گیرد اقدامات ورودی در ضربان بازی اعدام خواهد شد، پس اگر دریافت نکرد اقدامات ورودی برخی از بازیکنان (به عنوان مثال، به دلیل افزایش تاخیر)، او منتظر نمی ماند، اما به مشتری اطلاع می دهد: "من شما را در نظر نگرفتم. اقدامات ورودی، سعی می کنم آنها را در نوار بعدی اضافه کنم." این کار به این دلیل انجام می شود که به دلیل مشکلات مربوط به اتصال (یا رایانه) یک بازیکن، به روز رسانی نقشه برای بقیه کاهش نمی یابد. شایان ذکر است که اقدامات ورودی نادیده گرفته نمی شوند، بلکه به سادگی کنار گذاشته می شوند.
  • تأخیر کامل رفت و برگشت: سرور سعی می کند حدس بزند که تأخیر رفت و برگشت بین کلاینت و سرور برای هر کلاینت چقدر است. هر 5 ثانیه، در صورت لزوم، یک تأخیر جدید با مشتری مذاکره می کند (بر اساس نحوه رفتار اتصال در گذشته)، و بر این اساس تأخیر رفت و برگشت را افزایش یا کاهش می دهد.

این مکانیسم ها به خودی خود بسیار ساده هستند، اما وقتی با هم استفاده می شوند (که اغلب با مشکلات اتصال اتفاق می افتد)، مدیریت منطق کد و با موارد لبه زیاد دشوار می شود. علاوه بر این، هنگامی که این مکانیسم ها وارد عمل می شوند، سرور و صف تاخیر باید به درستی ویژه را پیاده سازی کنند اقدام ورودی نامیده می شود StopMovementInTheNextTick. به لطف این، اگر در اتصال مشکلی وجود داشته باشد، شخصیت به تنهایی اجرا نمی شود (مثلاً در مقابل قطار).

حال باید نحوه عملکرد انتخاب موجودیت را برای شما توضیح دهیم. یکی از انواع منتقل شده اقدام ورودی تغییر در وضعیت انتخاب موجودیت است. به همه می گوید که بازیکن روی کدام موجودیت شناور است. همانطور که می توانید تصور کنید، این یکی از رایج ترین اقدامات ورودی است که توسط مشتریان ارسال می شود، بنابراین برای صرفه جویی در پهنای باند، آن را بهینه سازی کرده ایم تا کمترین فضای ممکن را اشغال کند. روش کار به این صورت است که با انتخاب هر موجودیت، به جای ذخیره مختصات نقشه مطلق و با دقت بالا، بازی یک افست نسبی با دقت پایین از انتخاب قبلی را ذخیره می کند. این به خوبی کار می کند زیرا انتخاب های ماوس تمایل زیادی به انتخاب قبلی دارند. این امر دو الزام مهم را ایجاد می کند: اقدامات ورودی آنها هرگز نباید نادیده گرفته شوند و باید به ترتیب صحیح تکمیل شوند. این الزامات برای حالت بازی. اما از آنجایی که وظیفه وضعیت تأخیر در "به اندازه کافی خوب به نظر می رسند" برای بازیکن، آنها در حالت تاخیر راضی نیستند. وضعیت تأخیر را در نظر نمی گیرد بسیاری از موارد لبه، با پرش از چرخه های ساعت و تغییر تاخیرهای انتقال رفت و برگشت مرتبط است.

شما از قبل می توانید حدس بزنید که این به کجا می رود. ما بالاخره شروع به دیدن دلایل مشکل مگاپک می کنیم. ریشه مشکل این است که منطق انتخاب موجودیت بر آن تکیه دارد وضعیت تأخیر، و این حالت همیشه حاوی اطلاعات صحیح نیست. بنابراین، یک مگاپکت چیزی شبیه به زیر تولید می شود:

  1. پخش کننده مشکل اتصال دارد.
  2. مکانیسم هایی برای پرش از چرخه های ساعت و تنظیم تأخیر انتقال رفت و برگشت وارد عمل می شوند.
  3. صف حالت تاخیر این مکانیسم ها را در نظر نمی گیرد. این باعث می شود برخی از اقدامات به صورت نابهنگام حذف شوند یا به ترتیب اشتباه انجام شوند و در نتیجه نادرست باشند وضعیت تأخیر.
  4. پخش کننده مشکل اتصال دارد و برای اینکه به سرور برسد تا 400 سیکل را شبیه سازی می کند.
  5. در هر تیک، یک اقدام جدید، تغییر انتخاب موجودیت، تولید و برای ارسال به سرور آماده می شود.
  6. کلاینت یک دسته بزرگ از 400+ تغییرات انتخاب موجودیت را به سرور می فرستد (و با سایر اقدامات: حالت های تیراندازی، حالت های راه رفتن و غیره نیز از این مشکل رنج می برند).
  7. سرور 400 اقدام ورودی دریافت می کند. از آنجایی که امکان رد شدن از هیچ اقدام ورودی وجود ندارد، به همه مشتریان دستور می دهد تا آن اقدامات را انجام دهند و آنها را به سراسر شبکه ارسال می کند.

طعنه آمیز این است که مکانیزمی که برای صرفه جویی در پهنای باند طراحی شده بود، منجر به ایجاد بسته های شبکه عظیمی شد.

ما این مشکل را با رفع تمام موارد لبه پشتیبانی از به‌روزرسانی و صف پشتیبان برطرف کردیم. اگرچه کمی زمان برد، اما در نهایت ارزش آن را داشت که به جای اتکا به هک های سریع، آن را درست انجام دهید.

منبع: www.habr.com

اضافه کردن نظر