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

Popular posts from this blog

FiveM ยังน่าเล่นไหม? Enhanced เปลี่ยน FiveM แค่ไหน

FiveM คืออะไร เล่นอย่างไร สำหรับมือใหม่ เริ่มต้นตั้งแต่ศูนย์

วิธีตั้ง Admin Permission ด้วย add_ace และ add_principal FiveM แบบละเอียด