Cemu Patches .asm Format PowerPC PPC32

طريقة إنشاء باتشات Cemu بصيغة .asm وتحويل patches.txt

دليل للمطورين يشرح بنية باتشات Cemu الأصلية، وتحديد ملفات RPX وRPL عبر CRC، وكتابة التعليمات داخل Codecave، واستخدام Labels وConstants وData Directives، ثم تحويل باتشات Cemuhook القديمة إلى الصيغة الحديثة.

نافذة Graphic Packs في محاكي Cemu لتنزيل الحزم وتفعيلها

نافذة Graphic Packs التي يستخدمها المستخدم لتنزيل الحزم، البحث عنها، وتفعيل الباتش المطلوب داخل Cemu.

وش هي Cemu Patches؟

بداية من Cemu 1.17.0 صار المحاكي يدعم تعديل Game Code مباشرة من خلال Graphic Packs. قبل ذلك كانت عملية Assembly Patching تعتمد على Cemuhook وملف patches.txt.

الصيغة القديمة patches.txt الخاصة بـCemuhook، وما زالت بعض الحزم القديمة تستخدمها.
صيغة Cemu الأصلية patch_<anything>.asm وهي الصيغة المشروحة في هذا الموضوع.
هذا موضوع تطوير باتشات، مو شرح تفعيل Graphic Packs للمستخدم العادي. كتابة عنوان خاطئ أو CRC غير صحيح ممكن يمنع الباتش من العمل أو يكسر تنفيذ اللعبة.

مكان الملف وتسميته

عندما يطابق rules.txt اللعبة، يفحص Cemu مجلد Graphic Pack بحثًا عن أي ملف يطابق النمط:

File pattern ASM
patch_<anything>.asm
صحيح patch_main.asm
صحيح patch_fps.asm
غير مطابق my_patch.asm
تقدر تحط أكثر من ملف Patch داخل الحزمة، وتقدر تحط أكثر من Patch Group داخل نفس الملف.

وش يشوف المستخدم النهائي داخل Cemu؟

Cemu Wiki + Community Graphic Packs

المطور يكتب rules.txt وملفات patch_*.asm، لكن المستخدم النهائي ما يحتاج يفتح الكود. كل اللي يشوفه هو اسم الحزمة ومسارها ووصفها والخيارات الموجودة في نافذة Graphic Packs.

1
افتح Options → Graphic packs.
2
للحزم الرسمية اضغط Download latest community graphic packs.
3
للحزمة اليدوية أو التجريبية ضع المجلد داخل graphicPacks، وليس downloadedGraphicPacks.
4
فعّل المربع بجانب الحزمة، ثم شغل اللعبة أو أعد تشغيل Cemu.
5
ظهور اسم الحزمة باللون الأخضر أثناء تشغيل اللعبة يعني أنها Active.
لو عدلت حزمة موجودة داخل downloadedGraphicPacks، انسخها أولًا إلى مجلد graphicPacks حتى ما يستبدلها التحديث التلقائي للحزم.
مثال على نافذة Graphic Packs وخيارات الحزمة داخل Cemu

مثال واضح على ظهور الحزمة وخياراتها للمستخدم النهائي؛ الاسم والمسار والوصف والـPresets كلها تأتي من ملفات Graphic Pack.

ملاحظات مهمة من تطوير Cemu

Release Notes + Developer Tracker
Cemu 1.17.0 أضاف Automatic Codecave Sizing، وWrite Cursor، وLabels وVariables، وإمكانية تقسيم الباتش إلى عدة ملفات ومجموعات.
Cemu 1.20.2 صار Cemu نفسه يتولى تطبيق باتشات Cemuhook حتى لو كانت الإضافة مثبتة، مع تنبيه أن بعض Syntax وSemantics تختلف عند التحويل.
Cemu 1.22.2 صار Disassembly View يعرض أسماء Functions وLabels المعرفة داخل Graphic Pack، ويعرض نوع البيانات مثل .float.
Community Repository الأمثلة الحقيقية موجودة في مستودع cemu_graphic_packs، وخصوصًا مجلد Mods الذي يحتوي باتشات FPS والغش وتعديلات اللعب.
أفضل طريقة لتعلم الصيغة بعد فهم الأساسيات هي فتح باتش فعلي من المستودع، ومقارنة rules.txt مع patch_*.asm وسجل تشغيل اللعبة.

Patch Groups وmoduleMatches

كل مجموعة باتش تبدأ باسم داخل أقواس مربعة، ثم moduleMatches الذي يحتوي CRC واحدًا أو أكثر لتحديد ملفات RPX أو RPL المستهدفة.

