วิธีสร้าง Resource FiveM ตัวแรก ตั้งแต่ Folder ว่างจนรัน Script ได้จริง

 การสร้าง Resource FiveM ตัวแรก ไม่ได้ซับซ้อนอย่างที่หลายคนคิด เพราะ Resource ขั้นพื้นฐานต้องมีเพียง Folder, fxmanifest.lua และ Script ที่ต้องการให้ FiveM โหลด เช่น client.lua หรือ server.lua

โครงสร้างง่ายที่สุดสามารถเป็น

my_first_resource/
├── fxmanifest.lua
├── client.lua
└── server.lua

จากนั้นเขียน fxmanifest.lua

fx_version 'cerulean'
game 'gta5'

client_script 'client.lua'
server_script 'server.lua'

นำ Folder ไปไว้ใน

resources/[local]/

แล้วใช้ Server Console

refresh
ensure my_first_resource

เพียงเท่านี้ FXServer ก็สามารถค้นพบและ Start Resource ของเราได้

ในบทความนี้จะสร้าง Resource ตั้งแต่ศูนย์ พร้อม Command, Client Event, Server Event และระบบ Client ↔ Server แบบง่าย เพื่อให้เข้าใจวงจรของ FiveM Resource จริง ๆ

① เตรียม FiveM Server ก่อน

ก่อนสร้าง Resource ควรมี FXServer ที่สามารถ Start และเข้าเล่นได้แล้ว

โครงสร้างโดยทั่วไปจะมี

server-data/
├── server.cfg
└── resources/

Folder สำคัญสำหรับการเขียน Script คือ

resources/

เพราะ FXServer จะค้นหา Resources จากบริเวณนี้

② Resource คือ Folder หนึ่งชุด

สมมติเราจะสร้าง Resource ชื่อ

my_first_resource

ให้สร้าง

resources/
└── [local]/
    └── my_first_resource/

[local] เป็น Category Folder ที่นิยมใช้เก็บ Resource ที่เขียนเอง

ชื่อ Category ไม่บังคับ

คุณอาจใช้

[custom]
[scripts]
[jobs]
[core]

ก็ได้

③ ทำไมใช้ [local]

ข้อดีคือช่วยแยก

Resource ที่มากับ Server

ออกจาก

Resource ที่เราเขียนเอง

ตัวอย่าง

resources/
├── [system]
├── [gameplay]
└── [local]
    ├── my_first_resource
    ├── my_garage
    └── my_job

เมื่อ Server ใหญ่ขึ้น การจัด Folder ตั้งแต่แรกช่วยให้ดูแลง่ายขึ้นมาก

④ สร้าง fxmanifest.lua

ภายใน my_first_resource สร้างไฟล์

fxmanifest.lua

ดังนั้นตอนนี้จะเป็น

my_first_resource/
└── fxmanifest.lua

ไฟล์นี้ทำให้ FiveM รู้ว่า Folder ดังกล่าวเป็น Resource และต้องโหลดอะไรบ้าง

⑤ เขียน Manifest ขั้นต่ำ

เปิด fxmanifest.lua แล้วใส่

fx_version 'cerulean'
game 'gta5'

นี่คือ Header พื้นฐานของ FiveM Resource ปัจจุบัน

cerulean คือ FXv2 Resource Version

ส่วน

game 'gta5'

หมายถึง Resource ใช้ GTA V/FiveM API Set

⑥ เพิ่ม Metadata

สามารถเพิ่ม

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

รวมเป็น

fx_version 'cerulean'
game 'gta5'

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

Metadata ไม่ได้ทำให้ Script มี Feature เพิ่ม แต่ช่วยให้ Resource อ่านง่ายและดูเป็นระบบ

⑦ สร้าง client.lua

สร้างไฟล์

client.lua

ตอนนี้ Folder จะเป็น

my_first_resource/
├── fxmanifest.lua
└── client.lua

แล้วเพิ่มใน Manifest

client_script 'client.lua'

Manifest จะเป็น

fx_version 'cerulean'
game 'gta5'

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

client_script 'client.lua'

⑧ Client Script ทำงานตรงไหน

client.lua ทำงานบน FiveM Client ของ Player แต่ละคน

