حزمة الحزم

*This content is translated using AI (Beta) and may contain errors. To view this page in English, click here.

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

باستخدام خيارات التخصيص في الحزمة، يمكنك تخصيص حزمك لتلبية أهداف التصميم والت Monetization لتجاربك، مثل:

  • استهداف معدل التحويل المنخفض من خلال تقديم حزم بدء مخفضة توفر قيمة للاعبين الجدد وتشجع الإنفاق المبكر.
  • زيادة عمق الإنفاق من خلال تجميع العناصر بأسعار مختلفة لتلبية مجموعة من اللاعبين.
  • تحقيق الدخل من عمليات التشغيل الحية (LiveOps) الأحداث من خلال تقديم حزم محدودة الوقت من العناصر الحصرية.

الحصول على الحزمة

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

كل حزمة ميزات تتطلب حزمة النواة لتعمل بشكل صحيح. بمجرد أن تكون أصول حزمة النواة و الحزم ضمن مخزونك، يمكنك إعادة استخدامها في أي مشروع على المنصة.

للحصول على الحزم من مخزونك إلى تجربتك:

  1. أضف حزمة النواة و الحزم إلى مخزونك داخل الاستوديو من خلال النقر على رابط إضافة إلى المخزون في مجموعة المكونات التالية.

  2. من قائمة نافذة في الاستوديو أو شريط الأدوات في علامة التبويب الصفحة الرئيسية، افتح صندوق الأدوات.

  3. في نافذة صندوق الأدوات، انقر على علامة التبويب المخزون. يتم عرض فرز نماذجي.

    نافذة صندوق أدوات الاستوديو مع علامة تبويب Inventory المميزة.
  4. انقر على بلاطة حزمة ميزة النواة، ثم بلاطة حزمة ميزة الحزمة. تظهر كلا المجلدين الحزم في نافذة المستكشف.

  5. اسحب مجلدات الحزمة إلى ReplicatedStorage.

  6. سمح لاستدعاءات مخزن البيانات بتتبع مشتريات اللاعبين مع الحزم.

    1. افتح نافذة ملفإعدادات التجربة للاستوديو.
    2. انتقل إلى علامة التبويب الأمان، ثم قم بتمكين تمكين وصول الاستوديو إلى خدمات API.

تعريف العملات

إذا كانت تجربتك تحتوي على نظام عملات خاص بها، يمكنك تسجيلها مع حزمة النواة عن طريق تعريفها في ReplicatedStorage.FeaturePackagesCore.Configs.Currencies. هناك مثال مشروح على عملة الجواهر موجود بالفعل في هذا الملف؛ استبدله بعملتك الخاصة.

Currencies

Gems = {
displayName = "جواهر",
symbol = "💎",
icon = nil,
},

تخبر السكريبت Currencies حزمة النواة ببعض البيانات الوصفية حول عملتك:

  • (مطلوب) displayName - اسم عملتك. إذا لم تحدد رمزًا أو أيقونة، يتم استخدام هذا الاسم في أزرار الشراء (أي "100 جواهر").
  • (اختياري) symbol - إذا كان لديك حرف نصي لاستخدامه كأيقونة لعملتك، يتم استخدام هذا بدلاً من displayName في أزرار الشراء (أي "💎100").
  • (اختياري) icon - إذا كان لديك أيقونة صورة AssetId لعملتك، يتم استخدام هذا بدلاً من displayName في أزرار الشراء (أي ستوضع الصورة على يسار السعر "🖼️100").

بمجرد إعداد عملتك، تحتاج إلى تحديد سعر الحزمة يدويًا، العملة، والأيقونة لعرض العرض بدلاً من أن يتم جلب تلك المعلومات من المنتج المطور المرتبط بالحزمة.

Bundles

-- إذا كنت ترغب في استخدام منتج مطور، عليك تقديم devProductId فريد، فقط مستخدم من قبل حزمة واحدة.
-- سنقوم بجلب سعر الحزمة والأيقونة من المنتج المطور
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = 1795621566,
},
-- خلاف ذلك، إذا كنت ترغب في استخدام عملة داخل التجربة بدلاً من منتج مطور، يمكنك استخدام التالي:
-- السعر هنا في العملة داخل التجربة، وليس روبوكس
pricing = {
priceType = CurrencyTypes.PriceType.InExperience,
price = 79,
currencyId = "جواهر",
icon = 18712203759,
},

تحتاج أيضًا إلى الإشارة إلى سكريبت BundlesExample لاستدعاء setInExperiencePurchaseHandler.

BundlesExample

