FiveM डिबग तकनीकें: Lua और JS में बग्स जल्दी खोजें
FiveM स्क्रिप्ट्स को तेजी से डिबग करें। सर्वर लॉग्स, क्लाइंट प्रिंट्स, txAdmin टूल्स, प्रोफाइलर ट्रिक्स और सिद्ध वर्कफ़्लोज़ जो खिलाड़ियों के नोटिस करने से पहले समस्याओं को ठीक करते हैं।
Agency Scripts
Agency Scripts के संस्थापक और प्रमुख डेवलपर
FiveM स्क्रिप्ट्स डिबगिंग की कला
FiveM स्क्रिप्ट्स का डिबगिंग मूल रूप से मानक एप्लिकेशन के डिबगिंग से अलग है। आप एक विभाजित क्लाइंट-सर्वर आर्किटेक्चर से निपट रहे हैं जहां कोड दो अलग रनटाइम्स पर चलता है, इवेंट्स नेटवर्क के माध्यम से यात्रा करते हैं, और गेम स्टेट हर फ्रेम बदलता है। जब कुछ गलत होता है, तो त्रुटि सर्वर पर उत्पन्न हो सकती है लेकिन क्लाइंट पर प्रकट हो सकती है, या इसके विपरीत। डिबगिंग के लिए एक व्यवस्थित दृष्टिकोण विकसित करना आपको अनगिनत घंटे बचाएगा और आपके विकास वर्कफ़्लो को नाटकीय रूप से तेज़ बनाएगा। यह गाइड उन आवश्यक उपकरणों, तकनीकों और पैटर्न को कवर करता है जिन्हें पेशेवर FiveM डेवलपर्स दैनिक उपयोग करते हैं।
प्रिंट स्टेटमेंट्स का प्रभावी उपयोग
FiveM में सबसे मौलिक डिबगिंग टूल है print() function, लेकिन इसे प्रभावी ढंग से उपयोग करने के लिए केवल वेरिएबल्स को डंप करना पर्याप्त नहीं है। अपने डिबग आउटपुट को प्रीफिक्स के साथ संरचित करें जो स्क्रिप्ट, पक्ष (क्लाइंट या सर्वर), और उस function को पहचानें जहाँ प्रिंट होता है। महत्वपूर्ण संदेशों को कंसोल में अलग दिखाने के लिए रंग कोड का उपयोग करें। एक डिबग यूटिलिटी बनाएं जिसे आप ऑन और ऑफ टॉगल कर सकें बिना अपने कोड से डिबग लाइनों को हटाए।
-- shared/debug.lua
local DEBUG_ENABLED = GetConvar('myresource_debug', 'false') == 'true'
local RESOURCE_NAME = GetCurrentResourceName()
function DebugLog(module, message...)
if not DEBUG_ENABLED then return end
local side = IsDuplicityVersion() and 'SERVER' else 'CLIENT'
local formatted = type(message) == 'string' and message:format(...) or tostring(message)
local timestamp = os.date('%H:%M:%S')
print(('[^3%s^0][^5%s^0][^2%s^0] %s'):format(
timestamp, RESOURCE_NAME, side .. ':' .. module, formatted
))
end
function DebugTable(module, tbl, depth)
if not DEBUG_ENABLED then return end
depth = depth or 0
local indent = string.rep(' ', depth)
if type(tbl) ~= 'table' then
DebugLog(module, '%s%s', indent, tostring(tbl))
return
end
for k, v in pairs(tbl) do
if type(v) == 'table' then
DebugLog(module, '%s%s = {', indent, tostring(k))
DebugTable(module, v, depth + 1)
DebugLog(module, '%s}', indent)
else
DebugLog(module, '%s%s = %s (%s)', indent, tostring(k), tostring(v), type(v))
end
end
end
डिबग यूटिलिटी का उपयोग
With this utility in place, you can add debug logging throughout your scripts that is completely silent in production. Enable it by adding set myresource_debug true जब आपको समस्या निवारण की आवश्यकता हो तो अपने सर्वर कॉन्फ़िगरेशन को देखें। संरचित आउटपुट कंसोल लॉग्स में आसानी से खोज करने और ठीक वही खोजने में मदद करता है जो आप ढूंढ रहे हैं।
-- server/jobs.lua
RegisterNetEvent('myresource:startJob', function(jobName)
local src = source
DebugLog('jobs', 'Player %d attempting to start job: %s', src, jobName)
local playerData = GetPlayerData(src)
DebugTable('jobs', playerData)
if not playerData then
DebugLog('jobs', 'ERROR: No player data found for source %d', src)
return
end
if playerData.job == jobName then
DebugLog('jobs', 'Player %d already has job %s, skipping', src, jobName)
return
end
DebugLog('jobs', 'Job %s assigned to player %d successfully', jobName, src)
end)
सामान्य FiveM त्रुटियाँ और समाधान
SCRIPT ERROR: nil मान को इंडेक्स करने का प्रयास
यह FiveM विकास में सबसे सामान्य Lua त्रुटि है। इसका मतलब है कि आप एक ऐसे वेरिएबल पर प्रॉपर्टी या मेथड तक पहुँचने की कोशिश कर रहे हैं जो nil. सबसे सामान्य कारण हैं खिलाड़ी डेटा को लोड होने से पहले एक्सेस करना, उस फ्रेमवर्क फ़ंक्शन का संदर्भ देना जो आपके उपयोग किए जा रहे संस्करण में मौजूद नहीं है, या कुंजी में टाइपो के साथ कॉन्फ़िग मान पढ़ना। नेस्टेड प्रॉपर्टीज़ को एक्सेस करने से पहले हमेशा nil की जांच करें।
-- BAD: Will crash if GetPlayerData returns nil
local name = GetPlayerData(src).charinfo.firstname
-- GOOD: Defensive nil checks
local playerData = GetPlayerData(src)
if not playerData then
print('[ERROR] Player data is nil for source: ' .. src)
return
end
local charinfo = playerData.charinfo
if not charinfo then
print('[ERROR] charinfo missing for source: ' .. src)
return
end
local name = charinfo.firstname or 'Unknown'
SCRIPT ERROR: nil मान को कॉल करने का प्रयास
यह त्रुटि तब होती है जब आप किसी ऐसी फ़ंक्शन को कॉल करने की कोशिश करते हैं जो मौजूद नहीं है। FiveM में, यह आमतौर पर तब होता है जब आप किसी संसाधन से एक एक्सपोर्ट कॉल करते हैं जो अभी शुरू नहीं हुआ है, किसी फ्रेमवर्क फ़ंक्शन का उपयोग करते हैं जिसे अपडेट में नाम बदला गया हो, या अपनी मैनिफेस्ट में साझा फ़ाइल लोड करना भूल जाते हैं। अपनी जांच करें fxmanifest.lua सुनिश्चित करने के लिए कि सभी आवश्यक फ़ाइलें सूचीबद्ध हैं और सही क्रम में हैं।
-- Safely calling an export that might not be available
local function SafeExport(resource, exportName...)
local success, result = pcall(function(...)
return exports[resource][exportName](...)
end...)
if not success then
print(('[^1ERROR^0] Failed to call export %s:%s - %s'):format(
resource, exportName, tostring(result)
))
return nil
end
return result
end
-- Usage
local inventory = SafeExport('ox_inventory', 'GetInventory', src)
इवेंट पंजीकृत नहीं था
जब आप ऐसा इवेंट ट्रिगर करते हैं जिसके लिए कोई स्क्रिप्ट हैंडलर पंजीकृत नहीं है, तो FiveM इसे चुपचाप ड्रॉप कर देता है बिना कंसोल में कोई त्रुटि दिखाए। यह डिबग करने में पागलपन हो सकता है क्योंकि सब कुछ सही दिखता है लेकिन कुछ भी नहीं होता। इवेंट ट्रिगर करने से पहले यह सुनिश्चित करने के लिए एक हेल्पर फ़ंक्शन का उपयोग करें कि इवेंट पंजीकृत हैं, और विकास के दौरान अपने इवेंट ट्रिगर के आसपास लॉगिंग जोड़ें।
-- server/debug_events.lua
-- Wrap TriggerClientEvent to log when events fire
local originalTrigger = TriggerClientEvent
if GetConvar('myresource_debug', 'false') == 'true' then
TriggerClientEvent = function(eventName, target...)
print(('[^3EVENT^0] TriggerClientEvent: %s -> target: %s'):format(
eventName, tostring(target)
))
return originalTrigger(eventName, target...)
end
end
NUI डिबगिंग विथ DevTools
NUI इंटरफेस वाली स्क्रिप्ट्स के लिए, बिल्ट-इन Chromium DevTools अमूल्य हैं। इन्हें F8 कंसोल में टाइप करके खोलें nui_devtools पूर्ण Chrome इंस्पेक्टर तक पहुँचने के लिए। यह आपको DOM संरचना का निरीक्षण करने के लिए Elements पैनल, JavaScript त्रुटियों के लिए Console, संसाधन लोडिंग के लिए Network टैब, और ब्रेकपॉइंट सेट करने के लिए Sources पैनल देता है। NUI संचार समस्याओं के लिए, संदेश ब्रिज के दोनों पक्षों को लॉग करें।
// nui/js/debug.js
// Log all incoming NUI messages
window.addEventListener('message', (event) => {
if (event.data && event.data.action) {
console.log(
'%c[NUI Received]%c ' + event.data.action,
'background: #2dd4bf; color: #000; padding: 2px 6px; border-radius: 3px;',
'color: #94a3b8;',
event.data
);
}
});
// Wrap fetch to log NUI callbacks
const originalFetch = window.fetch;
window.fetch = function(url, options) {
const body = options?.body ? JSON.parse(options.body) : null;
console.log(
'%c[NUI Callback]%c ' + url,
'background: #8b5cf6; color: #fff; padding: 2px 6px; border-radius: 3px;',
'color: #94a3b8;',
body
);
return originalFetch.apply(this, arguments);
};
Resmon और Timing के साथ प्रोफाइलिंग
मूलभूत से परे resmon मॉनिटरिंग, आप अपने स्क्रिप्ट्स में सटीक टाइमिंग इंस्ट्रूमेंटेशन बना सकते हैं। मापें कि विशिष्ट ऑपरेशन्स में कितना समय लगता है और जब वे स्वीकार्य सीमा से अधिक हो जाएं तो चेतावनी लॉग करें। यह विशेष रूप से डेटाबेस क्वेरीज, जटिल गणनाओं, और कई एंटिटीज़ को प्रोसेस करने वाले लूप्स के लिए महत्वपूर्ण है।
-- shared/profiler.lua
local Profiler = {}
function Profiler.Start(label)
return {
label = label,
startTime = GetGameTimer()
}
end
function Profiler.Stop(timer, warnThresholdMs)
local elapsed = GetGameTimer() - timer.startTime
warnThresholdMs = warnThresholdMs or 5
if elapsed >= warnThresholdMs then
print(('[^1PERF WARNING^0] %s took %dms (threshold: %dms)'):format(
timer.label, elapsed, warnThresholdMs
))
elseif GetConvar('myresource_debug', 'false') == 'true' then
print(('[^2PERF^0] %s completed in %dms'):format(timer.label, elapsed))
end
return elapsed
end
-- Usage in a server event
RegisterNetEvent('myresource:heavyOperation', function(data)
local timer = Profiler.Start('heavyOperation')
-- ... expensive processing ...
local result = ProcessLargeDataSet(data)
Profiler.Stop(timer, 10) -- warn if over 10ms
end)
स्टेट बैग डिबगिंग
स्टेट बैग्स एक शक्तिशाली लेकिन कभी-कभी भ्रमित करने वाली सुविधा हैं। जब स्टेट बैग मान अपेक्षित रूप से अपडेट नहीं होते हैं, तो आमतौर पर इसका कारण यह होता है कि आप उन्हें गलत एंटिटी पर सेट कर रहे हैं, हैंडलर सही बैग नाम पकड़ नहीं रहा है, या प्रतिकृति में देरी हो रही है। एक स्टेट बैग इंस्पेक्टर कमांड बनाएं जो किसी दिए गए एंटिटी के लिए सभी स्टेट डंप करता है।
-- server/debug_statebags.lua
RegisterCommand('debugstate', function(source, args)
local targetId = tonumber(args[1])
if not targetId then
print('Usage: debugstate [playerId]')
return
end
local playerPed = GetPlayerPed(targetId)
if playerPed == 0 then
print('Player not found: ' .. targetId)
return
end
local entityState = Player(targetId).state
print(('[^3STATE BAGS^0] Player %d:'):format(targetId))
-- Print known state keys (state bags don't have an iterator)
local keysToCheck = {'job', 'gang', 'duty', 'dead', 'phone', 'inventory'}
for _, key in ipairs(keysToCheck) do
local val = entityState[key]
if val ~= nil then
print((' %s = %s (%s)'):format(key, tostring(val), type(val)))
end
end
end, true)
आवश्यक डिबगिंग चेकलिस्ट
- दोनों कंसोल जांचें। हमेशा सर्वर कंसोल (txAdmin या टर्मिनल) और क्लाइंट कंसोल (F8) दोनों में त्रुटियों को देखें। एक पक्ष की त्रुटि अक्सर दूसरे पक्ष पर टूटे हुए व्यवहार की व्याख्या करती है।
- संसाधन स्थिति सत्यापित करें। उपयोग करें
ensureअपने संसाधन को पुनः आरंभ करने के लिए औरrestartएकल संसाधन को पुनः आरंभ करने के लिए। जांचेंresmonसुनिश्चित करने के लिए कि संसाधन वास्तव में चल रहा है। - साफ़ वातावरण के साथ परीक्षण करें। उसी सिस्टम के साथ इंटरैक्ट करने वाले अन्य स्क्रिप्ट्स को अक्षम करें। कई बग संसाधनों के बीच संघर्षों से आते हैं न कि एकल स्क्रिप्ट के भीतर बग से।
- त्रुटि स्टैक ट्रेस को ध्यान से पढ़ें। Lua स्टैक ट्रेस आपको सही फ़ाइल और लाइन नंबर दिखाते हैं। त्रुटि तक पहुँचने वाली कॉल चेन को समझने के लिए इन्हें नीचे से ऊपर पढ़ें।
- जोखिम भरे ऑपरेशनों के लिए pcall का उपयोग करें। डेटाबेस क्वेरी, एक्सपोर्ट कॉल, और JSON डिकोडिंग को wrap करें
pcallत्रुटियों को सहजता से पकड़ने के लिए ताकि वे आपकी स्क्रिप्ट को क्रैश न करें। - अपनी कॉन्फ़िग्स का संस्करण बनाएं। जब खिलाड़ी बग रिपोर्ट करते हैं, तो पूछें कि वे कौन सा संस्करण चला रहे हैं। कई समस्याएं अपडेट के बाद पुराने कॉन्फ़िगरेशन फ़ाइलों से उत्पन्न होती हैं।