FiveM Entity Lockdown คืออะไร ป้องกัน Client Spawn Entity อย่างไร

 FiveM Entity Lockdown คือระบบของ OneSync ที่ให้ Server กำหนดได้ว่า Client สามารถสร้าง Networked Entity เช่น Vehicle, Ped หรือ Object ภายใน Routing Bucket ได้มากน้อยแค่ไหน โดยสามารถใช้ร่วมกับ Server-created Entities เพื่อทำให้ Server เป็นผู้ควบคุมการ Spawn Entity มากขึ้น

ตัวอย่างเช่นกำหนด Bucket 10 เป็น strict

SetRoutingBucketEntityLockdownMode(
    10,
    'strict'
)

แล้วย้าย Player เข้า Bucket นั้น

SetPlayerRoutingBucket(
    source,
    10
)

เมื่อเป็น strict เอกสาร Cfx.re ปัจจุบันระบุว่า Client จะไม่สามารถสร้าง Entity ใน Bucket นั้นได้

แนวคิดจึงเปลี่ยนจาก

Client
↓
Spawn Vehicle เอง
↓
Server รับรู้ภายหลัง

เป็น

Client
↓
ขอ Spawn Vehicle
↓
Server ตรวจสอบ
↓
Server อนุญาตหรือปฏิเสธ
↓
Server สร้าง Vehicle
↓
OneSync Sync ไป Client

นี่เป็นแนวทางสำคัญสำหรับ Server ที่ต้องการลดปัญหา Client Spawn รถ, Ped หรือ Object โดยไม่ได้รับอนุญาต

แต่ต้องเข้าใจว่า Entity Lockdown ไม่ใช่ Anti-Cheat สำเร็จรูป และไม่ได้แทน Server-side Validation ของ Money, Inventory, Permission หรือ Network Events

① FiveM Entity Lockdown คืออะไร

Entity Lockdown คือ Policy ระดับ Routing Bucket ที่ควบคุมการสร้าง Entity จาก Client

ตัวอย่าง

Bucket 0
→ inactive

Bucket 100
→ strict

Bucket 200
→ relaxed

แต่ละ Instance สามารถใช้ Policy ต่างกันได้

นี่ทำให้ Server ไม่จำเป็นต้องใช้ Security Policy เดียวกันกับทุก Gameplay Mode

② Entity Lockdown อยู่ในระบบอะไร

Entity Lockdown เป็น Feature ของ

OneSync
+
Routing Buckets

ดังนั้นก่อนใช้ต้องมี OneSync/State Awareness ทำงานอยู่

ตัวอย่าง server.cfg

set onesync on

Resource ที่ต้องใช้ OneSync โดยตรงยังสามารถประกาศ

dependency '/onesync'

ใน fxmanifest.lua

③ Entity Lockdown ป้องกันอะไร

เป้าหมายหลักคือจำกัด

Client-authored Entities

เช่น Client พยายามสร้าง

  • Vehicle

  • Ped

  • Object

ผ่าน Game/Script Networking

Server สามารถกำหนด Bucket ให้เข้มงวดขึ้นเพื่อไม่อนุญาตการสร้าง Entity ลักษณะนั้น

④ Entity Lockdown ป้องกันรถโกง Spawn ได้ไหม

ช่วยลดช่องทาง Client-created Network Entities ได้อย่างมาก โดยเฉพาะเมื่อใช้ strict

ตัวอย่างคนโกงพยายามสร้าง

Adder
Tank
Helicopter
Random Objects
NPC

ภายใน Bucket ที่เป็น strict

Network Entity Creation จาก Client จะถูก Block ตาม Policy

แต่ยังต้องมี Security ชั้นอื่นสำหรับ Events และ Server Actions

⑤ Function หลักคืออะไร

ใช้

SetRoutingBucketEntityLockdownMode(
    bucketId,
    mode
)

ตัวอย่าง

SetRoutingBucketEntityLockdownMode(
    100,
    'strict'
)

Parameter คือ

bucketId
→ Routing Bucket

mode
→ Lockdown Policy

⑥ Entity Lockdown Mode มีอะไรบ้าง

เอกสาร OneSync ปัจจุบันระบุ Mode หลัก

full
strict
relaxed
inactive

แต่ full มีข้อจำกัดเฉพาะ FiveM บน GTAV Enhanced

สำหรับ Server ทั่วไป Concept ที่เจอบ่อยที่สุดคือ

strict
relaxed
inactive

⑦ strict คืออะไร

strict เป็น Mode ที่เข้มงวดมาก

เอกสาร Cfx.re ระบุว่า

strict
→ Clients สร้าง Entities ไม่ได้

ดังนั้น Entity ที่ต้องการใช้ใน Bucket นี้ควรให้ Server เป็นผู้สร้าง

เหมาะกับระบบแบบ

Client Request
↓
Server Validate
↓
Server Spawn

⑧ relaxed คืออะไร

เอกสารปัจจุบันอธิบาย relaxed ว่า Block เฉพาะ Script-owned Entities ที่ Client สร้าง

