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

بازی ها از نظر شبکه به دو گروه پر ترافیک و کم ترافیک تقسیم می شوند. تعداد کاربران هم زمان، میزان داده ای که باید از هر بازی کن به سرور ارسال شود، میزان داده ای که سرور باید به هر بازی کن ارسال کند و تعداد دفعات مورد نیاز برای ارسال داده ها این موضوع را مشخص می کنند. بعضی بازی ها مثل بازی های MMO تحت وب شبیه تراویان میزان داده بسیار کمی را در فواصل زمانی طولانی بین کلاینت و سرور جا به جا می کنند و بعضی مثل Call of duty باید در ثانیه حدود 40 بار بخشی از داده های هر کلاینت را به سرور ارسال کنند و وضعیت فعلی دنیای بازی را نیز از سرور بگیرند. همچنین از نظر زمان پاسخ گویی، بعضی بازی ها طوری هستند که پاسخ می تواند چند صد میلی ثانیه بعد از سرور به کلاینت برگردد و در برخی بازی ها بیش از چند ده میلی ثانیه فاجعه محسوب می شود.

بازی هایی مثل clash royale که در وسط دو گروه بسیار سریع و بسیار کند قرار می گیرند و ارتباط realtime نسبتا سریع برای آن ها لازم است ولی اگر مثلا یک پیام 200 میلی ثانیه دیر برسد هم در کلاینت می توان جلوی بروز مشکل و متوجه شدن کاربر را گرفت. در مقابل برای بازی های FPS و Racing سرور حتما باید سریع باشد و همه چیز را با بالاترین سرعت ممکن بین کلاینت ها جا به جا کند و تصمیمات خود را نیز بگیرد. در بازی هایی مثل Clash of clans حتی یکی دو ثانیه هم قابل تحمل است و فشار شدیدی روی سرور نیست زیرا بازی کلا به شکل async می باشد و اصلا ارتباط real time بین کاربران برقرار نمی شود.

در نتیجه صحبت های بالا بازی ها را به سه گروه تقسیم می کنیم. گروه اول بازی هایی که تحمل دیر رسیدن پیام را تا حد زیادی دارند و در آن ها یا کاربران به طور مستقیم در ارتباط نیستند و یا اگر هستند طول کشیدن زمان حد اقل اگر متداول نباشد قابل پذیرش است. همه بازی های MMO تحت مرورگر وب و async multiplayer که بازی کنان لزوما هم زمان در بازی شرکت نمی کنند از این دسته هستند. شاید بتوان بازی هایی مثلا تخته نرد، انواع بازی با ورق و منچ و ... را نیز از این دسته دانست، هر چند گاهی شرکت ها و یا کاربران توقع ندارند سرور این بازی ها نیز چندان کند عمل کند. گروه دوم بازی هایی مثل Clash Royale هستند که کاربران با هم ارتباط real time دارند ولی دیر رسیدن پیام تا چند صد میلی ثانیه در گاهی اوقات قابل پذیرش است. گروه سوم بازی های بسیار سریع معمولا جنگی و یا مسابقه ای بسیار سریع هستند و نیاز است که اطلاعات زیادی در چند ده میلی ثانیه بین کاربران جا به جا شود و سرور نیز تصمیمات را بسیار سریع بگیرد. نوع دیگری از بازی ها هستند که از تعداد کاربران بسیار بالا پشتیبانی می کنند که MMO های معمول مثل World of Warcraft هستند که همان طور که در پست قبل گفته شد آن ها را بعدا بررسی خواهیم کرد.

 

روش های ساخت

برای ساخت بازی ها گروه اول امکان استفاده از تکنولوژی های معمول ساخت نرم افزار های تحت وب و Web API ها وجود دارد و می توان آن ها را به شکل stateless و با تکنولوژی هایی مثل ASP.NET Web API و PHP پیاده سازی کرد. ممکن است به دلایل مختلف شما این کار را ترجیح ندهید اما از نظر توانایی ساخت شما می توانید هر بازی و state فعلی آن را کاملا در database خود مدل کنید و با صدا زدن WebA API های مختلف آن را به روز کنید و یا وضعیت آخر بازی را از سرور بگیرید. مهمترین مزیت این کار سادگی پیاده سازی و آشنا بودن بسیاری از افراد با این تکنولوژی ها می باشد. در صورتی که خواستید از چنین تکنولوژی هایی برای ساخت بازی خود استفاده کنید، دقت کنید که از یک تکنولوژی مناسب ترجیحا با قابلیت های پردازش نامتقارن asynchronous استفاده کنید و databaseی را برگزینید که توانایی داشتن performance بالا هنگام نوشتن حجم زیادی از داده را داشته باشد.

نکته قابل توجه این است که شما می توانید این بازی ها را به شکل stateful و با تکنولوژی های مورد نیاز برای ساخت بازی های آنلاین گروه دو و سه نیز پیاده کنید و نسبت به منطق بازی ممکن است این کار را ترجیح هم بدهید. قبل از توضیح دادن روش ساخت بازی های گروه دو و سه مفاهیم مهم مربوط را بررسی می کنیم.

 

مفاهیم مربوط به ساخت سرور های بازی real time