local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- تحقق مما إذا كان لدى اللاعب ما يكفي من العملة لشراء الحزمة
-- تحديث بيانات اللاعب، منح العناصر، إلخ.
-- خصم العملة من اللاعب
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- الحزمة غير مرتبطة بمنتج مطور إذا لم يكن لها نوع سعر سوق
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- إذا كان لديك أي عملات داخل التجربة التي تستخدمها للحزم، اضبط المعالج هنا
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end

بالتحديد، تحتاج إلى ملء awardInExperiencePurchase، الذي يتم استدعاؤه بواسطة حلقة عبر Currencies داخل initializePurchaseHandlers المثالي (أي يتم ربط كل currencyId بالمعالج عبر Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)).

تعريف الحزم

يمكن تعريف جميع الحزم التي يمكن عرضها في تجربتك ضمن ReplicatedStorage.Bundles.Configs.Bundles، مع أنواع تم تصديرها من سكريبت Types في نفس المجلد.

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

إذا كنت ترغب في حزمة بها عناصر متعددة، وإذا كانت تلك العناصر قد تم تمثيلها بالفعل بواسطة منتجات مطورة في تجربتك، فلا تحتاج إلى تعيين سعر العنصر/assetId/name بصورة صريحة، التي سيتم جلبها عبر معلومات المنتج:

README

{
itemType = ItemTypes.ItemType.DevProduct,
devProductId = <DEV_PRODUCT_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- التسمية اختيارية! يمكنك أيضًا حذف هذا المجال
}
},

بخلاف ذلك، يمكنك تكوين تفاصيل العنصر تلك يدويًا:

README

{
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- التسمية اختيارية! يمكنك أيضًا ترك هذا المجال
}
},

على سبيل المثال، قد تبدو حزمة كاملة كالآتي:

README

local starterBundle: Types.RelativeTimeBundle = {
bundleType = Types.BundleType.RelativeTime,
-- إذا كنت ترغب في استخدام منتج مطور، عليك تقديم devProductId فريد، فقط مستخدم من قبل حزمة واحدة.
-- سنقوم بجلب سعر الحزمة والأيقونة من المنتج المطور
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = <DEV_PRODUCT_ID>,
},
-- خلاف ذلك، إذا كنت ترغب في استخدام عملة داخل التجربة بدلاً من منتج مطور، يمكنك استخدام التالي:
-- السعر هنا في العملة داخل التجربة، وليس روبوكس
-- pricing = {
-- priceType = CurrencyTypes.PriceType.InExperience,
-- price = 79,
-- currencyId = <CURRENCY_ID>,
-- icon = <IMAGE_ASSET_ID>,
-- },
includedItems = {
[1] = {
-- العنصر نفسه غير مُباع عبر منتج مطور، لذا أشر إلى مدى قيمته بالروبكس وقدم أيقونة
-- يساعد priceInRobux حزم في عرض القيمة النسبية لسعر الحزمة مقابل مجموع محتوياتها
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
-- بدلاً من ذلك، إذا كان لهذا منتج مطور، اترك السعر والأيقونة أعلاه واضبط فقط devProductId
-- سيتم جلب السعر والأيقونة من المنتج المطور
-- devProductId = <ITEM_DEV_PRODUCT_ID>
-- هناك المزيد من حقول البيانات الوصفية الاختيارية الخاصة بالواجهة إذا لزم الأمر
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
[2] = {
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 99,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
[3] = {
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 149,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
},
},
},
},
singleUse = true, -- بمجرد شرائها أو انتهاء صلاحيتها، لم تعد صالحة حتى لو حاولت تجربتك تحفيزها (onPlayerAdded). يمكنك جعلها false أثناء الاختبار في الاستوديو.
durationInSeconds = 900, -- 15 دقيقة
includesOfflineTime = false, -- احسب فقط الوقت المنقضي في التجربة
metadata = {
displayName = "حزمة البداية",
description = "احفظ 75% واحصل على بداية قوية!",
},
}

دمج منطق الخادم

انظر إلى ReplicatedStorage.Bundles.Server.Examples.BundlesExample، والذي يوضح كيف سيتفاعل خادمك مع حزمة ميزة الحزم والطرق أعلاه على ModuleScript. المقاطع أدناه هي من ذاك السكريبت.