จึงเปิดกว้างกว่า strict

เหมาะกับ Server ที่ต้องการเพิ่มข้อจำกัดบางส่วน แต่ยังมี Resource ที่ต้องพึ่ง Client Entity Creation อยู่

⑨ inactive คืออะไร

inactive หมายถึง Entity Lockdown ไม่ทำงานในลักษณะที่จำกัด Client Creation

Concept คือ

Client
→ สามารถสร้าง Entity ได้ตามระบบปกติ

เหมาะกับ Compatibility สูง แต่ Server ต้องพึ่ง Security Layer อื่นมากขึ้น

⑩ full คืออะไร

เอกสาร OneSync ปัจจุบันระบุ Mode

full

สำหรับ FiveM บน GTAV Enhanced เท่านั้น

Mode นี้เพิ่มการปิด Dummy Object Creation ตามระบบ Enhanced

หากไม่ได้ใช้งาน GTAV Enhanced ไม่ควรนำ Mode นี้มาใช้โดยไม่ตรวจ Environment

⑪ Mode ไหนปลอดภัยที่สุด

ถ้ามองเฉพาะการจำกัด Client-created Entity

strict

เป็นตัวเลือกที่เข้มมากสำหรับ FiveM ปกติ

แต่คำว่า “ปลอดภัยที่สุด” ไม่ได้หมายความว่าเปิดแล้ว Resource ทุกตัวจะทำงานได้

Compatibility ต้องตรวจด้วย

⑫ ทำไม strict อาจทำ Script พัง

เพราะ FiveM Resource จำนวนหนึ่งยังใช้ Client เป็นผู้สร้าง Entity

เช่น

CreateVehicle(...)
CreatePed(...)
CreateObject(...)

จาก Client

ถ้า Bucket เป็น strict

Entity Creation เหล่านี้อาจถูก Block

ดังนั้นก่อนเปิด Production ต้อง Audit Resource

⑬ Resource ประเภทไหนมักได้รับผล

ตัวอย่าง

  • Garage

  • Vehicle Shop

  • Job Vehicle

  • NPC Script

  • Prop System

  • Housing

  • Furniture

  • Carry Objects

  • Police Objects

  • Mechanic Props

ถ้า Resource เหล่านี้ Spawn Network Entity จาก Client ต้องตรวจ Architecture ก่อนใช้ strict

⑭ วิธีตรวจว่า Resource Spawn Entity ฝั่งไหน

ค้นหา Code เช่น

CreateVehicle
CreatePed
CreateObject
CreateObjectNoOffset

จากนั้นตรวจว่าอยู่ใน

client.lua

หรือ

server.lua

อย่าดูแค่ชื่อ Function เพราะ FiveM มี Client/Server Native Variants และ RPC Behavior ต่างกัน

⑮ Architecture ที่เหมาะกับ strict

แนวทางที่ดีคือ

Client
↓
Request
↓
Server
↓
Validation
↓
Server-side Entity Creation
↓
State Bag / Network ID
↓
Client

Client ทำหน้าที่ขอ

Server ทำหน้าที่ตัดสินและสร้าง

⑯ ตัวอย่าง Vehicle Spawn แบบเดิม

Client

local vehicle =
    CreateVehicle(
        model,
        x,
        y,
        z,
        heading,
        true,
        true
    )

ถ้า Server ใช้ Strict Lockdown Client-authored Entity แบบนี้อาจถูก Block

Resource จึงต้องปรับ Architecture หาก Vehicle ต้อง Network

⑰ ตัวอย่าง Spawn ผ่าน Server

Client

TriggerServerEvent(
    'garage:requestVehicle',
    vehicleId
)

Server

RegisterNetEvent(
    'garage:requestVehicle',
    function(vehicleId)

        local src = source

        -- validate vehicleId
        -- validate ownership
        -- validate garage
        -- validate cooldown

    end
)

หลัง Validation จึงสร้างรถ

⑱ Server-created Vehicle ใช้อะไร

หนึ่งใน API ที่ Cfx.re แนะนำคือ

CreateVehicleServerSetter(
    modelHash,
    vehicleType,
    x,
    y,
    z,
    heading
)

ตัวอย่าง

local vehicle =
    CreateVehicleServerSetter(
        joaat('sultan'),
        'automobile',
        215.0,
        -810.0,
        30.0,
        157.0
    )

จากนั้นนำ Entity เข้า Bucket เดียวกับ Player

⑲ Vehicle ต้องย้ายเข้า Bucket ด้วย

สมมติ Player อยู่

Bucket 100

หลัง Server สร้าง Vehicle แล้วควร

SetEntityRoutingBucket(
    vehicle,
    100
)

ไม่เช่นนั้น Player กับ Vehicle อาจอยู่คนละ Routing Context

⑳ ตัวอย่าง strict Bucket แบบพื้นฐาน

local bucket = 100

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

SetPlayerRoutingBucket(
    source,
    bucket
)

