معمارية تطبيقات المصادر المفتوحة › Thousand Parsec 22 / 51 السابق التالي

Thousand Parsec

معمارية تطبيقات المصادر المفتوحة (المجلد الأول)Thousand Parsec

معمارية تطبيقات المصادر المفتوحة (المجلد الأول) Thousand Parsec

Alan Laudicina and Aaron Mavrinac

إذا استمتعت بهذه الكتب، فقد يعجبك أيضًا التصميم البرمجي بالأمثلة في بايثون (Software Design by Example in Python) والتصميم البرمجي بالأمثلة في جافاسكربت (Software Design by Example in JavaScript).

إمبراطورية نجمية شاسعة تضم مئة عالم، وتمتد عبر ألف فرسخ (parsec) في الفضاء. وخلافًا لبعض المناطق الأخرى في المجرّة، لا يقيم هنا سوى عدد قليل من المحاربين؛ فهنا شعبٌ ذهنيّ، ذو تقليد ثقافي وأكاديمي غنيّ. وكواكبهم الرائعة، التي بُنيت دورًا بعد دور حول جامعات عظيمة للعلوم والتكنولوجيا، هي منارة نور لكل من في عصر السلام والازدهار هذا. وتصِل ناقلات النجوم من امتدادات الربع البعيد وما وراءه، حاملةً أبرز الباحثين من شتى الأطراف. ويأتون ليقدموا مهاراتهم في أكثر مشروع طموحًا شرع فيه الكائنات الواعية على الإطلاق: تطوير شبكة حاسوبية لا مركزية تربط المجرّة بأكملها بكل لغاتها وثقافاتها وأنظمتها القانونية.

Thousand Parsec ليست مجرد لعبة فيديو: إنها إطار عمل (framework)، ومعه مجموعة أدوات كاملة لبناء ألعاب استراتيجية لإمبراطوريات فضائية متعددة اللاعبين وقائمة على الأدوار. ويتيح بروتوكول اللعبة العام تنفيذات متنوّعة لبرمجيات العميل والخادم والذكاء الاصطناعي، فضلًا عن مجموعة هائلة من الألعاب الممكنة. ورغم أن حجمه جعل التخطيط والتنفيذ أمرًا صعبًا، وأجبر المساهمين على المشي على خيط رفيع بين التطوير الرأسي المفرط والتطوير الأفقي المفرط، إلا أنه يجعله أيضًا عيّنةً مثيرة للاهتمام عند مناقشة معمارية تطبيقات المصادر المفتوحة.

التسمية التي يطلقها الصحفي على النوع الذي تنتمي إليه ألعاب Thousand Parsec هي «4X»—اختصارًا لعبارة «explore, expand, exploit, and exterminate»، أي أسلوب عمل اللاعب الذي يقود إمبراطورية[1]. ففي ألعاب النوع 4X عادةً يقوم اللاعبون بالاستطلاع لكشف الخريطة (explore)، وإنشاء مستوطنات جديدة أو توسيع نفوذ المستوطنات القائمة (expand)، وجمع الموارد واستخدامها في المناطق التي يسيطرون عليها (exploit)، ومهاجمة اللاعبين المنافسين والقضاء عليهم (exterminate). ويؤدي التركيز على التنمية الاقتصادية والتكنولوجية، والإدارة الدقيقة، وتنوّع سبل الهيمنة، إلى عمق وتعقيد في اللعب لا مثيل له ضمن النوع الاستراتيجي الأوسع.

من منظور اللاعب، تتألف لعبة Thousand Parsec من ثلاثة مكوّنات رئيسية. أولها العميل (client): وهو التطبيق الذي يتفاعل عبره اللاعب مع الكون. يتصل هذا التطبيق بخادم عبر الشبكة—متواصلًا بواسطة البروتوكول الذي لا غنى عنه—، ويتصل بهذا الخادم عملاء لاعبون آخرون (أو، في بعض الحالات، الذكاء الاصطناعي). ويخزّن الخادم حالة اللعبة كاملةً، ويحدّث العملاء في بداية كل دور. ويستطيع اللاعبون بعد ذلك تنفيذ إجراءات متنوعة وإبلاغ الخادم بها، فيحسب الخادم الحالة الناتجة للدور التالي. وطبيعة الإجراءات التي يمكن للاعب تنفيذها تحدّدها مجموعة قواعد (ruleset): وهذه هي اللعبة المُلْعَبة في جوهرها، تُنفَّذ وتُطبَّق في جهة الخادم، ويجسّدها أي عميل مساند أمام اللاعب.

ولتنوّع الألعاب الممكنة، ولتعقيد البنية المطلوبة لدعم هذا التنوّع، فإن Thousand Parsec مشروع مثير لكل من اللاعبين والمطوّرين على حدّ سواء. ونرجو ألّا يفتقد حتى المبرمج الجادّ الذي لديه اهتمام ضئيل ببنية أطر الألعاب قيمةً في الآليات الكامنة وراء الاتصال بين العميل والخادم، والإعداد الديناميكي، ومعالجة البيانات الوصفية، والتنفيذ الطبقّي، وكلها نضجت على مر السنين نحو تصميم جيد بأسلوب المصادر المفتوحة النموذجي.

في جوهره، Thousand Parsec في المقام الأول مجموعة من المواصفات القياسية لبروتوكول لعبة ولوظائف أخرى ذات صلة. ويتناول هذا الفصل إطار العمل من هذه المنظورية المجرَّدة في معظمه، لكن في حالات كثيرة يكون الرجوع إلى التنفيذات الفعلية أكثر إضاءةً إلى حدٍّ بعيد. ولهذا الغرض اختار المؤلفان التنفيذات «الرئيسية» (flagship) لكل مكوّن رئيسي لمناقشتها بشكل ملموس.

العميل المعتمد كنموذج هو tpclient-pywx، وهو عميل ناضج نسبيًا مبني على wxPython، يدعم حاليًا أكبر مجموعة من الميزات وأحدث إصدار من بروتوكول اللعبة. ويؤازره libtpclient-py، وهي مكتبة مساعدة للعميل بايثون توفّر التخزين المؤقت ووظائف أخرى، وlibtpproto-py، وهي مكتبة بايثون تطبّق أحدث إصدار من بروتوكول Thousand Parsec. أما الخادم، tpserver-cpp، وهو التنفيذ الناضج المكتوب بلغة C++ والداعم لأحدث الميزات وإصدار البروتوكول، فهو العيّنة المعتمدة. ويضمّ هذا الخادم مجموعات قواعد عديدة، من بينها مجموعة قواعد المرحلة Missile and Torpedo Wars التي تُعدّ نموذجًا ممتازًا لأنها تحقق أقصى استفادة من الميزات ولأنها لعبة فضاء 4X «تقليدية».

21.1. تشريح إمبراطورية نجمية

من أجل تقديم العناصر المكوِّنة لكون Thousand Parsec تعريفًا صحيحًا، من المنطقي أولًا إعطاء نظرة سريعة على إحدى الألعاب. وسندرس لهذا الغرض مجموعة قواعد Missile and Torpedo Wars، وهي مجموعة قواعد المرحلة الثانية في المشروع، والتي تستخدم معظم الميزات الرئيسية في الإصدار الحالي الرئيسي من بروتوكول Thousand Parsec. وستُستخدم هنا بعض المصطلحات التي لن تكون مألوفة بعد؛ وسيوضح بقية هذا القسم معانيها بحيث تتّسع الصورة وتتحقق القطع في مواضعها.

Missile and Torpedo Wars مجموعة قواعد متقدمة بحكم أنها تطبّق جميع الطرق المتاحة في إطار عمل Thousand Parsec. وحتى وقت كتابة هذا الكتاب، فهي المجموعة الوحيدة التي تفعل ذلك، وهي تتوسع بسرعة لتصبح لعبة أكثر اكتمالًا ومتعة.

عند الاتصال بخادم Thousand Parsec، يقوم العميل باستكشاف الخادم بحثًا عن قائمة كيانات اللعبة، ثم ينتقل إلى تنزيل الفهرس كاملًا. ويشمل هذا الفهرس جميع الكائنات واللوحات والرسائل والفئات والتصاميم والمكوّنات والخصائص واللاعبين والموارد التي تشكّل حالة اللعبة، وكلها مشروحة بالتفصيل في هذا القسم. ورغم أن ذلك قد يبدو حملًا ثقيلًا على العميل في بداية اللعبة—وكذلك في نهاية كل دور—فإن هذه المعلومات بالغة الأهمية للعبة. وبعد تنزيل هذه المعلومات، وهو ما يستغرق عادةً بضع ثوانٍ، يمتلك العميل الآن كل ما يحتاجه لنسج هذه المعلومات على تمثيله لكون اللعبة.