تحتاج عادةً إلى ربط أربعة أشياء بمجرد سحب حزمة الحزم إلى تجربتك:

  1. ربط معالجات الشراء عبر Bundles.setPurchaseHandler لتحديد الوظائف التي سيتم استدعاؤها لمنح العناصر عند معالجة عملية الشراء.

    BundlesExample

    local function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })
    -- تحديث بيانات اللاعب، منح العناصر، إلخ.
    -- ... وتسجيل receiptInfo.PurchaseId حتى نتمكن من التحقق مما إذا كان المستخدم يمتلك هذه الحزمة بالفعل
    task.wait(2)
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function awardInExperiencePurchase(
    _player: Player,
    _bundleId: Types.BundleId,
    _currencyId: CurrencyTypes.CurrencyId,
    _price: number
    )
    -- تحقق مما إذا كان لدى اللاعب ما يكفي من العملة لشراء الحزمة
    -- تحديث بيانات اللاعب، منح العناصر، إلخ.
    -- خصم العملة من اللاعب
    task.wait(2)
    return true
    end
    local function initializePurchaseHandlers()
    local bundles = Bundles.getBundles()
    for bundleId, bundle in bundles do
    -- الحزمة غير مرتبطة بمنتج مطور إذا لم يكن لها نوع سعر سوق
    if not bundle or bundle.pricing.priceType ~= "Marketplace" then
    continue
    end
    Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
    receiptHandlers[bundle.pricing.devProductId] = receiptHandler
    end
    -- إذا كان لديك أي عملات داخل التجربة التي تستخدمها للحزم، اضبط المعالج هنا
    for currencyId, _ in Currencies do
    Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
    end
    end
  2. ربط منطقك لـ MarketplaceService.ProcessReceipt، ولكن قد يتم القيام بذلك في مكان آخر إذا كانت تجربتك لديها منتجات مطورة للبيع. ببساطة، عندما يتم معالجة إيصال منتج مطور، سيتصلون الآن بـ Bundles.getBundleByDevProduct للتحقق مما إذا كان المنتج ينتمي إلى حزمة. إذا كان الأمر كذلك، فإن السكريبت يتم استدعاؤه لـ Bundles.processReceipt.

    BundlesExample

    -- معالجة الإيصال من السوق لتحديد ما إذا كان يجب شحن اللاعب أم لا
    local function processReceipt(receiptInfo): Enum.ProductPurchaseDecision
    local userId, productId = receiptInfo.PlayerId, receiptInfo.ProductId
    local player = Players:GetPlayerByUserId(userId)
    if not player then
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    local handler = receiptHandlers[productId] -- الحصول على المعالج للمنتج
    local success, result = pcall(handler, receiptInfo, player) -- استدعاء المعالج للتحقق مما إذا كانت منطق الشراء ناجحًا
    if not success or not result then
    warn("فشل في معالجة الإيصال:", receiptInfo, result)
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function receiptHandler(receiptInfo: { [string]: any }, player: Player)
    local bundleId, _bundle = Bundles.getBundleByProductId(receiptInfo.ProductId)
    if bundleId then
    -- هذه الشراء تعود إلى حزمة، دع الحزم تتعامل معها
    local purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)
    return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGranted
    end
    -- هذه الشراء لا تعود إلى حزمة،
    -- ... تعامل مع كل المنطق الحالي هنا إذا كان لديك أي
    return false
    end
  3. ربط Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) حتى يتمكن الحزم من إعادة تحفيز أي حزم نشطة لم تنته صلاحيتها بعد للاعب.

    README

    local function onPlayerAdded(player: Player)
    -- قل للحزم عندما ينضم اللاعب حتى يتمكن من إعادة تحميل بياناتهم
    Bundles.onPlayerAdded(player)
    -- إذا كان لديك بعض الحزم المبدئية التي أردت عرضها لجميع المستخدمين الجدد، يمكنك تحفيزها هنا
    -- ... ستتعامل الحزم مع ما إذا كان اللاعب قد اشترى بالفعل ذلك أو إذا كانت قد انتهت صلاحيتها لأنها غير قابلة للتكرار
    -- Bundles.promptIfValidAsync(player, "StarterBundle")
    -- يتم استدعاء هذا هنا فقط لأغراض المثال، يمكنك استدعاء هذا في أي وقت أو في أي مكان تريده
    onPromptBundleXYZEvent(player)
    end
  4. تحفيز الحزم. بينما يعتمد هذا على طريقة اللعب، يقوم المثال بتحفيز اللاعبين بحزمة البدايات onPlayerAdded.

    • يضمن منطق حزمة الحزم عدم حصول كل لاعب على عرض متكرر إذا كانوا قد اشتروا بالفعل الحزمة، أو إذا سمحوا للعروض بالانتهاء (استنادًا إلى تكوين الحزمة).

    • كلما كنت تريد تحفيز حزمة للاعب، استدعِ Bundles.promptIfValidAsync(player, bundleId).

    README

    local function onPromptBundleXYZEvent(player: Player)
    -- اربط أي حدث تجربة تريد استخدامه لتحديد متى يتم تحفيز اللاعب على الحزمة
    -- ... سيكون كلما حققت معايير أهليتك لتحفيز اللاعب على الحزمة
    -- ... على سبيل المثال، إذا كنت ترغب في تحفيز الحزمة عندما ينضم اللاعب، أو عندما يرتقي اللاعب
    task.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)
    -- ... إذا كنت تنشئ حزم متعددة، استخدام task.spawn() لف الطعم الاستدعاء فوق سيساعد على تقليل التباينات بين العد التنازلي
    end