ตอนนี้ Player อยู่ใน Instance ที่ Client Entity Creation ถูกจำกัดอย่างเข้มงวด

㉑ ทำไม Cfx.re Example ปิด Population ด้วย

ถ้า Bucket เป็น strict และต้องการ Controlled Environment การปิด Population ช่วยไม่ให้ระบบ Ambient Population สร้างสิ่งที่ไม่ต้องการใน Instance

ใช้

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

เหมาะกับ

  • Character Selection

  • Mission

  • Private Lobby

  • Training

  • Controlled Scene

㉒ strict ต้องปิด Population เสมอไหม

ไม่จำเป็นเสมอไป

Entity Lockdown กับ Population เป็นคนละ Setting

Lockdown
→ Client Entity Creation

Population
→ Ambient Population Management

สามารถเลือกตาม Gameplay

แต่ Controlled Mission มักปิด Population เพื่อให้ World State Predictable มากขึ้น

㉓ Entity Lockdown ใช้ได้เฉพาะ Bucket 0 ไหม

ไม่

จุดเด่นคือกำหนดต่อ Routing Bucket

เช่น

SetRoutingBucketEntityLockdownMode(
    0,
    'inactive'
)

SetRoutingBucketEntityLockdownMode(
    100,
    'strict'
)

SetRoutingBucketEntityLockdownMode(
    200,
    'relaxed'
)

แต่ละ World/Instance มี Policy ต่างกันได้

㉔ Main World ควร strict ไหม

ขึ้นกับ Resource Architecture ทั้ง Server

ถ้า Server Resources ทั้งหมดรองรับ Server-created Entity และไม่มี Feature ที่จำเป็นต้องสร้าง Network Entity จาก Client ก็สามารถพิจารณา Policy ที่เข้มได้

แต่การเปิด strict ใน Bucket 0 โดยไม่ Audit Resources ก่อนอาจทำให้ระบบจำนวนมากพังพร้อมกัน

㉕ เริ่มจาก Private Bucket ดีกว่าไหม

สำหรับการ Migration Server เก่า วิธีที่ปลอดภัยกว่าคือเริ่มทดลองกับ Controlled Instance

เช่น

Character Selection
Mission Test
Training Bucket

ตั้งเป็น strict

แล้วตรวจ Resource Behavior

เมื่อ Architecture พร้อมค่อยขยาย Policy

㉖ Entity Lockdown เป็น Global Setting ไหม

ไม่ใน API นี้

เป็น

Per Routing Bucket

จึงสามารถกำหนด Security Context ได้ละเอียด

นี่เป็นข้อดีมากสำหรับ Server ที่มีหลาย Gameplay Systems

㉗ Client รู้ Bucket ID แล้วหลบ Lockdown ได้ไหม

ไม่ควรพึ่ง Bucket ID เป็น Security Secret

Server เป็นผู้กำหนดว่า Player อยู่ Bucket ไหน

Client ไม่ควรสามารถเปลี่ยน Bucket เองตามใจ

ดังนั้น Security Flow คือ

Server controls Bucket
+
Server controls Lockdown Mode

ไม่ใช่ซ่อนหมายเลข Bucket

㉘ อย่าเปิด Event ให้ Client ตั้ง Bucket เอง

ตัวอย่างอันตราย

RegisterNetEvent(
    'bucket:set',
    function(bucket)

        SetPlayerRoutingBucket(
            source,
            bucket
        )

    end
)

Client อาจขอเข้า Bucket ที่

  • relaxed

  • inactive

  • Private

  • Admin

  • Mission อื่น

แล้วหลีกเลี่ยง Policy ที่ตั้งใจไว้

㉙ วิธีที่ถูกต้อง

Client ส่ง Business Request

TriggerServerEvent(
    'mission:join',
    missionId
)

Server

ตรวจ Mission
↓
ตรวจ Membership
↓
หา Bucket
↓
Set Player Bucket

Client ไม่ได้เป็นคนเลือก Routing Security Policy

㉚ strict ป้องกัน TriggerServerEvent โกงไหม

ไม่

นี่เป็นคนละ Layer

Entity Lockdown ป้องกันด้าน

Client Entity Creation

แต่ Network Event อย่าง

TriggerServerEvent(
    'money:add',
    999999
)

ยังต้อง Secure ด้วย Server Validation

ดังนั้นต้องมีทั้ง

Entity Lockdown
+
Secure Events

㉛ strict ป้องกัน GiveMoney Cheat ไหม

ไม่โดยตรง

ถ้า Serverมี Event

RegisterNetEvent(
    'reward',
    function(amount)

        AddMoney(
            source,
            amount
        )

    end
)

คนโกงยังสามารถพยายาม Abuse Event ได้

Entity Lockdown ไม่เกี่ยวกับ Economy Validation

㉜ strict ป้องกัน Spawn จาก Server Event ที่ไม่ปลอดภัยไหม

ไม่

สมมติ Serverมี

RegisterNetEvent(
    'spawn:anyVehicle',
    function(model)

        CreateVehicleServerSetter(
            joaat(model),
            'automobile',
            ...
        )

    end
)