เหมาะกับสิ่งที่เกี่ยวข้องกับ

PlayerPedId
Controls
Camera
HUD
Marker
NUI
Local Game World

ตัวอย่างง่ายที่สุด

print('Hello from client')

เมื่อ Resource ถูกโหลดฝั่ง Player ข้อความจะปรากฏใน Client Console/F8

⑨ สร้าง Command ตัวแรก

ใน client.lua

RegisterCommand(
    'hello',
    function()

        print(
            'Hello FiveM'
        )

    end,
    false
)

เข้า Server แล้วพิมพ์

/hello

จะทำให้ข้อความ

Hello FiveM

ปรากฏใน Client Console

⑩ RegisterCommand คืออะไร

โครงสร้างหลักคือ

RegisterCommand(
    commandName,
    handler,
    restricted
)

ตัวอย่าง

RegisterCommand(
    'test',
    function()

        print('Working')

    end,
    false
)

false หมายถึง Command นี้ไม่ได้ใช้ ACE Restricted Command Policy

⑪ ทดสอบ PlayerPedId

ลองเพิ่ม Command

RegisterCommand(
    'myped',
    function()

        local ped =
            PlayerPedId()

        print(
            'My ped:',
            ped
        )

    end,
    false
)

PlayerPedId() คืน Local Player Ped Handle

นี่เป็นตัวอย่างแรกของการเรียก FiveM/GTA Native จาก Client Script

⑫ ทดสอบ Coordinates

เพิ่ม

RegisterCommand(
    'mycoords',
    function()

        local ped =
            PlayerPedId()

        local coords =
            GetEntityCoords(
                ped
            )

        print(
            coords
        )

    end,
    false
)

ตอนใช้

/mycoords

Client จะอ่านตำแหน่ง Player ปัจจุบัน

⑬ ตอนนี้ Resource มีอะไรแล้ว

โครงสร้าง

my_first_resource/
├── fxmanifest.lua
└── client.lua

Manifest

fx_version 'cerulean'
game 'gta5'

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

client_script 'client.lua'

เพียงเท่านี้ก็เป็น Client-only Resource ที่ใช้งานได้แล้ว

⑭ เพิ่ม server.lua

สร้าง

server.lua

โครงสร้าง

my_first_resource/
├── fxmanifest.lua
├── client.lua
└── server.lua

เพิ่ม Manifest

server_script 'server.lua'

รวมเป็น

fx_version 'cerulean'
game 'gta5'

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

client_script 'client.lua'
server_script 'server.lua'

⑮ server.lua ทำงานที่ไหน

ทำงานบน FXServer

เหมาะกับ

Database
Permissions
Money
Inventory
Server Validation
Player Data
Global State

สิ่งที่ต้องเป็น Authority ไม่ควรโยนไปไว้ Client เพียงเพราะเขียนง่ายกว่า

⑯ ทดสอบ Server Script

ใส่ใน server.lua

print(
    'My first resource server loaded'
)

เมื่อ Resource Start ข้อความนี้ควรปรากฏใน Server Console

จึงสามารถแยกง่าย ๆ ว่า

client.lua
→ F8 / Client

server.lua
→ FXServer Console

⑰ สร้าง Server Command

ใน server.lua

RegisterCommand(
    'serverhello',
    function(source)

        print(
            'Command source:',
            source
        )

    end,
    false
)

ถ้า Player ใช้ Command ค่า source จะเป็น Server ID ของ Player

ส่วนถ้ารันจาก Server Console ค่า Source มี Behavior ที่แตกต่างและควรตรวจตาม Use Case

⑱ source สำคัญอย่างไร

ใน Server Event หรือ Server Command

local src = source

มักหมายถึง Player ที่เป็นต้นทาง

เช่น

local playerName =
    GetPlayerName(src)

แล้ว

print(
    src,
    playerName
)

source เป็นข้อมูลสำคัญมากสำหรับ Server Logic

⑲ Client กับ Server คุยกันอย่างไร

FiveM ใช้ Network Events

พื้นฐาน Client → Server คือ

TriggerServerEvent

ส่วน Server รับด้วย

RegisterNetEvent

ตัวอย่าง Flow

Client
↓
TriggerServerEvent
↓
Network
↓
Server
↓
RegisterNetEvent Handler