عند الاتصال بالخادم لأول مرة، يتم توليد كوكب عشوائي وإسناده بوصفه «كوكب الأم» (home planet) للاعب الجديد، وتُنشأ أساطيل اثنين تلقائيًا فيه. يتكوّن كل أسطول من تصميمَي كشّاف (Scout) افتراضيين، مكوَّنين من هيكل كشّاف (Scout Hull) مع أنبوب صاروخ ألفا (Alpha Missile Tube). ولأن مكوّنًا متفجرًا (Explosive) لم يُضَف، فإن هذا الأسطول الافتراضي ليس قادرًا بعد على قتال أسطول مع أسطول أو أسطول مع كوكب؛ هو في الحقيقة فريسة سهلة.

في هذه اللحظة، من المهم أن يبدأ اللاعب بتجهيز الأساطيل بالأسلحة. ويُحقق ذلك بإنشاء تصميم سلاح باستخدام أمر Build Weapon، ثم تحميل المنتج النهائي على الأسطول الهدف من خلال أمر Load Armament. يحوّل أمر Build Weapon موارد الكوكب—لكل كوكب كميات ونسبًا تحددها توزيعية عشوائية—إلى منتج نهائي: رأس حارب متفجّر يُزرع على سطح الكوكب المُنشئ. ثم ينقل أمر Load Armament هذا السلاح المكتمل إلى أسطول في انتظاره.

بعد تنفد موارد السطح سهلة المنال من كوكب، من المهم الحصول على المزيد منها عبر التعدين. وتأتي الموارد في حالتين أخريين: قابلة للتعدين (mineable) وغير متاحة (inaccessible). فباستخدام أمر Mine على كوكب، يمكن تحويل الموارد القابلة للتعدين مع مرور الوقت إلى موارد سطح، يمكن استخدامها بعد ذلك في البناء.

21.1.1. الكائنات

في كون Thousand Parsec، كل شيء مادي هو كائن (object). بل إن الكون نفسه كائن أيضًا. ويتيح هذا التصميم مجموعة عناصر شبه غير محدودة في اللعبة، مع بقائه بسيطًا لمجموعات القواعد التي تحتاج إلى بضعة أنواع من الكائنات فحسب. وإلى جانب إضافة أنواع كائنات جديدة، يستطيع كل كائن تخزين بعض المعلومات الخاصة به، التي يمكن إرسالها واستخدامها عبر بروتوكول Thousand Parsec. وهناك خمسة أنواع كائنات مدمجة أساسية تُقدَّم افتراضيًا في الوقت الحالي: الكون (Universe)، والمجرّة (Galaxy)، والنظام النجمي (Star System)، والكوكب (Planet)، والأسطول (Fleet).

الكون (Universe) هو الكائن في المستوى الأعلى في لعبة Thousand Parsec، وهو متاح دائمًا لجميع اللاعبين. ورغم أن كائن الكون لا يسيطر فعليًا على اللعبة كثيرًا، إلا أنه يخزّن معلومة بالغة الأهمية: رقم الدور الحالي. ويُشار إليه أيضًا بـ«السنة» في مصطلح Thousand Parsec، ويرتفع رقم الدور طبيعيًا بعد انتهاء كل دور. ويُخزَّن في عدد صحيح غير موقَّع بطول 32 بت، مما يتيح للألعاب أن تمتد حتى السنة 4,294,967,295. ورغم أنه ليس مستحيلًا من الناحية النظرية، لم يشاهد المؤلفان حتى اليوم لعبةً قدّمت إلى هذا الحد.

المجرّة (Galaxy) حاوية لعدد من الكائنات المتقاربة—الأنظمة النجمية والكواكب والأساطيل—ولا توفّر أي معلومات إضافية. وقد يوجد عدد كبير من المجرّات في اللعبة، كل منها يستضيف قسمًا من الكون.

مثل الكائنين السابقين، النظام النجمي (Star System) في المقام الأول حاوية لكائنات أدنى مستوى. غير أن كائن النظام النجمي هو أول مستوى من الكائنات الذي يمثّله العميل بيانيًا. وقد تحتوي هذه الكائنات على كواكب وأساطيل (على الأقل مؤقتًا).

الكوكب (Planet) جسم سماوي كبير قد يكون مأهولًا ويوفّر مناجم موارد ومنشآت إنتاج وتسليحًا أرضيًا وغيرها. والكوكب هو أول مستوى من الكائنات الذي يمكن أن يملكه لاعب؛ فامتلاك كوكب إنجاز لا ينبغي الاستخفاف به، وغياب امتلاك أي كوكب حالة معتادة تُعلن بها مجموعات القواعد هزيمة اللاعب. ويمتلك كائن الكوكب كمية كبيرة نسبيًا من البيانات المخزَّنة، تشمل ما يلي:

  • معرّف اللاعب (player ID) لمالك الكوكب (أو ‎-1 إذا لم يكن مملوكًا لأي لاعب).
  • قائمة بموارد الكوكب، تحتوي على معرّف المورد (نوعه)، وكميات موارد السطح والموارد القابلة للتعدين والموارد غير المتاحة من هذا النوع على الكوكب.

الكائنات المدمجة الموصوفة أعلاه توفّر أساسًا جيدًا لكثير من مجموعات القواعد التي تتبع صيغة لعبة فضاء 4X التقليدية. وبدهيًا، ومن حيث المبادئ السليمة لهندسة البرمجيات، يمكن توسيع أصناف الكائنات داخل مجموعات القواعد. وهكذا يملك مصمم مجموعة القواعد القدرة على إنشاء أنواع كائنات جديدة أو تخزين معلومات إضافية في أنواع الكائنات القائمة بحسب ما تتطلبه مجموعة القواعد، مما يتيح قابلية توسيع شبه غير محدودة من حيث الكائنات المادية المتاحة في اللعبة.

21.1.2. الأوامر

تُعرَّف الأوامر (orders) من كل مجموعة قواعد، ويمكن إرفاقها بكائنات الأساطيل والكواكب معًا. ورغم أن نواة الخادم لا تتضمن أي أنواع أوامر افتراضية، إلا أنها جزء أساسي من حتى أبسط لعبة. وبحسب طبيعة مجموعة القواعد، قد تُستخدم الأوامر لإنجاز أي مهمة تقريبًا. وفي روح النوع 4X، هناك بعض الأوامر القياسية المنفَّذة في معظم مجموعات القواعد: وهي أوامر Move وIntercept وBuild وColonize وMine وAttack.

لتحقيق الأمر الأول في 4X وهو (explore)، ينبغي القدرة على التنقل في خريطة الكون. وعادةً ما يتحقق ذلك عبر أمر Move مُلحق بكائن أسطول. وفي روح إطار عمل Thousand Parsec المرن والقابل للتوسيع، يمكن تنفيذ أوامر Move بطرق مختلفة بحسب طبيعة مجموعة القواعد. في Minisec وMissile and Torpedo Wars، يأخذ أمر Move عادةً نقطة في فضاء ثلاثي الأبعاد كمعامل. وعلى جهة الخادم، يُحسب الوقت المقدَّر للوصول وتُعاد رسالة إلى العميل بعدد الأدوار المطلوبة. ويتصرف أمر Move أيضًا كأمر Attack صوري في مجموعات القواعد التي لا تنفّذ اللعب الجماعي. فمثلًا، الانتقال إلى نقطة يشغلها أسطول عدو في كل من Minisec وMissile and Torpedo Wars يكاد لا يتبعه سوى فترة من القتال العنيف. وهناك مجموعات قواعد تدعم أمر Move تهيّئ معاملاته بصورة مختلفة (أي دون استخدام نقاط ثلاثية الأبعاد). فمثلًا، لا تسمح مجموعة قواعد Risk إلا بالانتقال في دور واحد إلى الكواكب المتصلة مباشرةً بـ«ثقب دودي» (wormhole).

أمر Intercept، المُلحق عادةً بكائنات الأساطيل، يسمح لكائن بأن يلاقي كائنًا آخر (غالبًا أسطولًا عدائيًا) في الفضاء. وهذا الأمر مشابه لأمر Move، لكن بما أنه قد يكون الكائنان يتحركان في اتجاهين مختلفين أثناء تنفيذ الدور، فإن الهبوط مباشرةً على أسطول آخر بمجرد استخدام الإحداثيات المكانية مستحيل، لذا يلزم نوع أوامر مميز. يعالج أمر Intercept هذه المسألة، ويمكن استخدامه لمحو أسطول عدو في أعماق الفضاء أو لصد هجوم وشيك في لحظة حرجة.

يساعد أمر Build على تحقيق أمرين من أوامر 4X—expand وexploit. والوسيلة الواضحة للتوسع في أنحاء الكون هي بناء أعداد كبيرة من أساطيل السفن وتحريكها بعيدًا. وأمر Build مُلحق عادةً بكائنات الكواكب، وهو مرتبط غالبًا بمقدار الموارد التي يحتوي عليها الكوكب—وكيفية استغلالها. وإذا حظي لاعب بأن يكون لديه كوكب أم غني بالموارد، فقد يكتسب هذا اللاعب ميزة مبكرة في اللعبة عبر البناء.