แม้ Bucket เป็น strict

Client ยังสามารถพยายาม Trigger Event นี้ได้

และ Server เป็นผู้สร้าง Entity ให้เอง

ดังนั้น Event ต้องมี

  • Permission

  • Model Allowlist

  • Cooldown

  • Position Validation

  • State Validation

ด้วย

㉝ Entity Lockdown ไม่แทน Allowlist

ถ้า Client ขอ Vehicle

rhino
lazer
adder

Server ต้องมี Allowlist

local AllowedVehicles = {
    sultan = 'automobile',
    blista = 'automobile'
}

แล้วตรวจ

local vehicleType =
    AllowedVehicles[model]

if not vehicleType then
    return
end

ก่อน Spawn

㉞ Model ควรมาจาก Server หรือ Client

ถ้าระบบรู้ล่วงหน้าว่าจะ Spawn รุ่นไหน ให้ Serverกำหนดเองจะดีที่สุด

ตัวอย่าง Mission

ไม่จำเป็นต้อง Client ส่ง

model = sultan

ถ้า Config ฝั่ง Serverรู้อยู่แล้ว

local model =
    MissionConfig.vehicle

ลด Untrusted Input

㉟ Entity Lockdown กับ Vehicle Shop

Flow ที่ดี

Player ซื้อรถ
↓
Server ตรวจ Account
↓
Server ตรวจ Database
↓
สร้าง Vehicle Record
↓
Server Create Vehicle
↓
Set Routing Bucket
↓
Set State Bag
↓
ส่ง Network ID

Client ไม่ต้อง Spawn Network Vehicle เอง

㊱ Entity Lockdown กับ Garage

Client

ขอเบิกรถ ID 521

Server ตรวจ

รถมีจริงไหม?
เจ้าของตรงไหม?
รถถูกเก็บอยู่ไหม?
Garage ถูกต้องไหม?
Player อยู่ใกล้ Garage ไหม?
Cooldown ผ่านไหม?

แล้วจึง Create Entity

นี่เป็น Architecture ที่เข้ากับ strict ได้ดี

㊲ Entity Lockdown กับ Job Vehicle

Serverรู้ Job ของ Player อยู่แล้ว

Flow

Client Request Job Vehicle
↓
Server ตรวจ Job
↓
ตรวจ Duty
↓
ตรวจ Grade
↓
Server เลือก Model
↓
Create Vehicle

Client ไม่ควรส่ง

job = police
grade = 10
model = whatever

แล้ว Serverเชื่อทั้งหมด

㊳ Entity Lockdown กับ Props

ระบบ Police อาจสร้าง

  • Cone

  • Barrier

  • Spike Strip

แทนให้ Client Create Object แบบ Networked โดยตรง

Client สามารถส่ง

ขอวาง cone

Serverตรวจ

Job
Duty
Position
Rate Limit
จำนวน Props ที่วางแล้ว

แล้ว Serverสร้าง Object

ช่วยควบคุม Object Spam ได้มากขึ้น

㊴ ต้อง Rate Limit Entity Spawn ไหม

ควรสำหรับ Event ที่สามารถสร้าง Entity

แม้ Serverตรวจ Model แล้ว แต่ Client อาจ Spam

100 Requests / second

จน Serverสร้าง Entityจำนวนมาก

ดังนั้นควรมี

Cooldown
Rate Limit
Per-player Entity Limit
Global Limit

ตามระบบ

㊵ ตัวอย่าง Spawn Cooldown

local cooldowns = {}

local function canSpawn(src)

    local now =
        os.time()

    local last =
        cooldowns[src] or 0

    if now - last < 5 then
        return false
    end

    cooldowns[src] =
        now

    return true
end

ก่อน Spawn

if not canSpawn(src) then
    return
end

เป็นเพียง Pattern เบื้องต้น

㊶ จำกัดจำนวน Entity ต่อ Player

สามารถเก็บ

local PlayerEntities = {}

ตัวอย่าง

PlayerEntities[src] =
    PlayerEntities[src] or {}

ก่อน Spawn ตรวจ

if #PlayerEntities[src]
    >= 5 then

    return
end

ช่วยลด Spam แม้ Request ผ่าน Cooldown

㊷ ต้อง Cleanup Entity ด้วย

Security ไม่ควรจบตอน Spawn

ต้องคิด Lifecycle

Spawn
↓
Use
↓
Mission End
↓
Delete

ถ้า Player Spawn ได้ทีละคันแต่รถเก่าไม่เคยถูกลบ Server ก็ยังสะสม Entity ต่อไปได้

㊸ playerDropped ต้อง Cleanup ไหม

สำหรับ Temporary Entities ควรพิจารณา

AddEventHandler(
    'playerDropped',
    function()

        local src =
            source

        -- cleanup temporary entities

    end
)

อย่าปล่อย Job Vehicles หรือ Mission Props ค้างหลัง Player ออกจาก Server

㊹ Entity Lockdown กับ Entity Ownership