⑳ สร้าง Client → Server Event ตัวแรก

ใน client.lua

RegisterCommand(
    'pingserver',
    function()

        TriggerServerEvent(
            'my_first_resource:ping'
        )

    end,
    false
)

จากนั้น Server ต้องมี Handler

㉑ รับ Event ฝั่ง Server

ใน server.lua

RegisterNetEvent(
    'my_first_resource:ping',
    function()

        local src =
            source

        print(
            'Ping from player:',
            src
        )

    end
)

เมื่อ Player พิมพ์

/pingserver

Client จะ Trigger Event ไป Server

แล้ว Server Console จะแสดง Player ID

㉒ ทำไมใช้ชื่อ Event ยาว

แทน

ping

ควรใช้ Namespace เช่น

my_first_resource:ping

ช่วยลดโอกาสชื่อชนกับ Resource อื่น

Resource จริงอาจใช้

garage:storeVehicle
inventory:useItem
job:startMission

หรือ Prefix ที่เป็นชื่อ Resource

㉓ ส่ง Parameter ไป Server

Client

TriggerServerEvent(
    'my_first_resource:hello',
    'FiveM'
)

Server

RegisterNetEvent(
    'my_first_resource:hello',
    function(message)

        local src =
            source

        print(
            src,
            message
        )

    end
)

FiveM จะ Serialize Parameters แล้วส่งผ่าน Network Event

㉔ อย่าเชื่อ Parameter จาก Client

นี่คือหลัก Security ที่ควรเรียนตั้งแต่ Resource แรก

สมมติ Client ส่ง

TriggerServerEvent(
    'shop:buy',
    1
)

ไม่ได้หมายความว่า Server ควรเชื่อราคา 1

Server ควรหา Price จาก Server-side Config หรือ Database เอง

㉕ ตัวอย่าง Event ที่ไม่ควรเขียน

RegisterNetEvent(
    'money:add',
    function(amount)

        AddMoney(
            source,
            amount
        )

    end
)

เพราะ Client สามารถพยายามส่ง

amount = 999999999

ได้

Resource แรกควรเรียน Security Principle ไปพร้อมกับ Syntax

㉖ Server ควรเป็นคนตัดสิน

ตัวอย่างที่ดีกว่า

local Reward =
    500

RegisterNetEvent(
    'mission:complete',
    function()

        local src =
            source

        -- ตรวจ mission state
        -- ตรวจ position
        -- ตรวจ cooldown

        local reward =
            Reward

        -- จ่าย reward
    end
)

Client ขอ Action

Server ตรวจและตัดสินผล

㉗ Server ส่ง Event กลับ Client อย่างไร

ใช้

TriggerClientEvent(
    eventName,
    playerId,
    ...
)

เช่น

TriggerClientEvent(
    'my_first_resource:response',
    src,
    'Hello from server'
)

ฝั่ง Client ต้อง Register Event

㉘ สร้าง Server → Client Event

server.lua

RegisterNetEvent(
    'my_first_resource:ping',
    function()

        local src =
            source

        TriggerClientEvent(
            'my_first_resource:pong',
            src,
            'Pong!'
        )

    end
)

client.lua

RegisterNetEvent(
    'my_first_resource:pong',
    function(message)

        print(
            message
        )

    end
)

㉙ Flow Ping-Pong

ตอน Player ใช้

/pingserver

จะเกิด

Client Command
↓
TriggerServerEvent
↓
Server Handler
↓
TriggerClientEvent
↓
Client Handler
↓
Pong!

นี่เป็นพื้นฐาน Networking ของ FiveM Resource จำนวนมาก

㉚ เพิ่ม config.lua

Resource เริ่มใหญ่ขึ้นควรแยก Configuration

สร้าง

config.lua

โครงสร้าง

my_first_resource/
├── fxmanifest.lua
├── config.lua
├── client.lua
└── server.lua

㉛ เขียน config.lua

Config = {}

Config.Command =
    'helloresource'

Config.Message =
    'My first FiveM resource'

ถ้าทั้ง Client และ Server ใช้ ให้ประกาศ

shared_script 'config.lua'

㉜ Manifest หลังมี Shared Config

fx_version 'cerulean'
game 'gta5'

