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

FiveM डोर लॉक सिस्टम: सुरक्षित दरवाजे और चाबियाँ स्क्रिप्ट करें

किसी भी FiveM सर्वर में दरवाज़े के ताले जोड़ें। कॉन्फ़िग, चाबियाँ, केवल नौकरियों के लिए दरवाज़े और पुलिस स्टेशनों, घरों और व्यवसाय के अंदरूनी हिस्सों के लिए सर्वश्रेष्ठ दरवाज़ा लॉक स्क्रिप्ट।

Agency Scripts

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

रोलप्ले में डोर लॉक क्यों महत्वपूर्ण हैं

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

ox_doorlock सेट अप करना

ox_doorlock रिसोर्स FiveM इकोसिस्टम में सबसे व्यापक रूप से अपनाया गया डोर लॉक समाधान है, जो एक साफ API, दरवाजे लगाने के लिए बिल्ट-इन एडमिन UI, और डबल डोर और गैराज-स्टाइल एनिमेटेड दरवाजों दोनों का समर्थन प्रदान करता है। कोई भी कस्टम कोड लिखने से पहले, आपको एक ठोस आधार की आवश्यकता है। ox_lib के साथ ox_doorlock इंस्टॉल करें, जिस पर यह UI कंपोनेंट्स और उपयोगिता कार्यों के लिए निर्भर करता है। आपका server.cfg सुनिश्चित करना आवश्यक है कि संसाधन सही क्रम में शुरू हों, आपकी डेटाबेस पहले चल रही हो, फिर ox_lib, और अंत में ox_doorlock। चलने के बाद, अंतर्निर्मित एडमिन कमांड आपको गेम की दुनिया में किसी भी दरवाजे के पास जाकर एक क्लिक से उसे पंजीकृत करने देता है।

-- server.cfg load order
ensure oxmysql
ensure ox_lib
ensure ox_doorlock

-- Grant admin access for door placement
add_ace group.admin command.doorlock allow

एडमिन इंटरफेस के माध्यम से दरवाजे पंजीकृत करने के बाद, ox_doorlock प्रत्येक प्रविष्टि को डेटाबेस में निर्देशांक, हेडिंग, मॉडल हैश, और लॉक स्थिति के साथ संग्रहीत करता है। आप इन्हें प्रोग्रामेटिकली क्वेरी और मैनेज कर सकते हैं। रिसोर्स लॉक टॉगल करने, स्थिति जांचने, और एक्सेस प्रबंधन के लिए एक्सपोर्ट्स और इवेंट्स दोनों प्रदान करता है। कस्टम फीचर्स बनाने से पहले डेटा संरचना को समझना आवश्यक है।

-- Checking if a specific door is locked
local doorId = 1
local isLocked = exports.ox_doorlock:getDoorState(doorId)

-- Toggle a door lock from server side
exports.ox_doorlock:setDoorState(doorId, not isLocked)

-- Listen for door state changes
AddEventHandler('ox_doorlock:stateChanged', function(id, state, source)
    print(('Door %d changed to %s by player %s'):format(id, state and 'locked' or 'unlocked', source))
end)

लॉकपिकिंग मैकेनिक बनाना

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