สองระบบนี้ไม่เหมือนกัน

Entity Lockdown
→ ใครสามารถ Author/Create Entity

ส่วน

Entity Ownership
→ Client ใดกำลังควบคุม Network Simulation

แม้ Vehicle ถูก Serverสร้างภายใต้ Strict Bucket

Client ก็ยังสามารถเป็น Network Owner ในภายหลังได้

㊺ strict แปลว่า Client ไม่มี Entity Control เลยไหม

ไม่

strict จำกัด Entity Creation

ไม่ได้หมายความว่า Client จะไม่เป็น Network Owner ของ Server-created Entity

เมื่อ Vehicle ถูก Sync ไป Client ระบบ OneSync Ownership ยังทำงานตามปกติ

ต้องแยก

Creation Authority

ออกจาก

Network Simulation Ownership

㊻ Server-created Vehicle ยังขับได้ไหม

ได้ตาม Gameplay

Server สร้าง Vehicle ไม่ได้หมายความว่า Client ใช้ Vehicle ไม่ได้

Player ยังสามารถ

  • เข้า

  • ขับ

  • Interact

  • รับ Network Ownership

ตามระบบ FiveM

Strict Lockdown เพียงป้องกันไม่ให้ Client Author Entity Creation เอง

㊼ NetworkRequestControlOfEntity ยังเกี่ยวไหม

เกี่ยวกับ Existing Entity Control

ไม่ใช่ Entity Creation

ดังนั้นแม้ strict Client อาจยังมี Network Control Behavior กับ Entities ที่มีอยู่ตาม OneSync

Server Security ยังสามารถพิจารณา

sv_filterRequestControl

เพื่อจำกัด Control Requests เพิ่มเติม

㊽ Entity Lockdown กับ sv_filterRequestControl ต่างกันอย่างไร

จำง่าย ๆ

Entity Lockdown
→ ใครสร้าง Entity ได้
sv_filterRequestControl
→ Client ขอ Control Entity ได้แค่ไหน

ใช้แก้คนละปัญหา

Server Security ระดับสูงอาจใช้ทั้งสองร่วมกัน

㊾ Entity Lockdown กับ State Bag

Server-created Entity สามารถมี State Bag

Entity(vehicle).state:set(
    'garage:owner',
    src,
    true
)

หรือ

Entity(vehicle).state:set(
    'mission:id',
    missionId,
    true
)

ช่วยส่ง Runtime State ไป Relevant Clients

แต่ State Bag ไม่ใช่ Permission System โดยอัตโนมัติ

㊿ sv_stateBagStrictMode ใช้ร่วมได้ไหม

ได้ใน Architecture ที่ Resource รองรับ

set sv_stateBagStrictMode true

ตามเอกสารปัจจุบันจะทำให้เฉพาะ Server สามารถแก้ State Bags ได้

ดังนั้นสามารถมีแนวคิด

Entity Creation
→ Server only ผ่าน strict

State Bag Writing
→ Server only ผ่าน strict mode

ทำให้ Server Authority แข็งแรงขึ้น

แต่ต้อง Audit Resource Compatibility ก่อน

51 Controlled Mission Architecture

ตัวอย่าง Mission แบบควบคุมเข้ม

Bucket 100
↓
Entity Lockdown = strict
Population = false

Player
↓
Request Mission

Server
↓
Validate
↓
Create Vehicle
↓
Create Peds
↓
Create Objects
↓
Set Bucket
↓
Set State Bags

Client ทำหน้าที่แสดงผลและควบคุม Gameplay ที่ Serverอนุญาต

52 Character Selection ควรใช้ strict ไหม

เป็น Use Case ที่เหมาะมาก

Character Selection มักต้องการ

ไม่มี Traffic
ไม่มี Random NPC
ไม่มี Client Spawn

จึงสามารถตั้ง

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

เพื่อให้ Environment ควบคุมง่าย

53 Private Lobby ใช้ strict ได้ไหม

ได้เช่นกัน

ถ้า Lobby ไม่ต้องการ Client-created Entities

Lobby
↓
strict
↓
population off

แล้ว Serverสร้างเฉพาะ Entity ที่ Lobby ต้องการ

ช่วยลด State ที่ไม่แน่นอน

54 Entity Lockdown กับ Interior

Lockdown Policy ผูกกับ Routing Bucket

แต่ต้องจำว่า Cfx.re ไม่แนะนำ Routing Buckets เป็น Solution ทั่วไปสำหรับ Interior

ดังนั้นอย่าสร้าง Bucket ใหม่สำหรับทุก Interior เพียงเพื่อใช้ Lockdown โดยไม่พิจารณา Interior Architecture

55 Debug ว่า Client Spawn ถูก Block หรือไม่

สร้าง Test Bucket

Server

RegisterCommand(
    'lockdown',
    function(source)

        if source <= 0 then
            return
        end

        local bucket =
            9000

        SetRoutingBucketEntityLockdownMode(
            bucket,
            'strict'
        )

        SetRoutingBucketPopulationEnabled(
            bucket,
            false
        )

        SetPlayerRoutingBucket(
            source,
            bucket
        )

    end,
    true
)

