Skip to content

الدفعة الرابعة / الدفعة الخامسة / أوامر خادم CM —— تقرير بحث صعوبة النقل ​

موضوع البحث: قراءة متعمقة لكود مصدر citymania-org/cmclient (فرع vanilla 15.3) تاريخ البحث: 2026-08-14 الاستنتاج: صعوبة العمل الثلاثة مختلفة جداً، مع تقييم كل عنصر والترتيب الموصى به.


أولاً: الدفعة الرابعة: تقسيم المدن (بما في ذلك حفظ growth_tiles) ​

مكونات الوظيفة ​

المكونالملفالحجمالوصف
تعداد وضع التقسيمcm_zoning.hpp37 سطراً12 وضع تقييم (CHECKOPINION/CHECKBUILD/CHECKSTACATCH/CHECKACTIVESTATIONS/CHECKBULUNSER/CHECKINDUNSER/CHECKTOWNZONES/CHECKCBACCEPTANCE/CHECKCBTOWNLIMIT/CHECKTOWNADZONES/CHECKTOWNGROWTHTILES)
منطق التقييمcm_zoning_cmd.cpp413 سطراًدالة استعلام لكل وضع (ترجع SpriteID لوحة الألوان)، تتضمن خوارزمية نصف قطر TownZone/Tz، فحص تغطية StationFinder، فحص المباني/الصناعات غير المخدومة
واجهة مستخدم شريط أدوات التقسيمcm_zoning_gui.cpp204 سطراًنافذة اختيار وضع التقسيم للحلقة الداخلية/الخارجية (حالة عامة _zoning.inner/outer)
حفظ growth_tilescm_saveload.cpp/.hpp90 سطراًحقول Town الموسعة growth_tiles + growth_tiles_last_month (std::map<TileIndex, uint8_t>)، مخزنة باستخدام معالج SaveLoad vanilla
تمديد البياناتextensions/cmext_town.hpp~80 سطراًext::Town: growth_tiles ×2 + حقول كثيرة خاصة بأسلوب لعب خادم CM (إحصائيات بضائع CBTownInfo، تتبع الإعلانات/الأموال، عدد نمو المدن hs/cs/hr)
التدوير الشهري + التشغيلcm_game.cpp / town_cmd.cpp—تدوير growth_tiles شهرياً؛ تسجيل الحالة عند بناء/هدم/إعادة بناء المنازل

تقييم صعوبات النقل لكل عنصر ​

الصعوبةالخطورةالوصف
إعادة كتابة نظام الحفظ🟠 متوسطيستخدم growth_tiles DefaultSaveLoadHandler + SlSetStructListLength/SlObject الخاص بـ vanilla، jrpm يستخدم نظام sl/ الجديد (SlTableHeader/SlObjectSaveFiltered). يجب إعادة الكتابة باستخدام NSL/SLE + بوابة ميزة XSLF (إضافة XSLFI_TOWN_GROWTH_TILES، الإصدار 1)، الحفظ القديم لا يتأثر
تمديد هيكل Town🟢 منخفضأخذ خريطتي growth_tiles فقط (تخطي CBTownInfo/حقول الإعلانات/الأموال——تلك خاصة بأسلوب لعب CityBuilder في خادم CM)؛ إضافة حقل إلى jrpm Town + ربط جدول حفظ town_sl.cpp
منطق التقييم🟢 منخفض-متوسطمعظمها استعلامات خالصة (GetTileType/StationFinder/Town cache/فحص المباني)، واجهة برمجة تطبيقات jrpm موجودة؛ خوارزمية نصف قطر TownZone (squared_town_zone_radius) تحتاج إلى مطابقة اسم حقل jrpm
خط أنابيب العرض🟠 متوسط-مرتفعيحتاج DrawTileZoning إلى التعليق في خط أنابيب رسم viewport——يشترك مع تمييز الدفعة الثالثة في آلية عرض TileHighlight. بدون خط أنابيب تمييز، يجب بناؤه بشكل منفصل (يوصى بـ التمييز أولاً، ثم التقسيم)
موارد السبرايت🟠 متوسط12 لوحة ألوان تستخدم سبرايتات مخصصة CM_SPR_PALETTE_ZONING_*، jrpm لا يمتلكها ← يجب استخدام سبرايتات لوحة ألوان موجودة بدلاً منها أو إضافة موارد جديدة
خطافات الأحداث🟠 متوسطيعتمد تسجيل growth_tiles على ناقل الأحداث الخاص بـ cmclient (event::HouseBuilt/HouseCleared/...، Emit في cm_main.cpp). jrpm لا يحتوي على هذه الآلية ← إضافة خطافات مباشرة في town_cmd.cpp عند بناء/هدم المنازل + تدوير شهري (IntervalTimer)