author 'Your Name'
description 'My first FiveM resource'
version '1.0.0'

shared_script 'config.lua'

client_script 'client.lua'
server_script 'server.lua'

ทั้ง Client และ Server จะโหลด config.lua

แต่จำว่าเป็นคนละ Runtime

㉝ Shared ไม่ใช่ Shared Memory

Client ทำ

Config.Message =
    'Changed by client'

ไม่ได้ทำให้ Server เห็นค่าที่เปลี่ยนโดยอัตโนมัติ

ทั้งสองฝั่งเพียงโหลด Source Code จากไฟล์เดียวกัน

ถ้าต้อง Sync Runtime State ต้องใช้

Events
State Bags
Callbacks
Database

ตาม Requirement

㉞ ใช้ Config กับ Command

client.lua

RegisterCommand(
    Config.Command,
    function()

        print(
            Config.Message
        )

    end,
    false
)

ตอนนี้ชื่อ Command ไม่ Hardcode อยู่ใน Client Logic

แก้ใน config.lua จุดเดียวได้

㉟ ตั้งชื่อ Resource อย่างไรดี

ควร

สั้น
อ่านง่าย
ไม่ซ้ำ
อธิบายหน้าที่

เช่น

com_garage
com_jobs
city_inventory
police_tools

หลีกเลี่ยงชื่อมั่วอย่าง

newscript2-final-fixed-real

เพราะ Resource Name ถูกใช้อ้างใน Exports, Dependencies และ Logs

㊱ ใช้ขีดกลางหรือ underscore

FiveM รองรับชื่อ Resource หลากหลายแบบ แต่ควรเลือก Convention เดียวทั้ง Project

เช่น

my-garage

หรือ

my_garage

แล้วใช้สม่ำเสมอ

โดยเฉพาะเมื่อชื่อ Resource ถูก Hardcode ใน API หรือ NUI

㊲ Resource พร้อมแล้ว Start อย่างไร

ถ้าเพิ่ง Copy Folder เข้า resources/ ขณะที่ Server ทำงานอยู่ ให้ใช้ Console

refresh

คำสั่งนี้จะ Rescan Resource Folder และ Manifests

จากนั้น

ensure my_first_resource

㊳ refresh ทำอะไร

refresh จะ Scan Resource Folder ใหม่และโหลด Resource Manifests

จึงเหมาะเมื่อเพิ่งเพิ่ม Resource ใหม่

เช่น

resources/[local]/my_first_resource

แล้ว FXServer ยังไม่รู้จัก

ให้ใช้

refresh

ก่อน

㊴ ensure ทำอะไร

ensure มี Behavior คือ

Resource ยังไม่ Start
→ Start

Resource Start อยู่
→ Restart

จึงสะดวกมากใน Development

ใช้

ensure my_first_resource

㊵ start ใช้แทน ensure ได้ไหม

ได้ถ้า Resource ยัง Stopped

start my_first_resource

แต่ถ้ากำลังทำงานอยู่ start ไม่ได้มี Behavior เหมือน ensure

ในการตั้ง server.cfg มักนิยม

ensure my_first_resource

㊶ restart ใช้ตอนไหน

หลังแก้ Script สามารถใช้

restart my_first_resource

เพื่อ Stop แล้ว Start Resource ใหม่

ไม่จำเป็นต้อง Restart FXServer ทั้งเครื่องทุกครั้ง

ช่วยให้ Development เร็วขึ้นมาก

㊷ stop ใช้ตอนไหน

ใช้

stop my_first_resource

เมื่อไม่ต้องการให้ Resource ทำงาน

Resource ที่ดีควรรองรับ Stop โดยไม่ทิ้ง

Entity
NUI Focus
Camera
Blip
Runtime State

ที่ไม่ควรค้าง

㊸ เพิ่ม Resource ลง server.cfg

เมื่อทดสอบแล้วต้องการให้ Resource Start ทุกครั้งที่ Server เปิด

เพิ่ม

ensure my_first_resource

ใน server.cfg

ตัวอย่าง

ensure mapmanager
ensure chat

ensure my_first_resource

เมื่อ FXServer Start Resource จะถูก Start ตาม Configuration

㊹ Server Console บอก Started Resource หมายถึงจบไหม

