ब्लॉग पर वापस
Tutorial8 मिनट पढ़ें

FiveM मेल सिस्टम स्क्रिप्ट: इन-गेम संदेश और बिल

बिल, नौकरी नोट्स और सर्वर घोषणाओं के लिए FiveM मेल सिस्टम सेट अप करें। टॉप स्क्रिप्ट्स, फ्रेमवर्क सपोर्ट और मेल को आपकी नौकरियों में वायर करने के विचार।

Agency Scripts

Agency Scripts के संस्थापक और प्रमुख डेवलपर

भौतिक मेल का रोलप्ले मूल्य

एक ऐसे युग में जहां अधिकांश FiveM सर्वर पूरी तरह से फोन सूचनाओं और डिजिटल संदेशों पर निर्भर हैं, एक भौतिक मेल और पत्र प्रणाली एक ऐसा स्तर जोड़ती है जो अलग दिखता है। खिलाड़ी अन्य पात्रों को हस्तलिखित पत्र लिख सकते हैं, आइटम वाले पैकेज भेज सकते हैं, आधिकारिक सरकारी नोटिस प्राप्त कर सकते हैं, व्यवसायों से बिल प्राप्त कर सकते हैं, और यहां तक कि रहस्यमय गुमनाम नोट भी पा सकते हैं। यह भूमिका निभाने के अवसर पैदा करता है जिन्हें डिजिटल संचार दोहरा नहीं सकता। किसी के मेलबॉक्स में छोड़ा गया धमकी भरा पत्र एक टेक्स्ट संदेश की तुलना में अधिक प्रभावशाली होता है। हाथ से लिखा प्रेम पत्र ईमेल की तुलना में अधिक व्यक्तिगत लगता है। मेल द्वारा दिया गया कोर्ट समन अधिक आधिकारिक लगता है। भूमिका निभाने के मूल्य के अलावा, एक मेल सिस्टम पोस्टल वर्कर्स के लिए एक प्राकृतिक नौकरी अवसर बनाता है जो शहर भर में मेल उठाते, छांटते, और वितरित करते हैं। यह ट्यूटोरियल डेटाबेस स्कीमा से लेकर डिलीवरी मैकेनिक्स तक एक पूर्ण मेल सिस्टम बनाने को कवर करता है।

मेल सिस्टम के लिए डेटाबेस स्कीमा

डेटाबेस को पत्र, पैकेज, मेलबॉक्स असाइनमेंट, और डिलीवरी स्थितियों को संभालना चाहिए। प्रत्येक मेल आइटम में प्रेषक पहचानकर्ता, प्राप्तकर्ता पहचानकर्ता, पत्रों और पैकेजों को अलग करने वाला प्रकार, विषय पंक्ति, पत्रों के लिए बॉडी सामग्री, पैकेजों के लिए संलग्न आइटम डेटा, निर्माण और डिलीवरी के टाइमस्टैम्प, और स्थिति फ्लैग होते हैं जो मेल लंबित, ट्रांजिट में, डिलीवर किया गया, या पढ़ा गया है। मेलबॉक्स संपत्ति पतों से जुड़े होते हैं ताकि जो खिलाड़ी आवास के मालिक या किराएदार हों उनके पास व्यक्तिगत मेलबॉक्स हो। शहर में रखे सार्वजनिक मेलबॉक्स उन खिलाड़ियों के लिए होते हैं जिनके पास आवास नहीं है, जिन्हें अपना मेल लेने के लिए पोस्ट ऑफिस जाना पड़ता है। स्कीमा को स्वचालित नोटिस जैसे बिल, कोर्ट दस्तावेज़, नौकरी आवेदन, और सरकारी घोषणाओं के लिए सिस्टम-जनित मेल का समर्थन भी करना चाहिए जिन्हें स्क्रिप्ट बिना खिलाड़ी प्रेषक के ट्रिगर कर सकते हैं।