จากนั้นทดสอบ Resource ที่ Client Spawn Entity

อย่าทดลองบน Production Main Bucket ก่อนรู้ผลกระทบ

56 Command กลับ Main World

RegisterCommand(
    'unlocktest',
    function(source)

        if source <= 0 then
            return
        end

        SetPlayerRoutingBucket(
            source,
            0
        )

    end,
    true
)

ช่วยให้ Admin ออกจาก Test Bucket ได้

อย่าลืม Cleanup Test Entities ด้วย

57 ตรวจ Player Bucket ก่อน Spawn

Server Event

local bucket =
    GetPlayerRoutingBucket(
        src
    )

จากนั้นใช้ Bucket นี้กับ Entity

SetEntityRoutingBucket(
    vehicle,
    bucket
)

ไม่ควรให้ Client ส่ง Bucket ID มาเอง

58 ตัวอย่าง Secure Server Vehicle Spawn

local AllowedVehicles = {
    sultan = 'automobile',
    blista = 'automobile'
}

local cooldowns = {}

RegisterNetEvent(
    'vehicle:requestSpawn',
    function(model)

        local src =
            source

        if type(model)
            ~= 'string' then
            return
        end

        local vehicleType =
            AllowedVehicles[model]

        if not vehicleType then
            return
        end

        local now =
            os.time()

        local last =
            cooldowns[src] or 0

        if now - last < 5 then
            return
        end

        cooldowns[src] =
            now

        local ped =
            GetPlayerPed(src)

        if ped == 0 then
            return
        end

        local coords =
            GetEntityCoords(ped)

        local heading =
            GetEntityHeading(ped)

        local bucket =
            GetPlayerRoutingBucket(
                src
            )

        local vehicle =
            CreateVehicleServerSetter(
                joaat(model),
                vehicleType,
                coords.x + 5.0,
                coords.y,
                coords.z,
                heading
            )

        if vehicle == 0 then
            return
        end

        SetEntityRoutingBucket(
            vehicle,
            bucket
        )

        SetEntityOrphanMode(
            vehicle,
            2
        )
    end
)

Client ขอ Spawn

แต่ Server ตัดสินทุกอย่างสำคัญ

59 Checklist เปิด Entity Lockdown

ก่อนเปิด strict ตรวจ

① OneSync เปิดหรือยัง?
② Bucket ไหนต้องการ Lockdown?
③ Resource ใดสร้าง Vehicle ฝั่ง Client?
④ Resource ใดสร้าง Ped ฝั่ง Client?
⑤ Resource ใดสร้าง Object ฝั่ง Client?
⑥ Entity เหล่านั้นควรย้ายมาสร้าง Server-side หรือไม่?
⑦ ใช้ CreateVehicleServerSetter ได้หรือไม่?
⑧ Server Event Spawn มี Allowlist หรือไม่?
⑨ ตรวจ Permission หรือยัง?
⑩ ตรวจ Job/Grade หรือยัง?
⑪ ตรวจ Position หรือยัง?
⑫ มี Rate Limit หรือไม่?
⑬ จำกัดจำนวน Entity หรือไม่?
⑭ Entity ถูก Set Bucket ถูกต้องหรือไม่?
⑮ Population ต้องปิดหรือไม่?
⑯ Entity Cleanup ถูกออกแบบหรือไม่?
⑰ playerDropped Cleanup หรือไม่?
⑱ Resource พึ่ง Client-created Props หรือไม่?
⑲ Network Ownership ถูกแยกจาก Creation Authority หรือไม่?
⑳ sv_filterRequestControl ต้องปรับหรือไม่?
㉑ State Bags มี Client-written State หรือไม่?
㉒ sv_stateBagStrictMode เหมาะหรือไม่?
㉓ Test ใน Bucket แยกก่อน Production หรือยัง?

⑥⓪ ตัวอย่าง Entity Lockdown System แบบสมบูรณ์

ตัวอย่างนี้สร้าง Private Instance ที่

Entity Lockdown = strict
Population = off
Server เป็นผู้ Spawn Vehicle
Client เลือก Model ได้เฉพาะ Allowlist

server.lua

local nextBucket =
    5000

local PlayerBuckets = {}
local PlayerVehicles = {}

local AllowedVehicles = {
    sultan = 'automobile',
    blista = 'automobile'
}

local function createSecureBucket(
    src
)

    nextBucket =
        nextBucket + 1

    local bucket =
        nextBucket

    SetRoutingBucketEntityLockdownMode(
        bucket,
        'strict'
    )

    SetRoutingBucketPopulationEnabled(
        bucket,
        false
    )

    SetPlayerRoutingBucket(
        src,
        bucket
    )

    PlayerBuckets[src] =
        bucket

    return bucket
end

เข้า Secure Instance