ไม่

คำว่า Resource Started หมายถึง Runtime ถูกโหลดสำเร็จระดับหนึ่ง

ยังต้องทดสอบ Feature จริง

เช่น

Command ทำงานไหม?
Event ทำงานไหม?
Client Error ไหม?
Server Error ไหม?
Restart แล้วทำงานไหม?

Resource อาจ Start ผ่านแต่ Error ตอน Player เรียก Function ได้

㊺ ดู Client Error ที่ไหน

ใช้

F8

เพื่อเปิด FiveM Client Console

Client-side Errors เช่น

attempt to index a nil value
No such export
NUI error
Native error

มักตรวจได้ที่นี่

㊻ Server Error ดูที่ไหน

ดู FXServer Console หรือ txAdmin Console

ตัวอย่าง Error

SCRIPT ERROR

พร้อม Resource และ File/Line ที่เกี่ยวข้อง

ควรอ่าน Error ตั้งแต่บรรทัดแรก ไม่ใช่ Restart Resource ซ้ำอย่างเดียว

㊼ เพิ่ม Debug Print อย่างไร

Client

print(
    '[my_first_resource] client loaded'
)

Server

print(
    '[my_first_resource] server loaded'
)

ช่วยแยกว่าฝั่งใดถูกโหลดจริง

สำหรับ Resource ใหญ่ควรมี Logging Convention ที่ชัดเจน

㊽ ตรวจ Resource Name ใน Runtime

ใช้

local resourceName =
    GetCurrentResourceName()

print(
    resourceName
)

ช่วย Debug กรณี Resource ถูก Rename

และมีประโยชน์ใน Lifecycle Events

㊾ onResourceStart คืออะไร

Resource สามารถรู้ว่าตัวเองเริ่มทำงานเมื่อไร

AddEventHandler(
    'onResourceStart',
    function(resourceName)

        if resourceName ~=
            GetCurrentResourceName() then
            return
        end

        print(
            'Resource started'
        )

    end
)

เหมาะกับ Server Initialization

㊿ onResourceStop สำคัญอย่างไร

Resource ที่สร้าง State หรือ Entity ควร Cleanup

AddEventHandler(
    'onResourceStop',
    function(resourceName)

        if resourceName ~=
            GetCurrentResourceName() then
            return
        end

        print(
            'Resource stopping'
        )

    end
)

ใน Resource ขั้นสูงอาจใช้เพื่อ

Delete temporary entities
Reset NUI
Stop temporary systems
Clear runtime state

51 Client มี Lifecycle Event ด้วยไหม

มี Event ใน Client Context เช่น onClientResourceStart และ onClientResourceStop

ตัวอย่าง

AddEventHandler(
    'onClientResourceStart',
    function(resourceName)

        if resourceName ~=
            GetCurrentResourceName() then
            return
        end

        print(
            'Client resource ready'
        )

    end
)

ช่วยทำ Client Initialization หลัง Resource Start

52 อย่าใช้ CreateThread ถ้าไม่จำเป็น

Resource แรกมักถูกสอนให้เขียน

CreateThread(function()

    while true do
        Wait(0)

        -- code
    end

end)

แต่ไม่ได้หมายความว่าทุก Resource ต้องมี Infinite Loop

ถ้า Logic ทำงานจาก Command หรือ Event ให้ใช้ Event-driven Pattern ได้เลย

ช่วยลด CPU Work

53 ถ้าต้องใช้ Thread ต้องมี Wait

ตัวอย่าง

CreateThread(function()

    while true do

        Wait(1000)

        print(
            'Tick'
        )
    end
end)

อย่าเขียน Infinite Loop โดยไม่มี Yield

while true do
    -- no Wait
end

เพราะสามารถทำให้ Script/Client มีปัญหาอย่างรุนแรง

54 Resource ตัวแรกควรใช้ Framework ไหม

แนะนำให้เริ่ม Standalone ก่อน

เรียน

Resource
Manifest
Client
Server
Commands
Events
Natives

ให้เข้าใจก่อน

จากนั้นจึงเรียน

ESX
QBCore
Qbox
ox_lib

เพราะ Framework ไม่ได้แทนพื้นฐานของ FiveM