اولین مفهوم مهم Stateless و یا Stateful بودن سرور است. یک سرور Stateless هیچ داده ای در باره وضعیت فعلی برنامه را در حافظه نگه نمی دارد و همه توابع کل داده ها را روی پایگاه داده ذخیره کرده و بعد نیز هنگام نیاز از روی پایگاه داده می خوانند. این روش در گذشته با تعداد کمتر کاربران و توقع کمتر برای زمان پاسخ گویی باعث می شد مشکل scale شدن برنامه به تعداد کاربر بالا کاملا حل شود و بتوان به راحتی web server های جدید را برای پاسخ گویی بیشتر به سیستم اضافه کرد. در این سیستم وقتی میزان کاربران از حد تحمل پایگاه داده بیشتر شود درخواست ها شروع به کند شدن و یا حتی timeout شدن می کنند. برای جلوگیری از این مشکل می توان یه cache میان web server ها و database قرار داد اما Cache هم توانایی محدودی در پاسخ گویی دارد و مشکل قدیمی شدن داره را دارد که باید داده هایش را با Database به روز کند.

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

تحمل خطا یا Fault tolerance به توانایی پذیرش خطا هایی نرم افزاری و یا سخت افزاری توسط سرور گفته می شود. مثلا این توانایی که سروری که بر روی 5 ماشین کار می کند، با قطع شدن یکی از آن ها از شبکه و یا Crash کردنش نه از کار بیفتد و تا حد ممکن داده کمی از دست بدهد.

مقیاس پذیری یا Scalability به این توانایی گفته می شود که با زیاد شدن منابع سیستم بتواند به درخواست های بیشتری و با سرعت بالاتری پاسخ بدهد. این توانایی به دو مدل عمودی و عفقی تقسیم می شود. Horizontal Scalability یا همان روش افقی به توانایی مقیاس پذیر بودن روی چند ماشین گفته می شود، یعنی با زیاد کردن تعداد ماشین های سرور سیستم قدرت پاسخ گویی بیشتری پیدا می کند. Vertical Scalability یا همان روش عمودی به توانایی زیاد شدن قدرت پاسخ گویی با زیاد شدن منابع روی ماشین های فعلی مثل CPU و RAM گفته می شود.

 

مدل برنامه نویسی بازی های Real Time در سرور

برای پاسخ گویی به درخواست های کاربران به شکل سریع و داشتن ارتباط چند نفره معمولا بهتر است از یک socket دو طرفه مثلا ساکت (سوکت) TCP و یا UDP و یا پروتکل هایی بر روی این ها استفاده کرد و استفاده از درخواست های HTTP باعث زیاد شدن زمان پاسخ گویی می شود. همچنین باید از پروتکل های دودویی (Binary) برای ارسال و دریافت پیام ها استفاده کرد زیرا پردازش روش های متنی ارسال و دریافت داده و serialize کردن آن ها مثل JSON باعث کندی سیستم و مصرف بالای حافظه و پهنای باند می شوند. همچنین معمولا به دلیل نیاز به پاسخ گویی سریع این سیستم ها به شکل Stateful نوشته شده و تعداد درخواست های مختلف IO از جمله Database و یا File System به حد اقل می رسد.

برای پیاده سازی منطق بازی ممکن است از کتابخانه های معمولی برنامه نویسی و یا Game Engine ها استفاده شود. معمولا در بازی هایی که به فیزیک و Path Finding و ... برای اجرای سرور نیاز دارند یا از خود Game Engine و یا از کتابخانه های مورد استفاده در آن در پیاده سازی منطق بازی در سور نیز استفاده می شود. همچنین بعضی از انواع بازی Real Time به سادگی Scale شده و هر جلسه بازی کوتاه و بین چند نفر انجام می شود و برخی دیگر نیاز به تکنیک های خاص برای Scale شدن دارند. چون همیشه داده های کل عملیات ها در Database ذخیره نمی شود برای بالا بردن تحمل خطا نیز از تکنیک های خاصی استفاده می شود که در آینده بررسی خواهیم کرد.

پروتکل های شبکه و serialization داده ها و همچنین Scalability و Fault teolrance هر یک خود مطالب بسیار بزگری هستند که توضیح زیادشان این پست را طولانی می کند و در آینده به تفصیل به آن ها خواهیم پرداخت.

اگر بخواهیم چند تکنولوژی مناسب برای ساخت سرور بازی های Real Time را نام ببریم، استفاده از کتابخانه شبکه خود Game  Engine ها مثل Unity و UE4 روشی ساده برای پیاده سازی منطق اصلی بازی به شکل ساده می باشد و تکنولوژی هایی مثل Microsoft Orleans (که ما برای آپادانا از آن استفاده می کنیم)، Erlang، Akka و C++ به همراه کتابخانه های شبکه مناسب برای ساخت بخش های دیگر سیستم و گاهی خود منطق بازی مناسب هستند. بعضی ها اکنون به NodeJs فکر می کنند که چرا اسمی از آن و سیستم هایی مثل Parse نیاوردیم که در پستی به طور خاص به زودی درباره آن سخن خواهیم گفت. بای این که گفتن این جمله بدون توضیحات خطر کشته شدن توسط سیلی از برنامه نویسان را به سراغ من می آورد ولی NodeJs اصلا تکنولوژی مناسبی برای پیاده سازی سرور های قدرتمند بازی ها، به خصوص بازی های پر کاربر نیست.