استنتاج الصعوبة: 🟠 متوسط-مرتفع (حوالي 1.5–2 جولة خاصة، كل جولة 4–6 ساعات) ​

  • المتطلب الأساسي: يوصى بشدة بإكمال نظام التمييز للدفعة الثالثة أولاً (خط أنابيب العرض مشترك)
  • إذا تم فقط "تلوين 12 وضع تقسيم، بدون حفظ growth_tiles": تنخفض الصعوبة إلى 🟡 متوسط (توفير تمديد الحفظ، حوالي جولة واحدة)

ثانياً: الدفعة الخامسة: إعادة تشغيل الأوامر + التصدير/التسجيل ​

2.1 إعادة تشغيل الأوامر (cm_command_log + cm_commands + generated) ​

المكونالحجمالوصف
طبقة كائن الأوامرcm_command_type.hpp + generated/cm_gen_commands (2251+1418 سطراً)كل أمر vanilla يُغلف ككائن قابل للبرمجة (as_company/with_callback/set_auto)، يتضمن تسلسل الأمر ← تدفق بتات
تحميل سجل الأوامرcm_command_log.cpp (203 سطراً)فك ضغط lzma + تحليل تدفق بتات BitOStream ← قائمة انتظار _fake_commands (عداد tick/نتيجة متوقعة/بذرة عشوائية/CommandPacket)
تنفيذ الأوامرExecuteFakeCommandsتنفيذ حسب ترتيب عداد tick: ExecuteCommand(&cp) (واجهة برمجة تطبيقات داخلية vanilla) + التحقق من البذرة العشوائية/النتيجة (مكافحة الغش)، عند الاتصال عبر الشبكة، يُعاد توجيهها لجميع العملاء

الاختلافات الرئيسية (تحدد الصعوبة):

cmclientjrpmالتأثير
ExecuteCommand(CommandPacket*)لا توجد هذه الدالة، نواة الأمر هي DoCommandPInternal(Commands, TileIndex, CommandPayloadBase&, ...)يحتاج إلى كتابة طبقة تحويل CommandPacket ← DoCommandPInternal لـ payload 🟠
حقول CommandPacket (vanilla)CommandPacket موجود لكن هيكله مختلف (GeneralCommandPacket<DynBaseCommandContainer>)يحتاج إلى تكييف تعيين الحقول 🟠
GetCommandName✅ موجودة (command_func.h:166)🟢
outgoing_queue (إعادة التوجيه عبر الشبكة)طبقة شبكة jrpm مختلفة (OutgoingCommandPacket/ServerNetworkGameSocketHandler::SendCommand)إعادة تشغيل عبر الشبكة تحتاج إلى إعادة كتابة منطق إعادة التوجيه 🟠
المسجل (كيفية توليد ملف .cmd)خطاف التسجيل في cmclient يعتمد على اعتراض post() لطبقة كائن الأوامرأوامر jrpm هي Post مقولبة ← يحتاج إلى إضافة خطاف تسجيل في نقطة توزيع الأوامر 🔴 العمل الأساسي
تنسيق الملفخاص (معرف أمر vanilla + تدفق بتات)معرف أمر jrpm يختلف تماماً عن vanilla ← ملفات إعادة التشغيل غير متوافقة، يحتاج التنسيق إلى إعادة تصميم 🟠

2.2 التصدير / التسجيل (cm_export.cpp، 536 سطراً) ​

الوظيفةالوصفالصعوبة
ExportOpenttdDataتصدير JSON لمواصفات المنازل/مواصفات البضائع/لوحة الألوان/معلومات المحرك (JsonWriter)🟢 منخفض-متوسط (مستقل، قراءة هيكل Spec وكتابة JSON)
ViewportExport / ExportFrameSpritesتصدير سبرايتات viewport إطاراً بإطار (يعتمد على متجهات الرسم الداخلي لـ viewport TileSpriteToDrawVector/ParentSpriteToSortVector)🟠 متوسط-مرتفع (خط أنابيب viewport في jgrpp مختلف، يحتاج إلى محاذاة واجهة المتجه)