patch_main.asm Patch group
[group_name]
moduleMatches = 0x11223344, 0xCFF30E4E
اسم المجموعة يستخدم أساسًا في Debugging. رسائل الأخطاء تشير إلى اسم المجموعة ورقم السطر.
moduleMatches قائمة CRCs تطابق Modules مختلفة أو إصدارات مختلفة من نفس اللعبة.
تقدر تحصل CRC الخاص بكل Module من ملف log.txt بعد تشغيل اللعبة في Cemu.
Labels وConstants تقدر تُستخدم بين مجموعات مختلفة داخل نفس Graphic Pack فقط عندما تكون المجموعات مفعلة لنفس Module أو CRC. ما تقدر المجموعة تصل إلى تعريفات خارج الحزمة الحالية.

تعديل تعليمات منفردة

أبسط استخدام هو استبدال تعليمة PowerPC داخل عنوان محدد. اكتب العنوان، ثم علامة =، ثم التعليمة الجديدة.

patch_main.asm Per-line addresses
0x0200E3A4 = li r3, 0
0x0200E400 = nop
li r3, 0 يستبدل التعليمة الموجودة في العنوان ويضع القيمة 0 في r3.
nop يعطل التعليمة الأصلية في العنوان المحدد.

Write Cursor واستخدام .origin

لما تكتب عدة تعليمات متتالية، ما تحتاج تحسب عنوان كل سطر يدويًا. استخدم .origin لتحديد مؤشر الكتابة، وCemu يزيده تلقائيًا بعد كل تعليمة أو Data Directive.

patch_main.asm Text section
.origin = 0x0200E3A4
bla someLabel
blr
السطر الأول يكتب في 0x0200E3A4.
السطر الثاني يكتب تلقائيًا في 0x0200E3A8.
العنوان المكتوب مباشرة بصيغة address = instruction له أولوية أعلى من .origin، ولا يزيد مؤشر الكتابة الحالي.

كتابة Function داخل Codecave

الكلمة codecave تنقل مؤشر الكتابة إلى مساحة غير مستخدمة مخصصة للكود الإضافي.

patch_main.asm Codecave function
.origin = codecave

someLabel:
li r3, 0
blr
1
يبدأ Cemu الكتابة داخل منطقة Codecave.
2
ينشئ Label باسم someLabel في الموضع الحالي.
3
يكتب التعليمات بالتتابع ويحدث العناوين تلقائيًا.

Labels والعناوين الخارجية

عرّف Label بكتابة الاسم متبوعًا بنقطتين. Cemu يعالج Relocation تلقائيًا عشان يظل الاسم يشير إلى مكان الكود الصحيح في الذاكرة.

patch_main.asm Local label
OurLabel:

وتقدر تربط Label بعنوان موجود داخل Text أو Data Section في اللعبة:

patch_main.asm External address label
0x0202034C = ExternalLabel:
هذا مفيد عند استدعاء Function موجودة داخل اللعبة أو الوصول إلى Variable خارج كودك الإضافي.

Constants وExpressions

صيغة Cemu تدعم Constants وعمليات حسابية وقت التجميع، وتقدر تستخدم Preset Variables القادمة من Graphic Pack.

patch_main.asm Constant
myConst = $presetVariable + 5
li r3, myConst

أو تكتب التعبير مباشرة داخل التعليمة:

patch_main.asm Inline expression
li r3, $presetVariable + 5
Constant ما يحجز مساحة في الذاكرة، لذلك ما يصلح كهدف لتعليمات Load أو Store. لما تحتاج Variable قابلًا للعنونة استخدم Data Directive مع Label.

Data Directives المدعومة

.byteعدد 8-bit
.shortعدد 16-bit
.intعدد 32-bit
.ptrAlias لـ.int
.floatFloat 32-bit
.doubleFloat 64-bit
.stringنص بطول متغير
patch_main.asm Float variable
SomeFloat:
.float 123.45

lis r12, SomeFloat@ha
lfs f0, SomeFloat@l(r12)
Label SomeFloat يشير إلى مكان القيمة داخل الذاكرة، لذلك تقدر تستخدمه مع تعليمات Load وStore.

الفرق الخطير عند التحويل من Cemuhook

الصيغتان تقبلان كتابة name = value، لكن معنى السطر مختلف.

Cemuhook name = 0x12345 يتعامل معها كPointer إلى العنوان ويطبق Relocation.
Cemu .asm نفس السطر ينشئ Constant قيمته 0x12345 بدون Relocation.
للحصول على نفس سلوك Cemuhook اكتب: name = reloc(0x12345) أو: 0x12345 = name:

مثال كامل: الصيغة القديمة مقابل صيغة Cemu

Cemuhook — patches.txt
[PatchName]
moduleMatches = 0x12345678

# code Cave
codeCaveSize = 0x24

# preset variable
_ourVariable = 0x0000000
0x0000000 = .int $gfxPackPresetVariable

# function in code cave
_codeCaveFunction = 0x0000004
0x0000004 = lis r11, _ourVariable@ha
0x0000008 = lwz r11, _ourVariable@l(r11)
0x000000C = cmpwi r11, 1
0x0000010 = bne .+0x0C
0x0000014 = li r3, 0
0x0000018 = blr
0x000001C = addi r3, r3, 1
0x0000020 = blr