55 ทำไม Standalone สำคัญ

ถ้าเริ่มจาก Framework อย่างเดียว ผู้เรียนอาจจำเพียง

ESX.GetPlayerFromId
QBCore.Functions.GetPlayer

แต่ไม่เข้าใจว่า

source
RegisterNetEvent
TriggerClientEvent
Resource
fxmanifest

ทำงานอย่างไร

เมื่อ Framework เปลี่ยนจะ Debug ยากมาก

56 Resource ตัวแรกต้องใช้ Database ไหม

ไม่จำเป็น

สำหรับ Resource แรกควรให้

Command
↓
Client Event
↓
Server Event
↓
Client Response

ทำงานให้ครบก่อน

หลังจากนั้นค่อยเพิ่ม Database

หัวข้อ 451 เป็นต้นไปจะเข้าสู่ Database โดยตรง

57 Resource ตัวแรกต้องใช้ OneSync ไหม

Resource ง่าย ๆ ที่เป็น Command/Event ไม่จำเป็นต้องประกาศ /onesync

อย่าเพิ่ม

dependency '/onesync'

เพียงเพราะเห็น Resource อื่นใส่

เพิ่มเมื่อ Resource ต้องพึ่ง State Awareness เช่น

Routing Bucket
Server-side Entity State
OneSync-specific systems

จริง ๆ

58 ตัวอย่าง Resource ตัวแรกฉบับสมบูรณ์

โครงสร้าง

resources/
└── [local]/
    └── com_first/
        ├── fxmanifest.lua
        ├── config.lua
        ├── client.lua
        └── server.lua

fxmanifest.lua

fx_version 'cerulean'
game 'gta5'

author 'comsiam'
description 'My first FiveM resource'
version '1.0.0'

shared_script 'config.lua'

client_script 'client.lua'
server_script 'server.lua'

config.lua

Config = {}

Config.Command =
    'helloresource'

Config.WelcomeMessage =
    'My first resource is working'

client.lua

AddEventHandler(
    'onClientResourceStart',
    function(resourceName)

        if resourceName ~=
            GetCurrentResourceName() then
            return
        end

        print(
            '[com_first] client started'
        )

    end
)

RegisterCommand(
    Config.Command,
    function()

        TriggerServerEvent(
            'com_first:hello'
        )

    end,
    false
)

RegisterNetEvent(
    'com_first:welcome',
    function(message)

        print(
            message
        )

    end
)

server.lua

AddEventHandler(
    'onResourceStart',
    function(resourceName)

        if resourceName ~=
            GetCurrentResourceName() then
            return
        end

        print(
            '[com_first] server started'
        )

    end
)

RegisterNetEvent(
    'com_first:hello',
    function()

        local src =
            source

        local playerName =
            GetPlayerName(src)
            or ('Player %s')
                :format(src)

        print(
            ('Hello request from %s')
                :format(
                    playerName
                )
        )

        TriggerClientEvent(
            'com_first:welcome',
            src,
            Config.WelcomeMessage
        )

    end
)

59 วิธีติดตั้ง Resource ตัวอย่าง

นำ Folder

com_first

ไปไว้ที่

resources/[local]/com_first

ถ้า Server เปิดอยู่แล้ว ใช้

refresh

จากนั้น

ensure com_first

เข้าเกมแล้วพิมพ์

/helloresource

ควรเกิด Flow

Player Command
↓
client.lua
↓
TriggerServerEvent
↓
server.lua
↓
หา Player Name
↓
TriggerClientEvent
↓
client.lua
↓
แสดง Welcome Message

เมื่อระบบนี้ทำงาน แปลว่าคุณเข้าใจพื้นฐาน Resource, Client, Server และ Network Event ครบวงจรแล้ว

⑥⓪ Checklist ก่อนบอกว่า Resource ตัวแรกสำเร็จ

ตรวจให้ครบ