مثل أمر Build، يساعد أمر Colonize على تحقيق مبدأي expand وexploit. الملحق دائمًا تقريبًا بكائنات الأساطيل، يسمح لأمر Colonize للاعب بالاستيلاء على كوكب غير مطالب به. ويساعد ذلك على توسيع السيطرة على الكواكب في أنحاء الكون.

يجسّد أمر Mine مبدأ exploit. هذا الأمر، المُلحق عادةً بكائنات الكواكب والأجرام السماوية الأخرى، يسمح للاعب بالتعدين بحثًا عن موارد غير مستخدمة لا تتوفر فورًا على السطح. ويؤدي ذلك إلى إحضار هذه الموارد إلى السطح، مما يتيح استخدامها لاحقًا في البناء وبالتالي توسيع قبضة اللاعب على الكون.

المنفَّذ في بعض مجموعات القواعد، يسمح أمر Attack للاعب بأن يبدأ اشتباكًا صريحًا مع أسطول أو كوكب عدائي، محققًا الأمر الأخير من أوامر 4X وهو exterminate. وفي مجموعات القواعد القائمة على الفرق، فإن إدراج أمر Attack مميز (بدلًا من مجرد استخدام Move وIntercept لاستهداف الأهداف ضمنيًا) مهم لتجنب النيران الصديقة وتنسيق الهجمات.

ولأن إطار عمل Thousand Parsec يطلب من مطوّري مجموعات القواعد تعريف أنواع أوامرهم الخاصة، من الممكن—بل ويُستحسن—أن يفكّروا خارج الإطار المقبول وينشئوا أوامر مخصّصة لا توجد في مكان آخر. وتتيح القدرة على حزم بيانات إضافية في أي كائن للمطوّرين فعل أمور مثيرة للاهتمام جدًا مع أنواع الأوامر المخصّصة.

21.1.3. الموارد

الموارد (resources) هي قطع بيانات إضافية تُحزَم في كائنات اللعبة. وتُستخدم على نطاق واسع—وخاصةً بواسطة كائنات الكواكب—مما يسمح بتوسيع مجموعات القواعد بسهولة. وكما في العديد من قرارات التصميم في Thousand Parsec، كانت قابلية التوسيع هي العامل المحرّك لإدراج الموارد.

بينما تُنفّذ الموارد عادةً بواسطة مصمّم مجموعة القواعد، هناك مورد واحد يُستخدم على نطاق ثابت في الإطار كله: مورد الكوكب الأم (Home Planet)، الذي يُستخدم لتحديد كوكب الأم الخاص باللاعب.

وفق أفضل ممارسات Thousand Parsec، تُستخدم الموارد عادةً لتمثيل شيء يمكن تحويله إلى نوع ما من الكائنات. فمثلًا، تنفّذ Minisec مورد أجزاء السفن (Ship Parts)، الذي يُسنَد بكميات عشوائية إلى كل كائن كوكب في الكون. وعندما يتم استعمار أحد هذه الكواكب، يمكنك عندئذ تحويل مورد أجزاء السفن هذا إلى أساطيل فعلية باستخدام أمر Build.

قد تكون Missile and Torpedo Wars أكثر مجموعات القواعد استخدامًا للموارد حتى الآن. فهي أول مجموعة قواعد تكون فيها الأسلحة ذات طبيعة ديناميكية، أي أنها يمكن إضافتها إلى سفينة من كوكب، كما يمكن إزالتها من سفينة وإعادتها إلى كوكب. ولمصادفة ذلك، ينشئ اللعبة نوع مورد لكل سلاح يُنشأ في اللعبة. ويتيح ذلك للسفن تحديد نوع السلاح بواسطة مورد، ونقلها بحرية في أنحاء الكون. كما تتتبع Missile and Torpedo Wars المصانع (القدرة الإنتاجية للكواكب) باستخدام مورد المصانع (Factories) المرتبط بكل كوكب.

21.1.4. التصاميم

في Thousand Parsec، قد يتكوّن كل من الأسلحة والسفن من مكوّنات مختلفة. وتُجمع هذه المكوّنات لتكوّن أساس التصميم (Design)—أي نموذج أولي لشيء يمكن بناؤه واستخدامه داخل اللعبة. وعند إنشاء مجموعة قواعد، على المصمّم اتخاذ قرار شبه فوري: هل تسمح مجموعة القواعد بإنشاء تصاميم الأسلحة والسفن ديناميكيًا، أم أنها تستخدم قائمة محددة مسبقًا من التصاميم؟ فمن جهة، تصبح اللعبة التي تستخدم تصاميم معبّأة مسبقًا أسهل في التطوير والموازنة، ومن جهة أخرى، تضيف الإنشاء الديناميكي للتصاميم مستوىً جديدًا تمامًا من التعقيد والتحدي والمتعة إلى اللعبة.

تتيح التصاميم التي ينشئها المستخدمون أن تصبح اللعبة أكثر تقدمًا بكثير. ولأن على المستخدمين تصميم سفنهم وتسليحهم استراتيجيًا، تُضاف طبقة من التباين إلى اللعبة، مما قد يساعد في الحدّ من المزايا الكبيرة التي قد تُمنح للاعب بسبب الحظ (مثل توزيعه) وجوانب أخرى من استراتيجية اللعبة. وتحكم هذه التصاميم قواعد كل مكوّن، الموضحة في لغة مكوّنات Thousand Parsec (TPCL، التي تتناولها لاحقًا في هذا الفصل)، والمحدّدة لكل مجموعة قواعد. والنتيجة أنه لا يلزم أي برمجة إضافية من وظيفة من جانب المطوّر لتنفيذ تصميم الأسلحة والسفن؛ فتكوين بعض القواعد البسيطة لكل مكوّن متاح في مجموعة القواعد يكفي.

من دون تخطيط دقيق وموازنة سليمة، يمكن أن تتحول الميزة الكبرى لاستخدام تصاميم مخصّصة إلى عائق. وفي المراحل المتأخرة من اللعبة، قد يُنفَق وقت غير متناسب في تصميم أنواع جديدة من الأسلحة والسفن لبنائها. كما أن توفير تجربة مستخدم جيدة على جهة العميل للتعامل مع التصاميم يمثل تحديًا. ولأن معالجة التصاميم قد تكون جزءًا جوهريًا من إحدى الألعاب، بينما تكون غير ذات صلة تمامًا بأخرى، فإن دمج نافذة تصاميم في العملاء عقبة كبيرة. وأكثر عملاء Thousand Parsec اكتمالًا، tpclient-pywx، يضع حاليًا مُشغّل هذه النافذة في مكان بعيد نسبيًا عن الانتباه، في قائمة فرعية من شريط القوائم (وهي نادرًا ما تُستخدم أثناء اللعب).

صُمّمت وظيفة التصميم لتكون في متناول مطوّري مجموعات القواعد بسهولة، مع السماح للألعاب بالتوسع إلى مستويات تعقيد شبه غير محدودة. والكثير من مجموعات القواعد القائمة تسمح بتصاميم محددة مسبقًا فحسب. غير أن Missile and Torpedo Wars يسمح بتصميم كامل للأسلحة والسفن من مجموعة متنوعة من المكوّنات.

21.2. بروتوكول Thousand Parsec

يمكن القول إن بروتوكول Thousand Parsec هو الأساس الذي يُبنى عليه كل شيء آخر في المشروع. فهو يحدد الميزات المتاحة لمكتبي مجموعات القواعد، وكيف ينبغي أن تعمل الخوادم، وما ينبغي أن يكون العملاء قادرين على معالجته. والأهم من ذلك، تمامًا كمعيار لاتصالات بين النجوم، فإنه يتيح لمكوّنات البرمجيات المختلفة أن تفهم بعضها بعضًا.

يدير الخادم الحالة الفعلية وديناميكيات اللعبة وفق التعليمات التي توفرها مجموعة القواعد. وفي كل دور، يتلقى عميل اللاعب بعض المعلومات عن حالة اللعبة: الكائنات وملكيتها وحالتها الحالية، والأوامر قيد التنفيذ، ومخزون الموارد، والتقدم التكنولوجي، والرسائل، وكل ما هو آخر مرئي لذلك اللاعب بعينه. ويستطيع اللاعب عندئذ تنفيذ إجراءات معينة بحسب الحالة الحالية، مثل إصدار الأوامر أو إنشاء التصاميم، وإرسالها إلى الخادم لتُعالَج في حساب الدور التالي. وكل هذا الاتصال مؤطَّر في بروتوكول Thousand Parsec. ومن ثمار هذه البنية أثر مثير للاهتمام ومقصود لذاته هو أن عملاء الذكاء الاصطناعي—الذين يوجدون خارج الخادم ومجموعة القواعد، والذين هم الوسيلة الوحيدة لتوفير لاعبين حاسوبيين في اللعبة— يخضعون للقواعد نفسها التي يخضع لها العملاء البشريون، ولذلك لا يستطيعون «الغش» عبر الحصول على معلومات غير عادلة أو عبر القدرة على تحريف القواعد.

