انتشار بازیهای دسکتاپ MonoGame در Microsoft Store: راهنمای جامع MSIX و WAP
آوردن یک بازی مستقل به Microsoft Store در ویندوز ۱۰ و ویندوز ۱۱ به توسعهدهندگان دسترسی مستقیم به صدها میلیون بازیکن رایانه شخصی، بهروزرسانیهای خودکار، ادغام با Windows Game Bar و امنیت محیط ایزوله را میدهد. با این حال، اگر بازی شما با MonoGame (.NET 8.0 یا .NET 9.0 WindowsDX) ساخته شده است، ورود آن به استور نیازمند یک پل معماری است: متصل کردن یک فایل اجرایی سنتی Win32 (.exe) به مدل مدرن برنامه MSIX / AppX.
ما در Arar Games این مسیر را با عناوینی مانند Paint Trek و Blocked: Pixel Panzer از مراحل اولیه تا انتشار زنده با موفقیت طی کردهایم. در این راهنمای جامع و کاربردی، تمام مراحل فنی را تشریح میکنیم: پیکربندی پروژهها، تسلط بر گزینههای منوی Publish در ویژوال استودیو، تنظیم فایل Package.appxmanifest، مقیاسبندی آیکونها و کاشیها (tiles)، رفع خطاهای Windows App Certification Kit (WACK) و ثبت نهایی در Microsoft Partner Center.
۱. مبانی معماری: مقایسه Win32 و MSIX
بازیهای سنتی MonoGame به صورت یک فایل اجرایی معمولی Win32 به همراه کتابخانههای زمان اجرا (.dll) و یک پوشه Content/ شامل داراییهای باینری فشردهشده (بافتهای .xnb، فایلهای صوتی .ogg و شیدرهای HLSL) کامپایل میشوند.
اگرچه مایکروسافت استور اکنون از فایلهای اجرایی مستقل Win32 نیز پشتیبانی میکند، اما قرار دادن بازی در یک پروژه بستهبندی برنامههای ویندوز (WAP) برای ایجاد یک بسته MSIX bundle مزایای فنی و عملیاتی چشمگیری به همراه دارد:
flowchart TD
subgraph "پایگاه کد بازی"
Shared["کتابخانه مشترک
(مکانیک، سیستمها، وضعیت بازی، ریاضی)"]
Desktop["پروژه دسکتاپ (.NET 9.0 WindowsDX)
(نقطه ورود Win32 Executable)"]
Shared --> Desktop
end
subgraph "لایه بستهبندی (پروژه WAP)"
WAP["بستهبندی برنامه ویندوز (.wapproj)
(Microsoft Desktop Bridge)"]
Manifest["Package.appxmanifest
(هویت، دسترسیها، کاشیهای گرافیکی)"]
StoreAssoc["Package.StoreAssociation.xml
(اتصال به Partner Center)"]
Desktop --> WAP
Manifest --> WAP
StoreAssoc --> WAP
end
subgraph "خروجی و توزیع"
WAP -->|ایجاد بسته| Sideload["بسته سایدلودینگ
(*.appxbundle + Add-AppDevPackage.ps1)"]
WAP -->|حالت استور| UploadBundle["بسته آپلود استور
(*_bundle.appxupload / *.msixupload)"]
UploadBundle --> MSStore["Microsoft Partner Center
(انتشار زنده در استور)"]
end
چرا پروژه MonoGame را با WAP بستهبندی کنیم؟
- چرخه حیات ایزوله در کانتینر: برنامههای MSIX در یک محیط شبیهسازیشده و ایمن اجرا میشوند. هنگام حذف برنامه، تمام فایلها و کلیدهای رجیستری بدون باقی گذاشتن هیچگونه فایل اضافی از ویندوز پاک میشوند.
- توزیع پویا و بهینهسازی حجم: یک بسته
.appxuploadشامل باینریهای معماریx86وx64به همراه مقیاسهای مختلف تصویر (scale-100تاscale-400) است. مایکروسافت استور تنها معماری و تصاویر مورد نیاز دستگاه کاربر را تحویل میدهد که حجم دانلود را به شدت کاهش میدهد. - تلهمتری خودکار و گزارش خرابیها: ویژوال استودیو فایلهای نماد خطایابی (
.appxsym) را در بسته آپلود قرار میدهد. در صورت خرابی بازی در سیستم بازیکن، پشته کامل خطا (stack trace) با نام متدها و شماره خطوط در پنل پارتنر سنتر قابل مشاهده خواهد بود.
۲. سلسلهمراتب و پیکربندی پروژه
یک پروژه استاندارد MonoGame باید تفکیک کاملی بین منطق بازی و بستهبندی پلتفرم داشته باشد:
SolutionDir/
│
├── YourGame.Shared/ # مکانیک اصلی بازی، سطوح و سیستمها (کتابخانه مشترک)
│ └── YourGame.Shared.csproj
│
├── YourGame.Desktop/ # نقطه ورود اجرایی دسکتاپ (WinExe)
│ ├── Content/ # داراییهای پایپلاین MonoGame (.mgcb -> .xnb)
│ ├── Program.cs
│ └── YourGame.Desktop.csproj
│
└── YourGame.Package/ # پروژه بستهبندی WAP (.wapproj)
├── Images/ # آیکونها، کاشیها و صفحه لودینگ
├── Package.appxmanifest # هویت، دسترسیها و اطلاعات ظاهری
├── Package.StoreAssociation.xml
└── YourGame.Package.wapproj
گام اول: پیکربندی پروژه اصلی بازی (.csproj)
مطمئن شوید که پروژه دسکتاپ شما امکان ساخت برای معماریهای چندگانه را دارد:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
<!-- اطمینان از کپی شدن فایلهای محتوای بازی -->
<ItemGroup>
<Content Include="Content\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.*" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
</ItemGroup>
</Project>
گام دوم: بازیابی بستههای NuGet برای هر دو معماری
قبل از بستهبندی، بستهها را به طور مجزا برای زمان اجرای ۶۴ بیتی و ۳۲ بیتی بازیابی کنید:
dotnet restore YourGame.Desktop.csproj -r win-x64
dotnet restore YourGame.Desktop.csproj -r win-x86
۳. بررسی گزینههای منوی Publish در ویژوال استودیو
وقتی روی پروژه WAP در ویژوال استودیو راستکلیک کرده و منوی Publish را باز میکنید، سه گزینه مشاهده میکنید:
graph TD
Menu["راستکلیک روی پروژه WAP > Publish"]
Menu --> Opt1["1. Associate App with the Store..."]
Menu --> Opt2["2. Convert Content Group Map File"]
Menu --> Opt3["3. Create App Packages... (جریان اصلی کار)"]
Opt1 --> Sync["همگامسازی هویت ابری با مانیفست محلی
(تولید Package.StoreAssociation.xml)"]
Opt2 --> Streaming["تبدیل فایل نقشه نصب جریانی
(برای بازیهای حجیم با دانلود چندمرحلهای)"]
Opt3 --> Wizards["ویزارد بستهبندی:
- سایدلودینگ (تست محلی QA)
- بسته آپلود استور (_bundle.appxupload)"]
۱. Associate App with the Store... (اتصال برنامه به استور)
- هدف: متصل کردن پروژه محلی با حساب توسعهدهنده مایکروسافت پارتنر سنتر.
- کارکرد: با حساب توسعهدهنده خود وارد میشوید و نام بازی رزرو شده را انتخاب میکنید. ویژوال استودیو شناسه رسمی ناشر (Publisher ID)، نام بسته (Package Name) و شناسه خانوادگی بسته (PFN) را دریافت کرده و فایل
Package.StoreAssociation.xmlرا میسازد. - اهمیت: در صورت عدم انجام این کار، بسته با گواهی محلی موقت امضا میشود و مایکروسافت استور در هنگام آپلود آن را رد میکند.
۲. Convert Content Group Map File (تبدیل فایل نقشه گروههای محتوا)
- هدف: پشتیبانی از معماری نصب جریانی (Streaming Install) مایکروسافت.
- کارکرد: در بازیهای فوقالعاده حجیم (بیش از ۵۰ گیگابایت)، به بازیکن امکان میدهد در حین دانلود پسزمینه مراحل بعدی، مرحله اول را بازی کند. این گزینه فایل
SourceAppxContentGroupMap.xmlرا بهAppxContentGroupMap.xmlنهایی تبدیل میکند. - برای بازیهای مستقل: برای عناوین مستقل کمحجم نیازی به این ویژگی نیست و میتوانید آن را نادیده بگیرید.
۳. Create App Packages... (ایجاد بستههای برنامه - ویزارد اصلی)
ابزار اصلی برای ساخت، امضا و تولید بسته نهایی چه برای تست داخلی و چه برای ارسال به استور.
۴. پیکربندی ویزارد ایجاد بسته
در پنجره Create App Packages:
مرحله اول: انتخاب روش توزیع
- برای ارسال به استور: گزینه "Microsoft Store under a new or existing app name" را انتخاب کنید.
- برای تست داخلی (Sideloading): گزینه "Sideloading" را انتخاب کنید تا بستهای همراه با گواهی آزمایشی محلی (
.cer) و اسکریپت نصب پاورشل (Add-AppDevPackage.ps1) ایجاد شود.
مرحله دوم: تنظیمات معماری و نسخه
┌─────────────────────────────────────────────────────────────┐
│ Output location: .\AppPackages\ │
│ Version: 1.0.0.0 [☑ Automatically increment] │
│ │
│ Generate app bundle: Always │
│ │
│ Architectures: │
│ ☑ x86 پیکربندی: Release (x86) │
│ ☑ x64 پیکربندی: Release (x64) │
│ ☐ ARM (برای بازیهای Win32 دسکتاپ توصیه نمیشود) │
│ ☐ ARM64 (برای بازیهای Win32 دسکتاپ توصیه نمیشود) │
│ │
│ گزینهها: │
│ ☑ Include public symbol files │
│ ☑ Generate artifacts to validate app with WACK │
└─────────────────────────────────────────────────────────────┘
قانون طلایی شمارهگذاری نسخه:
- فرمت نگارش:
Major.Minor.Build.Revision. انتشار اولیه با1.0.0.0آغاز میشود. - قانون غیرقابل تغییر استور: نسخه هر بسته جدید آپلود شده در پارتنر سنتر باید حتماً بالاتر از نسخه فعال فعلی باشد.
- فعال بودن گزینه
Automatically incrementدر هر بار خروجی گرفتن، شماره Revision را یکی افزایش میدهد تا از تداخل نسخهها جلوگیری شود.
چرا x64 + x86 و Generate app bundle: Always؟
x64: سیستمهای مدرن ۶۴ بیتی (بیش از ۹۸٪ گیمرهای پیسی) را هدف قرار میدهد.x86: سازگاری برای سیستمهای ۳۲ بیتی قدیمی را تضمین میکند.- حالت
Alwaysهر دو معماری را در یک فایل فشرده منفرد (_bundle.appxupload) بستهبندی میکند.
۵. تنظیم فایل Package.appxmanifest
فایل مانیفست اطلاعات برنامه، دسترسیهای امنیتی و نمادهای گرافیکی را معین میکند:
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="YourPublisher.YourGame"
Publisher="CN=YOUR-OFFICIAL-PUBLISHER-ID"
Version="1.0.0.0" />
<Properties>
<DisplayName>نام بازی شما</DisplayName>
<PublisherDisplayName>نام استودیوی شما</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26100.0" />
</Dependencies>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="نام بازی شما"
Description="یک بازی اکشن دوبعدی ساخته شده با MonoGame."
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile
Wide310x150Logo="Images\Wide310x150Logo.png"
Square71x71Logo="Images\SmallTile.png"
Square310x310Logo="Images\LargeTile.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
<uap:InitialRotationPreference>
<uap:Rotation Preference="landscape"/>
</uap:InitialRotationPreference>
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
نکات کلیدی:
- مجوز
<rescap:Capability Name="runFullTrust" />: از آنجا که MonoGame از DirectX 11 و دسترسیهای مستقیم سیستمی استفاده میکند، نمیتواند در محیط سندروم محدود UWP اجرا شود. این قابلیت به بازی دسترسی کامل دسکتاپ میدهد در حالی که پاکیزگی نصب کانتینری حفظ میشود. - جهت چرخش
InitialRotationPreferenceرویlandscape: کنسولهای دستی ویندوزی (مانند ASUS ROG Ally و Lenovo Legion Go) نمایشگرهای عمودی با چرخش سختافزاری دارند. قفل کردن روی جهت افقی مانع چرخش ناخواسته تصویر میشود.
۶. مقیاس تصاویر و تله نشان قفل صفحه (BadgeLogo)
ویندوز تصاویر را با ضرایب مقیاس مختلف (scale-100, 125, 150, 200, 400) نمایش میدهد:
| نوع تصویر | اندازه پایه (scale-100) | scale-200 | scale-400 | کاربرد |
|---|---|---|---|---|
| Square44x44Logo | ۴۴ × ۴۴ پیکسل | ۸۸ × ۸۸ | ۱۷۶ × ۱۷۶ | آیکون نوار وظیفه و لیست برنامهها |
| Square150x150Logo | ۱۵۰ × ۱۵۰ | ۳۰۰ × ۳۰۰ | ۶۰۰ × ۶۰۰ | کاشی متوسط منوی استارت |
| Wide310x150Logo | ۳۱۰ × ۱۵۰ | ۶۲۰ × ۳۰۰ | ۱۲۴۰ × ۶۰۰ | کاشی عریض منوی استارت |
| LargeTile | ۳۱۰ × ۳۱۰ | ۶۲۰ × ۶۲۰ | ۱۲۴۰ × ۱۲۴۰ | کاشی بزرگ منوی استارت |
| SmallTile | ۷۱ × ۷۱ | ۱۴۲ × ۱۴۲ | ۲۸۴ × ۲۸۴ | کاشی کوچک منوی استارت |
| SplashScreen | ۶۲۰ × ۳۰۰ | ۱۲۴۰ × ۶۰۰ | ۲۴۸۰ × ۱۲۰۰ | بنر صفحه لودینگ |
| StoreLogo | ۵۰ × ۵۰ | ۱۰۰ × ۱۰۰ | ۲۰۰ × ۲۰۰ | آیکون بازی در فروشگاه استور |
| BadgeLogo | ۲۴ × ۲۴ | ۴۸ × ۴۸ | ۹۶ × ۹۶ | نشان اعلان صفحه قفل ویندوز |
Warning
قانون حیاتی BadgeLogo:
نشان صفحه قفل (BadgeLogo) باید کاملاً تکرنگ و فقط از پیکسلهای سفید خالص (#FFFFFF) با پسزمینه شفاف تشکیل شده باشد. استفاده از رنگهای دیگر باعث خطای تست تضاد رنگ در WACK و رد شدن تاییدیه میشود.
۷. تست WACK و خطایابی
خطای "The tool AppCert.exe wasn't found"
در صورت کلیک روی دکمه WACK و مواجهه با این خطا:
- این مشکل به علت نصب نشدن ابزار در ویژوال استودیو است. از طریق Visual Studio Installer $ ightarrow$ تب Individual components گزینه "Windows App Certification Kit" را نصب کنید.
- اجرای تست WACK در سیستم محلی اختیاری است؛ سیستم ابری مایکروسافت پس از آپلود به صورت خودکار تمامی این تستها را انجام میدهد.
هشدار مثبت کاذب فایلهای فشرده MonoGame
در صورت گزارش بافتها (.xnb) یا صداها (.ogg) به عنوان فایلهای مسدود شده در WACK، نگران نباشید؛ ساختار بایتهای فشرده گاهی مشابه هدر فایلهای اجرایی به نظر میرسد و تیم ارزیابی مایکروسافت این موضوع را در بازیها به عنوان فایل محتوای ایستا تایید میکند.
۸. تست محلی با سایدلودینگ (Sideloading)
قبل از آپلود نهایی، فایلهای پوشه AppPackages/YourGame_1.0.0.0_Test/ را بررسی کنید. با راستکلیک روی پاورشل و اجرای دستور زیر به عنوان مدیر (Administrator):
Set-ExecutionPolicy RemoteSigned -Scope Process
.\Add-AppDevPackage.ps1
بازی روی سیستم شما نصب شده و میتوانید عملکرد دسته بازی، صدا و روان بودن اجرای ۶۰ فریم آن را در محیط ایزوله کانتینر ارزیابی نمایید.
۹. چکلیست نهایی مایکروسافت پارتنر سنتر
فایل _bundle.appxupload را در داشبورد پارتنر سنتر بارگذاری نمایید:
- Pricing and Availability: انتخاب تمامی بازارهای جهانی (۲۴۰ کشور) و تعیین قیمت پایه بر حسب دلار (تبدیل ارزها خودکار انجام میشود).
- Properties: تعیین دستهبندی
Gamesو قرار دادن آدرس اینترنتی سیاست حفظ حریم خصوصی (Privacy Policy URL). - Age Ratings: تکمیل پرسشنامه IARC (بازیهای آرکید عموماً رتبه Everyone / PEGI 3 دریافت میکنند).
- Store Listings: آپلود اسکرینشاتهای 1920x1080 دسکتاپ (بدون دکمههای لمسی موبایل).
- Packages: آپلود بسته نهایی و زدن دکمه Submit to the Store. تاییدیه معمولاً بین ۲۴ تا ۷۲ ساعت صادر میشود.
نتیجهگیری
انتشار بازیهای دسکتاپ MonoGame در مایکروسافت استور به هیچ وجه نیازمند بازنویسی کدها برای UWP یا فدا کردن عملکرد نسخه ۹ داتنت نیست. با بهرهگیری از پروژه WAP، تنظیم دسترسی runFullTrust و تجمیع معماریهای x86 و x64، میتوانید بازی خود را در اختیار جامعه عظیم پیسی گیمرهای سراسر دنیا قرار دهید!