① Folder อยู่ใน resources หรือไม่?
② fxmanifest.lua อยู่ Root หรือไม่?
③ ชื่อไฟล์ถูกต้องหรือไม่?
④ fx_version เป็น cerulean หรือไม่?
⑤ game เป็น gta5 หรือไม่?
⑥ client.lua มีจริงหรือไม่?
⑦ server.lua มีจริงหรือไม่?
⑧ config.lua มีจริงหรือไม่?
⑨ Manifest Paths ถูกหรือไม่?
⑩ refresh แล้วหรือยัง?
⑪ ensure ชื่อ Resource ถูกหรือไม่?
⑫ Server Console มี Error หรือไม่?
⑬ F8 มี Error หรือไม่?
⑭ Client Command ทำงานหรือไม่?
⑮ TriggerServerEvent ทำงานหรือไม่?
⑯ RegisterNetEvent ฝั่ง Server รับได้หรือไม่?
⑰ source ถูกต้องหรือไม่?
⑱ TriggerClientEvent ส่งกลับถูก Player หรือไม่?
⑲ Client รับ Response ได้หรือไม่?
⑳ Restart Resource แล้วยังทำงานหรือไม่?
㉑ Client Input ถูกมองว่าไม่เชื่อถือหรือไม่?
㉒ Event Name มี Namespace หรือไม่?
㉓ Infinite Loop มี Wait หรือไม่?
㉔ Resource Stop มี Cleanup หากจำเป็นหรือไม่?
㉕ พร้อมเพิ่ม Feature ถัดไปหรือยัง?

ปัญหาที่พบบ่อยตอนสร้าง Resource FiveM ตัวแรก

Couldn't find resource

ตรวจว่า Folder อยู่ใน resources/

จากนั้น

refresh

แล้ว

ensure resource_name

อีกครั้ง

Resource ไม่มี fxmanifest.lua

ตรวจชื่อไฟล์ว่าเป็น

fxmanifest.lua

จริง

ไม่ใช่

fxmanifest.lua.txt

Failed to load script

ตรวจ Path ใน Manifest

เช่น

client_script 'client.lua'

แต่ File จริงอยู่

client/main.lua

ก็ต้องเปลี่ยน Manifest ให้ตรง

Command ไม่ทำงาน

ตรวจ

Resource Start หรือยัง?
client.lua ถูกโหลดไหม?
RegisterCommand ชื่อถูกไหม?
F8 มี Error หรือไม่?

TriggerServerEvent ไม่ทำงาน

ตรวจว่า Server มี

RegisterNetEvent(
    'ชื่อเดียวกัน',
    function()
    end
)

ชื่อ Event ต้องตรงทุกตัวอักษร

Server ส่งกลับแล้ว Client ไม่รับ

ตรวจว่า Client Register

RegisterNetEvent(
    'ชื่อ event',
    function(...)
    end
)

และ TriggerClientEvent() ใช้ Player ID ที่ถูกต้อง

แก้ Script แล้วไม่เปลี่ยน

ใช้

restart resource_name

หรือ

ensure resource_name

ตามสถานะ Resource

เพิ่ม Resource ใหม่แล้ว Server ไม่เห็น

ใช้

refresh

เพื่อ Rescan Resources

คำถามที่พบบ่อยเกี่ยวกับการสร้าง Resource FiveM

Resource FiveM ตัวแรกต้องมีไฟล์อะไร

ขั้นต่ำควรมี

fxmanifest.lua

และ Script อย่างน้อยหนึ่งไฟล์ตามระบบที่ต้องการ

Manifest พื้นฐานเขียนอย่างไร

fx_version 'cerulean'
game 'gta5'

จากนั้นเพิ่ม Client/Server Scripts

Client Script ประกาศอย่างไร

client_script 'client.lua'

Server Script ประกาศอย่างไร

server_script 'server.lua'

Shared Config ประกาศอย่างไร

shared_script 'config.lua'

Resource ควรอยู่ที่ไหน

โดยทั่วไปอยู่ใน resources/ ของ Server Data Directory

[local] จำเป็นไหม

ไม่บังคับ แต่เหมาะสำหรับจัด Resource ที่เขียนเอง

เพิ่ม Resource ใหม่ต้อง Restart Server ไหม

ไม่จำเป็นเสมอไป หาก Server กำลังทำงานสามารถใช้ refresh แล้ว Start/Ensure Resource ได้

refresh คืออะไร

Rescan Resource Folder และ Manifest Files

ensure คืออะไร

ถ้า Resource ยังไม่ Start จะ Start และถ้ากำลังทำงานจะ Restart