تصف مواصفة البروتوكول سلسلة من الإطارات (frames)، وهي هرمية بمعنى أن كل إطار (باستثناء إطار Header) له نوع إطار أساسي يضيف إليه بياناته الخاصة. وهناك مجموعة متنوعة من أنواع الإطارات المجرّدة التي لا تُستخدم صراحةً، بل توجد لوصف القواعد الأساسية للإطارات المجسّدة. وقد يكون للإطارات أيضًا اتجاه محدَّد، بحيث لا يلزم دعم هذه الإطارات للإرسال من طرف واحد (الخادم أو العميل) وللاستقبال من الطرف الآخر.

صُمّم بروتوكول Thousand Parsec للعمل إما باستقلالية فوق TCP/IP، أو ممرَّرًا عبر نفق عبر بروتوكول آخر مثل HTTP. وهو يدعم أيضًا تشفير SSL.

21.2.1. الأساسيات

يوفّر البروتوكول بضعة إطارات عامة حاضرة في كل مكان تقريبًا في الاتصال بين العميل والخادم. ويوفّر إطار Header المذكور سابقًا ببساطة أساسًا لجميع الإطارات الأخرى عبر نسبيه المباشرين: إطارَي Request وResponse. فالأول هو أساس الإطارات التي تبدأ الاتصال (في أي من الاتجاهين)، والثاني هو أساس الإطارات التي تحفَّز بها. ويوفّر إطارا OK وFail (كلاهما إطار Response) القيمتين للمنطق البولياني في التبادل. وإطار Sequence (وهو أيضًا Response) يُشعر المستقبِل بأن عدة إطارات ستتبع استجابةً لطلبه.

يستخدم Thousand Parsec معرّفات (IDs) رقمية للإشارة إلى الأشياء. وعليه، توجد مفردات من الإطارات لتحريك البيانات بواسطة هذه المعرّفات. والإطار Get With ID هو الطلب الأساسي للأشياء التي تحمل مثل هذا المعرّف؛ وهناك أيضًا إطار Get With ID and Slot للأشياء الموجودة في «فتحة» (slot) في شيء أب له معرّف (مثل أمر على كائن). ومن البديهي أنه غالبًا ما يكون من الضروري الحصول على متتاليات من المعرّفات، مثل عند تعبئة حالة العميل أولًا؛ ويُعالَج ذلك باستخدام طلبات من نوع Get ID Sequence واستجابات من نوع ID Sequence. والبنية المعتادة لطلب عناصر متعددة هي طلب Get ID Sequence واستجابة ID Sequence، يتبعهما سلسلة من طلبات Get With ID واستجابات مناسبة تصف العنصر المطلوب.

21.2.2. اللاعبون والألعاب

قبل أن يبدأ العميل التفاعل مع لعبة، هناك بعض الإجراءات الرسمية التي ينبغي استيفاؤها. يجب على العميل أولًا إرسال إطار Connect إلى الخادم، وقد يستجيب له الخادم بـOK أو Fail—وبما أن إطار Connect يتضمن إصدار بروتوكول العميل، فقد يكون تعارض في الإصدار أحد أسباب الفشل. ويمكن أيضًا أن يستجيب الخادم بإطار Redirect، وذلك للتنقلات أو مجموعات الخوادم. بعد ذلك، يجب على العميل إرسال إطار Login، الذي يعرّف اللاعب وقد يوثّق هويته؛ ويمكن للاعبين الجدد على خادم استخدام إطار Create Account أولًا إذا سمح لهم الخادم بذلك.

ولكل هذا التنوع الهائل في Thousand Parsec، يحتاج العميل إلى وسيلة لتحديد ميزات البروتوكول التي يدعمها الخادم؛ ويُحقق ذلك عبر طلب Get Features واستجابة Features. ومن بين الميزات التي قد يستجيب بها الخادم:

  • توافر تشفير SSL والتمرير عبر نفق HTTP (على هذا المنفذ أو منفذ آخر).
  • دعم حساب خصائص المكوّنات على جهة الخادم.
  • ترتيب متتاليات المعرّفات في الاستجابات (تصاعدي مقابل تنازلي).

وبالمثل، يبلّغ طلب Get Games ومتتالية استجابات Game العميل بطبيعة الألعاب النشطة على الخادم. ويحتوي إطار Game الواحد على المعلومات التالية عن اللعبة:

  • الاسم الطويل (الوصفي) للعبة.
  • قائمة بإصدارات البروتوكول المدعومة.
  • نوع الخادم وإصداره.
  • اسم مجموعة القواعد وإصدارها.
  • قائمة بإعدادات اتصال الشبكة الممكنة.
  • بعض العناصر الاختيارية (عدد اللاعبين، وعدد الكائنات، تفاصيل المسؤول، تعليق، رقم الدور الحالي، إلخ).
  • عنوان URL الأساسي للوسائط المستخدمة في اللعبة.

ومن البديهي أنه من المهم أن يعرف اللاعب من يواجهه (أو يعمل معه، بحسب الحال)، وهناك مجموعة من الإطارات لذلك. يتبع هذا التبادل النمط المعتاد لتسلسل العناصر مع طلب Get Player IDs، واستجابة List of Player IDs، وسلسلة من طلبات Get Player Data واستجابات Player Data. ويحتوي إطار Player Data على اسم اللاعب وسلالته.

تُضبط أدوار اللعبة أيضًا عبر البروتوكول. وعندما ينهي اللاعب تنفيذ إجراءاته، يمكنه الإشارة إلى جاهزيته للدور التالي عبر طلب Finished Turn؛ ويُحسب الدور التالي عندما يفعل ذلك جميع اللاعبين. ولأدوار أيضًا حد زمني يفرضه الخادم، بحيث لا يستطيع اللاعبون البطيئون أو غير المستجيبين تعطيل اللعبة؛ ويصدر العميل عادةً طلب Get Time Remaining، ويتتبع الدور بمؤقّت محلّي مضبوط على القيمة الواردة في استجابة Time Remaining من الخادم.

أخيرًا، يدعم Thousand Parsec الرسائل لأغراض متنوعة: بث اللعبة لجميع اللاعبين، وإشعارات اللعبة للاعب واحد، ومراسلات اللاعبين فيما بينهم. وتُنظَّم هذه الرسائل في حاويات «لوحات» (boards) تدير الترتيب والرؤية؛ ويتكوّن التبادل، وفقًا لنمط تسلسل العناصر، من طلب Get Board IDs، واستجابة List of Board IDs، وسلسلة من طلبات Get Board واستجابات Board.

وبعد أن يحصل العميل على معلومات عن لوحة رسائل، يستطيع إصدار طلبات Get Message للحصول على الرسائل الموجودة في اللوحة حسب الفتحة (ولهذا تستخدم Get Message إطار Get With ID and Slot الأساسي)؛ ويستجيب الخادم بإطارات Message تتضمن عنوان الرسالة ونصها، والدور الذي أُنشئت فيه الرسالة، وإشارات إلى أي كيانات أخرى وردت في الرسالة. وإلى جانب مجموعة العناصر المعتادة في Thousand Parsec (اللاعبون والكائنات وما شابه)، وهناك أيضًا بعض الإشارات الخاصة التي تشمل أولوية الرسالة، وإجراءات اللاعب، وحالة الأمر. ومن البديهي أن يستطيع العميل أيضًا إضافة الرسائل باستخدام إطار Post Message—حاملةً لإطار Messsage—وحذفها باستخدام إطار Remove Message (المبني على إطار GetMessage).

21.2.3. الكائنات والأوامر والموارد

تُنجز الجزء الأكبر من عملية التفاعل مع الكون عبر سلسلة من الإطارات التي تضم وظائف الكائنات والأوامر والموارد.

يجب أن يحصل العميل على الحالة المادية للكون—أو على الأقل ذلك الجزء منه الذي يتحكم فيه اللاعب أو يملك القدرة على رؤيته—عند الاتصال، وفي كل دور بعد ذلك. ويصدر العميل عادةً طلب Get Object IDs (وهو طلب من نوع Get ID Sequence)، ويرد الخادم عليه باستجابة List of Object IDs. ويستطيع العميل عندئذ طلب تفاصيل عن كائنات بعينها باستخدام طلبات Get Object by ID، التي يُرد عليها بإطارات Object تحتوي على تلك التفاصيل—وهي أيضًا خاضعة لرؤية اللاعب—مثل نوعها واسمها وحجمها وموضعها وسرعتها والكائنات التي تحتويها وأنواع الأوامر المنطبقة عليها وأوامرها الحالية. كما يوفّر البروتوكول طلب Get Object IDs by Position، الذي يتيح للعميل العثور على جميع الكائنات ضمن كرة محددة من الفضاء.