اعتبر الإرشادات التالية حول أفضل الممارسات بخصوص تسجيل إيصالات البيئة المتكررة:

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

  • لن تسجل حزمة الحزم ReceiptId إذا فشلت الشراء في أي خطوة، لذا يجب عليك التأكد من تسجيل ReceiptId في جداولك قبل معالجة الإيصال كجزء من purchaseHandler.

  • هذا التكرار يساعد على التأكد من أن جميع منطق الشراء قد تم التعامل معه بشكل مناسب وأن مخزن بياناتك ومخزن بيانات حزمة الحزم تصل في النهاية إلى التناسق، مع كون مخزن بياناتك هو المصدر الأساسي للحقيقة.

تكوين الثوابت

توجد الثوابت الخاصة بحزمة النواة في مكانين:

  • الثوابت المشتركة تعيش في ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants.

  • الثوابت الخاصة بالحزمة، وفي هذه الحالة حزمة الحزم، تعيش في ReplicatedStorage.Bundles.Configs.Constants.

الأشياء الرئيسية التي قد ترغب في تعديلها لتلبية متطلبات التصميم لتجربتك:

  • معرفات الأصول الصوتية
  • مدة تأثير الشراء وألوان الجسيمات
  • قابلية انهيار عرض heads up

بالإضافة إلى ذلك، يمكنك العثور على السلاسل لترجمة مفصلة في مكان واحد: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings.

تخصيص مكونات واجهة المستخدم

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

يتكون العرض العام من مكونين:

  • PromptItem – المكون الفردي المتكرر لكل عنصر داخل حزمة (صورة العنصر، التسمية، الاسم، السعر).
  • Prompt – نافذة التحفيز نفسها.

يتكون العرض العام أيضًا من مكونين:

  • HudItem – مكون فردي يمثل كل خيار من قائمة الخيارات في العرض العام.
  • Hud – ليمتلئ برمجيًا مع HudItems.

إذا كنت ترغب في الحصول على السيطرة الأكبر على العرض العام، بدلاً من استخدام واجهة HUD الحالية ضمن ReplicatedStorage.Bundles.Objects.BundlesGui، يمكنك تحريك الأشياء لتلبية متطلبات التصميم الخاصة بك. تأكد فقط من تحديث سلوك السكريبت العميلة في سكريبت ReplicatedStorage.Bundles.Client.UIController.

مرجع API

الأنواع

RelativeTime

بمجرد أن تتم عرض حزمة RelativeTime للاعب، تبقى متاحة حتى تنقضي فترة الزمن المحددة. يظهر هذا النوع في عرض heads up للاعب، ويقوم تلقائيًا بتحفيز في الجلسات المستقبلية حتى تنتهي الحزمة أو يشتريها اللاعب.

مثال شائع لهذا النوع من الحزم هو عرض حزمة بدء واحدة الاستخدام تظهر لجميع اللاعبين الجدد لمدة 24 ساعة.

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

إذا تم تعيينه، بعد الشراء أو انتهاء الصلاحية لأول مرة، لن يكون قابلاً للتحفيز مرة أخرى، حتى لو استدعيت Bundles.promptIfValidAsync مع bundleId.

FixedTime

بمجرد أن تتم عرض حزمة FixedTime للاعب، تبقى متاحة حتى نهاية زمن عالمي منسق (UTC) المحدد. يظهر هذا النوع في عرض heads up للاعب، ويقوم تلقائيًا بتحفيز في الجلسات المستقبلية حتى تنتهي الحزمة أو يشتريها اللاعب.

مثال شائع لهذا النوع من الحزم هو عرض عطلة متاحة فقط لشهر محدد.

OneTime

حزمة OneTime متاحة فقط في اللحظة التي تتم فيها عرضها للاعب. لا تظهر في عرض heads up للاعب، وبمجرد أن يغلق اللاعب التحفيز، لا يمكن فتحه مرة أخرى حتى يتم تحفيزه بواسطة الخادم مرة أخرى.

مثال شائع لهذا النوع من الحزم هو عرض شراء المزيد من العملة داخل التجربة في اللحظة التي ينفد فيها لدى اللاعب.

©2026 شركة Roblox Corporation. تُعد منصّة Roblox، وشعار Roblox وشعار "توسيع حدود المخيلة"، من ضمن علاماتنا التجارية المسجّلة وغير المسجّلة في الولايات المتحدة وبلدان أخرى.