این مقاله میان «پورت Native»، «بازکامپایل»، «بازسازی موتور» و «شبیهسازی» تفاوت قائل میشود. همه پروژههایی که بازی کنسولی را روی PC اجرا میکنند، لزوماً پورت Native نیستند.
۲. بررسی تخصصی روشهای پورت غیررسمی
برای جلوگیری از اشتباه، فناوریها را در چهار گروه قرار میدهیم:
- روشهای انتقال و بازسازی کد بازی
- روشهای شبیهسازی و ترجمه دستورالعملها
- روشهای بازسازی موتور و سازگاری نرمافزاری
- فناوریهای پشتیبان و مراحل مهندسی معکوس
۲.۱. Native Porting – پورت بومی انتقال بازی
Native Porting به معنای انتقال بازی به یک پلتفرم جدید با استفاده از کدی است که مستقیماً برای محیط مقصد کامپایل و اجرا میشود. در این روش، برنامه بهجای تکیه بر شبیهسازی کامل سختافزار کنسول، از امکانات سیستمعامل و سختافزار کامپیوتر استفاده میکند.
برای مثال، اگر یک بازی قدیمی با پردازنده PowerPC و API گرافیکی اختصاصی کنسول ساخته شده باشد، توسعهدهنده میتواند منطق بازی را به محیط x86-64 منتقل کند و بخش گرافیکی آن را با DirectX یا Vulkan پیادهسازی کند.
مراحل کلی:- بررسی معماری و ساختار بازی اصلی.
- شناسایی سیستم مدیریت حافظه، ورودی، صدا و گرافیک.
- انتقال منطق بازی به محیط جدید.
- بازنویسی بخشهای وابسته به سختافزار کنسول.
- سازگار کردن فایلهای بازی و سیستم بارگذاری منابع.
- کامپایل و آزمایش نسخه ویندوز.
زبانها و فناوریها: C، C++، Rust، C# و در برخی پروژهها زبانهای اختصاصی موتور بازی.
مزایا- امکان دستیابی به عملکرد Native.
- کنترل کامل روی رندرینگ و منابع.
- استفاده از قابلیتهای جدید سختافزار.
- امکان افزودن تنظیمات و امکانات جدید.
چالشها- نیاز به شناخت دقیق ساختار بازی.
- دشواری بازنویسی بخشهای وابسته به کنسول.
- احتمال نیاز به بازسازی بخش بزرگی از موتور.
نکته: Native بودن خروجی به این معنا نیست که کل بازی از ابتدا نوشته شده است. یک بازی میتواند با استفاده از کد Recompiled نیز به برنامهای Native تبدیل شود.
۲.۲. Static Recompilation – بازکامپایل ایستا یکی از روشهای مهم مدرن
در این روش، ابزاری تخصصی فایل اجرایی بازی را تحلیل کرده و دستورالعملهای پردازنده کنسول را پیش از اجرای بازی به کد قابل کامپایل برای کامپیوتر تبدیل میکند.
برای مثال، اگر بازی اصلی برای پردازنده MIPS ساخته شده باشد، Recompiler میتواند دستورالعملهای آن را به کد C یا C++ تبدیل کند تا کامپایلر ویندوز آن را برای پردازنده x86-64 یا ARM64 بسازد.
فایل اجرایی کنسول←تحلیل و شناسایی دستورالعملها
Disassembly / Metadata←تولید کد C یا C++←کامپایل←برنامه Native کامپیوتر
یکی از پروژههای مهم این حوزه N64Recomp است. این پروژه فایلهای اجرایی Nintendo 64 را به کد C تبدیل میکند. سپس کد تولیدشده با کامپایلر پلتفرم مقصد ساخته میشود.
این روش الزاماً به سورس کد اصلی بازی نیاز ندارد؛ بااینحال، اطلاعاتی مانند مرزبندی توابع، نمادها و اطلاعات جانبی میتوانند فرایند را آسانتر کنند.
ابزارها و زبانها: C و C++، LLVM و Clang، CMake، ابزارهای Disassembly و تحلیل ELF و Symbol.
مزایا- خروجی میتواند برنامه Native باشد.
- اجرای سریعتر نسبت به تفسیر دستورالعملها.
- امکان توسعه سیستم گرافیکی.
- قابلیت افزودن رزولوشن و نرخ فریم بالاتر.
چالشها- پشتیبانی دقیق از دستورالعملها.
- مدیریت حافظه و رفتار سختافزار.
- پیچیدگی کد پویا و Overlayها.
- تولید کد بهتنهایی اجرای بینقص را تضمین نمیکند.
مثال: پروژه Zelda 64: Recompiled از این فناوری استفاده میکند.
۲.۳. Dynamic Recompilation – بازکامپایل پویا
در Dynamic Recompilation، دستورالعملهای پردازنده اصلی هنگام اجرای بازی تحلیل و به دستورالعملهای قابل اجرا روی پردازنده میزبان تبدیل میشوند. تفاوت اصلی آن با Static Recompilation در زمان انجام ترجمه است.
- بازی یک بلوک کد را اجرا میکند.
- Recompiler دستورالعملهای آن بلوک را دریافت میکند.
- دستورالعملها به کد ماشین پردازنده PC تبدیل میشوند.
- کد ترجمهشده در حافظه نگهداری میشود.
- در اجرای مجدد همان بلوک، از نسخه ترجمهشده استفاده میشود.
این فناوری معمولاً از Cache برای نگهداری بلوکهای ترجمهشده استفاده میکند.
مزایا- امکان اجرای برنامههای دارای کد پویا.
- عدم نیاز به ترجمه کامل پیش از اجرا.
- مدیریت کدهایی که هنگام اجرا بارگذاری میشوند.
چالشها- هزینه اولیه ترجمه در زمان اجرا.
- پیچیدگی مدیریت Cache.
- تشخیص تغییر کد و بیاعتبار کردن بلوکهای قدیمی.
- احتمال تأخیر در اولین اجرای بخشها.
تفاوت با روش ایستا: در روش ایستا بخش بزرگی از کار پیش از اجرای بازی انجام میشود؛ اما در روش پویا، موتور ترجمه بخشی از محیط اجرای بازی است.
۲.۴. Static Binary Translation – ترجمه ایستای باینری
این فناوری دستورالعملهای یک فایل اجرایی را به دستورالعملهای معماری مقصد تبدیل میکند؛ برای مثال، تبدیل کد ماشین PowerPC به کد ماشین x86-64.
- Binary Translation اصطلاح عمومیتری برای ترجمه باینری است.
- Recompilation معمولاً به تولید یک نمایش میانی یا کد قابل کامپایل و ساخت مجدد اشاره میکند.
در عمل، این دو اصطلاح ممکن است در یک پروژه برای بخشهای متفاوت یک فرایند استفاده شوند.
۲.۵. Dynamic Binary Translation – ترجمه پویای باینری
در این روش، دستورالعملهای برنامه در زمان اجرا به دستورالعملهای معماری میزبان ترجمه میشوند. این فناوری میتواند در شبیهسازها، لایههای سازگاری و سیستمهای مجازیسازی به کار برود.
برای نمونه، یک برنامه ARM ممکن است روی سیستم x86 اجرا شود؛ درحالیکه بخشی از دستورالعملهای آن هنگام اجرا به دستورالعملهای x86 تبدیل میشوند. این روش با Dynamic Recompilation همپوشانی زیادی دارد.
۲.۶. Reverse Engineering – مهندسی معکوس فرایند پشتیبان
مهندسی معکوس یک روش مستقل برای اجرای بازی نیست؛ بلکه فرایندی برای شناخت ساختار داخلی نرمافزار است. توسعهدهندگان بدون دسترسی به سورس کد اصلی، رفتار و معماری داخلی بازی را بررسی میکنند.
موضوعات بررسیشده میتوانند شامل ساختار فایل اجرایی، توابع و ارتباط آنها، ساختار حافظه، ورودیها، رندرینگ، فایلهای صوتی و تصویری، بارگذاری مراحل و ارتباط بخشهای موتور باشند.
ابزارهایی مانند Ghidra و IDA Free برای تحلیل باینریها استفاده میشوند. مهندسی معکوس در پروژههای Recompilation، Engine Recreation و Porting کاربرد فراوانی دارد.
۲.۷. Source Porting – انتقال سورس کد
Source Porting یکی از مستقیمترین روشهای انتقال بازی به کامپیوتر است؛ البته به شرطی که سورس کد بازی در دسترس باشد. در این روش، توسعهدهنده کد اصلی بازی را برای سیستمعامل و سختافزار جدید آماده میکند.
برای مثال، اگر سورس یک بازی قدیمی C++ در دسترس باشد، میتوان بخشهای وابسته به کنسول را با معادلهای مناسب ویندوز جایگزین کرد.
نمونههای نزدیک به این رویکرد: OpenMW برای The Elder Scrolls III: Morrowind و OpenRCT2 برای RollerCoaster Tycoon 2. این دو پروژه صرفاً پورت مستقیم سورس رسمی منتشرشده نیستند؛ بلکه نمونههایی از بازپیادهسازی مبتنی بر مهندسی معکوس و کد مستقلاند.
مزایا- دسترسی به منطق برنامه.
- امکان تغییر مستقیم بخشهای مختلف بازی.
- قابلیت بهینهسازی و افزودن ویژگیها.
چالشها- نبود سورس کد در بسیاری از بازیها.
- وابستگی به کتابخانههای قدیمی.
- نیاز به سازگار کردن بخشهای سختافزاری و سیستمعامل.
۲.۸. Engine Recreation – بازسازی موتور بازی
در این روش، توسعهدهنده تلاش میکند موتور اصلی بازی را با تحلیل رفتار نسخه اصلی بازسازی کند. این کار لزوماً به معنای بازنویسی دقیق تمام بخشهای موتور نیست؛ هدف، ساخت موتوری جدید با رفتار سازگار با بازی اصلی است.
برای مثال، اگر موتور اصلی بازی دیگر روی ویندوز جدید قابل اجرا نباشد، میتوان سیستمهای فیزیک، رندرینگ، صدا، انیمیشن و مدیریت منابع آن را در معماری جدید بازسازی کرد.
۲.۹. Engine Reimplementation – پیادهسازی مجدد موتور
این روش با Engine Recreation همپوشانی دارد، اما تأکید آن بیشتر بر پیادهسازی مجدد رفتار و رابطهای موتور اصلی است. توسعهدهندگان بدون دسترسی به سورس موتور، پیادهسازی مستقلی ایجاد میکنند که بتواند فایلها و منطق بازی را پشتیبانی کند.
مثال: OpenGOAL نمونهای از این رویکرد در مجموعه Jak and Daxter است.
۲.۱۰. Game Code Reconstruction – بازسازی کد بازی
در این روش، توسعهدهندگان تلاش میکنند ساختار و عملکرد کد اصلی بازی را از روی باینری و رفتار برنامه بازسازی کنند. این کار ممکن است شامل شناسایی توابع، ساختار دادهها، الگوریتمها و ارتباط بین سیستمهای مختلف باشد.
بازسازی کد میتواند به تولید نسخهای قابل کامپایل از منطق بازی منجر شود؛ اما لزوماً به معنای بازیابی سورس کد دقیق و اصلی نیست.
۲.۱۱. Decompilation – دیکامپایل
Decompilation تلاش میکند فایل باینری کامپایلشده را به یک نمایش سطح بالاتر، مانند کد شبهC، تبدیل کند. خروجی Decompiler معمولاً سورس کد اصلی نیست.
نام متغیرها، کامنتها، ساختار کلاسها و بسیاری از اطلاعات زمان توسعه ممکن است در فایل اجرایی وجود نداشته باشند. بنابراین Decompilation با بازیابی کامل سورس کد اصلی تفاوت دارد.
۲.۱۲. JIT Compilation – کامپایل هنگام اجرا
JIT مخفف Just-In-Time Compilation است. در این روش، کد در زمان اجرای برنامه به کد ماشین تبدیل میشود. JIT میتواند در شبیهسازها یا موتورهای بازی مورد استفاده قرار بگیرد.
JIT مفهومی گستردهتر از Dynamic Recompilation است و میتواند کدهای یک زبان سطح بالا یا یک نمایش میانی را نیز به کد ماشین تبدیل کند.
۲.۱۳. HLE – شبیهسازی سطح بالا
High-Level Emulation بهجای تقلید دقیق از تکتک رفتارهای سختافزار، عملکرد بخشهای مهم سیستم اصلی را در سطح بالاتری بازسازی میکند.
برای مثال، بهجای شبیهسازی دقیق یک واحد سختافزاری صوتی، شبیهساز میتواند عملکرد مورد انتظار آن را با پیادهسازی نرمافزاری فراهم کند. مزیت اصلی HLE کاهش هزینه شبیهسازی است؛ اما ممکن است در بازیهای وابسته به رفتارهای خاص سختافزار ناسازگاری ایجاد شود.
۲.۱۴. LLE – شبیهسازی سطح پایین
Low-Level Emulation تلاش میکند رفتار سختافزار اصلی را با جزئیات بیشتری شبیهسازی کند. در این روش، بخشهایی مانند پردازنده، حافظه و واحدهای اختصاصی سختافزار با دقت بیشتری مدلسازی میشوند.
| ویژگی | HLE | LLE |
|---|
| سطح شبیهسازی | سطح بالا | سطح پایین |
| پیچیدگی | معمولاً کمتر | معمولاً بیشتر |
| دقت سختافزاری | وابسته به پیادهسازی | بالقوه بیشتر |
| سرعت | معمولاً بالاتر | معمولاً هزینهبرتر |
| سازگاری | وابسته به بازی | بالقوه دقیقتر |
۲.۱۵. Emulator-Based Execution – اجرای مبتنی بر شبیهساز
در این روش، بازی در محیطی اجرا میشود که سختافزار یا سیستمعامل کنسول را شبیهسازی میکند.
این روش با پورت Native تفاوت دارد؛ زیرا بازی همچنان در محیط شبیهسازیشده اجرا میشود.
۲.۱۶. API Translation – ترجمه رابط برنامهنویسی
API Translation به معنای تبدیل فراخوانیهای یک رابط برنامهنویسی به رابط دیگری است. برای مثال، یک برنامه ممکن است از API اختصاصی کنسول استفاده کند، اما لایه ترجمه درخواستهای آن را به فراخوانیهای معادل در ویندوز تبدیل کند.
این فناوری در لایههای سازگاری و برخی شبیهسازها کاربرد دارد.
۲.۱۷. Graphics API Translation – ترجمه API گرافیکی
این روش روی بخش گرافیکی تمرکز دارد. برای مثال، دستورات یک API گرافیکی میتوانند به دستورات API دیگری تبدیل شوند.
این ابزارها خودشان پورت بازی نیستند؛ بلکه لایه ترجمه گرافیکی هستند.
۲.۱۸. Compatibility Layers – لایههای سازگاری
لایه سازگاری تلاش میکند محیط مورد انتظار یک برنامه را در سیستمعامل دیگری فراهم کند. برای مثال، Wine امکان اجرای بسیاری از برنامههای ویندوزی روی لینوکس را فراهم میکند.
این فناوری بهتنهایی معماری پردازنده متفاوت را شبیهسازی نمیکند؛ بنابراین نباید آن را با Emulator یکی دانست.
۲.۱۹. Runtime Wrappers – پوششدهندههای زمان اجرا
Runtime Wrapper لایهای نرمافزاری است که بین برنامه و محیط اجرای آن قرار میگیرد. این لایه میتواند برخی توابع، ساختارها یا رفتارهای مورد انتظار برنامه را پیادهسازی یا به رابط دیگری منتقل کند.
Wrapperها ممکن است برای سازگار کردن سیستم ورودی، صدا، فایلها، حافظه یا گرافیک استفاده شوند.
۲.۲۰. Hybrid Porting – پورت ترکیبی
در Hybrid Porting، توسعهدهنده از چند روش مختلف بهصورت همزمان استفاده میکند. برای مثال، یک پروژه میتواند:
- کد اصلی را با Static Recompilation تبدیل کند.
- سیستم گرافیکی را با Renderer جدید بازسازی کند.
- از Wrapper برای برخی توابع کنسول استفاده کند.
- فایلهای بازی را از نسخه اصلی بارگذاری کند.
- بخشهایی از سختافزار را بهصورت نرمافزاری شبیهسازی کند.
بسیاری از پروژههای مدرن دقیقاً در یک دستهبندی ساده قرار نمیگیرند.
۲.۲۱. Asset Extraction & Reimplementation – استخراج منابع و بازپیادهسازی
در بسیاری از بازیها، فایلهای گرافیکی، مدلها، صداها، انیمیشنها و مراحل در قالبهای اختصاصی ذخیره شدهاند. Asset Extraction به استخراج و شناسایی این منابع اشاره دارد.
استخراج منابع بهتنهایی پورت محسوب نمیشود. برای تبدیل این منابع به یک بازی قابل اجرا، باید موتور یا سیستمی وجود داشته باشد که بتواند آنها را بارگذاری و پردازش کند. به همین دلیل این روش معمولاً در کنار Engine Recreation، Native Porting یا Recompilation استفاده میشود.