يحصل العميل على مجموعة الأوامر الممكنة وفقًا لنمط تسلسل العناصر المعتاد، عبر إرسال طلب Get Order Description IDs، ثم لكل معرّف في استجابة List of Order Description IDs، إرسال طلب Get Order Description وتلقي استجابة Order Description. وقد تطور تنفيذ الأوامر وطوابيرها نفسها بدرجة كبيرة عبر تاريخ البروتوكول. في الأصل، كان لكل كائن طابور أوامر واحد. وكان العميل يرسل طلب Order (يحتوي على نوع الأمر والكائن الهدف ومعلومات أخرى)، ويتلقى استجابة Outcome تفصّل النتيجة المتوقعة للأمر، وبعد اكتمال الأمر يتلقى إطار Result يحتوي على النتيجة الفعلية.

في الإصدار الثاني، ضمّ إطار Order محتوى إطار Outcome (لأنه، بناءً على وصف الأمر، لا يحتاج هذا إلى مُدخلات الخادم)، وحُذف إطار Result كليًا. أما أحدث إصدار من البروتوكول فقد أعاد هيكلة طابور الأوامر خارج الكائنات، وأضاف إطارات Get Order Queue IDs وList of Order Queue IDs وGet Order Queue وOrder Queue، التي تعمل بصورة مشابهة لوظائف الرسائل واللوحات[2]. ويتيح إطارا Get Order وRemove Order (كلاهما طلب من نوع GetWithIDSlot) للعميل الوصول إلى الأوامر في طابور وإزالتها منها على التوالي. وأصبح إطار Insert Order يعمل كحامل للحمولة Order؛ وقد فُعل ذلك لإتاحة إطار آخر هو Probe Order، يستخدمه العميل في بعض الحالات للحصول على معلومات للاستخدام المحلّي.

تتبع أوصاف الموارد أيضًا نمط تسلسل العناصر: طلب Get Resource Description IDs، واستجابة List of Resource Description IDs، وسلسلة من طلبات Get Resource Description واستجابات Resource Description.

21.2.4. معالجة التصاميم

تُقسَّم معالجة التصاميم في بروتوكول Thousand Parsec إلى معالجة أربع فئات فرعية منفصلة: الفئات، والمكوّنات، والخصائص، والتصاميم.

تميّز الفئات (categories) أنواع التصاميم المختلفة. وأكثر نوعَي تصاميم استخدامًا هما السفن والأسلحة. وإنشاء فئة أمر بسيط، إذ لا يتكوّن إلا من اسم ووصف؛ فإطار Category نفسه لا يحتوي إلا على هاتين السلسلتين. وتضيف كل مجموعة قواعد الفئة إلى مخزن التصاميم (Design Store) باستخدام طلب Add Category، وهو حامل لإطار Category. أما بقية إدارة الفئات فتتم وفق نمط تسلسل العناصر المعتاد مع طلب Get Category IDs واستجابة List of Category IDs.

تتألف المكوّنات (components) من الأجزاء والوحدات المختلفة التي تشكّل التصميم. وقد يكون ذلك أي شيء من هيكل سفينة أو صاروخ إلى الأنبوب الذي يسكن فيه الصاروخ. والمكوّنات أكثر تعقيدًا قليلًا من الفئات. ويحتوي إطار Component على المعلومات التالية:

  • اسم المكوّن ووصفه.
  • قائمة بالفئات التي ينتمي إليها المكوّن.
  • دالة Requirements، بلغة مكوّنات Thousand Parsec (TPCL).
  • قائمة بالخصائص وقيمها المقابلة.

جدير بالذكر بشكل خاص دالة Requirements المرتبطة بالمكوّن. ولأن المكوّنات هي الأجزاء التي تشكّل سفينة أو سلاحًا أو أي كائن مبني، من الضروري ضمان صلاحيتها عند إضافتها إلى تصميم. تتحقق دالة Requirements من أن كل مكوّن يُضاف إلى التصميم يطابق قواعد المكوّنات التي أُضيفت من قبله. فمثلًا، في Missile and Torpedo Wars، يستحيل حمل صاروخ ألفا (Alpha Missile) في سفينة دون أنبوب صاروخ ألفا. ويجري هذا التحقق في كلٍّ من جهة العميل وجهة الخادم، ولهذا يجب أن تظهر الدالة كاملةً في إطار من إطارات البروتوكول، ولهذا اختير لها لغة موجزة (TPCL، التي تتناولها لاحقًا في الفصل).

تُبلَّغ كل خصائص التصميم عبر إطارات Property. ويكشف كل تصميم قواعد مجموعة من الخصائص المستخدمة داخل اللعبة. وهذه تشكّل عادةً أمورًا مثل عدد أنابيب الصواريخ من نوع معيّن مسموح بها في السفينة، أو كمية الدروع المرفقة بنوع هيكل معيّن. تمامًا كإطارات Component، تستخدم إطارات Property لغة TPCL. ويحتوي إطار Property على المعلومات التالية:

  • اسم الخاصية (اسم العرض) ووصفها.
  • قائمة بالفئات التي تنتمي إليها الخاصية.
  • اسم الخاصية (معرّف TPCL صالح).
  • رتبة الخاصية.
  • دالتا Calculate وRequirements، بلغة مكوّنات Thousand Parsec (TPCL).

تُستخدم رتبة الخاصية لتمييز تسلسل هرمي للتبعيات. في TPCL، لا يجوز لأي دالة أن تعتمد على أي خاصية رتبتها أقل من أو مساوية لرتبة هذه الخاصية. أي أن لو كانت لدينا خاصية Invisibility برتبة 0 وخاصية Armor برتبة 1، ما كان لتكون خاصية Invisibility قادرة على الاعتماد مباشرةً على خاصية Armor. وقد نُفِّذ هذا الترتيب وسيلةً لوقف التبعيات الدائرية. وتُستخدم دالة Calculate لتعريف كيف تُعرض الخاصية، مميِّزةً بين طرائق القياس. وتستخدم Missile and Torpedo Wars تنسيق XML لاستيراد خصائص اللعبة من ملف بيانات اللعبة. ويعرض الشكل 21.2 خاصية نموذجية من بيانات اللعبة تلك.

<prop>
<CategoryIDName>Ships</CategoryIDName>
<rank value="0"/>
<name>Colonise</name>
<displayName>Can Colonise Planets</displayName>
<description>Can the ship colonise planets</description>
<tpclDisplayFunction>
    (lambda (design bits) (let ((n (apply + bits))) (cons n (if (= n 1) "Yes" "No")) ) )