start ต่างจาก ensure อย่างไร

start ใช้ Start Resource ที่ Stopped ส่วน ensure ทำให้ Resource อยู่ในสถานะ Started โดย Restart หากกำลังรันอยู่

แก้ Code แล้วต้องทำอะไร

โดยทั่วไปใช้

restart resource_name

เพื่อ Reload Resource

Client Error ดูตรงไหน

ดู FiveM F8 Console

Server Error ดูตรงไหน

ดู FXServer/txAdmin Console

Client ส่งข้อมูลให้ Server อย่างไร

ใช้

TriggerServerEvent(...)

Server รับอย่างไร

ใช้

RegisterNetEvent(...)

Server ส่งกลับ Client อย่างไร

ใช้

TriggerClientEvent(...)

Client Input เชื่อถือได้ไหม

ไม่ ควร Validate ทุกข้อมูลที่มีผลกับ Gameplay, Economy หรือ Permission ฝั่ง Server

Resource แรกควรใช้ ESX หรือ QBCore เลยไหม

ไม่จำเป็น การเริ่ม Standalone ช่วยให้เข้าใจ FiveM Core APIs ก่อน

Resource แรกต้องใช้ Database ไหม

ไม่จำเป็น

Resource แรกต้องใช้ OneSync ไหม

ไม่จำเป็นถ้าไม่ได้ใช้ Feature ที่พึ่ง State Awareness

lua54 'yes' ต้องใส่ไหม

ไม่ ปัจจุบัน Lua Scripts ใช้ Lua 5.4 และ Directive นี้ Deprecated แล้ว

สรุปวิธีสร้าง Resource FiveM ตัวแรก

วิธีสร้าง Resource FiveM ตัวแรกสามารถสรุปเป็น

① สร้าง Resource Folder
↓
② สร้าง fxmanifest.lua
↓
③ สร้าง client.lua
↓
④ สร้าง server.lua
↓
⑤ ประกาศ Files ใน Manifest
↓
⑥ refresh
↓
⑦ ensure Resource
↓
⑧ ทดสอบ Client
↓
⑨ ทดสอบ Server
↓
⑩ ทดสอบ Network Events

Manifest เริ่มต้นใช้

fx_version 'cerulean'
game 'gta5'

client_script 'client.lua'
server_script 'server.lua'

Client ส่ง Event ไป Server

TriggerServerEvent(
    'my_resource:hello'
)

Server รับ

RegisterNetEvent(
    'my_resource:hello',
    function()

        local src =
            source

    end
)

และส่งผลกลับ

TriggerClientEvent(
    'my_resource:response',
    src,
    'Hello'
)

นี่คือวงจรพื้นฐานที่ Resource FiveM จำนวนมากใช้ แม้ Resource ระดับใหญ่จะมีหลายร้อยไฟล์ หลักพื้นฐานก็ยังเป็น

Manifest
Client
Server
Events
State
Dependencies

เหมือนเดิม

สำหรับผู้ที่เริ่มเรียน FiveM Developer กับ comsiam จุดสำคัญไม่ได้อยู่ที่การสร้าง Script ใหญ่ตั้งแต่ Resource แรก แต่คือทำให้ Resource เล็ก ๆ ตัวหนึ่ง Start, Stop, Restart และสื่อสาร Client ↔ Server ได้อย่างถูกต้องก่อน

หลักสำคัญจาก comsiam คือ Client ควรทำสิ่งที่เกี่ยวกับเครื่องผู้เล่น ส่วน Server ควรเป็นผู้ตัดสินข้อมูลสำคัญและตรวจทุก Request ที่มาจาก Client หากเข้าใจหลักนี้ตั้งแต่ Resource แรก การพัฒนา Garage, Jobs, Inventory หรือ Framework Script ภายหลังจะง่ายขึ้นมาก

หัวข้อถัดไปคือ FiveM Resource Folder จัดโครงสร้างอย่างไร ซึ่งจะต่อยอดจาก Resource ตัวแรกไปสู่การแบ่ง client/, server/, shared/, modules/, html/, stream/ และการออกแบบ Folder สำหรับ Resource ขนาดใหญ่ให้ Maintain ง่าย

Comments

Popular posts from this blog

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

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

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