FiveM TriggerServerEvent คืออะไร
FiveM TriggerServerEvent() คือ Function ที่ใช้ส่ง Network Event จาก Client ไปยัง Server พร้อมส่งข้อมูลหรือ Parameter ที่ Server ต้องใช้ประมวลผลได้
ตัวอย่างง่ายที่สุดคือ Client เรียก
TriggerServerEvent('example:hello')
แล้วฝั่ง Server รับด้วย
RegisterNetEvent('example:hello', function()
local src = source
print('Event from player:', src)
end)
Flow คือ
Client
↓
TriggerServerEvent
↓
Network
↓
FXServer
↓
RegisterNetEvent
↓
Server Logic
TriggerServerEvent() เป็นหนึ่งใน Function ที่ FiveM Developer ใช้บ่อยที่สุด เพราะระบบอย่างร้านค้า Garage, Job, Inventory, Banking และ Admin มักต้องส่ง Request จาก Client ไปให้ Server ตรวจสอบ
แต่สิ่งสำคัญที่สุดคือ Server ห้ามเชื่อข้อมูลที่ Client ส่งเข้ามาทันที โดยเฉพาะ Money, Item, Reward, Permission และข้อมูลที่มีผลต่อ Economy ของ Server
① TriggerServerEvent ใช้ทำอะไร
TriggerServerEvent() มีหน้าที่ส่ง Event จาก
Client
→
Server
ตัวอย่าง Use Case เช่น
ซื้อสินค้า
เก็บรถเข้า Garage
ขอข้อมูล Character
แจ้งว่าผู้เล่นกดทำงาน
ขอรับ Reward
ส่ง Action จาก NUI
ขอใช้ Admin Feature
ทำ Banking Transaction
Client ทำหน้าที่ Request
Server ทำหน้าที่ Validate และตัดสินผล
② Syntax ของ TriggerServerEvent
รูปแบบพื้นฐานคือ
TriggerServerEvent(
'eventName'
)
สามารถส่ง Parameter เพิ่มได้
TriggerServerEvent(
'shop:buy',
'water',
2
)
ในตัวอย่างนี้ส่ง
eventName = shop:buy
itemName = water
amount = 2
ไปยัง Server
③ Server รับ TriggerServerEvent อย่างไร
Server ต้อง Register Network Event
ตัวอย่าง
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
local src = source
print(
src,
itemName,
amount
)
end
)
เมื่อ Client Trigger
TriggerServerEvent(
'shop:buy',
'water',
2
)
Server Handler จะทำงาน
④ source คืออะไร
ใน Server Event Handler จะมีค่าพิเศษ
source
ใช้ระบุ Player Source ที่ส่ง Event เข้ามา
ตัวอย่าง
RegisterNetEvent(
'example:test',
function()
local src = source
print('Player:', src)
end
)
ดังนั้น Server ไม่จำเป็นต้องให้ Client ส่ง Player ID ของตัวเองมาเพื่อบอกว่าใครเป็นคนเรียก Event
Server สามารถใช้ source จาก Event Context ได้
⑤ อย่าให้ Client ส่ง source เองโดยไม่จำเป็น
ตัวอย่างที่ไม่จำเป็น
TriggerServerEvent(
'example:test',
GetPlayerServerId(
PlayerId()
)
)
แล้ว Server รับ
RegisterNetEvent(
'example:test',
function(playerId)
-- ใช้ playerId จาก client
end
)
สำหรับการระบุผู้ Trigger Event โดยทั่วไป Server มี
source
อยู่แล้ว
จึงควรใช้
local src = source
แทน
โดยเฉพาะระบบ Security-sensitive
⑥ ทำไมควรเก็บ source เป็น local
รูปแบบที่พบได้บ่อยคือ
RegisterNetEvent(
'example:test',
function()
local src = source
-- logic
end
)
แทนการเรียก source ซ้ำไปมาใน Function ยาว ๆ
ช่วยให้
Code อ่านง่าย
รู้ชัดว่าผู้เล่นต้นทางคือใคร
ใช้งานสะดวกเมื่อมี Async Logic
ลดความสับสนใน Callback ที่ซับซ้อน
ถ้า Handler มีการรอหรือเรียก Async Function ควรเก็บ Source ที่เกี่ยวข้องไว้ตั้งแต่ต้น
⑦ TriggerServerEvent ต่างจาก TriggerEvent อย่างไร
จำง่าย ๆ ว่า
TriggerEvent
→ Event ฝั่งเดิม
TriggerServerEvent
→ Client ส่งไป Server
ตัวอย่าง
TriggerEvent('menu:open')
ใน Client จะ Trigger Local Client Event
แต่
TriggerServerEvent(
'garage:request'
)
จะส่ง Network Event ไป FXServer
สอง Function นี้จึงใช้แทนกันไม่ได้
⑧ TriggerServerEvent ต่างจาก TriggerClientEvent อย่างไร
ทิศทางตรงข้ามกัน
TriggerServerEvent
Client → Server
TriggerClientEvent
Server → Client
ตัวอย่าง Client
TriggerServerEvent(
'example:request'
)
Server ประมวลผลแล้วอาจตอบ
TriggerClientEvent(
'example:result',
source
)
เกิดเป็น Flow
Client
↓
Request
↓
Server
↓
Process
↓
Client
⑨ RegisterNetEvent สำคัญอย่างไร
ถ้า Lua Event ต้องรับข้อมูลข้าม Network ต้อง Register เป็น Network Event
ตัวอย่าง Server
RegisterNetEvent(
'garage:store',
function()
-- server logic
end
)
อีกรูปแบบคือ
RegisterNetEvent(
'garage:store'
)
AddEventHandler(
'garage:store',
function()
-- server logic
end
)
แต่รูปแบบ Callback ใน RegisterNetEvent() โดยตรงมักกระชับกว่า
⑩ TriggerServerEvent ส่ง String ได้ไหม
ได้
Client
TriggerServerEvent(
'example:name',
'John'
)
Server
RegisterNetEvent(
'example:name',
function(name)
print(name)
end
)
แต่ Server ยังควรตรวจ Type หากข้อมูลมีผลต่อระบบ
⑪ TriggerServerEvent ส่ง Number ได้ไหม
ได้
TriggerServerEvent(
'shop:buy',
'water',
5
)
Server
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
print(itemName)
print(amount)
end
)
อย่างไรก็ตาม Client สามารถพยายามส่ง
amount = -100
amount = 999999999
ได้
Server จึงต้อง Validate Range
⑫ TriggerServerEvent ส่งหลาย Parameter ได้ไหม
ได้
ตัวอย่าง
TriggerServerEvent(
'garage:store',
plate,
garageId,
vehicleType
)
Server
RegisterNetEvent(
'garage:store',
function(plate, garageId, vehicleType)
local src = source
-- validation
end
)
ควรตั้งชื่อ Parameter ให้มีความหมาย
หลีกเลี่ยง
function(a, b, c)
เมื่อ Project เริ่มใหญ่
⑬ TriggerServerEvent ส่ง Table ได้ไหม
ได้สำหรับข้อมูลที่ระบบ Serialization รองรับ
ตัวอย่าง
local data = {
item = 'water',
amount = 2
}
TriggerServerEvent(
'shop:buy',
data
)
Server
RegisterNetEvent(
'shop:buy',
function(data)
-- validate data
end
)
แต่ไม่ควรส่ง Table ใหญ่ทั้งก้อนหาก Server ต้องการข้อมูลเพียง 2–3 ค่า
⑭ ทำไมควรส่งข้อมูลให้น้อยที่สุด
ข้อมูลของ Event ต้องถูก Serialize ก่อนส่งผ่าน Network และ Decode อีกฝั่งหนึ่ง
ดังนั้น Event ควรส่งเพียงข้อมูลที่จำเป็น
ไม่ควรทำ
Player Data ทั้งหมด
Inventory ทั้งหมด
Vehicle Config ทั้งหมด
Resource Config ทั้งหมด
ถ้า Server ต้องการเพียง
itemName
amount
ส่งเฉพาะสองค่านี้ก็เพียงพอ
ช่วยลด
Network Traffic
Serialization
Processing
Complexity
⑮ TriggerServerEvent ใช้ส่งข้อมูลใหญ่มากได้ไหม
สำหรับข้อมูลขนาดเล็กหรือ Transaction ทั่วไป ใช้
TriggerServerEvent()
ได้
แต่ Cfx.re แนะนำว่า Payload ขนาดใหญ่ระดับหลาย KB ขึ้นไปควรพิจารณา Latent Event
เช่น
TriggerLatentServerEvent(
'example:largeData',
bps,
data
)
Latent Event ถูกออกแบบเพื่อส่งข้อมูลขนาดใหญ่โดยจำกัดอัตราการส่ง
Resource ทั่วไปไม่จำเป็นต้องใช้ Latent Event หาก Payload เล็ก
⑯ TriggerLatentServerEvent ต่างจาก TriggerServerEvent อย่างไร
สรุปง่าย ๆ
ข้อมูลเล็ก / Transaction ปกติ
→ TriggerServerEvent
ข้อมูลขนาดใหญ่
→ พิจารณา TriggerLatentServerEvent
Latent Event มี Parameter เพิ่มสำหรับกำหนด Bandwidth เช่น
bps
จึงเหมาะกับ Payload ขนาดใหญ่กว่าการโยนข้อมูลก้อนใหญ่ผ่าน Event ปกติ
⑰ TriggerServerEvent ปลอดภัยไหม
ตัว Function สามารถใช้สร้างระบบที่ปลอดภัยได้
แต่ ความปลอดภัยไม่ได้เกิดจาก TriggerServerEvent เอง
ปัญหาจะเกิดเมื่อ Server เขียน Handler แบบ
Client ส่งอะไรมา
↓
Server เชื่อ
↓
Server ทำตาม
Network Event ทุกตัวที่ Client เรียกได้ควรถูกมองว่า Client อาจพยายามเรียกเองหรือส่ง Parameter ที่ผิดจาก UI ปกติ
⑱ Client สามารถ Trigger Event เองได้ไหม
ควรออกแบบ Server ภายใต้สมมติฐานว่า Client ที่ถูกดัดแปลงสามารถพยายาม Trigger Network Events ได้
ดังนั้นการคิดว่า
Event นี้ถูกเรียกเฉพาะตอนกดปุ่มใน Menu ของฉัน
ไม่เพียงพอสำหรับ Security
ผู้โจมตีไม่จำเป็นต้องผ่าน Menu ตาม Flow ที่ Developer เขียนไว้
Server ต้อง Validate เอง
⑲ ตัวอย่าง TriggerServerEvent ที่อันตราย
Client
TriggerServerEvent(
'money:add',
1000000
)
Server
RegisterNetEvent(
'money:add',
function(amount)
AddMoney(
source,
amount
)
end
)
นี่เป็น Architecture ที่อันตราย
เพราะ Client กำหนดจำนวนเงินเอง
⑳ วิธีออกแบบ Reward ที่ดีกว่า
Client ควรส่งเพียง Request
TriggerServerEvent(
'delivery:complete'
)
Server
RegisterNetEvent(
'delivery:complete',
function()
local src = source
-- ตรวจว่างานเริ่มจริง
-- ตรวจ progress
-- ตรวจ position
-- ตรวจ cooldown
local reward = 500
AddMoney(
src,
reward
)
end
)
Server เป็นผู้กำหนด Reward
จึงเปลี่ยนจาก
Client Authority
เป็น
Server Authority
㉑ Shop Event ควรออกแบบอย่างไร
Client
TriggerServerEvent(
'shop:buy',
'water',
2
)
Server ควรตรวจ
water มีจริงหรือไม่
amount ถูกต้องหรือไม่
ราคา Server-side เท่าไร
Player มีเงินเท่าไร
Inventory รับได้หรือไม่
Player ใช้ร้านนี้ได้หรือไม่
แล้วจึงทำ Transaction
㉒ Client ไม่ควรส่งราคา
ไม่ควรออกแบบ
TriggerServerEvent(
'shop:buy',
'water',
2,
1
)
โดย Parameter สุดท้ายคือราคาที่ Client บอกว่า
1 บาท
Server ควรหา Price จาก Config หรือ Database ที่เชื่อถือได้เอง
เช่น
local item = Config.Items[itemName]
local price =
item.price * amount
㉓ Client ไม่ควรส่ง Reward
หลักเดียวกัน
ไม่ควร
TriggerServerEvent(
'job:complete',
50000
)
แล้ว Server ใช้ 50000 เป็น Reward
ควรส่ง
TriggerServerEvent(
'job:complete',
jobId
)
แล้ว Server ใช้ State ของตัวเองหาว่า Job นี้ควรได้ Reward เท่าไร
㉔ Client ไม่ควรส่ง Permission Result
ตัวอย่างผิด
TriggerServerEvent(
'admin:action',
true
)
แล้ว Serverคิดว่า
true = เป็น Admin
Permission ต้องตรวจ Server-side จากระบบที่เชื่อถือได้
เช่น
ACE Permission
Framework Permission
Server Role
Server Player Data
ตาม Architecture ของ Server
㉕ Server ควรตรวจ Type ของ Parameter
ตัวอย่าง
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
if type(itemName) ~= 'string' then
return
end
if type(amount) ~= 'number' then
return
end
-- continue
end
)
ช่วยป้องกัน Input ที่ผิด Format
แต่ Type Check เป็นเพียงขั้นแรก
ยังต้องตรวจ Business Rule ต่อ
㉖ ต้องตรวจ Range ด้วย
แม้ amount จะเป็น Number แต่ Client อาจส่ง
-100
0
99999999
ดังนั้นควรตรวจ
if amount < 1 then
return
end
if amount > 100 then
return
end
หรือ Limit ที่เหมาะสมกับระบบจริง
㉗ ควรตรวจ Integer หรือไม่
ถ้าระบบต้องการจำนวน Item เป็นจำนวนเต็ม
ควรตรวจให้เหมาะสม
ตัวอย่างแนวคิด
if amount % 1 ~= 0 then
return
end
รวมถึงตรวจ
Minimum
Maximum
Type
Business Rule
ก่อนใช้ข้อมูล
㉘ Server ควรตรวจ Item จริง
ตัวอย่าง
local item =
Config.Items[itemName]
if not item then
return
end
อย่าให้ Client ส่งชื่อ Item อะไรก็ได้แล้ว Server เพิ่มให้
ต้องมี Allowlist หรือ Item Definition ที่ Server เชื่อถือได้
㉙ Server ควรตรวจ Player State
บาง Event ต้องตรวจมากกว่า Parameter
เช่น Job Reward ควรตรวจ
Player เริ่มงานหรือยัง
อยู่ Stage ไหน
ได้รับ Reward ไปแล้วหรือยัง
อยู่จุดที่ถูกต้องหรือไม่
Cfx.re แนะนำให้ใช้ข้อมูลฝั่ง Server เช่น Position, Inventory, Money, State และ Permission เมื่อสามารถทำได้
㉚ ตรวจ Position ทำไม
สมมติ Client แจ้ง
ฉันมาถึงจุดส่งของแล้ว
ถ้า Serverให้ Reward ทันที ผู้เล่นอาจพยายาม Trigger Event จากที่ไหนก็ได้
Server ควรตรวจ Position ตาม Logic ที่ระบบรองรับ
Flow ที่ดีกว่า
Client Trigger
↓
Server ตรวจ Player Position
↓
ตรวจ Mission State
↓
ให้ Reward
㉛ ตรวจ Money ฝั่ง Server
ระบบซื้อของควรใช้ยอดเงินจริงฝั่ง Server
ไม่ใช่ Client ส่งว่า
ฉันมีเงิน 50,000
Server ควรอ่าน Player Data จาก Framework หรือระบบ Economy ของ Serverเอง
จากนั้นตรวจ
balance >= price
จึงทำ Transaction
㉜ ตรวจ Inventory ฝั่ง Server
ก่อน
เพิ่ม Item
ลบ Item
Craft
Trade
Drop
ควรใช้ Inventory State ที่ Server เชื่อถือได้
ไม่ควรให้ Client ส่ง
ฉันมี Item ครบแล้ว
แล้ว Serverทำตาม
㉝ ควรมี Cooldown หรือไม่
Event ที่มี Value หรือใช้ Resource สูงควรพิจารณา Cooldown
เช่น
Job Reward
Craft
Database Request
Vehicle Spawn
External API
Admin Action
แนวคิด
TriggerServerEvent
↓
Server Rate Limit
↓
Validation
↓
Business Logic
ช่วยป้องกัน Spam
㉞ Rate Limit ต่างจาก Validation อย่างไร
Validation ตรวจว่า Request ถูกต้องหรือไม่
เช่น
amount = 2
item = water
Rate Limit ตรวจว่าถูกเรียกบ่อยเกินไปหรือไม่
Event อาจมีข้อมูลถูกต้องทุกครั้ง แต่ถูก Trigger
500 ครั้ง/วินาที
ก็ยังสร้างปัญหาได้
จึงควรพิจารณาทั้งสองอย่าง
㉟ TriggerServerEvent ทุก Frame ได้ไหม
ทำได้ในเชิง API แต่โดยทั่วไป ไม่ควร หากไม่จำเป็น
ตัวอย่าง
CreateThread(function()
while true do
Wait(0)
TriggerServerEvent(
'player:update'
)
end
end)
สามารถสร้าง Network Traffic จำนวนมาก
ถ้าข้อมูลเปลี่ยนไม่บ่อยควร Trigger เฉพาะเมื่อเปลี่ยน
㊱ ส่ง Coordinates ทุก Frame ดีไหม
โดยทั่วไปไม่ควรส่ง Position ผ่าน Event ทุก Frameเพียงเพื่อให้ Serverรู้ตำแหน่ง
FiveM/OneSync มีระบบ Networking และ Server-side API สำหรับข้อมูลหลายประเภทอยู่แล้ว
ควรใช้ระบบที่เหมาะกับ Use Case แทนการสร้าง
Client → Server Event
ทุก Frame
เอง
㊲ TriggerServerEvent กับ Database
Use Case ที่พบบ่อยคือ
Client
↓
TriggerServerEvent
↓
Server
↓
Database
เช่น Save Vehicle
Client
TriggerServerEvent(
'garage:store',
networkId
)
Server ตรวจ Ownership และ State ก่อนบันทึก Database
Client ไม่ควรส่ง SQL Query ไปให้ Server Execute โดยตรง
㊳ อย่าส่ง SQL ผ่าน TriggerServerEvent
ตัวอย่างที่ไม่ควรทำ
TriggerServerEvent(
'database:query',
'DELETE FROM users'
)
Server ไม่ควรเปิด Generic Event ที่รับ SQL จาก Client แล้ว Execute
นี่เป็น Security Design ที่อันตรายมาก
ควรให้ Client Request Action ที่กำหนดชัดเจน
เช่น
garage:store
shop:buy
bank:deposit
แล้ว Server สร้าง Query เอง
㊴ TriggerServerEvent กับ NUI
NUI Action มักเดินทางแบบ
NUI
↓
RegisterNUICallback
↓
Client Lua
↓
TriggerServerEvent
↓
Server
ตัวอย่างผู้เล่นกดซื้อสินค้าใน UI
NUI ส่ง
item = water
amount = 2
Client ส่ง Request ไป Server
Server Validate ก่อนทำ Transaction
ดังนั้น NUI ไม่ควรมี Authority ของ Economy เช่นกัน
㊵ ตัวอย่าง NUI → Server Flow
Client
RegisterNUICallback(
'buyItem',
function(data, cb)
TriggerServerEvent(
'shop:buy',
data.item,
data.amount
)
cb({})
end
)
Server
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
local src = source
-- validate
end
)
จำไว้ว่า NUI Data มาจาก Client Environment เช่นกัน
จึงต้อง Validate Server-side
㊶ TriggerServerEvent ใช้กับ ESX ได้ไหม
ได้ และ ESX Script จำนวนมากใช้ Pattern นี้
เช่น
Client Interaction
↓
TriggerServerEvent
↓
ESX Server Logic
แต่การใช้ ESX Function หลังรับ Event ไม่ได้ทำให้ Event ปลอดภัยเอง
ยังต้องตรวจ
Player
Money
Item
Job
Permission
ตามระบบ
㊷ TriggerServerEvent ใช้กับ QBCore ได้ไหม
ได้
แนวคิดเหมือนกัน
Client
↓
TriggerServerEvent
↓
QBCore Server
↓
Get Player
↓
Validate
↓
Action
Framework ช่วยจัดการ Player Data แต่ Developer ยังต้องออกแบบ Event Security เอง
㊸ TriggerServerEvent ใช้กับ Qbox ได้ไหม
ได้
ไม่ว่า Framework จะเป็น
ESX
QBCore
Qbox
Standalone
TriggerServerEvent() ยังมีหน้าที่เดิมคือส่ง Network Event จาก Client ไป Server
Framework เปลี่ยน API ที่ใช้หลัง Event แต่ไม่เปลี่ยน Trust Boundary
㊹ TriggerServerEvent กับ OneSync
TriggerServerEvent() เป็น Network Event API
OneSync เป็นระบบ Networking/Entity/Player Synchronization อีกส่วนหนึ่ง
ไม่ได้หมายความว่าเปิด OneSync แล้ว Event จะปลอดภัยหรือ Optimize ให้อัตโนมัติ
ยังต้องออกแบบ
Event Frequency
Payload
Validation
Authority
เหมือนเดิม
㊺ TriggerServerEvent กับ State Bags
ถ้าต้องการส่ง “Action”
Event เหมาะ เช่น
ฉันต้องการซื้อ Item
ถ้าต้องการ Replicate “State” อาจพิจารณา State Bags ใน Use Case ที่เหมาะสม
ตัวอย่าง
Event:
vehicle:toggleLock
State:
locked = true
อย่าใช้ TriggerServerEvent เป็นระบบ Sync Global State ทุก Tick โดยไม่จำเป็น
㊻ TriggerServerEvent กับ Callback ต่างกันอย่างไร
TriggerServerEvent() เป็น One-way Request ตามธรรมชาติ
Client
↓
Server
ถ้าต้องการ Response สามารถให้ Server Trigger Event กลับ
Client
↓
Server
↓
Client
หรือใช้ Callback System ของ Framework/Library
Callback เหมาะเมื่อ Client ต้อง “ขอข้อมูลแล้วรอผล”
เช่นโหลดรายการรถจาก Database
㊼ TriggerServerEvent กับ Export ต่างกันอย่างไร
TriggerServerEvent()
ใช้ข้าม Network
Client → Server
Export มักใช้ให้ Resource เรียก Function ของ Resource อื่นภายใน Context ที่รองรับ
ดังนั้นถ้า Client ต้องสั่ง Server
Export ไม่ใช่สิ่งที่แทน Network Event ได้โดยตรงทุกกรณี
ต้องเลือกตาม Execution Context
㊽ TriggerServerEvent ไม่ทำงาน แก้อย่างไร
ตรวจตามลำดับ
① Resource Start หรือยัง
② Event Name ตรงไหม
③ Trigger อยู่ client.lua หรือไม่
④ Server RegisterNetEvent แล้วหรือไม่
⑤ server.lua ถูกโหลดหรือไม่
⑥ มี Error ก่อน Trigger หรือไม่
⑦ Parameter ถูกต้องไหม
⑧ ดู F8 Console หรือยัง
⑨ ดู Server Console หรือยัง
เริ่มจาก print() ทั้งสองฝั่ง
㊾ วิธี Debug TriggerServerEvent
Client
print('sending shop:buy')
TriggerServerEvent(
'shop:buy',
'water',
2
)
Server
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
local src = source
print(
'received shop:buy',
src,
itemName,
amount
)
end
)
ถ้า Client Print ทำงานแต่ Serverไม่ Print
ให้ตรวจ
Event Name
RegisterNetEvent
Resource
Server Script
Console Error
㊿ Event Name ควรตั้งอย่างไร
ควรใช้ Prefix ของ Resource
เช่น Resource
comsiam_shop
ใช้ Event
comsiam_shop:buy
comsiam_shop:sell
comsiam_shop:requestItems
แทน
buy
sell
get
ช่วยลดชื่อชนและทำให้ Search Code ง่ายขึ้น
แต่ชื่อ Event ที่เดายาก ไม่ใช่ Security
51 TriggerServerEvent ใช้ชื่อ Secret ป้องกันโกงได้ไหม
ไม่ได้
เช่น
x7a92_secret_reward_934
ไม่ได้ทำให้ Event ปลอดภัยจริง
Security ต้องมาจาก Server-side Checks
Player
Permission
Position
Money
Inventory
State
Cooldown
ไม่ใช่การซ่อนชื่อ Event
52 Event Contract ควรมีอะไร
Project ใหญ่ควรกำหนด Contract เช่น
Event:
shop:buy
Direction:
Client → Server
Arguments:
itemName: string
amount: number
Validation:
item exists
amount range
player money
inventory capacity
distance
cooldown
Developer คนอื่นจะเข้าใจทันทีว่า Event ทำอะไร
53 ไม่ควรสร้าง Generic Server Event มากเกินไป
ตัวอย่างอันตราย
server:execute
แล้ว Client ส่ง
action
amount
target
permission
ทุกอย่างผ่าน Event ตัวเดียว
Event ที่กว้างเกินไปมัก
Validate ยาก
Audit ยาก
Security ซับซ้อน
Debug ยาก
ควรออกแบบ Action ให้ชัดเจนตาม Feature
54 ควรแยก Business Logic ออกจาก Event Handler
แทน
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
-- logic 300 บรรทัด
end
)
สามารถแยก
local function buyItem(
src,
itemName,
amount
)
-- validation
-- transaction
end
แล้ว Handler
RegisterNetEvent(
'shop:buy',
function(itemName, amount)
local src = source
buyItem(
src,
itemName,
amount
)
end
)
ช่วยให้ Test และ Maintain ง่ายขึ้น
55 Server Event ควรคืน Error ให้ Client อย่างไร
ถ้า Validation ไม่ผ่าน Server สามารถส่ง Result กลับ Client
ตัวอย่าง
TriggerClientEvent(
'shop:result',
src,
false,
'not_enough_money'
)
Client รับแล้วแสดง Notification
Flow คือ
Client Request
↓
Server Validation
↓
Fail
↓
TriggerClientEvent
↓
Client Notification
ไม่จำเป็นต้องให้ Clientเดาว่าทำไม Transaction ไม่สำเร็จ
56 อย่าส่ง Error ภายในที่ Sensitive ให้ Client
Server สามารถส่งข้อความที่เหมาะกับผู้ใช้ เช่น
เงินไม่เพียงพอ
แต่ไม่ควรส่ง Internal Detail เช่น
SQL Query
Database Password
Stack Trace ที่ Sensitive
Internal Security Token
กลับ Client โดยไม่มีเหตุผล
Server Log สามารถเก็บรายละเอียดสำหรับ Developer แยกจาก User Message
57 TriggerServerEvent และ Performance ต้องจำอะไร
หลักสำคัญคือ
ส่งเมื่อจำเป็น
ส่งข้อมูลให้น้อย
Validate อย่างมีประสิทธิภาพ
อย่า Spam Database
อย่า Trigger ทุก Tick
Event ที่เขียนถูกต้องสามารถรองรับระบบใหญ่ได้
ปัญหามักเกิดจาก Architecture ที่ส่ง Event มากเกินความจำเป็น
58 TriggerServerEvent และ Security ต้องจำอะไร
จำประโยคนี้:
ทุก TriggerServerEvent คือ Request จาก Client ไม่ใช่คำสั่งที่ Server ต้องเชื่อ
Server ควรเป็นผู้ตรวจและตัดสินข้อมูลสำคัญเอง
โดยเฉพาะ
Money
Items
Rewards
Permissions
Positions
States
Transactions
59 Checklist ก่อนสร้าง TriggerServerEvent
ก่อนเปิด Network Event ใหม่ ให้ตรวจ
① Client จำเป็นต้องเรียก Server จริงไหม
② Event Name ชัดไหม
③ Parameter มีอะไร
④ Type ถูกตรวจไหม
⑤ Range ถูกตรวจไหม
⑥ Player State ถูกตรวจไหม
⑦ Permission ถูกตรวจไหม
⑧ Money/Inventory ใช้ Server Data ไหม
⑨ ต้องมี Cooldown/Rate Limit ไหม
⑩ Event Trigger บ่อยเกินไปหรือไม่
⑪ Payload ใหญ่หรือไม่
⑫ Client กำหนด Reward เองหรือไม่
ถ้าข้อสุดท้ายตอบว่าใช่ ควรกลับไปออกแบบใหม่
60 ตัวอย่าง TriggerServerEvent สำหรับฝึก
สร้างระบบ Job ง่าย ๆ
client.lua
RegisterCommand(
'finishjob',
function()
TriggerServerEvent(
'training:finishJob'
)
end,
false
)
server.lua
local activeJobs = {}
RegisterNetEvent(
'training:finishJob',
function()
local src = source
local job = activeJobs[src]
if not job then
print(
'Player has no active job:',
src
)
return
end
local reward = 500
print(
'Player completed job:',
src,
reward
)
activeJobs[src] = nil
-- เพิ่มเงินผ่านระบบ
-- Framework ของ Server
end
)
จุดสำคัญคือ Client ไม่ได้ส่ง
reward = 500
Server กำหนด Reward เอง
นี่คือ Concept ที่ควรติดเป็นนิสัยตั้งแต่ Resource แรก
คำถามที่พบบ่อยเกี่ยวกับ FiveM TriggerServerEvent
TriggerServerEvent คืออะไร
คือ Function สำหรับส่ง Network Event จาก FiveM Client ไปยัง FXServer
ใช้ TriggerServerEvent ที่ server.lua ได้ไหม
Function นี้ออกแบบสำหรับทิศทาง Client → Server หากต้อง Trigger Event ภายใน Server Context ใช้ TriggerEvent() ตาม Use Case
Server รับ TriggerServerEvent อย่างไร
ใน Lua ใช้ RegisterNetEvent() เพื่อ Register และ Handle Network Event
source คืออะไร
คือ Player Source ของ Client ที่ Trigger Event เข้ามาใน Server Event Context
TriggerServerEvent ส่ง Parameter ได้ไหม
ได้ สามารถส่ง Parameter หลายค่าได้
ส่ง Table ได้ไหม
ได้กับข้อมูลที่ระบบ Serialization รองรับ แต่ควรส่งเฉพาะข้อมูลจำเป็น
TriggerServerEvent ปลอดภัยไหม
ปลอดภัยได้ถ้า Server Validate ข้อมูลอย่างถูกต้อง แต่ไม่ควรเชื่อ Client Input โดยตรง
Client ส่ง Player ID เองจำเป็นไหม
โดยทั่วไปไม่จำเป็นสำหรับการระบุผู้เรียก Event เพราะ Server มี source
Client ส่งราคาให้ Server ได้ไหม
ส่งได้ทางเทคนิค แต่ Server ไม่ควรเชื่อราคานั้น ควรคำนวณจาก Server-side Data เอง
Client ส่ง Reward ให้ Server ได้ไหม
ไม่ควรใช้ค่าจาก Client เป็น Authority ของ Reward Server ควรคำนวณ Reward เอง
TriggerServerEvent ทำให้ Server Lag ได้ไหม
ได้หากถูก Trigger จำนวนมาก, Payload ใหญ่ หรือ Handler ทำงานหนัก เช่น Query Database ทุกครั้ง
TriggerServerEvent กับ TriggerLatentServerEvent ต่างกันอย่างไร
Event ปกติเหมาะกับ Transaction ขนาดเล็ก ส่วน Latent Event เหมาะกว่าเมื่อจำเป็นต้องส่ง Payload ขนาดใหญ่
TriggerServerEvent กับ TriggerEvent ต่างกันอย่างไร
TriggerEvent() ทำงานใน Context เดียวกัน ส่วน TriggerServerEvent() ส่งจาก Client ไป Server ผ่าน Network
สรุป FiveM TriggerServerEvent คืออะไร
FiveM TriggerServerEvent() คือ Function สำหรับส่ง Network Event จาก Client ไปยัง Server
รูปแบบพื้นฐานคือ
TriggerServerEvent(
'eventName',
parameter1,
parameter2
)
แล้ว Server รับด้วย
RegisterNetEvent(
'eventName',
function(parameter1, parameter2)
local src = source
-- validation
end
)
Flow ที่ควรจำคือ
Client
↓
TriggerServerEvent
↓
Network
↓
Server
↓
RegisterNetEvent
↓
Validation
↓
Business Logic
และหัวใจสำคัญที่สุดคือ
Client
→ Request
Server
→ Validate + Authority
ไม่ควรสร้าง Event แบบ
Client:
"ให้เงินฉัน 1,000,000"
Server:
"ได้"
แต่ควรเป็น
Client:
"ฉันทำงานเสร็จแล้ว"
Server:
ตรวจว่างานจริงไหม
ตรวจ State
ตรวจ Position
ตรวจ Cooldown
คำนวณ Reward
แล้วจึงให้เงิน
สำหรับคนที่เรียน FiveM Developer กับ comsiam การเข้าใจ TriggerServerEvent() อย่างถูกต้องจะช่วยลดช่องโหว่ที่พบบ่อยใน Script ได้มาก เพราะ Network Event คือจุดที่ Client Data เข้ามาถึง Server โดยตรง
เมื่อเข้าใจ Client → Server แล้ว ขั้นต่อไปของ comsiam คือ TriggerClientEvent() ซึ่งทำงานในทิศทางตรงกันข้าม คือ Server → Client และจะมีเรื่อง Target Player, Broadcast -1, Payload และ Network Performance เข้ามาเกี่ยวข้อง
Comments
Post a Comment