FiveM Export คืออะไร ใช้อย่างไร
FiveM Export คือระบบที่ทำให้ Resource หนึ่งเปิด Function ของตัวเองให้ Resource อื่นเรียกใช้งานได้โดยตรง เหมาะสำหรับสร้าง API ระหว่าง Resource เช่น ตรวจ Job, ดึงข้อมูล Vehicle, เรียก Notification, ตรวจ Permission หรือเรียก Function ของระบบกลาง
ตัวอย่าง Resource my_core เปิด Export
exports('GetServerName', function()
return 'My FiveM Server'
end)
Resource อื่นสามารถเรียก
local serverName =
exports['my_core']:GetServerName()
print(serverName)
จุดสำคัญคือ Export ไม่ใช่ Network Event
Client Export ทำงานใน Client Context ส่วน Server Export ทำงานใน Server Context ดังนั้นไม่สามารถใช้ Client Export เพื่อเรียก Function บน Server โดยตรงแทน TriggerServerEvent() ได้
แนวคิดคือ
Resource A
↓
Export Function
↓
Resource B เรียกใช้
Export จึงเป็นเครื่องมือสำคัญสำหรับสร้าง Resource แบบ Modular และลดการเขียน Code ซ้ำ
① FiveM Export คืออะไร
Export คือ Function ที่ Resource หนึ่งประกาศให้ Resource อื่นสามารถเรียกใช้ได้
สมมติมี
resources/
├── my_core/
└── my_garage/
my_core มี Function ตรวจ Job
exports('GetJob', function(playerId)
return 'police'
end)
จากนั้น my_garage สามารถเรียก
local job =
exports['my_core']:GetJob(
playerId
)
ทำให้ Garage ไม่ต้องเขียนระบบ Job ซ้ำเอง
② ทำไม FiveM ต้องมี Export
สมมติ Server มี Resource หลายตัว
Core
Garage
Inventory
Jobs
Banking
Police
Phone
หากทุก Resource เขียน Function ซ้ำกันเอง จะเกิด
Code ซ้ำ
Logic ไม่ตรงกัน
แก้ไขหลายจุด
Maintain ยาก
Export ช่วยสร้าง Resource กลาง
Core Resource
↓
API / Export
↓
Garage
Banking
Police
Phone
Resource อื่นจึงใช้ Logic ชุดเดียวกันได้
③ วิธีสร้าง Export Lua แบบปัจจุบัน
Cfx.re รองรับการสร้าง Export โดยใช้ Global exports
ตัวอย่าง
exports(
'SayHello',
function(name)
print(
'Hello ' .. tostring(name)
)
end
)
หรือแบบสั้น
exports('SayHello', function(name)
print('Hello ' .. tostring(name))
end)
ชื่อ
SayHello
คือชื่อ Export ที่ Resource อื่นจะใช้เรียก
④ วิธีเรียก Export จาก Resource อื่น
สมมติ Resource ที่สร้าง Export ชื่อ
hello_resource
Resource อื่นเรียก
exports['hello_resource']:SayHello(
'John'
)
หรือในรูปแบบที่ชื่อ Resource รองรับ Dot Syntax
exports.hello_resource:SayHello(
'John'
)
รูปแบบ Bracket อ่านชัดและเหมาะเมื่อชื่อ Resource มีอักขระที่ Dot Syntax ใช้ไม่สะดวก
⑤ Export Return ค่าได้ไหม
ได้
ตัวอย่าง
exports('GetPrice', function()
return 500
end)
Resource อื่นเรียก
local price =
exports['shop_core']:GetPrice()
print(price)
จะได้
500
นี่เป็นความแตกต่างสำคัญระหว่าง Export กับ Event หลายประเภท
Export สามารถใช้เหมือน Function Call และรับ Return Value ได้โดยตรงใน Context ที่รองรับ
⑥ Export รับ Parameter ได้ไหม
ได้
ตัวอย่าง
exports(
'CalculatePrice',
function(price, amount)
return price * amount
end
)
Resource อื่น
local total =
exports['shop_core']:CalculatePrice(
100,
5
)
print(total)
ผลคือ
500
⑦ Export รับหลาย Parameter ได้ไหม
ได้
exports(
'CanBuy',
function(money, price, amount)
local total =
price * amount
return money >= total
end
)
เรียก
local canBuy =
exports['shop_core']:CanBuy(
5000,
100,
2
)
Export จึงสามารถสร้าง API ที่ซับซ้อนได้ตามต้องการ
⑧ Export Return Table ได้ไหม
ได้
ตัวอย่าง
exports('GetVehicleData', function()
return {
model = 'sultan',
plate = 'ABC123',
stored = true
}
end)
Resource อื่น
local vehicle =
exports['garage_core']:GetVehicleData()
print(vehicle.model)
print(vehicle.plate)
แต่ควร Return เฉพาะข้อมูลที่ Consumer ต้องใช้
⑨ Client Export คืออะไร
Client Export คือ Export ที่ถูกสร้างจาก Client Script
ตัวอย่าง client.lua
exports('GetPlayerCoords', function()
local ped =
PlayerPedId()
return GetEntityCoords(ped)
end)
Client Resource อื่นสามารถเรียก
local coords =
exports['player_core']:GetPlayerCoords()
Export นี้ทำงานใน Client Context
⑩ Server Export คืออะไร
Server Export คือ Export ที่ประกาศจาก Server Script
ตัวอย่าง
exports(
'GetPlayerJob',
function(playerId)
-- server logic
return 'police'
end
)
Server Resource อื่นเรียก
local job =
exports['player_core']:GetPlayerJob(
playerId
)
Export นี้ทำงานใน Server Context
⑪ Client Export เรียก Server Export โดยตรงได้ไหม
ไม่ควรมอง Export เป็นระบบข้าม Network
หลักคือ
Client Export
→ Client Context
Server Export
→ Server Context
ถ้า Client ต้องขอข้อมูล Server ต้องใช้กลไก เช่น
TriggerServerEvent
Callback
Network Event
ตาม Use Case
ไม่ใช่
Client
↓
Server Export โดยตรง
Export ไม่ได้มาแทน Client/Server Networking
⑫ Server Export เรียก Client Function ได้ไหม
ไม่โดยตรงในลักษณะ Network Call
ถ้า Server ต้องการให้ Client ทำสิ่งใด ใช้
TriggerClientEvent()
หรือระบบ Network/Callback ที่เหมาะสม
จำง่าย ๆ ว่า
Export
=
Resource ↔ Resource
ใน Runtime Context เดียวกัน
Network Event
=
Client ↔ Server
⑬ Export ต่างจาก Event อย่างไร
Export คล้าย Function Call
Resource A
↓
เรียก Export
↓
Resource B Function
↓
ได้ Return Value
Event มีลักษณะ
Resource A
↓
Trigger Event
↓
Listener ที่สนใจ
ตัวอย่าง Export
GetPlayerJob()
เหมาะกับการ “ขอข้อมูล”
ตัวอย่าง Event
player:jobChanged
เหมาะกับการ “แจ้งว่าเหตุการณ์เกิดขึ้น”
⑭ ควรใช้ Export หรือ Event
ใช้ Export เมื่อ Resource ต้องการ
เรียก Function
หรือ
ขอข้อมูล
เช่น
GetPlayerData
GetVehiclePrice
HasPermission
AddItem
ShowNotification
ใช้ Event เมื่อ
ต้องแจ้งเหตุการณ์
เช่น
vehicleStored
playerLoaded
jobChanged
transactionCompleted
ไม่มีคำตอบว่าตัวไหนดีกว่าเสมอไป
ต้องเลือกตาม Intent
⑮ Export ต่างจาก Callback อย่างไร
Export เหมาะมากกับ Resource ที่อยู่ Context เดียวกัน
เช่น
Server Resource A
↓
Server Export
↓
Server Resource B
Callback มักใช้กับ Async Request/Response โดยเฉพาะ
Client
↓
Server
↓
Response
↓
Client
ถ้า Server Resource A ต้องการข้อมูลจาก Server Resource B โดยตรง การใช้ Export มักง่ายกว่าส่ง Client/Server Callback วนไปมา
⑯ Export ต่างจาก TriggerEvent อย่างไร
TriggerEvent() ไม่ได้ Return Function Result โดยตรงในรูปแบบเดียวกับ Export
ตัวอย่าง
TriggerEvent(
'core:getJob',
playerId
)
เป็น Event Notification/Execution
แต่
local job =
exports['core']:GetJob(
playerId
)
เป็น Direct Function API และได้ Result ทันทีตาม Function
จึงเหมาะกับคนละ Use Case
⑰ Export เหมาะกับ Core Resource อย่างไร
สมมติสร้าง Resource
my_core
มีระบบกลาง เช่น
Player
Permissions
Jobs
Notifications
Utilities
สามารถเปิด Export
GetPlayer
GetJob
HasPermission
Notify
GetIdentifier
Resource อื่นไม่ต้องรู้ Implementation ภายใน my_core
เพียงรู้ API ที่ Export เปิดไว้
นี่คือแนวคิด Encapsulation
⑱ Encapsulation คืออะไร
หมายถึงซ่อนรายละเอียดภายใน Resource
ตัวอย่าง Resource Garage ไม่จำเป็นต้องรู้ว่า Core เก็บ Job แบบไหน
Garage เรียกเพียง
local job =
exports['my_core']:GetJob(
playerId
)
ถ้าวันหนึ่ง Core เปลี่ยน Database หรือ Internal Table
Garage อาจไม่ต้องเปลี่ยนเลย หาก Export Contract ยังเหมือนเดิม
นี่เป็นข้อดีของ API Design
⑲ Export ช่วยลด Dependency กับ Framework ได้ไหม
ได้ถ้าออกแบบ Adapter Resource
ตัวอย่าง Resource อื่นเรียก
exports['my_bridge']:GetPlayerJob(
playerId
)
ภายใน my_bridge อาจเชื่อมกับ
ESX
QBCore
Qbox
เมื่อเปลี่ยน Framework อาจแก้เฉพาะ Bridge มากกว่าต้องแก้ Script ทุกตัว
แนวคิดนี้มีประโยชน์มากกับ Server ขนาดใหญ่
⑳ Export ใช้กับ ESX ได้ไหม
ได้
Resource สามารถเรียก Export ของ Resource/Framework ที่เปิดไว้
และ Resource ของคุณเองก็สามารถเปิด Export ให้ ESX Script อื่นเรียกได้
แต่ต้องตรวจ Documentation ของ ESX Version ที่ใช้งานจริง
อย่าเดาชื่อ Export จาก Script เก่า
㉑ Export ใช้กับ QBCore ได้ไหม
ได้
QBCore Resource จำนวนมากมี API, Exports หรือ Core Object Pattern ของตัวเอง
แนวคิด Export ของ FiveM ยังเหมือนเดิม
Resource
↓
เปิด Function
↓
Resource อื่นเรียก
แต่ชื่อ Function และ Contract ขึ้นอยู่กับ Framework/Resource
㉒ Export ใช้กับ Qbox ได้ไหม
ได้
Qbox และ Resource สมัยใหม่จำนวนมากพึ่ง
Exports
ox_lib
State Bags
Events
ร่วมกัน
Developer จึงควรเข้าใจว่า Export เหมาะกับ Direct API ส่วน Event เหมาะกับ Notification และ Callback เหมาะกับ Request/Response ข้าม Context
㉓ Export ใช้กับ ox_lib ได้ไหม
ได้
Resource สามารถใช้ Export และ ox_lib อยู่ใน Project เดียวกัน
แต่ ox_lib API หลายส่วนใช้ Global lib หรือ Module ของ Library มากกว่าการเรียกทุกอย่างผ่าน FiveM Export
ควรใช้ API ตาม Documentation ของ Library นั้นโดยตรง
อย่าบังคับทุก Dependency ให้ผ่าน Export หาก Library ออกแบบอีกแบบหนึ่ง
㉔ FiveM มี Export ตัวอย่างจริงไหม
มี
Resource มาตรฐานอย่าง chat มี Exports เช่นการเพิ่มข้อความหรือ Suggestion
ตัวอย่าง Lua สามารถพบ Pattern
exports.chat:addMessage({
args = {
'SYSTEM',
'Hello'
}
})
นี่เป็นตัวอย่าง Resource หนึ่งเรียก API ของอีก Resource โดยตรง
㉕ วิธีสร้าง Export ที่ Return Boolean
ตัวอย่าง
exports(
'IsPlayerAllowed',
function(playerId)
return playerId ~= nil
end
)
Resource อื่น
local allowed =
exports['permission_core']:IsPlayerAllowed(
playerId
)
if not allowed then
return
end
เหมาะกับ Permission Helper หรือ Validation Helper ที่อยู่ Server-side
㉖ วิธีสร้าง Export สำหรับ Notification
Client Resource
exports(
'Notify',
function(message)
print(
'[NOTIFY]',
message
)
end
)
Resource Client อื่น
exports['my_notify']:Notify(
'Vehicle stored'
)
Resource ที่เรียกไม่จำเป็นต้องรู้ว่า Notification ภายในใช้
NUI
Native
Scaleform
แบบไหน
㉗ Export สำหรับ Inventory
ตัวอย่างแนวคิด Server Export
exports(
'HasItem',
function(playerId, itemName, amount)
-- inventory logic
return true
end
)
Resource Crafting เรียก
local hasItem =
exports['inventory_core']:HasItem(
playerId,
'water',
2
)
ช่วยให้ Inventory เป็น Source of Truth เพียง Resource เดียว
㉘ Export สำหรับ Garage
Garage Core อาจเปิด
GetVehicle
IsVehicleOwned
StoreVehicle
GetGarage
Resource Police หรือ Mechanic สามารถใช้ API เหล่านี้แทนการ Query Database Garage โดยตรง
ช่วยลดการผูก Resource กับ Database Schema ของกันและกัน
㉙ ทำไมไม่ควรให้ทุก Resource Query Database ของกันและกัน
สมมติ Garage เปลี่ยน Table จาก
owned_vehicles
เป็น
player_vehicles
ถ้า Resource 20 ตัว Query Table นี้โดยตรง ทุกตัวต้องแก้
แต่ถ้าทั้งหมดเรียก
exports['garage']:GetVehicle(...)
Garage สามารถเปลี่ยน Database ภายในได้โดยคง API เดิม
นี่คือประโยชน์ของ Abstraction
㉚ Export สามารถเปลี่ยน Database Implementation ได้
ตัวอย่างเดิม
Resource A
↓
Garage Export
↓
MySQL
วันหนึ่งเปลี่ยนเป็น
Resource A
↓
Garage Export
↓
Cache + MySQL
Resource A ไม่จำเป็นต้องรู้
ตราบใดที่
GetVehicle()
ยัง Return Data ตาม Contract เดิม
㉛ Export API ควรตั้งชื่ออย่างไร
ควรเป็นชื่อ Function ที่เข้าใจง่าย
ตัวอย่าง
GetPlayer
GetPlayerJob
HasItem
AddItem
RemoveItem
GetVehicle
StoreVehicle
Notify
หลีกเลี่ยง
DoThing
Func1
Data2
X
Test
เพราะ Export คือ Public API ของ Resource
ชื่อควรบอกว่าทำอะไร
㉜ Export Name ตัวพิมพ์ใหญ่เล็กสำคัญไหม
ควรเรียกให้ตรงกับชื่อที่ประกาศ
ถ้าประกาศ
exports(
'GetPlayerJob',
function()
end
)
ก็ควรเรียก
exports['core']:GetPlayerJob()
ไม่ควรเปลี่ยนเป็น
getplayerjob
GetplayerJob
โดยคิดว่า Runtime จะจับคู่ให้อัตโนมัติ
ใช้ Naming Convention เดียวทั้ง Project
㉝ Resource Name สำคัญไหม
สำคัญมาก
ถ้า Resource ชื่อ
my_core
ต้องเรียก
exports['my_core']:GetPlayer()
ถ้าเรียกผิดเป็น
exports['core']:GetPlayer()
จะไม่พบ Export ของ Resource ที่ต้องการ
จึงต้องรู้ชื่อ Folder/Resource จริง
㉞ Resource Name มี - ใช้อย่างไร
หากชื่อ Resource เช่น
my-core
รูปแบบ Bracket ชัดเจนกว่า
exports['my-core']:GetPlayer()
แทน Dot Syntax
จึงนิยมใช้
exports['resource-name']:ExportName()
ใน Code ที่ต้องการรองรับชื่อ Resource หลากหลาย
㉟ Export ไม่พบ แก้อย่างไร
ถ้า Error เกี่ยวกับ
No such export
หรือ Export ไม่พบ ให้ตรวจ
① Resource Name ถูกไหม
② Export Name ถูกไหม
③ Resource Start แล้วหรือยัง
④ Script ที่ประกาศ Export ถูกโหลดหรือยัง
⑤ Client/Server Context ตรงกันไหม
⑥ Dependency Start ก่อนหรือยัง
⑦ มี Error ก่อนประกาศ Export หรือไม่
อย่าแก้ Function ก่อนตรวจ Resource State
㊱ Export ต้องรอ Resource Start ไหม
ต้องให้ Resource ที่ให้ Export พร้อมทำงานก่อน Consumer เรียก
ตัวอย่าง
my_core
↓
สร้าง Export
↓
my_garage
↓
เรียก Export
ถ้า my_garage เริ่มก่อนและเรียก Export ตอน my_core ยังไม่พร้อม อาจเกิด Error ได้
จึงควรกำหนด Dependency/Start Order ให้ถูกต้อง
㊲ dependency ใน fxmanifest.lua ช่วยอย่างไร
Resource ที่ต้องพึ่ง Resource อื่นสามารถกำหนด Dependency
ตัวอย่าง
dependency 'my_core'
หรือหลายตัวตาม Manifest Syntax
ทำให้ Dependency ของ Resource ชัดเจนกว่าอาศัยลำดับ ensure อย่างเดียว
ตัวอย่าง Concept
my_garage
depends on
my_core
เมื่ออ่าน Resource ก็รู้ทันทีว่าต้องมี my_core
㊳ server.cfg ควรจัดลำดับอย่างไร
ตัวอย่าง
ensure my_core
ensure my_inventory
ensure my_garage
Resource ที่เป็น Core/Dependency ควรพร้อมก่อน Resource ที่เรียก API ของมัน
แต่สำหรับ Dependency ที่เป็นเงื่อนไขจริง ควรประกาศใน fxmanifest.lua ให้ชัดด้วย
ไม่ควรพึ่ง Delay แบบ
Wait(5000)
เพื่อหวังว่าอีก Resource จะพร้อม
㊴ อย่าใช้ Wait แก้ Export not found
ตัวอย่างที่ไม่ควรใช้เป็น Solution หลัก
Wait(10000)
exports['core']:GetPlayer()
เพราะไม่ได้แก้ Dependency จริง
Server ที่ Load ช้าอาจยัง Error
Server ที่ Load เร็วก็เสียเวลาโดยไม่จำเป็น
ควรแก้ Resource Dependency และ Lifecycle ให้ถูกต้อง
㊵ Runtime Export พร้อมเมื่อไร
Cfx.re ระบุว่าการใช้ Export แบบที่ประกาศผ่าน Manifest จะพร้อมใช้งานหลัง Scheduler Tick แรก
นี่เป็นอีกเหตุผลที่ Initialization และ Resource Start Order มีความสำคัญ
สำหรับ Resource ใหม่ Cfx.re แนะนำให้พิจารณา Runtime Registration เช่น
exports(
'GetData',
function()
end
)
แทน Manifest-style Export ในหลายกรณี
㊶ export ใน fxmanifest.lua คืออะไร
FiveM Resource Manifest รองรับ
export 'FunctionName'
สำหรับ Client Export
ตัวอย่าง
client_script 'client.lua'
export 'GetData'
และ Function ต้องถูกประกาศในรูปแบบที่ Explicit Export สามารถเข้าถึงได้
อย่างไรก็ตาม Cfx.re แนะนำให้ใช้ Runtime exports('name', function...) หรือ Runtime Export API ของภาษาแทนใน Resource ใหม่เมื่อเหมาะสม
㊷ server_export คืออะไร
สำหรับ Server มี Manifest Directive
server_export 'FunctionName'
ตัวอย่าง
server_script 'server.lua'
server_export 'GetPlayer'
Resource อื่นฝั่ง Server สามารถเรียก Export นี้ได้เมื่อพร้อม
แต่เช่นเดียวกับ Client Export เอกสารปัจจุบันชี้ไปทาง Runtime Export API มากกว่า
㊸ Runtime Export ดีกว่า Manifest Export อย่างไร
ตัวอย่าง Runtime
exports(
'GetPlayer',
function(playerId)
return players[playerId]
end
)
ข้อดีคือ
Function อยู่ใกล้การประกาศ API
ไม่ต้องเพิ่มชื่อ Exportใน Manifest
เห็น Implementation ชัด
Local Function สามารถถูก Wrap ใน Export ได้ง่าย
ทำให้ Resource อ่านง่ายขึ้น
㊹ Manifest Export ยังใช้ได้ไหม
ยังมีอยู่ใน Resource Manifest ปัจจุบัน
ทั้ง
export
server_export
ยังถูก Document
แต่เอกสาร Cfx.re ระบุในส่วน export ว่าให้ลองใช้ Runtime exports('name', ..) หรือ Exports.Add แทน
ดังนั้น Resource ใหม่ควรเข้าใจ Runtime Export API เป็นหลัก
㊺ Export ใช้ Local Function ได้ไหม
Runtime Export ใช้ได้ดีมากกับ Local Function
ตัวอย่าง
local function getPrice(item)
return 500
end
จากนั้น
exports(
'GetPrice',
getPrice
)
หรือ
exports(
'GetPrice',
function(item)
return getPrice(item)
end
)
Internal Function ยังสามารถเป็น Local ไม่ต้องเปิด Global ทั้งไฟล์
㊻ ทำไม Local Function ดี
ช่วยลด Global Namespace Pollution
แทนที่จะสร้าง
function GetPrice()
end
เป็น Global โดยไม่จำเป็น
สามารถใช้
local function getPrice()
end
แล้วเปิดเฉพาะ API ที่ต้องการผ่าน Export
ทำให้ Resource มี Encapsulation ดีขึ้น
㊼ Export ควรเปิดทุก Function ไหม
ไม่ควร
Resource อาจมี Internal Functions เช่น
validateInput
loadCache
saveInternalState
cleanupVehicle
parseDatabaseRow
ถ้า Resource อื่นไม่จำเป็นต้องใช้ ก็ไม่ควร Export
หลักคือ
Public API
→ Export
Internal Logic
→ Local Function
ช่วยลด Coupling
㊽ Export มากเกินไปมีข้อเสียอะไร
ถ้า Resource เปิด Export 100 ตัวโดยไม่มี Structure
Consumer อาจเริ่มพึ่ง Internal Behavior จำนวนมาก
วันหนึ่งแก้ Resource จะกระทบ Resource อื่นจำนวนมาก
จึงควรออกแบบ Public API ให้
เล็ก
ชัด
Stable
มี Contract
ไม่ใช่ Export ทุก Function เพราะทำได้
㊾ Export Contract คืออะไร
ควรกำหนดว่า Export
ชื่ออะไร
รับ Parameter อะไร
Return อะไร
ใช้ฝั่งไหน
Error แบบไหน
ตัวอย่าง
Export:
GetVehicle
Context:
Server
Arguments:
plate: string
Returns:
table | nil
Purpose:
คืนข้อมูลรถตามทะเบียน
Developer คนอื่นจะใช้ API ได้ถูกต้อง
㊿ Export Error ควร Return อย่างไร
ขึ้นอยู่กับ API
ตัวอย่างไม่พบ Vehicle
return nil
หรือ API ที่ต้องการ Response ชัดเจน
return {
success = false,
error = 'vehicle_not_found'
}
Project ใหญ่ควรกำหนด Convention เดียวกัน
เพื่อไม่ให้ Consumer ต้องเดาว่า
nil
false
{}
แต่ละอย่างหมายถึงอะไร
51 Export กับ Async Function
ต้องระวัง
Export Function ที่ทำ Async Operation เช่น Database Query อาจไม่ได้ Return Result แบบ Sync ตามที่ Caller คาด
ตัวอย่าง
Export
↓
Database Query
↓
Response มาทีหลัง
ในกรณีนี้อาจต้องใช้
Callback
Promise
Await
Async API
ตาม Runtime และ Library
อย่าคิดว่า Export ทุกตัว Return Database Result ได้ทันที
52 Export + Citizen.Await ใช้ได้ไหม
สามารถออกแบบ Export ที่ภายในใช้ Promise/Await ใน Context ที่รองรับได้
แนวคิด
Caller
↓
Export
↓
Promise
↓
Database Async
↓
Resolve
↓
Return
แต่ต้องเข้าใจ Coroutine และ Blocking/Yield Behavior ของ Runtime
อย่าใช้ Await ใน Export ที่ถูกเรียกถี่มากโดยไม่ดู Performance
53 Export Query Database ทุก Tick ดีไหม
ไม่
ตัวอย่าง
ทุก Tick
↓
GetPlayerData Export
↓
Database SELECT
เป็น Architecture ที่ไม่ดี
Export เป็นเพียง API Layer ไม่ได้ทำให้ Database Query ฟรี
ควรใช้
Cache
Memory State
Event-driven Updates
ตาม Use Case
54 Export มีผลกับ Performance ไหม
Function Call ผ่าน Export มี Overhead บ้างเมื่อเทียบกับ Local Function Call แต่ปัญหาใหญ่ส่วนมากอยู่ใน Logic ภายใน Export เช่น
Database
Loop
Native Calls
Serialization
Heavy Calculation
ดังนั้นอย่า Optimize โดยกลัว Export ก่อนดู Profiler และ Logic จริง
55 Export ใช้ทุก Frame ได้ไหม
บาง Export ที่เบามากอาจถูกใช้ได้ แต่ไม่ควรเรียก Cross-resource API จำนวนมากทุก Frameโดยไม่จำเป็น
ตัวอย่าง
ทุก Frame
↓
Export A
↓
Export B
↓
Export C
↓
Heavy Logic
อาจเพิ่ม Client CPU
ถ้าค่าคงเดิมนาน ควร Cache เมื่อเหมาะสม
56 Export กับ Security ต้องคิดอะไร
Server Export ไม่ได้เปิดให้ Client เรียกผ่าน Network โดยตรงเหมือน Network Event
จึงเหมาะกับ Server-to-Server API มาก
แต่ Security ยังต้องพิจารณา
Resource ไหนเรียกได้
Parameter ถูกต้องไหม
Export ทำ Action สำคัญอะไร
Caller สามารถส่งข้อมูลจาก Client เข้ามาต่อได้ไหม
ถ้า Export ถูกเรียกจาก Network Event Handler ต้อง Validate Client Input ก่อนหรือภายใน Business Logic ตาม Architecture
57 อย่าใช้ Export ข้าม Security Validation
ตัวอย่าง Server Event
RegisterNetEvent(
'money:add',
function(amount)
exports['economy']:AddMoney(
source,
amount
)
end
)
แม้ AddMoney จะเป็น Server Export แต่ Code ยังอันตรายถ้า amount มาจาก Clientโดยไม่ Validate
Export ไม่ได้ทำให้ Client Input ปลอดภัย
Flow ที่ดีคือ
Client Request
↓
Server Validate
↓
Export
↓
Economy Action
58 Export ไม่ทำให้ Client เป็น Authority
ถ้า Client Resource เรียก Client Export
exports['hud']:SetMoney(
9999999
)
อาจเปลี่ยนแค่ Display บน Client
แต่เงินจริงต้องอยู่ Server
ดังนั้น Client Export ไม่ควรถูกใช้แทน Server-side Economy Authority
59 Checklist ก่อนสร้าง FiveM Export
ก่อนเปิด Export ใหม่ ให้ถามว่า
① Resource อื่นต้องเรียก Function นี้จริงไหม?
② เป็น Client Export หรือ Server Export?
③ ต้องข้าม Network หรือไม่?
④ ถ้าต้องข้าม Network Export อาจไม่ใช่คำตอบหรือไม่?
⑤ Parameter มีอะไร?
⑥ Return Type คืออะไร?
⑦ Function เป็น Sync หรือ Async?
⑧ มี Database Query หรือไม่?
⑨ Export ถูกเรียกบ่อยแค่ไหน?
⑩ ควร Cache Result หรือไม่?
⑪ API Name ชัดหรือไม่?
⑫ Internal Function จำเป็นต้องเปิด Public จริงไหม?
⑬ Dependency ถูกประกาศหรือยัง?
⑭ Error Contract ชัดหรือไม่?
ถ้าตอบได้ครบ Export API จะดูแลง่ายขึ้นมาก
⑥⓪ ตัวอย่าง Export สำหรับมือใหม่
สร้าง Resource
simple_math
fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_script 'server.lua'
server.lua
exports(
'Add',
function(a, b)
return a + b
end
)
สร้าง Resource อีกตัว
math_test
server.lua
RegisterCommand(
'testadd',
function()
local result =
exports['simple_math']:Add(
10,
20
)
print(
'Result:',
result
)
end,
true
)
ผลคือ
Result: 30
Flow คือ
math_test
↓
exports['simple_math']
↓
Add(10, 20)
↓
simple_math
↓
return 30
↓
math_test
นี่เป็นตัวอย่างที่ดีสำหรับทำความเข้าใจ FiveM Export ก่อนนำไปใช้กับ Framework หรือ Database
คำถามที่พบบ่อยเกี่ยวกับ FiveM Export
FiveM Export คืออะไร
คือระบบสำหรับเปิด Function ของ Resource หนึ่งให้ Resource อื่นเรียกใช้งานได้
วิธีสร้าง Export Lua FiveM
ใช้
exports(
'FunctionName',
function(...)
-- logic
end
)
วิธีเรียก Export
ใช้
exports['resource_name']:FunctionName()
Export Return ค่าได้ไหม
ได้
Export รับ Parameter ได้ไหม
ได้
Export Return Table ได้ไหม
ได้
Client Export กับ Server Export ต่างกันอย่างไร
Client Export ทำงานฝั่ง Client ส่วน Server Export ทำงานฝั่ง Server
Client เรียก Server Export โดยตรงได้ไหม
ไม่ควรใช้ Export เป็น Network RPC หาก Client ต้องติดต่อ Server ต้องใช้ Event/Callback หรือระบบ Networking ที่เหมาะสม
Export ต่างจาก Event อย่างไร
Export เหมือน Direct Function API และสามารถ Return ค่า ส่วน Event เหมาะกับการแจ้งเหตุการณ์
Export ต่างจาก Callback อย่างไร
Export เหมาะกับ Resource-to-Resource API ใน Context เดียวกัน ส่วน Callback เหมาะกับ Request/Response โดยเฉพาะ Async และ Client↔Server
Export ใช้กับ ESX ได้ไหม
ได้ หาก Resource หรือ Framework เปิด Export ที่ต้องการ
Export ใช้กับ QBCore ได้ไหม
ได้
Export ใช้กับ Qbox ได้ไหม
ได้
export ใน fxmanifest.lua ยังใช้ได้ไหม
ยังมีใน Resource Manifest แต่เอกสาร Cfx.re แนะนำให้ลองใช้ Runtime exports('name', function...) หรือ Runtime Export API ของภาษาแทนใน Resource ใหม่
server_export ยังมีไหม
ยังมีใน Resource Manifest สำหรับ Server Export
Export not found แก้อย่างไร
ตรวจ Resource Name, Export Name, Client/Server Context, Resource State, Dependency และ Error ของ Resource ที่ประกาศ Export
Export Query Database ได้ไหม
ได้ฝั่ง Server แต่ต้องจัดการ Async และ Performance ให้ถูกต้อง
Export ปลอดภัยกว่า Network Event ไหม
Server Export ไม่ได้เปิด Network Interface ให้ Client ในรูปแบบเดียวกับ Net Event แต่ถ้าข้อมูลต้นทางมาจาก Client ยังต้อง Validate ก่อนทำ Action สำคัญ
สรุป FiveM Export คืออะไร ใช้อย่างไร
FiveM Export คือระบบสำหรับสร้าง Public Function API ให้ Resource อื่นเรียกใช้งานได้โดยตรง
รูปแบบที่แนะนำสำหรับ Lua คือ
exports(
'GetData',
function(...)
return data
end
)
Resource อื่นเรียก
local data =
exports['resource_name']:GetData()
สิ่งที่ต้องจำคือ
Export
=
Resource → Resource API
ไม่ใช่
Client → Server Network RPC
Client Export และ Server Export อยู่คนละ Execution Context ถ้าต้องการสื่อสารข้าม Client/Server ต้องใช้ Network Event หรือ Callback ที่เหมาะสม
สำหรับ Resource ใหม่ Cfx.re รองรับและแนะนำ Runtime Export Registration เช่น
exports('GetData', function()
end)
ขณะที่ export และ server_export ใน fxmanifest.lua ยังคงมีอยู่ใน Resource Manifest ปัจจุบัน แต่ Runtime API มักทำให้ Code และ Public API อยู่ใกล้กันมากกว่า
สำหรับผู้ที่เรียน FiveM Developer กับ comsiam สิ่งที่ควรฝึกต่อจาก Syntax คือการออกแบบ Export ให้เป็น API ที่เล็ก ชัด และ Stable ไม่เปิด Internal Function ทุกอย่างออกมาโดยไม่จำเป็น
เมื่อออกแบบ Export ได้ดี Resource จะ Modular ขึ้น เปลี่ยน Database หรือ Framework ภายในได้ง่าย และ Resource อื่นไม่ต้องรู้ Implementation ทั้งหมด ซึ่งเป็นหลักสำคัญของ FiveM Server ขนาดใหญ่ที่ comsiam ต้องการให้เข้าใจก่อนเข้าสู่หัวข้อถัดไปคือ FiveM Native คืออะไร
Comments
Post a Comment