-- client/lockpicking.lua
local function AttemptLockpick(doorId)
    local hasLockpick = exports.ox_inventory:Search('count', 'lockpick')
    if hasLockpick < 1 then
        lib.notify({ title = 'No Lockpick', type = 'error' })
        return
    end

    -- Play lockpicking animation
    local ped = PlayerPedId()
    TaskPlayAnim(ped, 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', 'machinic_loop_mechandlenry', 8.0, -8.0, -1, 1, 0, false, false, false)

    -- Multi-stage skillcheck: easy, medium, hard
    local success = lib.skillCheck({'easy', 'medium', 'hard'}, {'w', 'a', 's', 'd'})

    ClearPedTasks(ped)

    if success then
        TriggerServerEvent('doorlock:lockpick:success', doorId)
        lib.notify({ title = 'Lock Picked', description = 'The door clicks open.', type = 'success' })
    else
        TriggerServerEvent('doorlock:lockpick:fail', doorId)
        lib.notify({ title = 'Failed', description = 'The lockpick snapped.', type = 'error' })
    end
end

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

-- server/lockpicking.lua
local cooldowns = {}

RegisterNetEvent('doorlock:lockpick:success', function(doorId)
    local src = source
    local playerCoords = GetEntityCoords(GetPlayerPed(src))

    -- Verify proximity to door (anti-cheat)
    local doorData = exports.ox_doorlock:getDoor(doorId)
    if not doorData then return end
    if #(playerCoords - doorData.coords) > 3.0 then return end

    -- Check cooldown
    local key = ('%s:%s'):format(src, doorId)
    if cooldowns[key] and os.time() - cooldowns[key] < 30 then return end

    exports.ox_doorlock:setDoorState(doorId, 0) -- Unlock
    cooldowns[key] = os.time()

    -- Auto-relock after 60 seconds
    SetTimeout(60000, function()
        exports.ox_doorlock:setDoorState(doorId, 1)
    end)
end)

RegisterNetEvent('doorlock:lockpick:fail', function(doorId)
    local src = source
    exports.ox_inventory:RemoveItem(src, 'lockpick', 1)

    -- Alert police dispatch
    TriggerEvent('dispatch:alert', {
        coords = GetEntityCoords(GetPlayerPed(src)),
        message = 'Attempted break-in reported',
        code = '10-31',
        job = 'police'
    })
end)

कीकार्ड सिस्टम लागू करना

कीकार्ड सरल कुंजी आइटम की तुलना में अधिक संरचित पहुँच नियंत्रण तंत्र प्रदान करते हैं। वे कॉर्पोरेट भवनों, सरकारी सुविधाओं, और प्रतिबंधित क्षेत्रों के लिए अच्छी तरह से काम करते हैं जहाँ पहुँच को विशिष्ट क्लियरेंस स्तरों से जोड़ा जाना चाहिए। कीकार्ड सिस्टम प्रत्येक दरवाज़े को 1 से 5 तक एक सुरक्षा स्तर असाइन करता है, और खिलाड़ियों के पास समान या उच्चतर क्लियरेंस वाला कीकार्ड होना चाहिए ताकि वे इसे अनलॉक कर सकें। यह एक प्राकृतिक पदानुक्रम बनाता है जहाँ लेवल 3 कीकार्ड सभी लेवल 1, 2, और 3 के दरवाज़े खोलता है लेकिन लेवल 4 या 5 के प्रतिबंधित क्षेत्रों तक पहुँच नहीं सकता। कीकार्ड नौकरी सिस्टम द्वारा जारी किए जा सकते हैं, लूट के रूप में पाए जा सकते हैं, या प्रगति प्रणाली के माध्यम से बनाए जा सकते हैं।

-- shared/config.lua
Config = {}
Config.KeycardLevels = {
    { name = 'keycard_1', label = 'Green Keycard',  level = 1 },
    { name = 'keycard_2', label = 'Blue Keycard',   level = 2 },
    { name = 'keycard_3', label = 'Yellow Keycard', level = 3 },
    { name = 'keycard_4', label = 'Red Keycard',    level = 4 },
    { name = 'keycard_5', label = 'Black Keycard',  level = 5 },
}

Config.DoorSecurity = {
    [10] = { level = 1, name = 'Office Lobby' },
    [11] = { level = 2, name = 'Server Room' },
    [12] = { level = 3, name = 'Executive Floor' },
    [13] = { level = 4, name = 'Vault Anteroom' },
    [14] = { level = 5, name = 'Main Vault' },
}

-- client/keycard.lua
local function TryKeycardAccess(doorId)
    local security = Config.DoorSecurity[doorId]
    if not security then return false end

    for _, card in ipairs(Config.KeycardLevels) do
        if card.level >= security.level then
            local count = exports.ox_inventory:Search('count', card.name)
            if count > 0 then
                -- Play card swipe animation
                lib.requestAnimDict('anim@heists@keycard@')
                TaskPlayAnim(PlayerPedId(), 'anim@heists@keycard@', 'exit', 5.0, 1.0, -1, 16, 0, 0, 0, 0)
                Wait(1200)
                ClearPedTasks(PlayerPedId())
                return true, card
            end
        end
    end
    return false
end

डोर ग्रुप्स और बिज़नेस एक्सेस

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

-- server/door_groups.lua
local DoorGroups = {
    police_station = {
        doors = {1, 2, 3, 4, 5, 6, 7, 8},
        access = {
            { type = 'job', name = 'police', minGrade = 0 },
            { type = 'job', name = 'sheriff', minGrade = 0 },
        }
    },
    pillbox_hospital = {
        doors = {20, 21, 22, 23, 24},
        access = {
            { type = 'job', name = 'ambulance', minGrade = 0 },
            { type = 'job', name = 'doctor', minGrade = 2 },
        }
    },
    vangelico = {
        doors = {30, 31},
        access = {
            { type = 'job', name = 'jeweler', minGrade = 0 },
            { type = 'item', name = 'vangelico_key' },
        }
    },
}

function HasGroupAccess(source, groupName)
    local group = DoorGroups[groupName]
    if not group then return false end

    for _, rule in ipairs(group.access) do
        if rule.type == 'job' then
            local job = GetPlayerJob(source)
            if job and job.name == rule.name and job.grade >= (rule.minGrade or 0) then
                return true
            end
        elseif rule.type == 'item' then
            local count = exports.ox_inventory:GetItem(source, rule.name, nil, true)
            if count and count > 0 then return true end
        end
    end
    return false
end

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

क्लाइंट्स के बीच दरवाजे की स्थिति सिंक करना

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

-- server: broadcast door state to nearby players only
local function SyncDoorToNearby(doorId, state, coords, range)
    range = range or 100.0
    local players = GetPlayers()
    for _, playerId in ipairs(players) do
        local ped = GetPlayerPed(playerId)
        if ped and DoesEntityExist(ped) then
            local playerCoords = GetEntityCoords(ped)
            if #(playerCoords - coords) <= range then
                TriggerClientEvent('doorlock:sync', tonumber(playerId), doorId, state)
            end
        end
    end
end

-- client: apply synced door state
RegisterNetEvent('doorlock:sync', function(doorId, state)
    local door = exports.ox_doorlock:getDoor(doorId)
    if door then
        door.state = state
    end
end)

सुरक्षा विचार और एंटी-एक्सप्लॉइट

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

सभी को एक साथ रखना

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

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

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