-- SQL schema
CREATE TABLE IF NOT EXISTS mail_items (
    id           INT AUTO_INCREMENT PRIMARY KEY,
    sender_id    VARCHAR(64),
    sender_name  VARCHAR(64) DEFAULT 'Unknown',
    recipient_id VARCHAR(64) NOT NULL,
    mail_type    ENUM('letter','package','notice') DEFAULT 'letter',
    subject      VARCHAR(128) NOT NULL,
    body         TEXT,
    attachments  JSON DEFAULT '[]',
    postage_paid INT DEFAULT 0,
    status       ENUM('pending','transit','delivered','read','returned')
                 DEFAULT 'pending',
    mailbox_id   INT DEFAULT NULL,
    created_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    delivered_at TIMESTAMP NULL,
    read_at      TIMESTAMP NULL,
    INDEX idx_recipient (recipient_id, status),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS mailboxes (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    owner_id    VARCHAR(64),
    property_id INT DEFAULT NULL,
    location_x  FLOAT NOT NULL,
    location_y  FLOAT NOT NULL,
    location_z  FLOAT NOT NULL,
    box_type    ENUM('residential','public','business') DEFAULT 'residential',
    capacity    INT DEFAULT 20,
    UNIQUE KEY unique_owner (owner_id)
);

Letters लिखना और भेजना

पत्र लेखन इंटरफ़ेस को एक वास्तविक पत्र लिखने जैसा महसूस होना चाहिए। खिलाड़ियों को एक NUI प्रस्तुत करें जो कागज के टुकड़े जैसा दिखता हो जिसमें प्राप्तकर्ता का नाम, विषय पंक्ति, और मुक्त-पाठ बॉडी के लिए क्षेत्र हों। NUI में हस्तलिखित शैली का फ़ॉन्ट उपयोग करें ताकि भौतिक पत्र की भावना बनी रहे। प्राप्तकर्ता क्षेत्र को नाम से पात्र डेटाबेस खोजने देना चाहिए, न कि खिलाड़ियों को आंतरिक पहचानकर्ताओं को जानना पड़े। जब खिलाड़ी लिखना समाप्त करता है और भेजें पर क्लिक करता है, तो क्लाइंट डेटा सर्वर को भेजता है जो सामग्री को मान्य करता है, जांचता है कि प्रेषक के पास डाक शुल्क के लिए पर्याप्त पैसे हैं, लागत घटाता है, और मेल आइटम को डेटाबेस में पेंडिंग स्थिति के साथ डालता है। बॉडी लंबाई पर उचित सीमाएं लगाएं, शायद मानक पत्रों के लिए 500 अक्षर और प्रीमियम डाक के लिए 1000, ताकि दुरुपयोग न हो और फिर भी सार्थक संदेश संभव हों। पत्र फिर डिलीवरी पाइपलाइन में प्रवेश करता है और डाक कर्मचारी के संसाधित करने या स्वचालित डिलीवरी टाइमर के समाप्त होने का इंतजार करता है।

-- server/mail.lua
local Config = {
    postageCost     = 50,
    premiumPostage  = 150,
    maxBodyLength   = 500,
    premiumMaxBody  = 1000,
    autoDeliverTime = 900, -- 15 minutes if no postal worker
    packagePostage  = 200,
}

RegisterNetEvent('mail:send', function(data)
    local src = source
    local sender = GetPlayerIdentifier(src, 0)

    -- Validate recipient exists
    local recipient = MySQL.single.await([[
        SELECT identifier, CONCAT(firstname,' ',lastname) as name
        FROM characters WHERE CONCAT(firstname,' ',lastname) LIKE ?
        LIMIT 1
    ]], {'%' .. data.recipientName .. '%'})

    if not recipient then
        TriggerClientEvent('mail:notify', src, 'Recipient not found.')
        return
    end

    -- Check postage funds
    local cost = data.premium and Config.premiumPostage or Config.postageCost
    local maxLen = data.premium and Config.premiumMaxBody or Config.maxBodyLength

    if #data.body > maxLen then
        TriggerClientEvent('mail:notify', src, 'Letter exceeds maximum length.')
        return
    end

    -- Deduct postage (framework-specific money removal)
    local paid = exports['framework']:RemoveMoney(src, cost, 'cash')
    if not paid then
        TriggerClientEvent('mail:notify', src, 'Not enough cash for postage.')
        return
    end

    -- Insert mail
    MySQL.insert([[
        INSERT INTO mail_items
            (sender_id, sender_name, recipient_id, mail_type,
             subject, body, postage_paid, status)
        VALUES (?, ?, ?, 'letter', ?, ?, ?, 'pending')
    ]], {
        sender, data.senderName, recipient.identifier,
        data.subject, data.body, cost
    })

    TriggerClientEvent('mail:notify', src, 'Letter sent! Postage: $' .. cost)
end)

पैकेज सिस्टम विथ आइटम अटैचमेंट्स

पैकेज मेल सिस्टम को टेक्स्ट से आगे बढ़ाते हैं जिससे खिलाड़ी एक-दूसरे को भौतिक वस्तुएं भेज सकते हैं। एक खिलाड़ी पोस्ट ऑफिस जाता है, अपने इन्वेंटरी से आइटम चुनता है जिन्हें पैकेज में शामिल करना है, वैकल्पिक नोट लिखता है, और पैकेज पोस्टेज रेट का भुगतान करता है। सर्वर भेजने वाले के इन्वेंटरी से आइटम हटा देता है और उन्हें मेल आइटम के अटैचमेंट्स कॉलम में JSON ब्लॉब के रूप में स्टोर करता है। जब प्राप्तकर्ता अपने मेलबॉक्स या पोस्ट ऑफिस में पैकेज खोलता है, तो सर्वर अटैचमेंट डेटा को डीसिरियलाइज़ करता है और प्रत्येक आइटम को प्राप्तकर्ता के इन्वेंटरी में वापस जोड़ता है, पहले उपलब्ध स्थान की जांच करता है। यदि प्राप्तकर्ता का इन्वेंटरी भरा हुआ है, तो पैकेज उनके मेलबॉक्स में तब तक रहता है जब तक वे जगह नहीं बनाते। यह ऑफलाइन खिलाड़ियों को वस्तुएं भेजने का वैध तरीका बनाता है और केयर पैकेज, सबूत ड्रॉप, और उपहार विनिमय के लिए रोलप्ले खोलता है। डुप्लिकेशन एक्सप्लॉइट्स को रोकने के लिए सर्वर पर सभी आइटम डेटा को मान्य करें, और प्रत्येक पैकेज लेन-देन को एडमिन समीक्षा के लिए लॉग करें।

-- server/packages.lua
RegisterNetEvent('mail:sendPackage', function(data)
    local src = source
    local sender = GetPlayerIdentifier(src, 0)

    -- Validate items exist in sender inventory
    local validItems = {}
    for _, item in ipairs(data.items) do
        local hasItem = exports['ox_inventory']:Search(src, 'count', item.name)
        if hasItem < item.count then
            TriggerClientEvent('mail:notify', src,
                'You do not have enough ' .. item.name)
            return
        end
        table.insert(validItems, {
            name  = item.name,
            count = item.count,
            meta  = item.metadata or {}
        })
    end

    -- Remove items from sender
    for _, item in ipairs(validItems) do
        exports['ox_inventory']:RemoveItem(src, item.name, item.count)
    end

    -- Deduct postage
    local paid = exports['framework']:RemoveMoney(
        src, Config.packagePostage, 'cash')
    if not paid then
        -- Refund items if payment fails
        for _, item in ipairs(validItems) do
            exports['ox_inventory']:AddItem(src, item.name, item.count)
        end
        return
    end

    MySQL.insert([[
        INSERT INTO mail_items
            (sender_id, sender_name, recipient_id, mail_type,
             subject, body, attachments, postage_paid, status)
        VALUES (?, ?, ?, 'package', ?, ?, ?, ?, 'pending')
    ]], {
        sender, data.senderName, data.recipientId,
        data.subject or 'Package',
        data.note or '',
        json.encode(validItems),
        Config.packagePostage
    })
end)

डाक कर्मचारी नौकरी और डिलीवरी रूट्स

डाक कर्मचारी का काम मेल डिलीवरी को एक पृष्ठभूमि प्रक्रिया से सक्रिय रोलप्ले सामग्री में बदल देता है। जो खिलाड़ी डाकघर में क्लॉक इन करते हैं उन्हें एक डिलीवरी वैन और डिलीवर करने के लिए लंबित मेल आइटमों का एक रूट मिलता है। रूट सभी लंबित मेल आइटमों को क्वेरी करके, उन्हें डिलीवरी ज़ोन द्वारा समूहित करके, और यात्रा दूरी को न्यूनतम करने वाले क्रमबद्ध वेपॉइंट्स की एक श्रृंखला बनाकर उत्पन्न किया जाता है। रूट पर प्रत्येक स्टॉप मानचित्र पर एक ब्लिप और गंतव्य मेलबॉक्स पर एक मार्कर रखता है। जब डाक कर्मचारी मार्कर तक पहुँचता है और इंटरैक्शन कुंजी दबाता है, तो मेल आइटम लंबित से डिलीवर किए गए स्थिति में बदल जाता है और प्राप्तकर्ता के मेलबॉक्स में उपलब्ध हो जाता है। डाक कर्मचारी एक बेस वेतन के साथ प्रति डिलीवरी बोनस भी कमाते हैं, जो एक ईमानदार आय स्रोत बनाता है। जिन सर्वरों पर सक्रिय डाक कर्मचारी नहीं हैं, उनके लिए एक स्वचालित डिलीवरी टाइमर लागू करें जो एक कॉन्फ़िगर करने योग्य विलंब के बाद लंबित मेल को डिलीवर किए गए स्थिति में बदल देता है, यह सुनिश्चित करते हुए कि मेल अंततः पहुँच जाता है भले ही कोई डाक मार्ग पर काम न कर रहा हो।

मेलबॉक्स इंटरैक्शन और पढ़ने का इंटरफ़ेस

जब कोई खिलाड़ी अपने मेलबॉक्स के पास जाता है और उससे इंटरैक्ट करता है, तो सर्वर सभी मेल आइटमों को क्वेरी करता है जो उन्हें संबोधित हैं और जिनकी स्थिति डिलीवर या पढ़ी गई है। NUI एक इनबॉक्स-शैली सूची दिखाता है जिसमें प्रत्येक मेल आइटम के प्रेषक का नाम, विषय, प्रकार आइकन, और टाइमस्टैम्प होता है। अनपढ़ पत्र हाइलाइट या बैज संकेत के साथ दिखाई देते हैं। एक पत्र पर क्लिक करने से यह पूर्ण-दृश्य मोड में खुलता है जो कागज पर एक भौतिक पत्र की तरह स्टाइल किया गया है, जिसमें शीर्ष पर प्रेषक और तारीख, केंद्र में मुख्य पाठ, और एक बंद करने का बटन होता है। पैकेज के लिए, दृश्य संलग्न नोट और शामिल वस्तुओं की सूची दिखाता है जिसमें "Open Package" बटन होता है जो आइटम को खिलाड़ी के इन्वेंटरी में स्थानांतरित करता है। पत्रों को खोलने पर पढ़ा हुआ चिह्नित करें और डेटाबेस बढ़ने से रोकने के लिए एक कॉन्फ़िगर करने योग्य प्रतिधारण अवधि के बाद मेलबॉक्स से हटा दें। एक उत्तर बटन जोड़ें जो प्राप्तकर्ता क्षेत्र को मूल प्रेषक के नाम से पूर्व-भरता है, जिससे पत्राचार सुविधाजनक हो जाता है। सिस्टम नोटिस के लिए, उन्हें खिलाड़ी-लिखित मेल से अलग करने के लिए आधिकारिक लेटरहेड के साथ अलग स्टाइल करें।

सिस्टम नोटिफिकेशन और स्वचालित मेल

खिलाड़ी से खिलाड़ी संचार से परे, मेल सिस्टम अन्य सर्वर स्क्रिप्ट्स के लिए एक शक्तिशाली उपकरण बन जाता है जो immersive सूचनाएं प्रदान करता है। साधारण टोस्ट सूचनाओं के बजाय, स्क्रिप्ट्स औपचारिक मेल भेज सकते हैं। एक कोर्ट सिस्टम सरकारी लेटरहेड पर आधिकारिक सम्मन भेजता है। एक व्यवसाय चालान और भुगतान अनुस्मारक भेजता है। एक संपत्ति प्रबंधन स्क्रिप्ट किराया देय नोटिस और निकासी चेतावनी भेजता है। एक फ्रैक्शन सिस्टम भर्ती पत्र या मिशन ब्रीफिंग भेजता है। एक सरल सर्वर एक्सपोर्ट बनाएं जिसे कोई भी संसाधन सिस्टम मेल आइटम को कतारबद्ध करने के लिए कॉल कर सके बिना मेल सिस्टम के आंतरिक कार्यों को समझे। एक्सपोर्ट एक प्राप्तकर्ता पहचानकर्ता, विषय, बॉडी, मेल प्रकार, और वैकल्पिक संलग्नक स्वीकार करता है। यह आपके मेल सिस्टम को एक सार्वभौमिक सूचना परत में बदल देता है जो गेम दुनिया में एकीकृत महसूस होती है न कि एक आक्रामक UI ओवरले जो immersion तोड़ता है।

-- server/exports.lua
-- Universal mail export for other resources
function SendSystemMail(recipientId, subject, body, mailType, attachments)
    mailType = mailType or 'notice'
    attachments = attachments or '[]'

    if type(attachments) == 'table' then
        attachments = json.encode(attachments)
    end

    MySQL.insert([[
        INSERT INTO mail_items
            (sender_id, sender_name, recipient_id, mail_type,
             subject, body, attachments, status)
        VALUES ('system', 'City of Los Santos', ?, ?, ?, ?, ?, 'pending')
    ]], {recipientId, mailType, subject, body, attachments})
end

exports('SendSystemMail', SendSystemMail)

-- Usage from another resource:
-- exports['mailsystem']:SendSystemMail(
--     playerId, 'Rent Due',
--     'Your rent of $2,500 is due in 3 days.',
--     'notice'
-- )

शुरू करने के लिए तैयार?

हमारी शॉप से स्क्रिप्ट लें, या सपोर्ट, अपडेट और आगे आने वाली चीज़ों की झलक के लिए Discord से जुड़ें।