FiveM TriggerClientEvent คืออะไร? ส่ง Event จาก Server ไป Client อย่างไร
FiveM TriggerClientEvent() คือ Function ฝั่ง Server สำหรับส่ง Network Event ไปยัง Client ที่ต้องการ โดยสามารถเลือกส่งให้ผู้เล่นเพียงคนเดียว ผู้เล่นเฉพาะกลุ่ม หรือ Broadcast ไปยัง Client ทุกคนได้
ตัวอย่างพื้นฐานที่สุดคือ
TriggerClientEvent(
'example:hello',
playerId,
'Hello'
)
จากนั้น Client รับด้วย
RegisterNetEvent(
'example:hello',
function(message)
print(message)
end
)
Flow คือ
Server
↓
TriggerClientEvent
↓
Network
↓
Client เป้าหมาย
↓
RegisterNetEvent
↓
Client Logic
TriggerClientEvent() จึงถูกใช้มากในระบบ FiveM เช่น Notification, HUD, Job, Garage, Inventory, Banking, Admin System และการอัปเดต UI หลัง Server ประมวลผลเสร็จ
① TriggerClientEvent คืออะไร
รูปแบบ Syntax ของ Lua คือ
TriggerClientEvent(
eventName,
playerId,
...
)
ประกอบด้วย
eventName
→ ชื่อ Event
playerId
→ Player Source ที่ต้องการส่ง Event ไปให้
...
→ Parameter เพิ่มเติม
ตัวอย่าง
TriggerClientEvent(
'garage:open',
source
)
หมายถึง Server ส่ง Event garage:open ไปยัง Client ของ Player ที่กำหนด
② TriggerClientEvent ใช้ฝั่งไหน
โดยทั่วไปใช้ใน Server Script
เช่น
server.lua
ตัวอย่าง
RegisterCommand(
'welcome',
function(source)
TriggerClientEvent(
'example:welcome',
source
)
end,
false
)
Client รับ
RegisterNetEvent(
'example:welcome',
function()
print('Welcome!')
end
)
จึงเกิดการสื่อสาร
Server
→
Client
③ Client รับ TriggerClientEvent อย่างไร
ใน Lua Client ต้อง Register Network Event
ตัวอย่าง
RegisterNetEvent(
'example:message',
function(message)
print(message)
end
)
Server ส่ง
TriggerClientEvent(
'example:message',
playerId,
'Hello FiveM'
)
Parameter ที่ Server ส่งหลัง playerId จะถูกส่งเข้า Client Handler ตามลำดับ
④ playerId ใน TriggerClientEvent คืออะไร
playerId คือ Server ID หรือ Player Source ของ Client ที่ Server ต้องการส่ง Event ไปให้
ตัวอย่าง
local target = 15
TriggerClientEvent(
'example:test',
target
)
หมายถึงส่ง Event ไปยัง Player Source 15
ไม่ได้หมายถึง
Ped Handle
PlayerPedId
Entity Handle
Steam ID
โดยตรง
แต่เป็น Server-side Player ID ที่ FiveM ใช้สำหรับ Target ของ Event นี้
⑤ ใช้ source เป็น Target ได้ไหม
ได้ และพบได้บ่อยมากใน Server Event
เช่น Client ส่ง Request
TriggerServerEvent(
'shop:request'
)
Server
RegisterNetEvent(
'shop:request',
function()
local src = source
TriggerClientEvent(
'shop:open',
src
)
end
)
Client รับ
RegisterNetEvent(
'shop:open',
function()
print('Opening shop')
end
)
Flow คือ
Player
↓
TriggerServerEvent
↓
Server
↓
source
↓
TriggerClientEvent
↓
Player คนเดิม
⑥ ทำไมมักเก็บ source เป็น local
รูปแบบที่นิยมคือ
local src = source
แล้วใช้
TriggerClientEvent(
'event:name',
src
)
ข้อดีคือ
อ่านง่าย
รู้ชัดว่า Target คือผู้ Trigger
ใช้สะดวกใน Logic ยาว
ลดความสับสนเมื่อมีหลาย Player ID
โดยเฉพาะ Server Event ที่มี Async Logic การเก็บ Source ไว้ชัดเจนตั้งแต่ต้นเป็นนิสัยที่ดี
⑦ ส่ง Event ให้ Client ทุกคนได้ไหม
ได้
ใน Lua สามารถใช้ Target
-1
ตัวอย่าง
TriggerClientEvent(
'server:announcement',
-1,
'Server restart in 10 minutes'
)
จะส่ง Event ไปยัง Client ที่เชื่อมต่ออยู่ทั้งหมด
Client
RegisterNetEvent(
'server:announcement',
function(message)
print(message)
end
)
นี่เรียกว่า Broadcast
⑧ -1 ใน TriggerClientEvent หมายถึงอะไร
จำง่าย ๆ
15
→ ส่ง Player 15
27
→ ส่ง Player 27
-1
→ ส่งทุก Client
ดังนั้น
TriggerClientEvent(
'example:update',
-1
)
หมายถึง Broadcast Event
ควรใช้ -1 เมื่อทุก Player ต้องได้รับข้อมูลจริง ๆ เท่านั้น
⑨ ควร Broadcast ทุก Event หรือไม่
ไม่ควร
ตัวอย่างยอดเงินของ Player 10 ควรส่ง
TriggerClientEvent(
'bank:updateBalance',
10,
balance
)
ไม่ควร
TriggerClientEvent(
'bank:updateBalance',
-1,
balance
)
เพราะ Player คนอื่นไม่จำเป็นต้องได้รับข้อมูลนี้
หลักคือ
ส่งให้เฉพาะ Client ที่ต้องใช้
ช่วยลดทั้ง Network Traffic และการเปิดเผยข้อมูลโดยไม่จำเป็น
⑩ TriggerClientEvent ส่ง String ได้ไหม
ได้
Server
TriggerClientEvent(
'notify:show',
source,
'Vehicle stored'
)
Client
RegisterNetEvent(
'notify:show',
function(message)
print(message)
end
)
Use Case นี้พบได้บ่อยกับ Notification
⑪ ส่ง Number ได้ไหม
ได้
TriggerClientEvent(
'player:updateMoney',
source,
5000
)
Client
RegisterNetEvent(
'player:updateMoney',
function(money)
print(
'Money:',
money
)
end
)
Client สามารถใช้ค่านี้แสดง HUD
แต่ Server ควรยังเป็น Authority ของยอดเงินจริง
⑫ ส่งหลาย Parameter ได้ไหม
ได้
Server
TriggerClientEvent(
'player:update',
source,
'John',
5000,
'police'
)
Client
RegisterNetEvent(
'player:update',
function(name, money, job)
print(name)
print(money)
print(job)
end
)
Parameter จะถูกส่งตามลำดับ
ดังนั้น Event Contract ควรกำหนดให้ชัด
⑬ ส่ง Table ได้ไหม
ได้สำหรับ Data Type ที่ FiveM Runtime สามารถ Serialize ได้
ตัวอย่าง
local data = {
name = 'John',
job = 'police',
money = 5000
}
TriggerClientEvent(
'player:data',
source,
data
)
Client
RegisterNetEvent(
'player:data',
function(data)
print(data.name)
print(data.job)
end
)
แต่ไม่ควรส่ง Table ใหญ่เกินจำเป็น
⑭ ทำไม Payload ควรเล็ก
Network Event ต้องผ่านขั้นตอนประมาณ
Server Data
↓
Serialize
↓
Network
↓
Deserialize
↓
Client
ดังนั้นการส่งข้อมูลขนาดใหญ่หรือส่งซ้ำถี่มากมีต้นทุน
ถ้า Client ต้องการเพียง
money
job
ไม่จำเป็นต้องส่ง Player Object ทั้งก้อน
⑮ TriggerClientEvent ต่างจาก TriggerServerEvent อย่างไร
ต่างกันที่ทิศทาง
TriggerServerEvent
Client
↓
Server
ส่วน
TriggerClientEvent
Server
↓
Client
ตัวอย่าง Full Flow
Client
↓
TriggerServerEvent
↓
Server
↓
ตรวจข้อมูล
↓
TriggerClientEvent
↓
Client
นี่เป็นหนึ่งใน Pattern ที่ใช้มากที่สุดใน FiveM
⑯ TriggerClientEvent ต่างจาก TriggerEvent อย่างไร
TriggerEvent() ใช้ Event ภายใน Context เดียวกัน
เช่น
Client → Client
หรือ
Server → Server
ส่วน TriggerClientEvent() เป็น Network Event
Server → Client
ดังนั้น Server เขียน
TriggerEvent(
'example:test'
)
ไม่ได้ทำให้ Client รับ Event นั้นโดยอัตโนมัติ
⑰ ตัวอย่าง Request → Response
Client
RegisterCommand(
'getjob',
function()
TriggerServerEvent(
'player:requestJob'
)
end,
false
)
Server
RegisterNetEvent(
'player:requestJob',
function()
local src = source
local job = 'police'
TriggerClientEvent(
'player:receiveJob',
src,
job
)
end
)
Client
RegisterNetEvent(
'player:receiveJob',
function(job)
print(
'Your job:',
job
)
end
)
Flow คือ
Client Request
↓
Server
↓
Server Data
↓
Client Response
⑱ TriggerClientEvent ใช้ทำ Notification ได้ไหม
ได้ และเหมาะมาก
Server
TriggerClientEvent(
'notify:show',
source,
'ซื้อสินค้าสำเร็จ'
)
Client
RegisterNetEvent(
'notify:show',
function(message)
-- notification logic
end
)
ข้อดีคือ Server ตัดสิน Transaction ก่อน แล้ว Client แสดง Result
⑲ ตัวอย่าง Shop System
Client ส่ง
TriggerServerEvent(
'shop:buy',
'water',
2
)
Server ตรวจ
Item
Amount
Price
Money
Inventory
Position
ถ้าสำเร็จ
TriggerClientEvent(
'shop:result',
source,
true,
'ซื้อสินค้าสำเร็จ'
)
ถ้าไม่สำเร็จ
TriggerClientEvent(
'shop:result',
source,
false,
'เงินไม่เพียงพอ'
)
Client มีหน้าที่แสดงผล
Server มีหน้าที่ตัดสิน Transaction
⑳ Client ควรเชื่อข้อมูลจาก TriggerClientEvent ไหม
ต้องแยกตาม Use Case
ถ้า Server ส่ง
ยอดเงิน
Job
Permission Result
เพื่อแสดง UI Client สามารถใช้ข้อมูลนั้นกับ Presentation ได้
แต่ Client Copy ไม่ควรถูกเปลี่ยนให้กลายเป็น Authority ของระบบในอนาคต
เช่น
Server → Client
money = 5000
จากนั้น Client เปลี่ยน Local Variable เป็น
99999999
ไม่ควรทำให้ยอดเงินจริงใน Server เปลี่ยนตาม
Authority ยังอยู่ Server
㉑ TriggerClientEvent ใช้เปิด NUI ได้ไหม
ได้
Server
TriggerClientEvent(
'garage:openUi',
source,
vehicles
)
Client
RegisterNetEvent(
'garage:openUi',
function(vehicles)
SetNuiFocus(
true,
true
)
SendNUIMessage({
action = 'open',
vehicles = vehicles
})
end
)
Flow คือ
Server Data
↓
TriggerClientEvent
↓
Client
↓
SendNUIMessage
↓
NUI
ใช้ได้กับ Inventory, Garage, Phone, Banking และ Menu ต่าง ๆ
㉒ แต่ควรส่ง Database ทั้งหมดให้ NUI ไหม
ไม่ควร
Server ควรส่งเฉพาะข้อมูลที่ UI ต้องใช้
เช่น Garage อาจต้องการ
plate
model
label
stored
ไม่จำเป็นต้องส่ง
Internal Database Fields
Secret Metadata
Security Data
Data ของผู้เล่นอื่นทั้งหมด
หลักการคือ
Minimum Necessary Data
㉓ TriggerClientEvent ใช้กับ HUD ได้ไหม
ได้
ตัวอย่างหลังเงินเปลี่ยน
TriggerClientEvent(
'hud:updateMoney',
source,
newBalance
)
Client
RegisterNetEvent(
'hud:updateMoney',
function(balance)
SendNUIMessage({
action = 'money',
balance = balance
})
end
)
แต่ถ้าข้อมูลเปลี่ยนถี่มาก ควรออกแบบ Update Frequency ให้เหมาะสม
㉔ TriggerClientEvent ทุก Tick ดีไหม
โดยทั่วไปไม่ดี
ตัวอย่าง
CreateThread(function()
while true do
Wait(0)
TriggerClientEvent(
'player:update',
-1,
data
)
end
end)
นี่อาจ Broadcast Data ทุก Server Tick อย่างมหาศาล
ควรเปลี่ยนเป็น
ข้อมูลเปลี่ยน
↓
Trigger Event
หรือ Update เป็นช่วงเวลาที่เหมาะสม
㉕ Event-driven Update ดีกว่าอย่างไร
สมมติ Player Job เปลี่ยนเพียงบางครั้ง
ไม่จำเป็นต้องส่ง
job = police
ทุกวินาที
ส่งเฉพาะเมื่อ Job เปลี่ยน
TriggerClientEvent(
'player:jobChanged',
source,
newJob
)
ช่วยลด Network Traffic และ Client Processing
㉖ TriggerClientEvent ส่งให้หลาย Player เฉพาะกลุ่มได้ไหม
สามารถ Loop Target ที่ต้องการได้
ตัวอย่าง Concept
for _, playerId in ipairs(targetPlayers) do
TriggerClientEvent(
'police:update',
playerId,
data
)
end
เหมาะเมื่อ Event ต้องส่งเฉพาะกลุ่ม เช่น
Police
EMS
Party Members
Mission Players
Instance Players
ดีกว่า Broadcast แล้วให้ Client ทุกคนทิ้งข้อมูลภายหลังในหลายกรณี
㉗ ส่งเฉพาะ Police ดีกว่า -1 อย่างไร
สมมติ Server มีผู้เล่น 200 คน แต่ตำรวจมี 10 คน
ถ้าข้อมูลใช้เฉพาะตำรวจ
การส่ง
200 Clients
อาจไม่จำเป็น
สามารถส่งเฉพาะ
10 Police Clients
ช่วยลด Network และ Processing
แต่ต้องตรวจ Role/Job จาก Server-side Data ก่อนเลือก Target
㉘ TriggerClientEvent กับ Routing Bucket
ถ้าระบบมี Instance หรือ Routing Bucket อาจต้องส่ง Event เฉพาะ Player ที่เกี่ยวข้อง
เช่น Mission ใน Bucket 50
ไม่จำเป็นต้อง Broadcast Mission Data ให้ผู้เล่นใน Bucket อื่นทั้งหมด
Developer สามารถจัด Target List ตาม State ของ Server แล้ว Trigger เฉพาะผู้เล่นที่ต้องใช้
㉙ TriggerClientEvent กับ OneSync
OneSync จัดการ Player/Entity Networking หลายส่วน
ส่วน TriggerClientEvent() เป็น Event Transport สำหรับ Server → Client
ทั้งสองระบบทำงานร่วมกันได้ แต่ไม่ใช่สิ่งเดียวกัน
อย่าพยายามใช้ Event เพื่อทำสิ่งที่ Entity Replication หรือ State Bags จัดการได้เหมาะกว่า
㉚ TriggerClientEvent กับ State Bags ต่างกันอย่างไร
Event เหมาะกับ “เหตุการณ์”
เช่น
เปิด Notification
เล่น Animation
Transaction สำเร็จ
State Bag เหมาะกับ “State”
เช่น
locked = true
duty = true
fuel = 80
ตัวอย่าง
Server
↓
เปลี่ยน State
↓
State Replication
อาจเหมาะกว่าการ Trigger Event ซ้ำเพื่อบอก State ปัจจุบันทุกครั้ง
เลือกตาม Use Case
㉛ TriggerClientEvent ใช้กับ Vehicle ได้ไหม
ได้
ตัวอย่าง Server ตรวจ Permission แล้วสั่ง Client ทำ Action
TriggerClientEvent(
'vehicle:action',
source,
networkId
)
Client
RegisterNetEvent(
'vehicle:action',
function(networkId)
-- client vehicle logic
end
)
แต่ Entity ที่ส่งข้าม Network ควรใช้ Identifier ที่เหมาะสม เช่น Network ID ตาม Architecture ไม่ใช่สมมติว่า Local Entity Handle ของ Client หนึ่งใช้ได้กับ Client อื่นเสมอ
㉜ TriggerClientEvent ใช้กับ Animation ได้ไหม
ได้
Server อาจตรวจ Permission หรือ State แล้วส่ง
TriggerClientEvent(
'job:playAnimation',
source,
'clipboard'
)
Client เป็นผู้เล่น Animation เพราะ Animation/Game Presentation ส่วนใหญ่อยู่ Client-side
นี่เป็นตัวอย่างการแบ่ง Responsibility ที่เหมาะสม
㉝ TriggerClientEvent ใช้กับ Teleport ได้ไหม
ได้ในระบบที่ออกแบบให้ Client เป็นผู้ทำ Teleport หลัง Server อนุมัติ
เช่น Admin Teleport
Client Request
↓
Server ตรวจ Admin
↓
TriggerClientEvent
↓
Client Teleport
Server ไม่ควรเชื่อ Client ว่าเป็น Admin เพียงเพราะ Client ส่ง Boolean true
Permission ต้องตรวจ Server-side ก่อน
㉞ TriggerClientEvent ใช้กับ ESX ได้ไหม
ได้
ESX Resource สามารถใช้ FiveM Network Event API ปกติ
ตัวอย่าง
ESX Server Logic
↓
TriggerClientEvent
↓
ESX Client Resource
เช่น
Notification
Job Update
UI Refresh
Gameplay Result
Framework ไม่ได้เปลี่ยนหลักการของ TriggerClientEvent()
㉟ TriggerClientEvent ใช้กับ QBCore ได้ไหม
ได้เช่นกัน
ตัวอย่าง
QBCore Server
↓
ตรวจ Player Data
↓
TriggerClientEvent
↓
QBCore Client
Resource QBCore จำนวนมากใช้ Server → Client Event ในการ Update State หรือเรียก Client Action
แต่ควรตรวจว่า Framework มี Event/API มาตรฐานสำหรับสิ่งนั้นอยู่แล้วหรือไม่ก่อนสร้างระบบซ้ำ
㊱ TriggerClientEvent ใช้กับ Qbox ได้ไหม
ได้
FiveM Event Runtime ยังเหมือนเดิมไม่ว่า Framework จะเป็น
ESX
QBCore
Qbox
Standalone
สิ่งที่ต่างคือ Framework API รอบ ๆ Event
ความเข้าใจ FiveM Core จึงช่วยให้ย้าย Framework และ Debug Script ได้ง่ายขึ้น
㊲ TriggerClientEvent กับ Callback
หาก Client ส่ง Request แล้วต้องได้ Response สามารถใช้
TriggerServerEvent
+
TriggerClientEvent
สร้าง Flow เองได้
เช่น
requestVehicles
↓
Server
↓
vehiclesResult
แต่ Framework หรือ Library หลายตัวมี Callback System อยู่แล้ว
ถ้าเป็น Request/Response โดยตรง Callback อาจทำให้ Code อ่านง่ายกว่า
㊳ ตัวอย่าง Event Response
Client
TriggerServerEvent(
'garage:requestVehicles'
)
Server
RegisterNetEvent(
'garage:requestVehicles',
function()
local src = source
local vehicles = {
'sultan',
'adder'
}
TriggerClientEvent(
'garage:receiveVehicles',
src,
vehicles
)
end
)
Client
RegisterNetEvent(
'garage:receiveVehicles',
function(vehicles)
-- update UI
end
)
ใช้ได้ แต่เมื่อ Request/Response ซับซ้อนมาก Callback อาจเหมาะกว่า
㊴ TriggerClientEvent กับ Export ต่างกันอย่างไร
TriggerClientEvent() ข้าม Network
Server
→
Client
ส่วน Export ใช้ให้ Resource เรียก Function ของ Resource อื่นใน Runtime Context ที่รองรับ
ดังนั้น Export ไม่ใช่ตัวแทนของ Server → Client Event ในทุกกรณี
ต้องดูว่า Code อยู่ฝั่งไหน
㊵ Client Event ต้อง RegisterNetEvent หรือไม่
ถ้า Event ถูกส่งจาก Server ผ่าน Network และ Client Lua ต้องรับ Event นั้น ควร Register เป็น Network Event
ตัวอย่าง
RegisterNetEvent(
'garage:open',
function()
-- client logic
end
)
หรือ
RegisterNetEvent(
'garage:open'
)
AddEventHandler(
'garage:open',
function()
-- client logic
end
)
Cfx.re ระบุว่า Lua/JavaScript Event ที่ต้องใช้ข้าม Network ต้อง Register ให้เป็น Network Event ก่อน
㊶ อย่า Register Event เป็น Network ถ้าไม่จำเป็น
ถ้า Event ใช้เฉพาะ
Client → Client
สามารถใช้ Local Event ด้วย AddEventHandler()
ไม่จำเป็นต้องเปิดเป็น Network Event
หลักนี้ช่วยแยก Event Context ให้ชัดเจนและลด Attack Surface ที่ไม่จำเป็น
㊷ TriggerClientEvent มี Security Risk ไหม
มีประเด็นที่ต้องคิด แม้ทิศทางจะเป็น Server → Client
สิ่งสำคัญคือ
Client ได้รับข้อมูลแล้ว
≠
ข้อมูลนั้นกลายเป็น Secret
Client-side Code และ Data ไม่ควรถูกถือว่าเป็น Security Boundary
ดังนั้น Server ไม่ควรส่ง
Password
Secret API Key
Private Token
Internal Security Data
ไปยัง Client โดยไม่จำเป็น
㊸ อย่าส่ง Secret ผ่าน TriggerClientEvent
ตัวอย่างที่ไม่ควรทำ
TriggerClientEvent(
'config:secret',
source,
databasePassword
)
เมื่อข้อมูลถูกส่งไป Client แล้ว ไม่ควรถือว่าเป็น Server-only Secret อีกต่อไป
ข้อมูลลับควรอยู่ Server Context
Client ควรได้รับเฉพาะผลลัพธ์ที่จำเป็น
㊹ ส่ง Permission ไป Client ได้ไหม
สามารถส่งเพื่อแสดง UI ได้
เช่น
TriggerClientEvent(
'admin:setUiAccess',
source,
true
)
เพื่อให้ Client เปิด Admin Menu
แต่เมื่อ Player กด Admin Action จริง Server ต้องตรวจ Permission อีกครั้ง
อย่าออกแบบ
Server บอก Client ครั้งหนึ่งว่า isAdmin=true
↓
จากนั้นเชื่อทุก Action จาก Client ตลอดไป
Server-side Permission Check ยังต้องอยู่ใน Action สำคัญ
㊺ ส่ง Money ไป Client ได้ไหม
ได้เพื่อแสดง HUD
TriggerClientEvent(
'hud:setMoney',
source,
balance
)
แต่ Client Money เป็น Display Copy
ยอดเงินจริงควรอยู่ Server-side
ถ้า Client เปลี่ยน HUD เป็น
999,999,999
ไม่ควรทำให้ Database หรือ Server Money เปลี่ยน
㊻ TriggerClientEvent ส่งข้อมูลขนาดใหญ่ได้ไหม
ทำได้ทางเทคนิค แต่สำหรับ Payload ขนาดใหญ่ FiveM มี
TriggerLatentClientEvent
ซึ่งเหมาะกว่า เพราะ Latent Event สามารถจำกัดอัตราการส่งข้อมูลและช่วยหลีกเลี่ยงการ Block Network Channel ด้วย Payload ก้อนใหญ่
Cfx.re ระบุว่าหลักเดียวกับฝั่ง Client → Server ใช้กับ Server → Client เช่นกัน
㊼ TriggerLatentClientEvent คืออะไร
ใช้สำหรับ Server → Client เมื่อจำเป็นต้องส่งข้อมูลขนาดใหญ่
แนวคิดคือ
ข้อมูลเล็ก
→ TriggerClientEvent
ข้อมูลใหญ่หลาย KB+
→ พิจารณา TriggerLatentClientEvent
Latent Event มีค่า Bandwidth
bps
เพื่อกำหนดอัตราการส่ง
ไม่ควรเปลี่ยน Event ทุกตัวเป็น Latent Event
ใช้เมื่อมี Payload ใหญ่จริง
㊽ ทำไม Payload ใหญ่จึงอันตรายต่อ Network
Cfx.re อธิบายว่า Event ปกติที่ส่ง Data ก้อนใหญ่อาจ Block Network Channel ของ Client และหาก Block นานเกินไปอาจเกี่ยวข้องกับ Timeout ได้
Latent Event จึงถูกออกแบบมาเพื่อทยอยส่ง Data ตาม Bandwidth ที่กำหนดแทน
อย่างไรก็ตาม วิธีที่ดีที่สุดก่อนอื่นคือถามว่า
จำเป็นต้องส่งข้อมูลก้อนใหญ่นี้จริงหรือไม่?
㊾ ก่อนใช้ Latent Event ลองลด Payload ก่อน
ตัวอย่าง Server มี Player Data 100 Fields
แต่ UI ใช้เพียง
name
job
money
ไม่ควรส่งทั้ง Object ก่อน แล้วค่อยแก้ด้วย Latent Event
ควรเริ่มจาก
ลด Payload
↓
ส่งเฉพาะข้อมูลจำเป็น
↓
ถ้ายังใหญ่จริง
↓
พิจารณา Latent Event
นี่เป็น Architecture ที่ดีกว่า
㊿ TriggerClientEvent ไม่ทำงาน ตรวจอะไรบ้าง
ตรวจตามลำดับ
① server.lua ถูกโหลดหรือไม่
② Resource Start แล้วหรือไม่
③ Event Name ตรงไหม
④ Target Player ถูกไหม
⑤ Client RegisterNetEvent แล้วหรือไม่
⑥ client.lua ถูกโหลดหรือไม่
⑦ มี Server Error หรือไม่
⑧ มี F8 Error หรือไม่
⑨ Parameter ถูกต้องหรือไม่
อย่าแก้หลายจุดพร้อมกันโดยยังไม่รู้ว่า Event หายตรงไหน
51 วิธี Debug TriggerClientEvent
Server
print(
'sending event to:',
source
)
TriggerClientEvent(
'example:test',
source,
'Hello'
)
Client
RegisterNetEvent(
'example:test',
function(message)
print(
'event received:',
message
)
end
)
ถ้า Server Print ทำงานแต่ Client Print ไม่ทำ
ให้ตรวจ
Target
Event Name
RegisterNetEvent
Client Resource
F8 Error
52 Target ผิดทำให้ Event ไม่ทำงานได้ไหม
ได้
ตัวอย่าง
TriggerClientEvent(
'example:test',
99999
)
ถ้าไม่มี Player Source นั้น Event ก็ไม่ไปถึง Client ที่คาดไว้
ดังนั้นควรตรวจ Player State หรือ Target ที่ใช้ตาม Logic
โดยเฉพาะระบบที่เก็บ Player ID ไว้เป็นเวลานาน
53 Player Source ใช้ถาวรได้ไหม
ไม่ควรถือ Player Source เป็น Persistent Identity
Source ใช้ระบุ Connection ปัจจุบัน
หาก Player Disconnect แล้วกลับเข้าใหม่ Source อาจเปลี่ยนได้
ถ้าต้องการ Persistent Identity ควรใช้ Identifier หรือ Framework Character/User ID ที่เหมาะสม
แต่เวลาส่ง TriggerClientEvent() ไปยัง Connection ปัจจุบัน ต้องใช้ Player Source ที่ถูกต้อง
54 Event Name ควรตั้งอย่างไร
ควรมี Prefix ตาม Resource
เช่น
comsiam_garage:open
comsiam_garage:update
comsiam_garage:notify
ดีกว่า
open
update
notify
เพราะ
Search ง่าย
ลดชื่อชน
Debug ง่าย
อ่าน Log รู้ Feature
แต่ชื่อ Event ที่ซับซ้อนไม่ใช่ Security Mechanism
55 Event Contract สำหรับ TriggerClientEvent
Project ใหญ่ควร Document เช่น
Event:
garage:open
Direction:
Server → Client
Target:
Player Source
Arguments:
vehicles: table
garageId: string
Purpose:
เปิด Garage UI หลัง Server ตรวจสิทธิ์แล้ว
ช่วยให้ Developer รู้ว่า
ใคร Trigger
ใครรับ
Data คืออะไร
Event ใช้เมื่อไร
56 อย่าใช้ Generic Client Event ใหญ่เกินไป
ตัวอย่าง
client:execute
แล้วส่ง
action
data
permission
command
ทุกอย่างผ่าน Event เดียว
จะทำให้
Debug ยาก
Contract ไม่ชัด
Security Review ยาก
Maintain ยาก
Event ควรสื่อความหมายของ Feature เช่น
garage:open
garage:notify
job:updateRoute
bank:updateBalance
57 TriggerClientEvent และ Performance ต้องจำอะไร
จำหลักสามข้อ
ส่งเฉพาะ Target ที่ต้องใช้
ส่งเฉพาะข้อมูลที่จำเป็น
ส่งเฉพาะเมื่อข้อมูลเปลี่ยน
หลีกเลี่ยง
Broadcast ทุกคน
+
Payload ใหญ่
+
Trigger ทุก Tick
เพราะเป็นสูตรสร้าง Network Load ที่ไม่จำเป็น
58 TriggerClientEvent และ Security ต้องจำอะไร
แม้ Server จะเป็นผู้ส่ง แต่ Client ยังไม่ใช่ Trusted Storage
ดังนั้น
Server Secret
→ อย่าส่ง Client
Authority State
→ เก็บ Server
Display State
→ ส่ง Client ได้ตามจำเป็น
และถ้า Client นำข้อมูลนั้นกลับมาส่งผ่าน TriggerServerEvent() Server ต้อง Validate ใหม่
59 Checklist ก่อนใช้ TriggerClientEvent
ก่อนสร้าง Event Server → Client ให้ถาม
① Client คนไหนต้องได้รับ?
② จำเป็นต้อง Broadcast -1 หรือไม่?
③ Payload มีอะไร?
④ ส่งข้อมูลเยอะเกินไปหรือไม่?
⑤ มี Secret อยู่ใน Payload หรือไม่?
⑥ Event Trigger บ่อยแค่ไหน?
⑦ ใช้ State Bag เหมาะกว่าหรือไม่?
⑧ Payload ใหญ่จนควรใช้ Latent Event หรือไม่?
⑨ Client RegisterNetEvent แล้วหรือยัง?
⑩ Event Name มี Prefix ชัดเจนไหม?
ถ้าตอบได้ครบ จะลดปัญหาทั้ง Network และ Architecture ได้มาก
60 ตัวอย่าง TriggerClientEvent สำหรับมือใหม่
สร้าง Command ฝั่ง Server
server.lua
RegisterCommand(
'welcome',
function(source)
if source <= 0 then
return
end
TriggerClientEvent(
'training:welcome',
source,
'Welcome to FiveM!'
)
end,
false
)
client.lua
RegisterNetEvent(
'training:welcome',
function(message)
print(message)
end
)
Flow คือ
Player ใช้ Command
↓
Server
↓
รู้ source
↓
TriggerClientEvent
↓
Client คนเดียว
↓
RegisterNetEvent
↓
แสดงข้อความ
จากตัวอย่างนี้สามารถต่อยอดไป Notification, NUI หรือ Gameplay Action ได้
คำถามที่พบบ่อยเกี่ยวกับ FiveM TriggerClientEvent
TriggerClientEvent คืออะไร
คือ Function ฝั่ง Server สำหรับ Trigger Network Event ไปยัง Client ที่ระบุ
TriggerClientEvent ใช้ฝั่ง Client ได้ไหม
สำหรับ Lua รูปแบบ Server → Client ใช้ TriggerClientEvent() ฝั่ง Server ส่วน Client → Server ใช้ TriggerServerEvent()
ส่งหา Player คนเดียวอย่างไร
ระบุ Player Source เป็น Target
TriggerClientEvent(
'event:name',
playerId
)
ส่งให้ทุก Player อย่างไร
ใช้ Target
-1
เช่น
TriggerClientEvent(
'event:name',
-1
)
TriggerClientEvent ส่ง Parameter ได้ไหม
ได้ สามารถส่งข้อมูลเพิ่มเติมหลัง Player Target ได้
ส่ง Table ได้ไหม
ได้กับข้อมูลที่ Runtime รองรับ แต่ควรส่งเฉพาะสิ่งที่ Client ต้องใช้
Client รับ Event อย่างไร
ใน Lua ใช้ RegisterNetEvent() เพื่อ Register Network Event แล้ว Handle Callback
TriggerClientEvent กับ TriggerServerEvent ต่างกันอย่างไร
TriggerClientEvent() คือ Server → Client ส่วน TriggerServerEvent() คือ Client → Server
TriggerClientEvent กับ TriggerEvent ต่างกันอย่างไร
TriggerEvent() ใช้ Event ใน Context เดียวกัน ส่วน TriggerClientEvent() ส่งข้าม Network จาก Server ไป Client
-1 หมายถึงอะไร
หมายถึงส่ง Event ไปยัง Client ทุกคนที่เชื่อมต่ออยู่
ควรใช้ -1 ตลอดไหม
ไม่ควร ใช้เฉพาะเมื่อทุก Client ต้องได้รับข้อมูลจริง ๆ
Payload ใหญ่มากควรทำอย่างไร
พิจารณา TriggerLatentClientEvent() และลดข้อมูลให้เหลือเฉพาะสิ่งจำเป็นก่อน
TriggerClientEvent ทำ Server Lag ได้ไหม
สามารถเพิ่ม Network และ Processing Load ได้หาก Broadcast บ่อย ส่ง Payload ใหญ่ หรือ Trigger ถี่มาก
สรุป FiveM TriggerClientEvent คืออะไร
FiveM TriggerClientEvent() คือ Function ที่ Server ใช้ส่ง Network Event ไปยัง Client
รูปแบบพื้นฐานคือ
TriggerClientEvent(
'eventName',
playerId,
parameter1,
parameter2
)
Client รับด้วย
RegisterNetEvent(
'eventName',
function(parameter1, parameter2)
-- client logic
end
)
สิ่งที่ต้องจำที่สุดคือ
Client → Server
= TriggerServerEvent
Server → Client
= TriggerClientEvent
Client → Client
หรือ
Server → Server
= TriggerEvent
ถ้าต้องส่งให้ทุก Client ใช้
-1
แต่ไม่ควร Broadcast โดยไม่มีเหตุผล เพราะการส่งเฉพาะ Player ที่ต้องใช้ช่วยลด Network Traffic ได้มากกว่า
สำหรับ Payload ใหญ่ FiveM มี TriggerLatentClientEvent() เพื่อส่งข้อมูลแบบจำกัด Bandwidth แทนการ Block Network Channel ด้วยข้อมูลก้อนใหญ่
สำหรับผู้ที่เรียน FiveM Developer กับ comsiam สิ่งสำคัญคืออย่ามอง TriggerClientEvent() เพียงว่าเป็น Function สำหรับ “สั่ง Client” แต่ให้คิดถึง Target, Payload, Frequency และ Client/Server Authority ทุกครั้ง
เมื่อเข้าใจทั้ง TriggerServerEvent() และ TriggerClientEvent() แล้ว จะเห็นภาพ Network Flow ของ FiveM ชัดเจนขึ้นมาก และบทความต่อไปของ comsiam จะเข้าสู่ RegisterNetEvent คืออะไร ซึ่งเป็นฝั่งรับ Network Event ที่ต้องใช้คู่กับระบบเหล่านี้
Comments
Post a Comment