RegisterNetEvent(
    'secureInstance:enter',
    function()

        local src =
            source

        if PlayerBuckets[src] then
            return
        end

        if GetPlayerRoutingBucket(src)
            ~= 0 then
            return
        end

        createSecureBucket(
            src
        )
    end
)

Request Vehicle

RegisterNetEvent(
    'secureInstance:spawnVehicle',
    function(model)

        local src =
            source

        if type(model)
            ~= 'string' then
            return
        end

        local vehicleType =
            AllowedVehicles[model]

        if not vehicleType then
            return
        end

        local bucket =
            PlayerBuckets[src]

        if not bucket then
            return
        end

        if GetPlayerRoutingBucket(src)
            ~= bucket then
            return
        end

        local oldVehicle =
            PlayerVehicles[src]

        if oldVehicle
        and DoesEntityExist(
            oldVehicle
        ) then

            DeleteEntity(
                oldVehicle
            )
        end

        local ped =
            GetPlayerPed(src)

        if ped == 0 then
            return
        end

        local coords =
            GetEntityCoords(ped)

        local heading =
            GetEntityHeading(ped)

        local vehicle =
            CreateVehicleServerSetter(
                joaat(model),
                vehicleType,
                coords.x + 4.0,
                coords.y,
                coords.z,
                heading
            )

        if vehicle == 0 then
            return
        end

        SetEntityRoutingBucket(
            vehicle,
            bucket
        )

        SetEntityOrphanMode(
            vehicle,
            2
        )

        Entity(vehicle).state:set(
            'secureInstance:vehicle',
            true,
            true
        )

        PlayerVehicles[src] =
            vehicle

        local netId =
            NetworkGetNetworkIdFromEntity(
                vehicle
            )

        TriggerClientEvent(
            'secureInstance:vehicleCreated',
            src,
            netId
        )
    end
)

ออกจาก Instance

local function leaveInstance(
    src
)

    local vehicle =
        PlayerVehicles[src]

    PlayerVehicles[src] =
        nil

    if vehicle
    and DoesEntityExist(
        vehicle
    ) then

        DeleteEntity(
            vehicle
        )
    end

    PlayerBuckets[src] =
        nil

    SetPlayerRoutingBucket(
        src,
        0
    )
end

RegisterNetEvent(
    'secureInstance:leave',
    function()

        leaveInstance(
            source
        )

    end
)

Disconnect Cleanup

AddEventHandler(
    'playerDropped',
    function()

        local src =
            source

        local vehicle =
            PlayerVehicles[src]

        PlayerVehicles[src] =
            nil

        PlayerBuckets[src] =
            nil

        if vehicle
        and DoesEntityExist(
            vehicle
        ) then

            DeleteEntity(
                vehicle
            )
        end
    end
)

Flow ทั้งระบบคือ

Player
↓
ขอเข้า Secure Instance
↓
Server Allocate Bucket
↓
strict Lockdown
↓
Population Off
↓
Player เข้า Bucket
↓
Client ขอ Vehicle
↓
Server Allowlist
↓
Server Validation
↓
Server Create Vehicle
↓
Vehicle เข้า Bucket
↓
OneSync Replicate
↓
Client ใช้งาน
↓
Leave / Disconnect
↓
Cleanup

นี่คือพื้นฐานของ Server-authoritative Entity Creation ที่ใช้ Entity Lockdown ได้อย่างมีประสิทธิภาพ

คำถามที่พบบ่อยเกี่ยวกับ FiveM Entity Lockdown

FiveM Entity Lockdown คืออะไร

คือ OneSync Feature ที่กำหนดว่า Client สามารถสร้าง Entity ใน Routing Bucket ได้มากน้อยแค่ไหน

ใช้ Function อะไร

ใช้

SetRoutingBucketEntityLockdownMode(
    bucket,
    mode
)

strict คืออะไร

ไม่อนุญาตให้ Clients สร้าง Entity ใน Bucket นั้น

relaxed คืออะไร

ตามเอกสารปัจจุบัน จะ Block Script-owned Entities ที่ Client สร้าง แต่เปิดกว้างกว่า strict

inactive คืออะไร

Client สามารถสร้าง Entity ได้ตามปกติ ไม่มี Lockdown ในลักษณะที่ Mode อื่นกำหนด

full คืออะไร

Mode สำหรับ FiveM บน GTAV Enhanced ที่เกี่ยวกับการปิด Dummy Object Creation เพิ่มเติม

strict ป้องกัน Client Spawn รถได้ไหม

ช่วย Block Client-authored Entity Creation ใน Bucket นั้น

strict ป้องกัน TriggerServerEvent Cheat ไหม

ไม่ Network Events ต้อง Secure Server-side แยกต่างหาก

strict ป้องกัน Money Cheat ไหม

ไม่โดยตรง

strict ทำให้ Client ขับรถไม่ได้ไหม

ไม่ Server-created Vehicle ยังสามารถถูก Sync และใช้งานโดย Clientได้

strict ทำให้ Server เป็น Network Owner ตลอดไหม

