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

Popular posts from this blog

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

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

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