استنتاج الصعوبة: 🟠 متوسط-مرتفع (حوالي جولتين خاصتين) ​

  • إعادة تشغيل الأوامر هي الأكبر: العمل الأساسي = ① إضافة خطاف تسجيل في نقطة توزيع الأوامر (تكييف نظام الأوامر المقولب في jrpm) ② طبقة تنفيذ CommandPacket → DoCommandPInternal ③ تصميم تنسيق ملف جديد. يوصى بنقل طبقة كائن الأوامر أولاً (أساس مخططات الدفعة الثالثة، وأيضاً أساس إعادة التشغيل)
  • التصدير: تصدير بيانات JSON يمكن القيام به بشكل مستقل أولاً (منخفض-متوسط)؛ تسجيل الإطارات يعتمد على محاذاة viewport (نفس دفعة التمييز)

ثالثاً: أوامر خادم CM (cm_console_cmds.cpp، 289 سطراً) ​

قائمة الأوامر وتقييم الصعوبة لكل عنصر ​

الأمرالوظيفةالصعوبة على jrpmملاحظات
cmgamespeed [n]تغيير سرعة اللعبة🟢 منخفض جداً (~20 سطراً)jrpm لديه بالفعل _game_speed العام (gfx.cpp:52)، فقط يحتاج إلى غلاف أمر
cmstep [n]تقدم n tick⏭️ jrpm لديه بالفعلأمر step (ConStepGame) له نفس الوظيفة، تخطي
cmexportتصدير openttd.json🟢 منخفض-متوسطيعتمد على ExportOpenttdData (انظر الدفعة الخامسة)
cmtreemap <file>زراعة أشجار حسب خريطة الارتفاع🟡 متوسطقراءة خريطة الارتفاع + أمر زراعة الأشجار، مستقل
cmreset_town_growthمسح سجل نمو المدينة🟢 منخفضيعتمد على حقل تقسيم المدن
cmload_commandsتحميل إعادة تشغيل الأوامر🟠 متوسط-مرتفعيعتمد على البنية التحتية لإعادة تشغيل الأوامر
cmstart_record / cmstop_recordتسجيل الإطارات🟠 متوسط-مرتفعيعتمد على البنية التحتية للتسجيل
cmgamestatsإحصائيات جلسة اللعبة🟢 منخفضمستقل
cmgfxdebugتصحيح الرسومات🟢 منخفضمستقل

استنتاج الصعوبة: 🟢 إجمالي منخفض (أمر واحد 0.5–2 ساعة) ​

الترتيب الموصى به: cmgamespeed (10 دقائق) ← cmgamestats/cmgfxdebug (كل ~1 ساعة) ← cmexport (مع تصدير الدفعة الخامسة) ← cmtreemap (~2 ساعة) ← cmreset_town_growth (مع الدفعة الرابعة) ← cmload_commands/cmstart_record (مع إعادة تشغيل/تسجيل الدفعة الخامسة).


رابعاً: المسار العام الموصى به ​

① نظام التمييز (أساس الدفعة الثالثة، ~2-3 جولات)      ← أساس عرض المخططات/التقسيم
② طبقة كائن الأوامر (أساس مخططات الدفعة الثالثة + إعادة تشغيل الدفعة الخامسة، ~1-2 جولة)
③ المخططات (~1 جولة)
④ تقسيم المدن (~1.5 جولة، يعتمد على ① خط أنابيب العرض؛ growth_tiles باستخدام بوابة XSLF)
⑤ إعادة تشغيل الأوامر + التصدير (~2 جولة، يعتمد على ②؛ يمكن تصدير JSON بشكل مستقل مسبقاً)
⑥ أوامر خادم CM (تُدرج متفرقة بين الدفعات، gamespeed/step يمكن القيام بهما فوراً)

خامساً: العناصر التي يمكن تنفيذها فوراً بتكلفة منخفضة (لا تعتمد على أي مشروع كبير) ​

  1. أمر cmgamespeed (~20 سطراً، تغيير _game_speed)
  2. step موجود بالفعل ← لا حاجة للتنفيذ
  3. cmgamestats / cmgfxdebug (كل ~1 ساعة، مستقل)
  4. تصدير JSON لـ cmexport (~2 ساعة، مستقل)
  5. cmtreemap (~2 ساعة، مستقل)

هذه العناصر الخمسة حوالي نصف يوم عمل، يمكن تنفيذها كـ "دفعة صفرية" أولاً، بالتوازي مع الدفعات الثالثة/الرابعة/الخامسة دون تعارض.