FiveM NUI ไม่ขึ้น ค้าง หรือเมาส์ติดหน้าจอ แก้อย่างไร
ปัญหา FiveM NUI ไม่ขึ้น, NUI ค้าง, กดเมนูไม่ได้, เปิด Inventory แล้วจอดำ, ปิด Menu แล้วเมาส์ยังติดหน้าจอ หรือเดินไม่ได้หลังปิด UI มักไม่ได้มีต้นเหตุเพียงจุดเดียว เพราะระบบ NUI ของ FiveM มีหลายชั้น ตั้งแต่ Resource, fxmanifest.lua, ui_page, HTML/CSS/JavaScript, SendNUIMessage, NUI Callback ไปจนถึง SET_NUI_FOCUS
FiveM Fullscreen NUI เป็นหน้า UI ที่ Overlay บนเกมและอาจมีหรือไม่มี Input Focus โดย APIs หลักที่เกี่ยวข้องคือ SEND_NUI_MESSAGE และ SET_NUI_FOCUS.
บทความนี้จาก comsiam จะไล่ตรวจแบบเป็นระบบ เพื่อหาว่าปัญหาเกิดที่ Resource, Browser UI, Message, Callback หรือ Focus กันแน่
① แยกอาการ NUI ก่อน
คำว่า NUI พังอาจหมายถึงหลายอาการ
NUI ไม่ขึ้นเลยNUI ขึ้นแต่เป็นหน้าว่างNUI ขึ้นแต่ไม่มีข้อมูลNUI ขึ้นแต่กดไม่ได้ปุ่มกดแล้วไม่ทำงานNUI ค้างปิด NUI ไม่ได้เมาส์ติดหน้าจอเดินไม่ได้หลังปิด NUINUI หายหลัง Restart Resource
แต่ละอาการควรตรวจคนละ Layer
② Flow ของ FiveM NUI
จำ Flow นี้ให้ได้
RESOURCE↓fxmanifest.lua↓ui_page↓HTML / CSS / JS↓SendNUIMessage↓JavaScript↓UI
เวลาผู้เล่นกด Button จะย้อนกลับประมาณ
UI↓NUI Callback↓Client Script↓Server ถ้าจำเป็น
FiveM รองรับ Message จาก Game Script ไปยัง Fullscreen NUI และรองรับ NUI Callbacks สำหรับส่งข้อมูลกลับจาก UI เข้าสู่ Game Script.
③ NUI ไม่ขึ้นเลยให้ตรวจ Resource ก่อน
อย่าเริ่มจาก CSS
ตรวจว่า Resource Start อยู่หรือไม่
เช่น
ensure inventory
หรือ Resource ที่เป็น NUI ของคุณ
ถ้า Resource ไม่ทำงาน client.lua, ui_page และ NUI Logic ภายใน Resource นั้นก็จะไม่เริ่มทำงาน
④ ตรวจ fxmanifest.lua
Resource FiveM ต้องมี Resource Manifest และ fxmanifest.lua ใช้ประกาศ Scripts/Files ที่ Resource ใช้.
ตัวอย่าง
fx_version 'cerulean'game 'gta5'client_script 'client.lua'ui_page 'html/index.html'files {'html/index.html','html/style.css','html/app.js'}
⑤ ui_page สำคัญอย่างไร
FiveM ใช้
ui_page 'html/index.html'
เพื่อกำหนดหน้า NUI ของ Resource
ถ้าใช้ Local File ตัวหน้า UI และ Dependencies ต้องถูกอ้างใน files.
ดังนั้น Path ผิดเพียงตัวเดียวก็ทำให้ NUI ไม่โหลดตามที่คาด
⑥ ตัวอย่าง ui_page ผิด
Manifest
ui_page 'html/index.html'
แต่ไฟล์จริงอยู่
web/index.html
กรณีนี้ Resource Structure กับ Manifest ไม่ตรงกัน
ให้แก้ Path ก่อนตรวจ JavaScript
⑦ ลืม files ทำให้ NUI พังได้ไหม
ได้
Cfx.re ระบุว่า Local ui_page และ Dependencies ต้องถูกเพิ่มผ่าน files.
เช่น
files {'html/index.html','html/style.css','html/app.js','html/logo.webp'}
⑧ HTML ไม่ขึ้นเลยให้ทำ Test Page
เปลี่ยนชั่วคราวเป็น
<!DOCTYPE html><html><body><h1>NUI TEST</h1></body></html>
ถ้า NUI TEST ยังไม่ขึ้น
ให้เน้น
Resourcefxmanifestui_pagefiles
ก่อน
⑨ HTML ขึ้นแล้วถือว่าแก้อะไรได้บ้าง
ถ้าเห็นข้อความ Test
คุณพิสูจน์ได้อย่างน้อยว่า
Resource→ ui_page→ HTML
ทำงานแล้ว
จากนั้นค่อยไปตรวจ
CSSJavaScriptMessage
⑩ CSS ทำให้ NUI ดูเหมือนหายได้ไหม
ได้
เช่น
display: none;
หรือ
visibility: hidden;
หรือ
opacity: 0;
หน้า UI อาจโหลดแล้ว แต่ถูกซ่อนด้วย Style
⑪ Position ผิดก็ทำให้ NUI ดูเหมือนหาย
เช่น
left: -5000px;
หรือ Transform ผิด
transform: translateX(-200vw);
Element ยังอยู่ใน DOM แต่หลุดออกนอกจอ
จึงควรตรวจผ่าน NUI Developer Tools
⑫ เปิด NUI Developer Tools อย่างไร
FiveM มีคำสั่ง
nui_devtools
สำหรับเปิด NUI DevTools จาก Game Process.
ใช้ตรวจ
ConsoleElementsCSSJavaScriptNetworkDOM
⑬ F8 กับ NUI DevTools ต่างกันอย่างไร
จำง่าย ๆ
F8→ FiveM Client / ScriptNUI DevTools→ HTML / CSS / JavaScript
FiveM Client Console มีคำสั่งสำหรับ Debug Resources และ nui_devtools ใช้เปิดเครื่องมือ Debug ของ NUI โดยเฉพาะ.
⑭ JavaScript Error ทำให้ UI ไม่ขึ้นได้ไหม
ได้
เช่น
const menu =document.getElementById('menu');menu.classList.remove('hidden');
แต่ Element menu ไม่มีอยู่จริง
JavaScript อาจ Error และ Code ส่วนหลังไม่ทำงาน
เปิด Console ใน NUI DevTools แล้วแก้ Error แรกก่อน
⑮ SendNUIMessage คืออะไร
FiveM มี
SendNUIMessage(data)
สำหรับส่งข้อมูลไปยัง NUI.
ตัวอย่าง
SendNUIMessage({action = 'open'})
⑯ ตัวอย่าง Test Message
Client
RegisterCommand('testnui', function()SendNUIMessage({action = 'test',message = 'hello'})end)
FiveM รองรับการส่ง Table ผ่าน SendNUIMessage ไปยัง NUI.
⑰ JavaScript รับ Message อย่างไร
ตัวอย่าง
window.addEventListener('message',function(event) {console.log('NUI MESSAGE:',event.data);});
Fullscreen NUI ใช้ Browser message Event สำหรับรับข้อมูลจาก Game Script.
⑱ Console ไม่เห็น Message เลย
ตรวจ
Client Script ทำงานไหมSendNUIMessage ถูกเรียกไหมResource ถูกไหมui_page โหลดไหม
อย่าแก้ DOM ก่อนพิสูจน์ว่า Message มาถึง Browser
⑲ Message เข้าแต่ UI ไม่เปลี่ยน
แสดงว่า Transport Layer ใช้งานได้แล้ว
ให้ตรวจ
Action NameJavaScript ConditionDOM SelectorCSSUI State
แทน
⑳ Action Name ไม่ตรงเป็นปัญหาที่พบบ่อย
Client ส่ง
SendNUIMessage({action = 'openMenu'})
แต่ JavaScript ตรวจ
if (event.data.action=== 'openmenu') {}
ตัวอักษรไม่ตรง
Logic จึงไม่ทำงาน
㉑ วิธี Debug Action ที่เร็วที่สุด
ก่อนเขียน Condition ซับซ้อน
ใช้
console.log(event.data);
ดูข้อมูลจริงก่อน
แล้วค่อยตรวจ
actiondatastate
㉒ NUI ขึ้นแต่ข้อมูลเป็นค่าว่าง
เช่น HUD ขึ้นแต่
Money = undefinedJob = undefinedHealth = undefined
ให้ดูชื่อ Property ที่ Client ส่ง
เช่น
SendNUIMessage({money = 5000})
JavaScript ต้องอ่าน
event.data.money
ไม่ใช่
event.data.cash
㉓ NUI เปิดแต่คลิกไม่ได้
จุดสำคัญคือ
SET_NUI_FOCUS
FiveM มี SET_NUI_FOCUS(BOOL hasFocus, BOOL hasCursor) สำหรับกำหนด Focus และ Cursor ของ NUI.
㉔ ตัวอย่างเปิด Focus
SetNuiFocus(true,true)
เหมาะกับ UI เช่น
InventoryPhoneBankMenuSettings
ที่ต้องใช้ Mouse
㉕ HUD จำเป็นต้อง SetNuiFocus ไหม
ถ้า HUD ใช้แสดงข้อมูลอย่างเดียว เช่น
HealthArmorSpeedFuel
โดยไม่มี Interaction
ไม่จำเป็นต้องให้ HUD ถือ Mouse/Keyboard Focus
㉖ NUI ขึ้นแต่ Mouse ไม่ขึ้น
ตรวจว่า Code เปิด
SetNuiFocus(true,true)
จริงหรือไม่
Native นี้รับค่าแยกสำหรับ Focus และ Cursor.
㉗ เมาส์ติดหน้าจอหลังปิด NUI
นี่เป็นหนึ่งในอาการยอดนิยมที่สุด
ตอนปิด UI ต้องคืน Focus
SetNuiFocus(false,false)
ถ้าไม่ได้เรียก Focus สามารถค้างจาก State ที่ Resource ตั้งไว้ก่อนหน้าได้ เพราะ IS_NUI_FOCUSED จะคืน Current NUI Focus State ที่เคยตั้งด้วย SET_NUI_FOCUS.
㉘ ตัวอย่าง Close Menu ที่ถูกโครงสร้าง
local menuOpen = falselocal function closeMenu()menuOpen = falseSetNuiFocus(false,false)SendNUIMessage({action = 'close'})end
ปิดทั้ง
Visual+Focus
ไม่ใช่แค่ซ่อน HTML
㉙ CSS display:none ไม่ได้คืน Focus
นี่เป็นจุดที่ผิดบ่อย
JavaScript ทำ
menu.style.display = 'none';
แค่ซ่อน UI
แต่ถ้า Client ยังมี
NUI Focus = true
ผู้เล่นอาจยัง
หมุนกล้องไม่ได้เดินไม่ได้เมาส์ค้าง
ต้องคืน Focus ฝั่ง FiveM Script ด้วย
㉚ ตรวจว่า NUI Focus ค้างหรือไม่
FiveM มี
IS_NUI_FOCUSED
ซึ่งคืน Current Focus State.
สำหรับ Debug สามารถตรวจได้ว่าหลัง Close Menu Focus กลับเป็น false หรือยัง
㉛ ตัวอย่าง Debug Focus
RegisterCommand('checkfocus',function()print('NUI focused:',IsNuiFocused())end)
ถ้าปิด Menu แล้วค่าเป็น true
Close Flow ยังไม่ Cleanup Focus
㉜ ทำคำสั่งแก้ Mouse ค้างชั่วคราว
สำหรับ Debug
RegisterCommand('fixnui',function()SetNuiFocus(false,false)SetNuiFocusKeepInput(false)end)
นี่ควรใช้เป็น Debug/Fallback ไม่ใช่แทนการแก้ Close Lifecycle
SET_NUI_FOCUS_KEEP_INPUT มีไว้กำหนด Input Behavior ระหว่าง NUI Focus.
㉝ SetNuiFocusKeepInput คืออะไร
FiveM มี
SET_NUI_FOCUS_KEEP_INPUT
รับ Boolean keepInput.
และมี
IS_NUI_FOCUS_KEEPING_INPUT
สำหรับตรวจว่า Keyboard Input ถูกเปิดไว้ระหว่าง NUI Focus หรือไม่.
㉞ เมื่อปิด UI ควร Reset KeepInput ไหม
ถ้า Resource เคยใช้
SetNuiFocusKeepInput(true)
ก็ควรมี Lifecycle ที่คืน State เมื่อ Menu ปิด
เช่น
SetNuiFocusKeepInput(false)SetNuiFocus(false, false)
เพื่อไม่ให้ Input State ค้างจาก Resource
㉟ NUI ขึ้นแต่เดินได้ทั้งที่ Menu เปิด
ถ้า Resource เปิด Focus พร้อมใช้ KeepInput
Input บางส่วนสามารถถูกออกแบบให้ยังส่งเข้าเกมได้
ตรวจ
SetNuiFocusKeepInput(...)
ก่อนสรุปว่า Focus พัง
FiveM มี Getter สำหรับตรวจ Keep-input State โดยตรง.
㊱ UI หลายตัวแย่ง Focus กันได้ไหม
Fullscreen NUI มี Focus Stack และ Resource ที่ถูก Focus ล่าสุดจะอยู่ด้านบนของ Focus Stack ตามเอกสาร Cfx.re.
ตัวอย่าง Server มี
InventoryPhoneBankHUD SettingsAdmin Menu
หลายตัวเปิดพร้อมกัน
อาจเกิด Focus Conflict ได้
㊲ เปิด Inventory แล้ว Phone ใช้ไม่ได้
ตรวจว่า Resource ไหนเรียก
SetNuiFocus
ล่าสุด
เพราะ NUI Focus มี Stack ระหว่าง Fullscreen NUI Resources.
㊳ เปิด Phone แล้ว Inventory หาย
อาจเป็น
UI Visibility ConflictFocus StackNUI State
ไม่ควรแก้ด้วยการเพิ่ม z-index: 9999999 ทันที
CSS z-index กับ NUI Focus Stack เป็นคนละ Layer
㊴ NUI Callback คืออะไร
NUI Callback ใช้ส่งข้อมูลจาก UI กลับเข้าสู่ Game Script
Cfx.re ระบุว่าข้อมูลต้อง JSON-encodable และข้อมูลที่ส่งผ่าน cb จะถูกส่งกลับไปยัง UI.
㊵ ตัวอย่าง Close Callback
Lua
RegisterNUICallback('close',function(data, cb)SetNuiFocus(false,false)cb({ok = true})end)
㊶ ทำไม NUI Callback ต้อง cb
Cfx.re ระบุชัดว่าควร Return Data ผ่าน Callback เสมอ ไม่เช่นนั้น Request จะ Timeout และ Error สามารถย้อนกลับไปยัง fetch ของ UI.
ดังนั้นอย่าเขียน
RegisterNUICallback('close',function(data, cb)SetNuiFocus(false, false)-- ไม่มี cbend)
㊷ NUI กดปุ่มแล้วหมุนค้างเกิดจาก Callback ได้ไหม
ถ้า JavaScript กำลังรอ Response จาก fetch แต่ Lua Callback ไม่เคยตอบ cb
Request สามารถ Timeout ได้ตาม NUI Callback Documentation.
อาจทำให้ UI Logic ที่รอ Response ไม่เดินต่อ
㊸ Callback Data ต้องเป็นแบบไหน
ข้อมูลรับส่งต้องสามารถ JSON Encode ได้.
ใช้ข้อมูลพื้นฐาน เช่น
stringnumberbooleanarrayobject/table
ที่สามารถ Serialize ได้
㊹ NUI กด Close แต่เมาส์ยังอยู่
ตรวจสองจุด
JavaScript Close ถูกเรียก?↓NUI Callback เข้า Lua?↓SetNuiFocus(false, false) ถูกเรียก?
อย่าตรวจ CSS อย่างเดียว
㊺ เพิ่ม Log ใน NUI Callback
RegisterNUICallback('close',function(data, cb)print('[NUI] close callback')SetNuiFocus(false,false)cb({ok = true})end)
ถ้ากด Close แล้วไม่มี Log
Callback Route ยังไม่เข้าถึง Client Script
㊻ NUI ค้างหลัง Restart Resource
นี่เป็น Lifecycle Problem ที่ควรตรวจ
FiveM มี onClientResourceStart ซึ่งถูกเรียกหลัง Resource เริ่มทำงาน และ onClientResourceStop ถูกเรียกหลัง Resource หยุด.
ใช้ Events เหล่านี้ช่วย Initialize/Cleanup State ได้
㊼ ปัญหา Restart ตอน Menu เปิด
สถานการณ์
Inventory เปิด↓NUI Focus = true↓Resource ถูก Restart↓Close Function ไม่ได้ทำงานตามปกติ
ถ้า Cleanup ไม่ดี ผู้เล่นอาจรู้สึกว่า Input/Focal State ผิดหลัง Restart
จึงควรออกแบบ Resource Stop Handling ไว้
㊽ ตัวอย่าง Cleanup ตอน Resource Stop
AddEventHandler('onClientResourceStop',function(resourceName)if resourceName~= GetCurrentResourceName()thenreturnendSetNuiFocusKeepInput(false)SetNuiFocus(false, false)end)
onClientResourceStop เป็น Client Event ที่ FiveM เรียกหลัง Resource หยุด.
㊾ Start Resource แล้ว NUI State ผิด
ใช้ onClientResourceStart ช่วย Reinitialize
AddEventHandler('onClientResourceStart',function(resourceName)if resourceName~= GetCurrentResourceName()thenreturnendSetNuiFocus(false, false)SendNUIMessage({action = 'reset'})end)
onClientResourceStart ถูกเรียกหลัง Resource Start ฝั่ง Client.
㊿ NUI หายหลัง Restart แต่ Focus ยังทำงาน
นี่บอกใบ้ว่า
Browser/UI State
กับ
Focus State
ไม่ Sync กัน
ควรมี State กลาง เช่น
local menuOpen = false
แล้วทุก Open/Close/Restart อ้าง State เดียวกัน
51. อย่าให้หลาย Function เปิด Focus โดยไม่รู้กัน
ตัวอย่าง
openInventory()openPhone()openSettings()
ทุกตัวเรียก
SetNuiFocus(true, true)
แต่ Close Function ของตัวหนึ่งเรียก
SetNuiFocus(false, false)
ทั้งที่อีก Menu ยังเปิด
จะเกิด State Conflict ได้
52. ใช้ UI Manager ช่วยได้
Server ที่มีหลาย NUI ควรกำหนด Ownership ชัด
เช่น
PhoneInventoryBankAdmin
อย่างน้อยต้องรู้ว่า
Menu ไหนเปิดอยู่ใครถือ Focusเมื่อไรคืน Focus
ไม่ควรให้แต่ละ Resource เดาเองทั้งหมด
53. NUI เป็นหน้าขาว
ตรวจ
HTML PathCSSJavaScriptExternal Assets
ถ้า ui_page Local ผิดหรือ Dependencies ไม่อยู่ใน files หน้า UI สามารถโหลดไม่ครบได้ เพราะ Resource Manifest กำหนดให้ Local UI Page และ Dependencies ถูกอ้างใน files.
54. NUI ขึ้นพื้นหลังแต่ไม่มี Menu
แสดงว่า Root Document/CSS บางส่วนอาจโหลดแล้ว
ตรวจ
JavaScriptvisibility statemessage action
ต่อ
55. เปิด NUI แล้วเห็นเมนูแวบเดียวแล้วหาย
ตรวจ Message Flow
อาจมี
open↓close
เข้ามาติดกัน
ใช้
console.log(Date.now(),event.data);
เพื่อดู Sequence จริง
56. NUI เปิดสองครั้งเกิดอะไร
ถ้า Open Event ถูก Trigger ซ้ำ
อาจเกิด
Duplicate StateDuplicate TimerDuplicate Listener
ถ้า Resource Initialization Register Events ซ้ำหลัง Restart หรือ Character Load
ต้องตรวจ Lifecycle
57. setInterval ซ้ำทำให้ NUI ค้างได้ไหม
ถ้าเปิด Menu ทุกครั้งแล้วสร้าง
setInterval(...)
ใหม่โดยไม่ Clear
Timer สามารถสะสมได้
หลังเปิด/ปิดหลายรอบ UI อาจทำงานซ้ำจำนวนมาก
ควรเก็บ Timer Handle และ Cleanup เมื่อไม่ใช้
58. Event Listener ซ้ำต้องระวัง
อย่า Register
window.addEventListener('message',...);
ใหม่ทุกครั้งที่เปิด Menu
ถ้า Script File โหลดครั้งเดียว Listener หลักก็ควรสร้างตาม Lifecycle ที่ตั้งใจ
59. NUI ค้างเพราะ Message ถี่เกินไปได้ไหม
SendNUIMessage ใช้ส่งข้อมูลเข้า NUI ทุกครั้งที่ถูกเรียก.
หาก Resource ส่ง
HealthMoneyJobInventorySpeedVoice
ซ้ำ ๆ โดยไม่จำเป็น
UI ต้องประมวลผล Messages เพิ่มขึ้น
ควรส่งตาม State/ข้อมูลที่เปลี่ยน
60. UI เปิดแล้ว FPS ลด
ใช้
resmon true
FiveM Resource Monitor จะแสดง CPU และ Memory Usage ของ Resources.
ถ้า Client Resource สูง ให้ตรวจ
LoopsNative CallsSendNUIMessage
เพิ่มเติม
61. resmon ต่ำแต่ NUI ยังหน่วง
ให้ตรวจ Browser Layer
JavaScriptDOMCSS EffectsAnimationLarge Images
ผ่าน NUI DevTools
เพราะ NUI เป็น HTML-based UI ที่ทำงานบน Chromium Embedded Framework.
62. อย่าใช้ console.log ทุก Frame ใน Production
ระหว่าง Debug ใช้ได้
แต่ถ้า Message เข้ามาถี่มาก
console.log(event.data);
จะสร้าง Console Noise จำนวนมาก
หลังแก้เสร็จควรถอด Log ที่ไม่จำเป็น
63. NUI Focus ควรเปิดทุก Frame ไหม
โดยทั่วไปควรเปลี่ยน Focus เมื่อ State เปลี่ยน เช่น
Menu Open→ Set FocusMenu Close→ Remove Focus
ไม่จำเป็นต้อง Reapply Focus ทุก Frameโดยไม่มีเหตุผล
ให้ State ของ Resource เป็นตัวควบคุม
64. UI เปิดด้วย Key แต่ปิดไม่ได้
ตรวจ
Key CommandNUI CallbackEscape HandlerClose Function
ควรมี Close Path อย่างน้อยหนึ่งทางที่คืน
Visibility+Focus
พร้อมกัน
65. ESC ปิด UI แต่ Mouse ยังติด
เป็นอาการชัดว่าฝั่ง Browser ซ่อน UI แล้ว แต่ Client Focus Cleanup ไม่ครบ
ตรวจว่า ESC Handler เรียก NUI Callback กลับ Lua หรือซ่อน DOM อย่างเดียว
66. ตัวอย่าง ESC Close ฝั่ง JavaScript
document.addEventListener('keydown',function(event) {if (event.key === 'Escape') {// เรียก callback// แล้วให้ client เป็นคนคืน focus}});
หลักสำคัญคืออย่าให้ JavaScript เป็นคนซ่อน UI อย่างเดียว หาก Client ยังถือ NUI Focus
67. NUI ที่ดีควรมี State เดียว
เช่น
local isOpen = false
Open
isOpen = trueSetNuiFocus(true, true)SendNUIMessage({action = 'open'})
Close
isOpen = falseSetNuiFocus(false, false)SendNUIMessage({action = 'close'})
ช่วยลด Visual State กับ Focus State ไม่ตรงกัน
68. วิธี Debug FiveM NUI แบบเร็วที่สุด
ขั้นที่ 1 — ตรวจ Resource
Resource Start หรือไม่
ขั้นที่ 2 — ตรวจ Manifest
fxmanifest.luaui_pagefiles
Local ui_page และ Dependencies ต้องประกาศใน files.
ขั้นที่ 3 — HTML Test
<h1>NUI TEST</h1>
ขั้นที่ 4 — เปิด NUI DevTools
nui_devtools
FiveM มีคำสั่งนี้สำหรับเปิด NUI Dev Tools.
ขั้นที่ 5 — Test SendNUIMessage
SendNUIMessage({action = 'test'})
ขั้นที่ 6 — Log Message
console.log(event.data);
ขั้นที่ 7 — ถ้าคลิกไม่ได้
ตรวจ
SET_NUI_FOCUS
ขั้นที่ 8 — ถ้าเมาส์ค้าง
ตรวจ
IS_NUI_FOCUSEDSET_NUI_FOCUS_KEEP_INPUT
ขั้นที่ 9 — ถ้าปุ่ม Callback ค้าง
ตรวจว่า cb ถูกตอบทุกครั้ง.
ขั้นที่ 10 — ถ้าพังหลัง Restart
ตรวจ onClientResourceStart และ onClientResourceStop.
69. ตารางสรุป NUI มีปัญหา
| อาการ | จุดที่ควรตรวจ |
|---|---|
| NUI ไม่ขึ้น | Resource / ui_page |
| HTML ไม่โหลด | files / Path |
| NUI หน้าขาว | HTML / JS / Assets |
| UI ขึ้นแต่ข้อมูลไม่มี | SendNUIMessage |
| Message เข้าแต่ UI ไม่เปลี่ยน | JavaScript / DOM |
| UI ขึ้นแต่คลิกไม่ได้ | SET_NUI_FOCUS |
| Mouse ไม่ขึ้น | Cursor Focus |
| Mouse ค้างหลังปิด | Focus Cleanup |
| เดินไม่ได้หลังปิด | Focus/Keep Input |
| Callback กดแล้วค้าง | ไม่ตอบ cb |
| UI แวบแล้วหาย | State/Open-Close Messages |
| Restart แล้ว NUI พัง | Resource Lifecycle |
| NUI เปิดซ้ำ | Duplicate Events |
| UI หน่วง | JS/DOM/Message Frequency |
| Resource CPU สูง | Client Loop / resmon |
70. Checklist FiveM NUI
☐ Resource Started☐ fxmanifest.lua ถูก☐ ui_page ถูก☐ files ครบ☐ HTML โหลด☐ CSS โหลด☐ JavaScript ไม่มี Error☐ SendNUIMessage ทำงาน☐ Message Listener ทำงาน☐ Action Names ตรงกัน☐ SetNuiFocus ตอนเปิดถูก☐ SetNuiFocus ตอนปิดถูก☐ KeepInput ถูก☐ Callback ทำงาน☐ Callback ตอบ cb☐ Resource Stop Cleanup ถูก☐ Resource Start Reset ถูก☐ ไม่มี Duplicate Listener☐ ไม่มี Duplicate Timer☐ resmon ไม่สูงผิดปกติ
71. ตัวอย่าง NUI Open/Close แบบครบ
local isOpen = falselocal function openMenu()if isOpen thenreturnendisOpen = trueSetNuiFocus(true,true)SetNuiFocusKeepInput(false)SendNUIMessage({action = 'open'})endlocal function closeMenu()if not isOpen thenreturnendisOpen = falseSetNuiFocusKeepInput(false)SetNuiFocus(false,false)SendNUIMessage({action = 'close'})end
SET_NUI_FOCUS ใช้กำหนด Focus/Cursor ส่วน SET_NUI_FOCUS_KEEP_INPUT ควบคุม Input Behavior ระหว่าง NUI Focus.
72. ตัวอย่าง NUI Callback Close
RegisterNUICallback('close',function(data, cb)closeMenu()cb({ok = true})end)
NUI Callback ควรตอบ cb เสมอเพื่อไม่ให้ Request Timeout.
73. ตัวอย่าง Cleanup เมื่อ Resource Stop
AddEventHandler('onClientResourceStop',function(resourceName)if resourceName~= GetCurrentResourceName()thenreturnendSetNuiFocusKeepInput(false)SetNuiFocus(false, false)end)
FiveM เรียก onClientResourceStop หลัง Client Resource หยุด จึงใช้เป็นจุด Cleanup ได้.
74. ตัวอย่าง Reset ตอน Resource Start
AddEventHandler('onClientResourceStart',function(resourceName)if resourceName~= GetCurrentResourceName()thenreturnendSetNuiFocusKeepInput(false)SetNuiFocus(false, false)SendNUIMessage({action = 'reset'})end)
onClientResourceStart ถูกเรียกหลัง Resource เริ่มทำงานฝั่ง Client.
75. อย่าแก้ Mouse ค้างด้วย Restart FiveM อย่างเดียว
Restart Client อาจทำให้ State หายชั่วคราว
แต่ถ้า Resource ยังมี
Open→ SetNuiFocus(true,true)Close→ ไม่คืน Focus
ปัญหาจะกลับมาอีก
ต้องแก้ Close Lifecycle
76. อย่าซ่อน NUI อย่างเดียว
การทำ
document.body.style.display ='none';
ไม่ได้หมายความว่า FiveM คืน Focus แล้ว
ต้องแยก
Visual State
กับ
Input Focus State
ออกจากกัน
77. อย่าใส่ SetNuiFocus(false,false) ทุก Frame
การแก้ Focus Conflict ควรทำจาก Event/State ที่ชัด
เช่น
Menu CloseResource StopEmergency Recovery
ไม่ใช่ Loop ที่บังคับคืน Focus ตลอดเวลา เพราะ Resource อื่นอาจต้องใช้ NUI Focus อยู่
78. อย่าล้าง Cache เป็นขั้นตอนแรก
ถ้าต้นเหตุคือ
ui_page ผิดCallback ไม่ตอบ cbSetNuiFocus ไม่คืนJavaScript Error
การล้าง FiveM Cache ไม่แก้ Root Cause เหล่านี้
Debug Resource ก่อน
79. อย่าเปลี่ยน NUI Resource ทั้งตัวทันที
ถ้า UI
เปิดได้แต่ Mouse ค้าง
ปัญหาอาจเป็น Code เพียงบรรทัดเดียวใน Close Flow
ไม่จำเป็นต้องเปลี่ยน Inventory/HUD/Phone Resource ใหม่ทั้งระบบ
80. สูตรจำง่ายเมื่อ NUI พัง
PAGE↓MESSAGE↓JAVASCRIPT↓CALLBACK↓FOCUS↓CLEANUP
ถ้าแยกหกชั้นนี้ได้ การหาปัญหา NUI จะเร็วขึ้นมาก
สรุป FiveM NUI ไม่ขึ้น ค้าง หรือเมาส์ติดหน้าจอ แก้อย่างไร
ถ้า FiveM NUI ไม่ขึ้นเลย ให้เริ่มจาก
Resource↓fxmanifest.lua↓ui_page↓files↓HTML
ก่อน เพราะ FiveM กำหนด NUI Page ผ่าน ui_page และถ้าใช้ Local Files หน้า UI พร้อม Dependencies ต้องถูกอ้างใน files.
ถ้า HTML ขึ้นแต่ไม่มีข้อมูล ให้ตรวจ SendNUIMessage และ Browser message Listener เพราะ FiveM ใช้ Message Flow นี้ส่งข้อมูลจาก Game Script ไปยัง Fullscreen NUI.
ถ้า Message เข้ามาแล้วแต่ NUI ยังไม่เปลี่ยน ให้เปิด
nui_devtools
จาก F8 แล้วตรวจ JavaScript, DOM และ CSS โดยตรง เพราะ FiveM มีคำสั่งนี้สำหรับเปิด NUI Developer Tools.
ถ้า NUI เปิดแต่คลิกไม่ได้หรือ Mouse ไม่ขึ้น ให้ตรวจ SET_NUI_FOCUS ซึ่งใช้กำหนด Focus และ Cursor ของ NUI.
ถ้า ปิด NUI แล้ว Mouse ยังติดหน้าจอหรือเดินไม่ได้ ให้ตรวจว่ามี
SetNuiFocus(false, false)
และหาก Resource ใช้ SET_NUI_FOCUS_KEEP_INPUT ก็ควรคืน State นั้นด้วย โดย FiveM มี IS_NUI_FOCUSED และ IS_NUI_FOCUS_KEEPING_INPUT สำหรับตรวจ Current State.
ถ้า กด Button แล้ว UI ค้าง ให้ตรวจ NUI Callback เพราะ Cfx.re ระบุว่าต้อง Return ข้อมูลผ่าน cb; ถ้าไม่ตอบ Request จะ Timeout และ Error จะย้อนกลับไปยัง fetch ฝั่ง UI.
ถ้า NUI พังหลัง Restart Resource ให้เพิ่ม Lifecycle Cleanup ผ่าน onClientResourceStop และ Initialization ผ่าน onClientResourceStart เพื่อให้ Focus/UI State กลับสู่สถานะที่ถูกต้องเมื่อ Resource หยุดหรือเริ่มใหม่.
ถ้า NUI หน่วงหรือ FPS ลด ให้ใช้ resmon true ตรวจ CPU/Memory ของ Resource แล้วเปิด NUI DevTools ตรวจ JavaScript/DOM ต่อ เพราะ Resource Monitor ของ FiveM มีไว้ช่วยตรวจ Performance ของ Resources ระหว่าง Gameplay.
แนวทางของ comsiam คือ Debug NUI ตามลำดับ Resource → Page → Message → JavaScript → Callback → Focus → Cleanup อย่าล้าง Cache หรือเปลี่ยน Resource ก่อนรู้ว่า Layer ไหนเสีย เพราะปัญหาอย่าง “เมาส์ติดหน้าจอ” หลายครั้งไม่ได้เกิดจาก NUI ทั้งระบบ แต่เกิดจาก Resource ซ่อน Interface แล้วลืมคืน SET_NUI_FOCUS เพียงจุดเดียว
Comments
Post a Comment