# redirect game code
0x21EFAA8 = bla _codeCaveFunction
Cemu — patch_main.asm
[PatchName]
moduleMatches = 0x12345678

.origin = codecave

# preset variable
_ourVariable:
.int $gfxPackPresetVariable

# function in code cave
_codeCaveFunction:
lis r11, _ourVariable@ha
lwz r11, _ourVariable@l(r11)
cmpwi r11, 1
bne label_skip
li r3, 0
blr

label_skip:
addi r3, r3, 1
blr

# redirect game code
0x21EFAA8 = bla _codeCaveFunction
صيغة Cemu أوضح لأن Labels تستبدل الحسابات اليدوية لعناوين Codecave، و.origin = codecave يدير مؤشر الكتابة بدل تحديد Offset لكل سطر.

ترتيب إنشاء باتش جديد

1
أنشئ Graphic Pack صحيحًا يحتوي rules.txt.
2
شغل اللعبة واستخرج CRC للـRPX أو RPL من log.txt.
3
أنشئ ملفًا باسم يبدأ بـ patch_ وينتهي بـ.asm.
4
أضف Patch Group واكتب moduleMatches.
5
ضع الكود الإضافي في Codecave، ثم اربط Game Code به باستخدام Branch مناسب مثل bla.
6
فعّل Graphic Pack، شغل اللعبة، وراجع log.txt لأي Parse أو Assembly Error.

تأكد أن الباتش اشتغل من log.txt

Cemu Bug Tracker — سجل حقيقي

سجل Cemu يعطيك ثلاث معلومات أساسية: اسم الـModule، والـChecksum، واسم Patch Group الذي تم تطبيقه. المثال التالي مأخوذ من تقرير مطورين حقيقي خاص بباتش Mario Kart 8:

log.txt Runtime verification
Loaded module 'turbo' with checksum 0xd09700ce
Applying patch group 'MK8FullDrawVer4_1'
Activate graphic pack: Mario Kart 8/Mods/60FPS in splitscreen
Applying patch group 'MK8AspectVer4_1' (Codecave: 01800000-01800018)
Loaded module + checksum هذه القيمة هي اللي تقارنها مع moduleMatches.
Applying patch group ظهورها يعني أن CRC طابق وأن Cemu بدأ تطبيق المجموعة.
Codecave range ظهور النطاق يؤكد أن Cemu حجز مساحة للكود الإضافي.
Activate graphic pack يوضح اسم الحزمة والمسار والـPreset الذي اشتغل فعليًا.
ابحث داخل السجل عن: Loaded module checksum Applying patch group Codecave
إذا الحزمة ظهرت Active لكن ما ظهر Applying patch group، فالسبب الأقرب CRC غير مطابق، اسم ملف غير صحيح، أو Parse Error قبل التطبيق.

أخطاء شائعة تمنع الباتش من العمل

اسم الملف غير صحيح لازم يطابق patch_<anything>.asm.
CRC غير مطابق الباتش ما يتفعل إذا Module CRC مختلف عن moduleMatches.
Relocation خاطئ نقل تعريفات Cemuhook بصيغة name = address بدون reloc().
Branch خارج المدى استخدم طريقة Branch مناسبة ومكان Codecave صحيح.
Preset Variable مفقود تأكد أن الاسم معرف في rules.txt.
تعارض Graphic Packs حزمتان تعدلان العنوان نفسه ممكن تسببان كراش أو سلوكًا غير متوقع.

متى المشكلة من الباتش وليست من Cemu؟

في Bug Tracker الرسمي أُغلق تقرير كراش لأن العطل كان يظهر فقط مع Graphic Pack، وتم توجيهه ليُصلح داخل الحزمة نفسها بدل تعديل Cemu Core.

1
عطل الحزمة وحدها وجرب نفس المكان داخل اللعبة.
2
إذا اختفت المشكلة، أعد تفعيل الحزمة وحدد أي Patch Group يسببها.
3
أرفق log.txt بعد حدوث المشكلة مباشرة.
4
اكتب Cemu Version، إصدار اللعبة، Region، Module Checksum، واسم الحزمة والـPreset.
5
افتح التقرير في Issues الخاصة بمستودع Community Graphic Packs عندما تكون المشكلة مرتبطة بالحزمة فقط.
المشاكل اللي تستمر بعد تعطيل جميع Graphic Packs تُفحص بعدها كمشكلة في Cemu أو اللعبة أو التعريفات، مو كخطأ باتش.

المصادر الرسمية

استخدم CRC الصحيح، اكتب الكود الإضافي داخل Codecave، واعتمد على Labels بدل حساب العناوين يدويًا. عند تحويل باتش قديم، راجع معنى Relocation قبل نقل أي تعريف بصيغة name = address.