</tpclDisplayFunction>
<tpclRequirementsFunction>
    (lambda (design) (cons #t ""))
</tpclRequirementsFunction>
</prop>

الشكل 21.2: خاصية نموذجية

في هذا المثال، لدينا خاصية تنتمي إلى فئة Ships (السفن)، برتبة 0. وتُسمّى هذه الخاصية Colonise، وهي تتعلق بقدرة السفينة على استعمار الكواكب. ونظرة سريعة على دالة Calculate في TPCL (المدرجة هنا باسم tpclDisplayFunction) تكشف أن هذه الخاصية تُخرج إما «Yes» أو «No» حسب ما إذا كانت السفينة المعنية تملك تلك القدرة أم لا. وإضافة الخصائص بهذا الأسلوب تمنح مصمم مجموعة القواعد تحكمًا دقيقًا في مقاييس اللعبة والقدرة على مقارنتها بسهولة وإخراجها بتنسيق يفهمه اللاعب.

يُنشأ التصميم الفعلي للسفن والأسلحة وقطع اللعبة الأخرى ويُعالَج باستخدام إطار Design والإطارات المرتبطة به. وفي جميع مجموعات القواعد الحالية، تُستخدم هذه الإطارات لبناء السفن والتسليح باستخدام مجموعة المكوّنات والخصائص القائمة. وبما أن قواعد التصاميم تُعالَج بالفعل في دوال Requirements بصيغة TPCL في كل من الخصائص والمكوّنات، فإن إنشاء التصميم أمر في متناول اليد. ويحتوي إطار Design على المعلومات التالية:

  • اسم التصميم ووصفه.
  • قائمة بالفئات التي ينتمي إليها التصميم.
  • عدد النسخ الموجودة من التصميم.
  • مالك التصميم.
  • قائمة بمعرّفات المكوّنات والكميات المقابلة لها.
  • قائمة بالخصائص ونصوص العرض المقابلة لها.
  • التغذية الراجعة على التصميم.

هذا الإطار مختلف قليلًا عن غيره. وأبرز ما فيه أن التصميم، بما أنه عنصر مملوك في اللعبة، له علاقة بمالك كل تصميم. كما يتتبع التصميم عدد مرات إنشائه بعدّاد.

21.2.5. إدارة الخادم

يتوفر أيضًا امتداد لبروتوكول يتيح التحكم الحيّ عن بُعد في الخوادم الداعمة. وحالة الاستخدام المعيارية هي الاتصال بالخادم عبر عميل إدارة—ربما واجهة أوامر تشبه الصدفة (shell) أو لوحة تكوين رسومية (GUI)—لتغيير الإعدادات أو تنفيذ مهام صيانة أخرى. غير أن استخدامات أخرى أكثر تخصّصًا ممكنة، مثل الإدارة خلف الكواليس للألعاب ذات اللاعب الواحد.

وكما في بروتوكول اللعبة الموصوف في الأقسام السابقة، يبدأ عميل الإدارة أولًا بالتفاوض على اتصال (على منفذ منفصل عن منفذ اللعبة العادي) والمصادقة باستخدام طلبَي Connect وLogin. وبعد الاتصال، يمكن للعميل تلقي رسائل السجل من الخادم وإصدار أوامر إليه.

تُدفع رسائل السجل إلى العميل عبر إطارات Log Message. وتحتوي هذه على مستوى خطورة ونص؛ ويختار العميل، حسب ملاءمته للسياق، أن يعرض كل رسائل السجل التي يتلقاها أو بعضها أو لا شيء منها.

قد يُصدر الخادم أيضًا إطار Command Update يطلب من العميل تعبئة مجموعة أوامره المحلّية أو تحديثها؛ وتُكشف الأوامر المدعومة للعميل في استجابة الخادم لإطار Get Command Description IDs. ويجب بعدئذٍ الحصول على أوصاف الأوامر المفردة بإرسال إطار Get Command Description لكل منها، ويرد الخادم بإطار Command Description.

هذا التبادل وظيفيًا مشابه جدًا لتبادل إطارات الأوامر المستخدمة في بروتوكول اللعبة الرئيسي (بل كان مبنيًا عليه في الأصل). وهو يتيح وصف الأوامر للمستخدم وفحصها محلّيًا إلى حدٍّ ما، مما يقلّل استهلاك الشبكة. وقد صُوّر بروتوكول الإدارة في وقت كان فيه بروتوكول اللعبة ناضجًا بالفعل؛ فبدلًا من البدء من الصفر، وجد المطوّرون وظيفة قائمة في بروتوكول اللعبة كانت تفعل ما تطلّبه الحاجة تقريبًا، وأضافوا الشيفرة إلى مكتبات البروتوكول نفسها.

21.3. الوظائف الداعمة

21.3.1. حفظ الحالة في الخادم

ألعاب Thousand Parsec، مثل كثير من الألعاب في النوع الاستراتيجي القائم على الأدوار، قد تمتد إلى وقت طويل. فإلى جانب أنها تجري في الغالب مدة أطول بكثير من الإيقاعات البيولوجية اليومية (circadian rhythms) لنوع اللاعبين، فإن عملية الخادم قد تُنهى في هذه المدة الممتدة لأي سبب من الأسباب. ولكي يتمكن اللاعبون من استئناف اللعبة من حيث توقفوا، توفر خوادم Thousand Parsec آلية حفظ (persistence) من خلال تخزين حالة الكون كاملةً (أو حتى عدة أكوان) في قاعدة بيانات. وتُستخدم هذه الوظيفة أيضًا بصورة ذات صلة لحفظ الألعاب ذات اللاعب الواحد، التي ستتناولها بقية هذا القسم بتفصيل أكبر.

يوفّر الخادم الرئيسي tpserver-cpp واجهة حفظ مجرّدة ونظام إضافات معياريًا يتيحان مختلف محرّكات قواعد البيانات الخلفية. وحتى وقت كتابة هذا الكتاب، يأتي tpserver-cpp مع وحدات (modules) لـ MySQL وSQLite.

تصف الصنف المجرّد Persistence الوظيفة التي تتيح للخادم حفظ عناصر اللعبة المختلفة وتحديثها واسترجاعها (كما هو موضح في قسم «تشريح إمبراطورية نجمية»). وتُحدَّث قاعدة البيانات باستمرار من مواضع مختلفة في شيفرة الخادم حيث تتغير حالة اللعبة، وأيًّا كانت النقطة التي أُنهيت عندها عملية الخادم أو انهارت، يفترض أن تُستعاد كل المعلومات حتى تلك النقطة عند تشغيل الخادم مجددًا من البيانات المحفوظة.

21.3.2. لغة مكوّنات Thousand Parsec

وُجدت لغة مكوّنات Thousand Parsec (TPCL) لتتيح للعملاء إنشاء التصاميم محلّيًا دون التفاعل مع الخادم—مما يتيح تغذية راجعة فورية عن خصائص التصاميم وتركيبها وصلاحيتها. وهذا يتيح للاعب أن ينشئ تفاعليًا، على سبيل المثال، أصنافًا جديدة من ناقلات النجوم، عبر تخصيص البنية والدفع وأجهزة القياس والدفاعات والتسليح وغيرها بحسب التكنولوجيا المتاحة.

لغة TPCL مجموعة جزئية من Scheme مع بعض التغييرات الطفيفة، لكنها قريبة بما يكفي من معيار Scheme R5RS بحيث يمكن استخدام أي مفسّر متوافق. وقد اختيرت Scheme في الأصل بسبب بساطتها، ووجود سوابق كثيرة على استخدامها كلغة مدمجة، وتوافر مفسّرات منفَّذة بلغات أخرى كثيرة، و— وهو الأهم بالنسبة إلى مشروع مفتوح المصدر— الكم الهائل من التوثيق سواء حول استخدامها أو حول تطوير مفسّرات لها.

تأمّل المثال التالي لدالة Requirements بلغة TPCL، المستخدمة في المكوّنات والخصائص، والتي تُضمَّن مع مجموعة القواعد على جهة الخادم وتُبلَّغ إلى العميل عبر بروتوكول اللعبة:

(lambda (design)
  (if (> (designType.MaxSize design) (designType.Size design))
      (if (= (designType.num-hulls design) 1)
          (cons #t "")
          (cons #f "Ship can only have one hull")
      )
      (cons #f "This many components can't fit into this Hull")
  )
)

ولا شك أن القرّاء المعتادين على Scheme سيجدون هذه الشيفرة سهلة الفهم. تستخدمها اللعبة (في كل من العميل والخادم) للتحقق من خصائص المكوّنات الأخرى (MaxSize وSize وNum-Hulls) للتأكد من إمكانية إضافة هذا المكوّن إلى تصميم. وهي تتحقق أولًا من أن Size المكوّن ضمن الحجم الأقصى للتصميم، ثم تتأكد من عدم وجود هياكل أخرى في التصميم (ويكشف الاختبار الأخير أن هذه هي دالة Requirements الخاصة بهيكل سفينة).

21.3.3. BattleXML

في الحرب، كل معركة تُحسب، من الاشتباك القصير في أعماق الفضاء بين أسراب من المركبات الاستطلاعية الصغيرة ذات التسليح الخفيف، إلى المواجهة النهائية الضخمة بين أسطولين من السفن الرائدة في سماء فوق عالم عاصمة. وعلى إطار عمل Thousand Parsec، تُعالَج تفاصيل القتال داخل مجموعة القواعد، ولا توجد وظيفة صريحة على جهة العميل تتعلق بتفاصيل القتال—فعادةً، يبلَّغ اللاعب ببدء القتال ونتائجه عبر الرسائل، وتُطبَّق التغييرات المناسبة على الكائنات (مثل إزالة السفن المدمَّرة). ورغم أن تركيز اللاعب سيكون على مستوى أعلى عادةً، فإن مجموعات القواعد ذات آليات القتال المعقدة قد تجعل فحص المعركة بتفصيل أكثر فائدة (أو على الأقل ممتعًا).

هنا يأتي دور BattleXML. وتنقسم بيانات المعركة إلى قسمين رئيسيين: تعريف الوسائط (media definition)، الذي يوفّر تفاصيل الرسوميات المستخدمة، وتعريف المعركة (battle definition)، الذي يحدّد ما حدث فعلًا أثناء المعركة. وهذه مصمَّمة ليقرأها عارض معارك (battle viewer)، ويملك Thousand Parsec حاليًا اثنين منها: واحد ثنائي الأبعاد (2D) والآخر ثلاثي الأبعاد (3D). ومن البديهي، بما أن طبيعة المعارك هي خاصية كليًا لمجموعة القواعد، فإن شيفرة مجموعة القواعد هي المسؤولة عن إنتاج بيانات BattleXML فعليًا.

يرتبط تعريف الوسائط بطبيعة العارض، ويُخزَّن في دليل أو أرشيف يحتوي على بيانات XML وأي ملفات رسومية أو نماذج يشير إليها. وتصف البيانات نفسها أي وسائط ينبغي استخدامها لكل نوع من السفن (أو غيرها من الكائنات)، ومشاهد حركته لإجراءات مثل الإطلاق والموت، ووسائط وتفاصيل أسلحته. وتُفترض مواقع الملفات منسوبةً إلى ملف XML نفسه، ولا يمكنها الإشارة إلى المجلدات الأصل.

تعريف المعركة مستقل عن العارض وعن الوسائط. أولًا، يصف سلسلة من الكيانات في كل جانب عند بداية المعركة، بمعرّفات فريدة ومعلومات مثل الاسم والوصف والنوع. ثم يصف كل جولة من المعركة: حركة الكائنات، واشتعال الأسلحة (مع المصدر والهدف)، والأضرار التي لحقت بالكائنات، وموت الكائنات، ورسالة سجل. ويحدّد مجموعة القواعد مقدار التفصيل المستخدم لوصف كل جولة.

21.3.4. الخادم الوسيط (Metaserver)

العثور على خادم Thousand Parsec عام للعب عليه يشبه إلى حدٍّ كبير العثور على مركبة استطلاع خفية وحيدة في أعماق الفضاء—مهمة مرهبة لمن لا يعرف أين يبحث. لحسن الحظ، يمكن للخوادم العامة أن تعلن عن نفسها إلى خادم وسيط (metaserver)، ويجب أن يكون موقعه، بوصفه مركزًا محوريًا، معروفًا لدى اللاعبين قدر الإمكان.

التنفيذ الحالي هو metaserver-lite، وهو سكربت PHP يوجد في مكان مركزي مثل موقع Thousand Parsec على الويب. وترسل الخوادم الداعمة طلب HTTP يحدّد إجراء التحديث ويحتوي على النوع، والموقع (البروتوكول والمضيف والمنفذ)، ومجموعة القواعد، وعدد اللاعبين، وعدد الكائنات، والمسؤول، ومعلومات اختيارية أخرى. وتنتهي صلاحية قوائم الخوادم بعد مهلة محددة (10 دقائق افتراضيًا)، لذا يُتوقع من الخوادم أن تحدّث الخادم الوسيط دوريًا.

وعند استدعاء السكربت دون تحديد إجراء، يمكن استخدامه لتضمين قائمة الخوادم مع تفاصيلها في موقع ويب، معروضًا عناوين URL قابلة للنقر (عادةً باسم مخطط tp://). وبدلًا من ذلك، يعرض إجراء الشارة قوائم الخوادم بتنسيق «شارة» مضغوط.

يستطيع العملاء إصدار طلب إلى خادم وسيط باستخدام إجراء get للحصول على قائمة الخوادم المتاحة. في هذه الحالة، يعيد الخادم الوسيط إلى العميل إطارًا واحدًا أو أكثر من نوع Game لكل خادم في القائمة. وفي tpclient-pywx، تُعرض القائمة الناتجة عبر متصفح خوادم في نافذة الاتصال الأولية.

21.3.5. وضع اللاعب الواحد

صُمّم Thousand Parsec من الأساس لدعم الألعاب متعددة اللاعبين عبر الشبكة. غير أنه لا شيء يمنع لاعبًا من تشغيل خادم محلّي، وربط بضعة عملاء ذكاء اصطناعي، ثم الانتقال الفائق (hyperjump) إلى كون مخصّص ذي لاعب واحد جاهزًا للغزو. ويعرّف المشروع بعض البيانات الوصفية والوظائف القياسية لدعم تبسيط هذه العملية، بحيث يصبح الإعداد سهلًا كتشغيل معالج رسومي (GUI wizard) أو النقر المزدوج على ملف سيناريو.

في قلب هذه الوظيفة يوجد تعريف DTD بصيغة XML يحدّد تنسيق البيانات الوصفية المتعلقة بقدرات كل مكوّن وخصائصه (مثل الخادم، وعميل الذكاء الاصطناعي، ومجموعة القواعد). وتأتي حزم المكوّنات مصحوبة بملف XML واحد أو أكثر، وفي نهاية المطاف يُجمَع كل هذه البيانات الوصفية في مصفوفة ترابطية مقسّمة إلى قسمين رئيسيين: الخوادم وعملاء الذكاء الاصطناعي. وداخل بيانات الخادم الوصفية سيُعثر عادةً على بيانات وصفية لمجموعة قواعد واحدة أو أكثر—وتجد مكانها هنا لأن مجموعة القواعد، وإن كانت قد نُفِّذت لأكثر من خادم، فقد تختلف بعض تفاصيل التكوين بينها، لذا يلزم عمومًا بيانات وصفية منفصلة لكل تنفيذ. ويحتوي كل إدخال لأحد هذه المكوّنات على المعلومات التالية:

  • بيانات وصفية، تتضمّن اسمًا قصيرًا (ثنائيبايت)، واسمًا طويلًا (وصفيًا)، ووصفًا.
  • الإصدار المثبَّت من المكوّن، وأقدم إصدار تكون بيانات الحفظ فيه متوافقة مع الإصدار المثبَّت.
  • سلسلة الأمر (إن انطبقت) وأي معاملات إجبارية تُمرَّر إليها.
  • مجموعة معاملات يمكن أن يحددها اللاعب.

المعاملات الإجبارية غير قابلة للتهيئة من قبل اللاعب، وهي عادةً خيارات تتيح للمكوّنات أن تعمل بشكل سليم في سياق محلّي ذي لاعب واحد. أما معاملات اللاعب فلها تنسيقها الخاص الذي يبيّن تفاصيل مثل الاسم والوصف ونوع البيانات والقيمة الافتراضية ونطاق القيمة، وسلسلة التنسيق التي تُلحق بسلسلة الأمر الرئيسية.

رغم إمكانية وجود حالات تخصّصية (مثل تكوينات ألعاب جاهزة للعملاء المرتبطين بمجموعة قواعد بعينها)، فإن العملية المعتادة لبناء لعبة ذات لاعب واحد تتضمن انتقاء مجموعة من المكوّنات المتوافقة. والانتقاء الضمني للعميل لأن اللاعب يكون قد شغّل واحدًا بالفعل كي يلعب اللعبة؛ والعميل المصمَّم جيدًا يتبع سير عمل قائمًا على المستخدم لإعداد ما تبقى. والاختيار الطبيعي التالي هو مجموعة القواعد، فيُعرض على اللاعب قائمة—وفي هذه المرحلة لا حاجة إلى الانشغال بتفاصيل الخادم. وفي حال كانت مجموعة القواعد المختارة منفَّذة في عدة خوادم مثبَّتة (وهي على الأرجح حالة نادرة)، يُطلب من اللاعب انتقاء أحدها؛ وإلا فسيُنتقَل تلقائيًا إلى الخادم المناسب. بعد ذلك، يُطلب من اللاعب تكوين خيارات مجموعة القواعد والخادم، مع قيم افتراضية معقولة مستمدة من البيانات الوصفية. وأخيرًا، إن ثُبِّت أي عملاء ذكاء اصطناعي متوافقون، يُطلب من اللاعب تكوين واحد أو أكثر منهم ليلعب ضدهم.

بعد ضبط اللعبة على هذا النحو، يشغّل العميل الخادم المحلّي بمعاملات تكوين مناسبة (بما في ذلك مجموعة القواعد ومعاملاتها وأي معاملات يضيفها إلى تكوين الخادم)، مستخدمًا معلومات سلسلة الأمر الواردة في البيانات الوصفية. وبعد أن يتحقق من أن الخادم يعمل ويقبل الاتصالات، ربما باستخدام امتداد بروتوكول الإدارة الذي ناقشناه سابقًا، يشغّل كلًا من عملاء الذكاء الاصطناعي المحدَّدين بطريقة مماثلة، ويتحقق من نجاح اتصالهم باللعبة. وإذا سارت الأمور على ما يرام، يتصل العميل بعدها بالخادم—تمامًا كما لو كان يتصل بلعبة عبر الإنترنت—ويبدأ اللاعب في الاستكشاف والتجارة والفتح وكل الإمكانات الأخرى التي يوفرها الكون.

ومن الاستخدامات البديلة—وهي مهمة جدًا—لوظيفة اللاعب الواحد: حفظ الألعاب وتحميلها، و— على نحو مكافئ إلى حدٍّ ما— تحميل السيناريوهات الجاهزة للعب. وفي هذه الحالة، تحفظ بيانات الحفظ (على الأرجح، وإن لم يكن بالضرورة، في ملف واحد) بيانات تكوين اللعبة ذات اللاعب الواحد إلى جانب بيانات الحفظ الخاصة باللعبة نفسها. شريطة أن تكون جميع المكوّنات المناسبة بالإصدارات المتوافقة مثبَّتة على نظام اللاعب، يصبح تشغيل لعبة محفوظة أو سيناريو آليًا بالكامل. وبذلك توفر السيناريوهات تحديدًا مدخلًا جذابًا بضغطة واحدة إلى لعبة. ورغم أن Thousand Parsec لا يملك حاليًا محرّر سيناريوهات مخصّصًا ولا عميلًا بوضع تحرير، فإن الفكرة هي توفير بعض وسائل صياغة بيانات الحفظ خارج التشغيل المعتاد لمجموعة القواعد، والتحقق من اتساقها وتوافقها.

حتى الآن، كان وصف هذه الوظيفة مجرَّدًا إلى حدٍّ كبير. وعلى مستوى أكثر ملموسية، فإن مكتبة مساعدات العميل بايثون libtpclient-py هي حاليًا الكائن الوحيد الذي يحوي التجسيد الكامل لآليات اللاعب الواحد في مشروع Thousand Parsec. وتوفّر المكتبة الصنف SinglePlayerGame، الذي عند إنشائه يجمع تلقائيًا كل البيانات الوصفية المتاحة للاعب الواحد على النظام (لأن هناك بطبيعة الحال إرشادات معينة حول ما ينبغي أن تُثبَّت عليه ملفات XML على منصة معيّنة). ويمكن بعد ذلك أن يستعلم العميل هذا الكائن عن معلومات مختلفة حول المكوّنات المتاحة؛ وتُخزَّن الخوادم ومجموعات القواعد وعملاء الذكاء الاصطناعي والمعاملات في شكل قواميس (مصفوفات بايثون الترابطية). وإتبعًا للعملية العامة لبناء اللعبة التي سبق شرحها، قد يؤدي عميل نموذجي ما يلي:

  1. الاستعلام عن قائمة مجموعات القواعد المتاحة عبر SinglePlayerGame.rulesets، وتكوين الكائن بمجموعة القواعد المختارة عبر تعيين SinglePlayerGame.rname.
  2. الاستعلام عن قائمة الخوادم المنفِّذة لمجموعة القواعد عبر SinglePlayerGame.list_servers_with_ruleset، ومطالبة المستخدم باختيار واحد إذا لزم الأمر، وتكوين الكائن بالخادم المختار (أو الوحيد) عبر تعيين SinglePlayerGame.sname.
  3. الحصول على مجموعة المعاملات الخاصة بالخادم ومجموعة القواعد عبر SinglePlayerGame.list_rparams وSinglePlayerGame.list_sparams على التوالي، ومطالبة اللاعب بتكوينها.
  4. العثور على عملاء الذكاء الاصطناعي المتاحين الذين يدعمون مجموعة القواعد عبر SinglePlayerGame.list_aiclients_with_ruleset، ومطالبة اللاعب بتكوين واحد أو أكثر منهم باستخدام المعاملات التي تم الحصول عليها عبر SinglePlayerGame.list_aiparams.
  5. تشغيل اللعبة باستدعاء SinglePlayerGame.start، الذي يُعيد منفذ TCP/IP للاتصال به عند النجاح.
  6. إنهاء اللعبة في النهاية (وإنهاء أي عمليات خادم وعملاء ذكاء اصطناعي تم تشغيلها) باستدعاء SinglePlayerGame.stop.

يقدّم عميل Thousand Parsec الرئيسي tpclient-pywx معالجًا سهل الاستخدام يتبع مثل هذا الإجراء، مع مطالبته في البداية بدلًا من ذلك بملف لعبة محفوظة أو ملف سيناريو لتحميله. وسير العمل القائم على المستخدم المطوَّر لهذا المعالج مثال على التصميم الجيد الناجم عن عملية تطوير المشروع مفتوحة المصدر: فقد اقترح المطوّر في البداية عملية مختلفة تمامًا وأكثر ارتباطًا بكيفية سير الأمور تحت السطح، لكن المناقشة المجتمعية وبعض التطوير التعاوني أنتجا نتيجة أكثر قابلية للاستخدام بكثير باللاعب.

أخيرًا، تُنفَّذ الألعاب المحفوظة والسيناريوهات حاليًا عمليًا في tpserver-cpp، مع وظائف داعمة في libtpclient-py وواجهة في tpclient-pywx. ويُحقق ذلك عبر وحدة حفظ تستخدم SQLite، وهو نظام إدارة قواعد بيانات علائقية مفتوح المصدر في المجال العام لا يتطلب عملية خارجية ويخزّن قواعد البيانات في ملف واحد. ويُضبط الخادم، عبر معامل إجباري، على استخدام وحدة حفظ SQLite إن كانت متاحة، وكالمعتاد يُحدَّث ملف قاعدة البيانات (الموجود في موقع مؤقت) باستمرار طوال المباراة. وحين يختار اللاعب حفظ اللعبة، يُنسخ ملف قاعدة البيانات إلى الموقع المحدد، وتُضاف إليه جدول خاص يحتوي على بيانات تكوين اللاعب الواحد. وينبغي أن يكون الأمر واضحًا للقارئ إلى حدٍّ كبير كيفية تحميله بعد ذلك.

21.4. الدروس المستفادة

أتاح إنشاء إطار عمل Thousand Parsec الواسع ونموه للمطوّرين فرصًا وفيرة للنظر إلى الوراء وتقييم قرارات التصميم التي اتُّخذت في الطريق. فقد بنى المطوّرون الأصليون (Tim Ansell وLee Begg) الإطار الأصلي من الصفر، وقد شاركوا معنا بعض الاقتراحات حول بدء مشروع مماثل.

21.4.1. ما نجح

كان أحد المفاتيح الرئيسية في تطوير Thousand Parsec هو القرار بتعريف مجموعة جزئية من الإطار وبنائها، ثم تنفيذها. وقد سمحت عملية التصميم التكرارية والتدرّجية للإطار بأن ينمو عضويًا، مع إضافة ميزات جديدة بسلاسة. وقد أدّى ذلك مباشرةً إلى قرار وضع إصدارات لبروتوكول Thousand Parsec، ويُنسب إليه عدد من الإنجازات الكبيرة للإطار. وقد سمح وضع الإصدارات للبروتوكول للإطار بأن ينمو مع الوقت، بما يتيح طرق لعب جديدة في الطريق.

عند تطوير إطار عمل اتساع كهذا، من المهم أن تكون الأهداف والتكرارات ذات الأفق قصير جدًا. فقد سمحت التكرارات القصيرة، التي تكون في حدود الأسابيع لإصدار ثانوي، للمشروع بالتقدم بسرعة مع عوائد فورية في الطريق. وكان نموذج العميل والخادم من ناجحات التنفيذ، إذ أتاح تطوير العملاء بعيدًا عن أي منطق للعبة. وكان فصل منطق اللعبة عن برمجيات العميل مهمًا للنجاح العام لـ Thousand Parsec.

21.4.2. ما لم ينجح

كان أحد العوائق الكبرى لإطار عمل Thousand Parsec هو القرار باستخدام بروتوكول ثنائي. ويمكنك تخيل أن تنقيح بروتوكول ثنائي ليس مهمة ممتعة، وقد أدّى هذا إلى جلسات تنقيح مطوّلة كثيرة. ونوصي بشدة بألا يسلك أحد هذا المسار في المستقبل. كما نما البروتوكول ليصبح مرنًا أكثر من اللازم؛ فعند إنشاء بروتوكول، من المهم تنفيذ الميزات الأساسية المطلوبة فحسب.

كبرت تكراراتنا أحيانًا أكثر من اللازم. فعند إدارة إطار عمل كبير كهذا وفق جدول تطوير مفتوح المصدر، من المهم أن تضم كل تكرار مجموعة صغيرة من الميزات المضافة لإبقاء التطوير مسيرًا.

21.4.3. الخاتمة

مثل زورق إنشائي يفتّش الهيكل العظمي لسفينة حربية نموذجية ضخمة في ساحة بناء مدارية، فقد مررنا على تفاصيل معمارية Thousand Parsec المختلفة. ورغم أن معايير التصميم العامة من المرونة وقابلية التوسيع كانت في ذهن المطوّرين منذ البداية البتة، فهو واضح لنا، عند النظر في تاريخ الإطار، أن النظام البيئي مفتوح المصدر، وهو غزير بالأفكار وجهات النظر الجديدة، هو وحده ما كان قادرًا على إنتاج هذا الحجم الهائل من الإمكانات مع البقاء صالحًا للعمل ومتماسكًا. إنه مشروع طموح بشكل استثنائي، وكما حال كثير من نظيره في المشهد مفتوح المصدر، ما زال الكثير مما يجب إنجازه؛ ونأمل وننتظر أن يواصل Thousand Parsec التطور وتوسيع قدراته مع تطوير ألعاب جديدة وأكثر تعقيدًا فوقه. فبعد كل شيء، رحلة الألف فرسخ تبدأ بخطوة واحدة.

حواشٍ

  1. من الأمثلة التجارية الممتازة لإلهام Thousand Parsec: VGA Planets وStars!، وكذلك سلسلة Master of Orion وGalactic Civilizations وSpace Empires. أما القرّاء غير الملمّين بهذه العناوين، فسلسلة Civilization مثال شائع على أسلوب اللعب نفسه، وإن كان في سياق مختلف. وهناك أيضًا عدد من ألعاب 4X الآنية، مثل Imperium Galactica وSins of a Solar Empire.
  2. في الواقع، العكس هو الصحيح: اشتُقّت الرسائل واللوحات من الأوامر في الإصدار الثاني من البروتوكول.

  1. من الأمثلة التجارية الممتازة لإلهام Thousand Parsec: VGA Planets وStars!، وكذلك سلسلة Master of Orion وGalactic Civilizations وSpace Empires. أما القرّاء غير الملمّين بهذه العناوين، فسلسلة Civilization مثال شائع على أسلوب اللعب نفسه، وإن كان في سياق مختلف. وهناك أيضًا عدد من ألعاب 4X الآنية، مثل Imperium Galactica وSins of a Solar Empire. ↩︎

  2. في الواقع، العكس هو الصحيح: اشتُقّت الرسائل واللوحات من الأوامر في الإصدار الثاني من البروتوكول. ↩︎