TurnedOff. ولا يعمل دونه إلا ثلاثة: الفيديو الاختباري، وإجابة
اللاعب عن سؤال الموافقة، ومعرّف Steam الذي يُحفظ للجلسة القادمة. وإعداد البناء مشروح في صفحة
حزمة Unity.
ما الذي سمح به اللاعب
يسأل البناء لاعبه عمّا يجوز لاختبار اللعب أن يجمعه قبل أن يجمع أي شيء، وإجابته تقرّر ما تفعله بقية هذه الصفحة:
وتجيب
ProtokitePlaytest.IsFeatureEnabled عن الأمرين معًا: الميزة التي يشغّلها اختبار اللعب ويستثنيها
اللاعب تُقرأ مطفأة في كل مكان. والتقاط الاستثناءات يتبع بيانات اللعب هناك، أما الاستثناءات نفسها
فمن شأن حزمة Flock، تبلّغ عنها بإعدادها الخاص مهما أجاب اللاعب.
نموذج الملاحظات لا تشمله تلك الإجابة. فهو لا يُرسل إلا حين يملؤه اللاعب ويضغط Send، وذلك من فعله في
كل حال — والنموذج الذي لم يستطع تشغيلٌ سابق إرساله يُرسل لاحقًا، مهما أجاب اللاعب بعد ذلك.
على الهاتف: الشبكات التي تُرفع عليها التسجيلات
في بناء Android يسجّل الفيديو، تتبع الإجابةَ التي تسمح بتسجيل الشاشة، على اللوحة نفسها، سؤالٌ ثانٍ: Upload on Wi-Fi only (الرفع على Wi-Fi فقط)، أو Upload on Wi-Fi or mobile data (الرفع على Wi-Fi أو بيانات الهاتف). وتذكر الإجابة الثانية نحو كم تستهلك دقيقة اللعب من بيانات الهاتف بمعدّل بتات التسجيل (نحو 11 ميغابايت بالقيمة الافتراضية 1500 kbps).
السؤال الثاني على الهاتف، بعد إجابة تسمح بتسجيل الشاشة.
playtest_upload_network: wifi_only أو wifi_and_mobile_data أو not_asked (حاسوب مكتبي، أو بناء لا
يسأل أحدًا، أو إجابة لا تسجّل شيئًا). وتُسجَّل الشاشة في الأثناء؛ واللعبة التي تُغلق والسؤال ما زال مفتوحًا لا جلسة لتلك
الثواني، فيحذفها التشغيل التالي. ولا يُطرح شيء على Windows، ولا ينتظر شيء هناك.
تسجيل الفيديو
تُسجَّل شاشة اللعبة منذ لحظة تحميل اختبار اللعب وسماح اللاعب بذلك، قبل أن يسجّل أحد دخوله: تسجيل واحد لكل تشغيل، يُكتب أثناء التسجيل في ملف MP4 يشغّله المتصفّح دون تثبيت أي شيء، بعد أن يرمّزه مرمّز الفيديو الخاص ببطاقة الرسوميات (أو بالهاتف على Android) بصيغة H.264. والتسجيل الذي يقطعه انهيار اللعبة يحتفظ بكل إطار قبل القطع. ويُستثنى الوقت الذي تقضيه اللعبة في الخلفية. الإعدادات في Protokite → Playtest → Settings: الأربعة الأولى تحت Video recording (64-bit Windows)، ويقرؤها بناء Windows والمحرّر، والثلاثة الأخيرة تحت Recordings (every platform). أما مشغّلات Android فتقرأ قسمها الخاص، Video recording (Android)؛ راجع التسجيل على الهاتف.
يُنسخ الإطار ويُحجَّم ويُحوَّل على بطاقة الرسوميات ويُقرأ دون انتظارها، ثم يُرمَّز على بطاقة الرسوميات أيضًا؛ ويعمل
تسليم الإطارات إلى المرمّز وكتابة الملف كلٌّ في خيط خاص به، والإطار الذي لا يلحق يُسقَط بدل أن يوقف اللعبة. وحين
ينتهي التسجيل تذكر نافذة Console ما يحويه، وأيّ مرمّز صنعه، وكم إطارًا أُسقط، ولماذا.
متى يُرفع التسجيل
يُرفع التسجيل إلى جلسته بعد أن يكتمل ملفه وتبدأ الجلسة، أيّهما جاء ثانيًا. ويكتمل الملف حين:- يبلغ Max Recording Minutes أو Max Recording Size Mb؛
- يضغط اللاعب Upload your recording في نموذج الملاحظات، أو تستدعي لعبتك
ProtokitePlaytest.StopRecordingAndSendIt()؛ - توقفه لعبتك نهائيًا بـ
ProtokitePlaytest.StopVideoRecording().
الإغلاق لا يرفع. لا يمكن إرسال تسجيل كامل بينما تُغلق اللعبة، فالتسجيل الجاري عند الإغلاق يُكمَل
ويُحفظ، ويرسله التشغيل التالي. ويرسل التشغيل اللاحق كل تسجيل حفظه تشغيل سابق — رفع فاشل، أو إغلاق، أو
انهيار — الأقدم أولًا، حتى مع إطفاء Playtesting Enabled، فلا يضيّع بناء النشر ما سجّله بناء اختبار لعب.
أما التسجيل الذي لم تبدأ له أي جلسة فيُحذف، إذ لا يمكن إرساله أبدًا.
ProtokitePlaytest.CanSendTheRecording صحيحة. فهي خاطئة حين
لم تبدأ جلسة للتسجيل، والزر المضغوط حينها يوقف التسجيل ولا يرسل شيئًا:
المساحة على قرص اللاعب
Recordings Disk Budget Mb (وعلى Android Android Recordings Disk Budget Mb) أقصى ما يجوز أن تشغله كل التسجيلات المحفوظة على الجهاز معًا. قبل أن يبدأ تسجيل، تُحذف التسجيلات التي تركتها تشغيلات سابقة حتى يتّسع له المكان: مقاطع الفيديو الاختبارية أولًا، ثم التسجيلات المنتظرة للرفع، الأقدم أولًا. والتسجيل الجاري رفعه، أو الذي تمسكه نسخة من اللعبة ما زالت تعمل، لا يُحذف أبدًا. ولا يفسح التسجيل مكانًا إلا لما يسجّله حدّ طوله بمعدّل بتاته، مع ربع زائد (نحو 810 ميغابايت بالقيم الافتراضية)، فلا يحذف تسجيلٌ قصير تسجيلًا يتّسع بجانبه. وإن بقي أقل من ميغابايت واحد، لا يسجّل ذلك التشغيل فيديو، ويذكر تحذيرٌ الإعدادَ الذي يجب رفعه. وما دامت عمليات الرفع على الهاتف تنتظر إجابة اللاعب (Wi-Fi فقط والهاتف خارج Wi-Fi، أو السؤال لم يُجب بعد)، لا يُحذف تسجيل ينتظر الرفع أبدًا من أجل تسجيل جديد: يسجّل الجديد في المكان المتبقّي، وإن بقي أقل من ميغابايت واحد لا يسجّل شيئًا في ذلك التشغيل وتذكر نافذة Console السبب. وبالقيمة الافتراضية 1024 ميغابايت، يمكن لنحو 94 دقيقة من اللعب أن تنتظر Wi-Fi كاملة. ولا تنزل التسجيلات أبدًا بالمساحة الحرة للهاتف تحت الحدّ الذي ينبّه عنده Android إلى أن التخزين يكاد ينفد (500 ميغابايت، أو 5% من التخزين إن كانت أقل): فالهاتف الأكثر امتلاءً يعطي التسجيل مكانًا أقل. والتسجيل الذي قطعه انهيار أو انقطاع كهرباء أو إنهاء قسري للعبة يُكمله التشغيل التالي بكل إطار كامل فيه، ثم يُرفع إلى جلسته كغيره؛ أما الذي لم تبدأ جلسته قط فيُحذف.التسجيل على الهاتف
تقرأ مشغّلات Android قسمها الخاص من Protokite → Playtest → Settings، وهو Video recording (Android):
والتسجيل الذي توقّف بسبب الحرارة أو البطارية يُحفظ ويُرفع كغيره. ويسري Max Recording Minutes وMax Recording Size Mb
على كل المنصّات. والهاتف الذي لا يقبل مرمّزه حجم الفيديو أو معدّله يسجّل بالحجم الأصغر التالي الذي يقبله، ثم بـ15 و10
إطارات في الثانية، وتذكر نافذة Console أيّها.
وحين تذهب اللعبة إلى الخلفية، يُكتب كل ما يحمله التسجيل إلى ملفه، فاللعبة التي ينهيها Android وهي غائبة تحتفظ بكل إطار
سُجّل قبل أن تغادر. ويُعاد مرمّز الهاتف إلى الهاتف في الأثناء، ويبدأ أول إطار بعد العودة من جديد على إطار مفتاحي (keyframe)
في الملف نفسه.
التحليلات الثقيلة
يرسل اختبار اللعب هذه عبر تحليلات حزمة Flock، ضمن فئةplaytest، وتُقرأ في Dashboards → Game Metrics:
-
performance_windowلكل عشر ثوانٍ من اللعب: الوسيط والمئين 95 والمئين 99 لزمن الإطار، وhitches(الإطارات التي استغرقت Hitch Frame Time Ms، أي 60 افتراضيًا، أو أكثر)، والذاكرة المستعملة وذروتها، وmapأي المشهد النشط. وزمن الإطار هو الوقت الفعلي بين إطار والذي يليه، فالحركة البطيئة أو اللعبة الموقوفة تُقاس بالإطارات التي رآها اللاعب. -
level_loadedلكل مشهد تحمّله اللعبة مكان الذي قبله، مع المشهد السابق وload_seconds، أي المدة التي أوقف فيها التحميلُ اللعبة. - أحداثك الخاصة، على الخط الزمني نفسه وفي الفئة نفسها:
RecordPlaytestEvent بـtrue حين يوضع الحدث في الطابور، ويمكن استدعاؤها من أي خيط، ولا ترسل إلا ما دامت
التحليلات الثقيلة تعمل، وهي تبدأ بعد تحميل اختبار اللعب؛ والحدث المسجّل قبل ذلك في التشغيل يجيب بـfalse ولا
يُحفظ. ويُرفض الاسمان اللذان يرسلهما اختبار اللعب بنفسه.
تحتاج التحليلات الثقيلة إلى Analytics Enabled في حزمة Flock: فإن كان مطفأً لا يُقاس شيء، وتذكر نافذة
Console ذلك مرة واحدة. والأحداث أحداث Flock كغيرها، فهي تنتظر لاعبًا مسجّل الدخول وتتبع موافقة التحليلات
الخاصة بحزمة Flock. راجع التحليلات والأحداث لترى كيف تتلاءم الفئة ولوحات
المعلومات.
الاستثناءات
تبقى الاستثناءات من شأن حزمة Flock. فهي تلتقط استثناءات اللعبة من كل خيط، والمهام الفاشلة التي لم ينتظرها أحد، عبر Analytics Capture Exceptions في Flock → Settings → Advanced Settings (مفعّل افتراضيًا)، وتبلّغ عنها في Diagnostics → Errors. ومفتاح الاستثناءات في اختبار اللعب لا يشغّل ذلك ولا يطفئه أبدًا. وإذا كان مفتاح حزمة Flock مطفأً تُتخطّى خطوة الاستثناءات في الاختبار الذاتي الحي ويُذكر اسمه؛ ويخبركAnalytics.GetExceptionCaptureCoverage() في الحزمة بما يسمعه الالتقاط.
والاستثناء نفسه إذا رُمي مرة بعد مرة يصل إلى لوحة المعلومات تقريرًا واحدًا، ثم تقريرَ تكرار واحدًا يعدّ
البقية حين تُغلق نافذة التكرار (Analytics Exception Repeat Window، أي 60 ثانية). أما أسطر Debug.LogError
فليست استثناءات ولا يُبلَّغ عنها.
نموذج الملاحظات
حين ينشر اختبار اللعب نموذج ملاحظات في Protokite، يفتحه اللاعب فوق اللعبة بـF9 ويملؤه. وهو مبني ممّا نشرته — كل سؤال وتسمية ونص مساعد وخيار — فتعديل النموذج في Protokite لا يحتاج إلى بناء جديد.
نموذج منشور، مرسوم من اختبار اللعب: كل سؤال، والزر الذي يرسل التسجيل.
- يفحص Send الإجابات كما يفحصها Protokite، ويعرض كل مشكلة بجانب سؤالها قبل إرسال أي شيء: سؤال مطلوب تُرك فارغًا، أو تقييم خارج النطاق، أو خيار لا يعرضه السؤال.
- النموذج المرسَل يُحفظ على الجهاز أولًا ويُرسل من هناك، فلا يضيّعه إغلاق اللعبة ولا انقطاع الشبكة: ما لم يستطع الذهاب الآن يُرسل حين تعود الشبكة، أو بعد دقيقتين، أو في تشغيل لاحق. والإرسال مجددًا في الجلسة نفسها يستبدل الإجابات السابقة.
- إغلاقه دون إرسال يحفظ ما كُتب لبقية التشغيل.
- يظهر Upload your recording ما دام هذا التشغيل يسجّل الشاشة وقد بدأت جلسته: يوقف التسجيل ويرسله الآن. وفتح النموذج لا يوقف التسجيل من تلقاء نفسه أبدًا.
نموذج خاص بك
تعطيProtokitePlaytest.FeedbackForm واجهتك الأسئلة: لكل حقل Id وType وLabel وHelpText وOptions،
وهل هو Required. أجب عنها وافحصها وأرسلها عبر الفحص والحفظ نفسيهما اللذين يمرّ بهما النموذج المدمج:
Type الخاص بالحقل بثوابت ProtokitePlaytestFormFieldTypes بدل كتابته، وعامل النوع الذي لا تعرفه على
أنه نص، فهكذا يقرؤه الخادم.
الاستدعاءات المتاحة للعبتك
كلها علىProtokitePlaytest، في مساحة الأسماء Protokite.Playtest. استدعها من الخيط الرئيسي؛ وتعمل
RecordPlaytestEvent من أي خيط آخر أيضًا.
ومثال الحزمة،
Samples/PlaytestSample/ProtokitePlaytestSample.cs، يضع كل هذه على شاشة واحدة: أضفه إلى
GameObject واضغط Play.
التجربة في المحرّر
في النصف السفلي من نافذة الإعداد، Protokite → Playtest → Setup Checks And Test Video، كل ما يلزم للاختبار. وفي Play Mode تبدو هكذا:
نافذة الإعداد في Play Mode: الفحوص، وإجابة هذا الجهاز، والفيديو الاختباري، والاختبار الذاتي المباشر.
- Forget This Machine’s Answer ينسى إجابات هذا الجهاز، فيطرح Play التالي سؤال الموافقة مجددًا.
- Open Feedback Form يفتح النموذج كما يفتحه مفتاحه.
- Record Test Video يسجّل نافذة Game للثواني التي تضبطها، بإعدادات الفيديو ودون حاجة إلى اختبار لعب:
فلا بأس أن يكون اختبار اللعب مطفأً وألا يكون أحد مسجّل الدخول. يُحفظ الفيديو الاختباري في
ProtokitePlaytest/Recordings/TestVideos/داخل مجلد البيانات الدائمة للعبة، ولا يُرفع أبدًا، وتعرض النافذة أين ذهب. ويُرفض ما دام تسجيل اختبار اللعب نفسه جاريًا، ويفسح له الطريق. وككل فيديو، لا يُسجَّل إلا على Windows بنواة 64 بت وAndroid، ويستخدم في المحرّر إعدادات Windows. - Run Live Self-Test يفحص اختبار اللعب كله مقابل Protokite الحقيقي لديك (أدناه).
فحص بناء اختبار لعب
يفحص الاختبار الذاتي المباشر كل ما يفعله بناء اختبار اللعب مقابل Protokite الحقيقي لديك دفعة واحدة، ويسجّل سطرًا لكل خطوة وعدًّا في النهاية. شغّله في Play Mode بـRun Live Self-Test، أو من الشيفرة في المحرّر أو في بناء تطوير (بناء النشر يرفضه):- سجّل دخول لاعب أولًا، وأجب عن سؤال الموافقة. فهو لا يسجّل دخول أحد؛ والخطوات التي تحتاج إلى جلسة أو إجابة تُتخطّى مع ذكر السبب.
- شغّله في Play أو تشغيل خاص به. فهو يوقف تسجيل هذا التشغيل ليرفعه، ويرسل نموذجًا مملوءًا يستبدل ما أرسله اللاعب في هذا التشغيل، ويرمي استثناءين عمدًا — فإن كان Error Pause مفعّلًا في Console يتوقّف Play عندهما حتى تستأنفه.
- يترك أثرًا في لوحات معلوماتك: نموذجًا مملوءًا واحدًا في الجلسة، وحدث
playtest_self_testواحدًا، واستثناءً واحدًا مرميًّا مرتين ليُحتسب تكراره، وتسجيل التشغيل. وكلٌّ منها يحمل معرّف التشغيل (report.RunId)، لتجدها في Flock وProtokite. - تُتخطّى الخطوة مع ذكر السبب حين لا يشغّل اختبار اللعب ميزتها، وحين لا يكون في البناء مرمّز فيديو (كل منصّة
سوى Windows بنواة 64 بت وAndroid)، وفي اختبار اللعب المغلق ما لم تسمِّ واحدًا: مرّر معرّف Game Version لاختبار لعب مغلق
إلى
RunAsync، أو اكتبه في Closed Playtest Version ID في النافذة.
ما يبقى على جهاز اللاعب
تحتProtokitePlaytest/ في مجلد البيانات الدائمة للعبة (Application.persistentDataPath):
المنصّات
كل ما في هذه الصفحة يعمل حيثما تعمل حزمة Flock، عدا الفيديو. يُسجَّل الفيديو على Windows بنواة 64 بت، في المحرّر وفي المشغّلات، مع Mono وIL2CPP على السواء، عبر مرمّز H.264 الخاص بـWindows على بطاقة الرسوميات. ولا تشحن الحزمة أي ملف أصلي (native)، فلا يجد Smart App Control في Windows 11 شيئًا من الحزمة يرفضه. والحاسوب الذي لا تملك بطاقة رسومياته مرمّز H.264 لا يسجّل فيديو ويذكر السبب مرة واحدة في Console، ما لم يكن Allow Software Encoder مشغّلًا؛ وكذلك نسخة Windows N التي لا تحوي Media Feature Pack. وتذكر نافذة الإعداد المرمّز الذي يعرضه Windows أولًا على حاسوبك أنت، ويُظهر فيديو اختباري هل يسجّل به فعلًا. ويعمل التسجيل على Direct3D 11 و12 وVulkan وOpenGL، في Built-in Render Pipeline وURP، وبالألوان Linear وGamma، ويحتاج إلى بطاقة رسوميات تشغّل compute shaders. على Android تُسجَّل الشاشة بمرمّز H.264 العتادي الخاص بالهاتف، فلا تشحن الحزمة هناك أيضًا أي ملف أصلي (native). وقد قيس ذلك على هاتف رائد واحد (Galaxy S23 Ultra)، فاعتبر أرقامه أفضل الحالات. فمقارنةً باللعبة نفسها مبنيةً دون الحزمة، وهي ترسم 400 مكعّب مضاء متحرّك بدقة الهاتف الكاملة بمعدّل 60 إطارًا في الثانية، لم يكلّف التسجيل بالقيم الافتراضية شيئًا من معدّل الإطارات في مشغّلات IL2CPP (64 بت) أو Mono (32 بت)، ولم يكلّف جمع بيانات اللعب وحده شيئًا يمكن قياسه. وما يكلّفه التسجيل يقع على إطار واحد من كل أربعة، وهو الإطار الذي يُلتقط: نحو 1 إلى 3.5 ميلي ثانية إضافية من وقت بطاقة الرسوميات وحتى 2 ميلي ثانية إضافية من خيط الرسم في تلك الإطارات، ونحو 6% من نواة معالج في خدمة الوسائط على الهاتف؛ ويقضي الخيط الرئيسي في بناء Mono نحو 3 ميلي ثانية إضافية فيها أيضًا. وتضيف الحزمة نحو 7 ميغابايت إلى بناء IL2CPP و1.4 ميغابايت إلى بناء Mono. وتقرأ مشغّلات Android إعداداتها الخاصة (راجع التسجيل على الهاتف). والهاتف الذي لا تشغّل رسومياته compute shaders، أو لا يملك مرمّز H.264 عتاديًا، لا يسجّل فيديو ويذكر السبب مرة واحدة. ولا يبني Unity مشغّلات Mono إلا لمعالجات ARM بنواة 32 بت؛ أما بناء 64 بت فيكون بـIL2CPP. ولم تُقَس أجهزة Android بمعالجات x86. «لا فيديو على هذه المنصّة» يعني ذلك بالضبط ولا شيء أكثر: البناء لأي منصّة أخرى — macOS أو Linux أو iOS أو WebGL أو Windows بنواة 32 بت أو ARM64 — لا مرمّز فيديو فيه، ويذكر مرة واحدة في Console أنه لا يسجّل فيديو، ويشغّل كل شيء آخر: الجلسة، وسؤال الموافقة، والتحليلات الثقيلة، والاستثناءات، ونموذج الملاحظات. وتنبّهك نافذة الإعداد مسبقًا: «Players built for … record no video». واللعبة التي لا ترسم شيئًا (بناء خادم، أو لعبة بدأت بـ-nographics أو -batchmode) لا تسجّل شيئًا كذلك، ولا تستطيع عرض سؤال الموافقة: أجب عنه من الشيفرة
بـSetPlaytestConsent، أو أطفئ السؤال.
على WebGL تُنسخ ملفات اختبار اللعب — إجابة الموافقة، ومعرّف الجهاز، ونماذج الملاحظات المنتظرة للإرسال — إلى
تخزين المتصفّح بعد كل تغيير، فتكون موجودة في زيارة اللاعب التالية حيثما يحفظ المتصفّح بيانات الموقع. والنافذة
الخاصة تنساها حين تُغلق.