ไม่ Entity Network Ownership ยังทำงานตาม OneSync และสามารถ Migration ไปยัง Client

Server ควรสร้าง Vehicle อย่างไร

ในหลาย Use Cases สามารถใช้ Server Setter เช่น

CreateVehicleServerSetter(...)

Vehicle ที่สร้างต้อง Set Bucket ไหม

ถ้าต้องอยู่ Instance เดียวกับ Player ควร

SetEntityRoutingBucket(
    vehicle,
    bucket
)

ต้องปิด Population ด้วยไหม

ไม่บังคับ แต่ Controlled Instance จำนวนมากเหมาะกับ SetRoutingBucketPopulationEnabled(bucket, false)

Entity Lockdown ใช้กับ Bucket 0 ได้ไหม

ได้ แต่ควร Audit Resources ทั้ง Server ก่อนใช้ Policy เข้มกับ Main World

Client-created Script เก่าจะพังไหม

มีโอกาสถ้า Resource พึ่ง Client Network Entity Creation

ควรเปิด strict ทันทีทั้ง Server ไหม

Server เก่าควรทดสอบทีละ Controlled Bucket ก่อน แล้ว Audit Compatibility

Entity Lockdown ใช้แทน Anti-Cheat ได้ไหม

ไม่ได้ ควรใช้เป็น Defense-in-depth

Entity Lockdown กับ Entity Ownership ต่างกันอย่างไร

Lockdown ควบคุมการสร้าง Entity ส่วน Ownership ระบุว่าใครกำลัง Simulation Network Entity

Entity Lockdown กับ sv_filterRequestControl ต่างกันอย่างไร

Lockdown จำกัด Entity Creation ส่วน sv_filterRequestControl จำกัดการขอ Control ของ Existing Entity

Entity Lockdown กับ sv_stateBagStrictMode ใช้ร่วมกันได้ไหม

ได้ หาก Resources รองรับ โดยตัวแรกควบคุม Entity Creation ส่วนตัวหลังควบคุมว่าใครแก้ State Bags ได้

Routing Bucket จำเป็นไหม

Entity Lockdown Policy ถูกกำหนดต่อ Routing Bucket จึงเกี่ยวข้องโดยตรง

สรุป FiveM Entity Lockdown คืออะไร ป้องกัน Client Spawn Entity อย่างไร

FiveM Entity Lockdown คือระบบของ OneSync ที่ช่วยให้ Server ควบคุม Client-created Entities ในแต่ละ Routing Bucket และเป็นหนึ่งในเครื่องมือสำคัญสำหรับสร้าง Server-authoritative Entity Architecture

ถ้าตั้ง

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

Client ใน Bucket นั้นจะไม่สามารถ Author Entity Creation ได้ตาม Policy ของ strict

Architecture ที่ควรใช้คือ

Client
↓
Request
↓
Server
↓
Validate Player
↓
Validate Permission
↓
Validate Model
↓
Validate State
↓
Rate Limit
↓
Server Create Entity
↓
Set Routing Bucket
↓
Set State
↓
OneSync Replicate

สำหรับ Controlled Instance ยังสามารถใช้

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

เพื่อปิด Ambient Population และสร้าง World ที่ Serverควบคุมได้ง่ายขึ้น

แต่ต้องจำว่ามีหลาย Layer ที่แตกต่างกัน

Entity Lockdown
→ ใครสร้าง Entity ได้
Network Ownership
→ ใคร Simulation Entity
sv_filterRequestControl
→ Client ขอ Control Existing Entity ได้แค่ไหน
sv_stateBagStrictMode
→ ใครแก้ State Bag ได้

และ

Secure Events
→ Client Request ถูกตรวจอย่างไร

จึงไม่ควรเปิด strict แล้วคิดว่า Server ปลอดภัยจาก Cheat ทุกประเภททันที

ถ้า Server Event ยังรับ

model
reward
money
permission

จาก Client แล้วเชื่อทั้งหมด ช่องโหว่ก็ยังมีอยู่

สำหรับผู้ที่กำลังเรียน FiveM Developer กับ comsiam วิธีที่ควรคิดคือ Entity Lockdown ไม่ได้มีไว้แค่ Block คนโกง Spawn รถ แต่มีไว้เปลี่ยน Architecture จาก Client-authoritative Spawn ไปสู่ Server-controlled Spawn

และหลักสำคัญจาก comsiam คือ Client ควรบอก Server ว่าอยากทำอะไร ไม่ใช่สร้างสิ่งนั้นเองแล้วบอก Server ว่าทำเสร็จแล้ว

เมื่อเข้าใจ Entity Lockdown แล้ว เราจะจบกลุ่ม OneSync/Entity Security และเข้าสู่พื้นฐาน Resource โดยตรงในหัวข้อถัดไปคือ FiveM Resource คืออะไร ซึ่งเป็นรากฐานของ Script FiveM ทุกตัว ตั้งแต่ Folder, fxmanifest.lua, Client Script, Server Script ไปจนถึง Resource Lifecycle

Comments

Popular posts from this blog

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

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

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