FiveM Routing Bucket คืออะไร

FiveM Routing Bucket คือระบบสำหรับแยก Player และ Entity ออกเป็นโลกหรือ Instance คนละชุดภายใน Server เดียวกัน แนวคิดคล้าย Dimension, Virtual World หรือ Instance ที่พบใน Multiplayer Server รูปแบบอื่น

ตัวอย่าง Server มีผู้เล่น 100 คน

ปกติทุกคนอยู่

Bucket 0

แต่เราสามารถย้าย Player กลุ่มหนึ่งไป

Bucket 10

และอีกกลุ่มไป

Bucket 20

ผลคือ

Bucket 0
→ Main World

Bucket 10
→ Mission A

Bucket 20
→ Mission B

Player และ Entity ที่อยู่คนละ Routing Bucket จะถูกแยกออกจากกันตามระบบ Routing ของ OneSync

ตัวอย่างย้าย Player ไป Bucket 10

SetPlayerRoutingBucket(
    source,
    10
)

และถ้ามี Vehicle ของ Mission ก็ควรย้าย Vehicle ไป Bucket เดียวกัน

SetEntityRoutingBucket(
    vehicle,
    10
)

Routing Bucket จึงเหมาะมากกับระบบอย่าง

  • Character Selection

  • Mission Instance

  • Party

  • Lobby

  • Multi-mode Server

  • Private Session

  • Match

  • Dungeon/Scenario

แต่มีข้อสำคัญคือ Cfx.re ระบุชัดว่า Routing Bucket ไม่ใช่เครื่องมือที่แนะนำสำหรับการทำ Interior Instance ทั่วไป ซึ่งจะอธิบายเพิ่มเติมด้านล่าง

① Routing Bucket คืออะไร

Routing Bucket คือการแบ่ง Game State ออกเป็นกลุ่ม

สมมติ

Player A
Bucket 1

Player B
Bucket 1

Player C
Bucket 2

Player A กับ B อยู่ Bucket เดียวกัน

จึงสามารถอยู่ใน Routing Context เดียวกัน

แต่ Player C อยู่ Bucket 2

จึงถูกแยกออก

Concept คือ

Server เดียว
↓
หลาย Routing Buckets
↓
หลาย Instance

ไม่ต้องเปิด FiveM Server แยกกัน

② Routing Bucket เหมือน Dimension ไหม

ใกล้เคียงมาก

Cfx.re เองอธิบายว่า Routing Bucket มี Concept คล้าย

Dimension
Virtual World
Instance

จาก Multiplayer Platform อื่น

ดังนั้นหากเคยเขียนระบบ

Dimension 0
Dimension 1
Dimension 2

สามารถมอง FiveM Routing Bucket เป็น Concept ใกล้เคียงกันได้

แต่ Implementation และ Networking Behavior ของ FiveM มีรายละเอียดเฉพาะของตัวเอง

③ Routing Bucket ต้องใช้ OneSync ไหม

ใช่

Routing Bucket เป็นส่วนหนึ่งของ OneSync/State Awareness Architecture

Resource ที่พึ่งระบบนี้จึงควรออกแบบให้ทำงานใน Environment ที่เปิด OneSync ตาม Requirement

ใน fxmanifest.lua ยังสามารถระบุ Constraint เช่น

dependencies {
    '/onesync'
}

เพื่อบอกว่า Resource ต้องการ State Awareness

④ Bucket 0 คืออะไร

โดยทั่วไป

Bucket 0

คือ Main Routing Bucket

Player ที่ไม่ได้ถูกย้ายไป Instance อื่นมักอยู่ Bucket 0

ตัวอย่างเมื่อ Player จบ Mission

SetPlayerRoutingBucket(
    source,
    0
)

คือย้ายกลับ Main World

ดังนั้นระบบ Instance จำนวนมากใช้ Pattern

เข้า Mission
→ Bucket X

ออก Mission
→ Bucket 0

⑤ SetPlayerRoutingBucket คืออะไร

ใช้เปลี่ยน Routing Bucket ของ Player

ตัวอย่าง

SetPlayerRoutingBucket(
    source,
    15
)

ตอนนี้ Player จะอยู่ Bucket 15

ในระบบ Mission อาจใช้

local bucket =
    1000 + source

SetPlayerRoutingBucket(
    source,
    bucket
)

เพื่อสร้าง Private Instance ของ Player

แต่การ Generate Bucket ID ต้องออกแบบไม่ให้ชนกัน

⑥ GetPlayerRoutingBucket คืออะไร

ใช้ตรวจว่า Player อยู่ Bucket ไหน

ตัวอย่าง

local bucket =
    GetPlayerRoutingBucket(
        source
    )

print(
    'Player bucket:',
    bucket
)

มีประโยชน์สำหรับ

  • Validation

  • Debug

  • Party System

  • Mission

  • Instance Cleanup

Server สามารถตรวจ Player Bucket ก่อนทำ Action สำคัญได้

⑦ SetEntityRoutingBucket คืออะไร

ใช้กำหนด Routing Bucket ของ Entity

ตัวอย่าง Vehicle

SetEntityRoutingBucket(
    vehicle,
    15
)

หาก Player อยู่ Bucket 15 และ Vehicle ก็อยู่ Bucket 15 ทั้งคู่จะอยู่ Routing Context เดียวกัน

Entity สามารถเป็น

  • Vehicle

  • Ped

  • Object

ตามระบบที่รองรับ

⑧ GetEntityRoutingBucket คืออะไร

ใช้ตรวจว่า Entity อยู่ Bucket ไหน

local bucket =
    GetEntityRoutingBucket(
        vehicle
    )

print(bucket)

ช่วย Debug ปัญหาเช่น

Player เห็นรถไม่ได้

แล้วพบว่า

Player Bucket = 10
Vehicle Bucket = 0

ทั้งสองอยู่คนละ Bucket

⑨ Player กับ Vehicle ต้องอยู่ Bucket เดียวกันไหม

ถ้าต้องการให้ Vehicle เป็นส่วนหนึ่งของ Instance เดียวกับ Player โดยทั่วไปควรจัดให้อยู่ Bucket เดียวกัน

เช่น

Player
Bucket 50

Mission Vehicle
Bucket 50

Mission Ped
Bucket 50

Mission Props
Bucket 50

ไม่ควรย้ายเฉพาะ Player แล้วปล่อย Mission Entities อยู่ Bucket 0 โดยไม่คิดถึง Routing

⑩ ตัวอย่างสร้าง Mission Instance

Server

local bucket = 100

SetPlayerRoutingBucket(
    source,
    bucket
)

local ped =
    GetPlayerPed(source)

local coords =
    GetEntityCoords(ped)

local vehicle =
    CreateVehicleServerSetter(
        joaat('sultan'),
        'automobile',
        coords.x + 5.0,
        coords.y,
        coords.z,
        0.0
    )

SetEntityRoutingBucket(
    vehicle,
    bucket
)

ตอนนี้ Player กับ Mission Vehicle อยู่ Instance เดียวกัน

⑪ Routing Bucket แยก Player อย่างไร

สมมติ Player สองคนยืน Coordinates เดียวกัน

Player A
x=100 y=200 z=30
Bucket 10

Player B
x=100 y=200 z=30
Bucket 20

แม้ Coordinates เหมือนกัน

แต่ Routing Context ต่างกัน

จึงไม่ควรมองว่าอยู่ในโลก Multiplayer เดียวกันในลักษณะปกติ

นี่ทำให้สามารถใช้พื้นที่เดียวกันสำหรับ Mission หลาย Instance ได้

⑫ Mission หลายทีมใช้พื้นที่เดียวกันได้ไหม

ได้ และเป็น Use Case ที่ดีมาก

สมมติ Mission Warehouse อยู่ Coordinates เดียว

Party A

Bucket 101

Party B

Bucket 102

Party C

Bucket 103

ทุก Party สามารถใช้พื้นที่เดียวกันในคนละ Instance โดยไม่ต้องสร้าง Map Copy หลายแห่ง

⑬ Party System ใช้ Routing Bucket อย่างไร

เมื่อ Party เริ่ม Mission

Server Generate Bucket

local bucket =
    CreatePartyBucket()

แล้ว Player ทุกคนใน Party ถูกย้ายไป Bucket เดียวกัน

for _, playerId in ipairs(
    partyPlayers
) do

    SetPlayerRoutingBucket(
        playerId,
        bucket
    )
end

จากนั้น Spawn Mission Entities ใน Bucket เดียวกัน

⑭ Private Instance สำหรับ Player คนเดียว

Character Selection เป็นตัวอย่างที่ Cfx.re ระบุว่าเหมาะกับ Routing Bucket

Flow เช่น

Player Connect
↓
Bucket ส่วนตัว
↓
Character Selection
↓
เลือก Character
↓
โหลดข้อมูล
↓
Bucket 0
↓
Main World

ช่วยไม่ให้ Player ที่ยังเลือก Character ไปปรากฏในโลกหลัก

⑮ Character Selection ใช้ Bucket แบบไหนดี

สามารถ Generate Unique Bucket จาก Server State

ตัวอย่าง Concept

local bucket =
    10000 + source

จากนั้น

SetPlayerRoutingBucket(
    source,
    bucket
)

หลัง Character พร้อมแล้ว

SetPlayerRoutingBucket(
    source,
    0
)

แต่ Production System ควรมี Bucket Allocator ที่ควบคุม Collision และ Reuse อย่างชัดเจน

⑯ Lobby ใช้ Routing Bucket ได้ไหม

ได้

ตัวอย่าง

Lobby A
Bucket 200

Lobby B
Bucket 201

Lobby C
Bucket 202

Player ใน Lobby เดียวกันสามารถถูกจัดอยู่ใน Bucket เดียวกัน

จากนั้นเมื่อ Match เริ่มอาจใช้ Bucket เดิมหรือย้ายไป Match Bucket ตาม Architecture

⑰ Multi-mode Server ใช้ได้ไหม

ได้ และเป็นหนึ่งใน Use Case ที่ Cfx.re ระบุโดยตรง

Server หนึ่งอาจมี

Roleplay
Deathmatch
Racing
Training

แยกกัน

แต่ต้องออกแบบระบบอื่นร่วมด้วย เช่น

  • Player Data

  • Commands

  • Voice

  • UI

  • Economy

  • Events

Routing Bucket แยก Networking Context แต่ไม่ได้แยกทุกระบบใน Resource ให้อัตโนมัติ

⑱ Routing Bucket แยก Database ไหม

ไม่

Player อยู่คนละ Bucket แต่ Server Resource และ Database ยังคงเป็นระบบ Server เดียวกัน

สมมติ

Player A
Bucket 10

Player B
Bucket 20

ทั้งคู่ยังสามารถ Query

players
vehicles
inventory

ใน Database เดียวกันได้ถ้า Script ออกแบบแบบนั้น

Routing Bucket ไม่ใช่ Database Isolation

⑲ Routing Bucket แยก Lua Variable ไหม

ไม่

ตัวอย่าง Server

local players = {}

Table นี้ไม่ได้ถูกสร้างแยกต่อ Bucket อัตโนมัติ

ถ้าต้องการ State แยก Instance ต้องเขียนเอง เช่น

local instances = {}

instances[bucket] = {
    players = {},
    vehicles = {},
    missionState = {}
}

Routing Bucket จัด Network Routing ไม่ได้สร้าง Application State Architecture ให้ทั้งหมด

⑳ Routing Bucket แยก Events อัตโนมัติไหม

อย่าคิดว่า Event ทุกตัวจะถูก Filter ด้วย Bucket ให้อัตโนมัติใน Business Logic ของคุณ

ถ้า Serverทำ

TriggerClientEvent(
    'mission:update',
    -1,
    data
)

-1 ยังหมายถึง Broadcast ไป Clients ตาม Event Semantics

ดังนั้นระบบ Instance ควร Target เฉพาะ Players ที่เกี่ยวข้อง

เช่น

for _, playerId in ipairs(
    instance.players
) do

    TriggerClientEvent(
        'mission:update',
        playerId,
        data
    )
end

㉑ อย่า Broadcast Event ทุกคนแล้วหวัง Bucket Filter

Architecture ที่ดีควรรู้ว่า

Bucket 150
มี Player ใครบ้าง

แล้วส่ง Event เฉพาะกลุ่ม

ช่วยลด

  • Network Traffic

  • Client Processing

  • Data Exposure

โดยเฉพาะ Server ขนาดใหญ่

㉒ Routing Bucket กับ State Bag

สามารถใช้ร่วมกันได้ดี

ตัวอย่าง Mission Entity

Vehicle
Bucket = 50

พร้อม State

mission:id = 125
mission:team = 2

ผ่าน State Bag

Routing Bucket บอกว่า Entity อยู่ Instance ไหน

State Bag บอก Custom State ของ Entity

สองระบบทำหน้าที่ต่างกัน

㉓ Routing Bucket กับ Entity Ownership

Entity ใน Routing Bucket ยังมี Network Ownership ตาม OneSync

Bucket ไม่ได้ทำให้ Server กลายเป็น Network Owner ของ Entity ทั้งหมด

เช่น

Vehicle
Bucket 50
↓
Network Owner
Client A

Ownership ยังสามารถ Migration ได้ตามระบบ

㉔ Routing Bucket กับ Network ID

Entity ที่เป็น Networked Entity ยังมี Network ID

ตัวอย่าง

Vehicle
Net ID = 84
Bucket = 50

Network ID บอกว่าเป็น Entity ตัวไหน

Routing Bucket บอกว่า Entity อยู่ Routing Context ไหน

อย่าใช้ข้อมูลสองอย่างนี้แทนกัน

㉕ Routing Bucket กับ Scope

Bucket เป็น Boundary สำคัญของ Routing

Entity และ Player ต้องอยู่ใน Routing Context ที่เกี่ยวข้องก่อนจึงจะเกิด Scope/Visibility ตาม OneSync

ดังนั้นเมื่อ Debug Entity หาไม่เจอ ต้องตรวจทั้ง

Network ID
Scope
Routing Bucket

ไม่ใช่ดูแค่ Coordinates

㉖ Player อยู่ใกล้กันแต่ไม่เห็นกัน เพราะอะไร

หนึ่งในสาเหตุสำคัญคือ Routing Bucket ต่างกัน

ตรวจ Server

local bucket =
    GetPlayerRoutingBucket(
        source
    )

print(bucket)

ถ้าสอง Player อยู่

Player A = 0
Player B = 50

แม้ Coordinates เหมือนกันก็สามารถถูกแยกด้วย Routing Bucket ได้

㉗ รถหายหลังย้าย Player เข้า Bucket เพราะอะไร

สาเหตุที่พบบ่อยคือย้ายเฉพาะ Player

SetPlayerRoutingBucket(
    source,
    50
)

แต่รถยังอยู่

Bucket 0

จึงถูกแยกออกจาก Player

ถ้ารถต้องตามเข้า Mission ต้อง Set Entity Bucket ด้วย

SetEntityRoutingBucket(
    vehicle,
    50
)

㉘ ย้าย Player พร้อมรถทำอย่างไร

ต้อง Resolve Vehicle ฝั่ง Server และตรวจ Ownership/Entity ก่อน

Concept:

Player
↓
Vehicle
↓
Validate
↓
SetEntityRoutingBucket(vehicle, bucket)
↓
SetPlayerRoutingBucket(player, bucket)

Order และ State Handling ควรออกแบบตามระบบจริง

โดยเฉพาะรถที่มีผู้โดยสารหลายคน

㉙ Vehicle มีผู้เล่นหลายคนต้องทำอย่างไร

ถ้ารถมี Driver และ Passengers

ไม่ควรย้าย Driver คนเดียวไป Bucket ใหม่แล้วปล่อย Passenger อยู่ Bucket เดิม

ระบบควร

ตรวจ occupants
↓
กำหนด Party/Session
↓
ย้าย Players ที่เกี่ยวข้อง
↓
ย้าย Vehicle

ตาม Gameplay Requirement

ไม่เช่นนั้นอาจเกิด State แปลก ๆ

㉚ Routing Bucket กับ Ped และ Object

ไม่ใช่แค่ Vehicle

Mission อาจมี

NPC
Enemies
Props
Doors
Mission Objects

Entities เหล่านี้ควรถูกกำหนด Bucket เดียวกับ Mission ตาม Architecture

ตัวอย่าง

SetEntityRoutingBucket(
    missionPed,
    bucket
)

SetEntityRoutingBucket(
    missionObject,
    bucket
)

㉛ Population ใน Routing Bucket คืออะไร

แต่ละ Routing Bucket มี World Grid ของตัวเองสำหรับ Population Ownership

FiveM ยังมี API

SetRoutingBucketPopulationEnabled(
    bucket,
    enabled
)

สำหรับเปิดหรือปิด Population ใน Bucket

เช่น Private Character Screen อาจไม่ต้องการ Ambient NPC/Traffic

㉜ วิธีปิด Population ใน Bucket

ตัวอย่าง

SetRoutingBucketPopulationEnabled(
    100,
    false
)

ตอนนี้ Bucket 100 ถูกกำหนดไม่ให้ Population ทำงานตาม Policy นั้น

เหมาะกับ

  • Character Screen

  • Controlled Mission

  • Private Scene

  • Lobby

ที่ไม่ต้องการ Random NPC/Traffic เข้ามารบกวน

㉝ ควรปิด Population ทุก Bucket ไหม

ไม่

ขึ้นกับ Gameplay

Racing Instance อาจต้องการ Traffic หรือไม่ต้องการก็ได้

Mission Open World อาจต้องการ Population

Character Screen ส่วนใหญ่ไม่ต้องการ

ดังนั้นกำหนดตาม Requirement

Controlled Instance
→ อาจปิด

Open-world Instance
→ อาจเปิด

㉞ Entity Lockdown Mode ต่อ Bucket คืออะไร

Routing Bucket สามารถตั้ง Entity Lockdown Mode ได้

เช่น

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

ใช้กำหนดว่าฝั่ง Client สามารถสร้าง Entity ใน Bucket นั้นได้มากแค่ไหน

นี่เป็น Feature สำคัญสำหรับ Server Security

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

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

strict
relaxed
inactive

และสำหรับ FiveM GTAV Enhanced มี full เพิ่มในเอกสารปัจจุบัน

ความหมายโดยย่อคือ

strict
→ Client สร้าง Entity ไม่ได้

relaxed
→ จำกัด Script-owned Client Entities

inactive
→ Client สร้าง Entity ได้ตามปกติ

ส่วน full มีข้อกำหนดเฉพาะ GTAV Enhanced

㊱ strict เหมาะกับอะไร

เหมาะกับ Instance ที่ต้องการ

Server-authoritative Entity Creation

เช่น Mission

Client
↓
ขอ Spawn Vehicle
↓
Server Validate
↓
Server Create Vehicle
↓
Set Entity Bucket

แทนปล่อย Client สร้าง Entity ได้ตามใจ

㊲ ตัวอย่าง Bucket แบบ strict

local bucket = 100

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

SetPlayerRoutingBucket(
    source,
    bucket
)

ตอนนี้ Bucket ถูกควบคุมเข้มขึ้น

Mission Entities ควรถูกสร้างจาก Server ตาม Architecture

㊳ relaxed ต่างจาก strict อย่างไร

relaxed จำกัดเฉพาะ Client-created Entities บางประเภทตาม Script Ownership Rule

ส่วน

strict

เข้มกว่า โดยไม่ให้ Client สร้าง Entity ใน Bucket นั้น

ถ้า Server Resource เก่าพึ่ง Client Spawn Vehicle/Ped/Object มาก การเปิด strict อาจทำให้ Resource ทำงานไม่ได้

ต้อง Audit ก่อนใช้

㊴ inactive คืออะไร

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

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

เหมาะกับ Bucket ที่ต้อง Compatibility สูง แต่ Security ของ Client-created Entity ต้องจัดการด้วยวิธีอื่น

㊵ Routing Bucket เป็น Security Boundary 100% ไหม

ไม่ควรมองแบบนั้น

มันช่วยแยก Routing Context แต่ Application Security ยังต้องมี

  • Server Validation

  • Permission

  • Event Security

  • Database Validation

  • State Validation

ตัวอย่าง Player อยู่ Bucket 50 ไม่ได้หมายความว่า Server Event จาก Player ควรเชื่อถือทันที

㊶ ตรวจ Bucket ใน Server Event ได้ไหม

ได้ และมีประโยชน์มาก

สมมติ Mission Complete ต้องเกิดเฉพาะ Bucket ของ Mission

local playerBucket =
    GetPlayerRoutingBucket(
        src
    )

if playerBucket ~=
    mission.bucket then

    return
end

ช่วยเพิ่ม Server-side State Validation

㊷ Bucket ID จาก Client เชื่อได้ไหม

ไม่ควร

อย่าให้ Clientส่ง

myBucket = 50

แล้ว Serverเชื่อว่าผู้เล่นอยู่ Bucket 50

Serverสามารถหาเองด้วย

GetPlayerRoutingBucket(
    source
)

จึงไม่มีเหตุผลให้ Clientเป็น Authority ของข้อมูลนี้

㊸ Client ขอเลือก Bucket เองได้ไหม

Client สามารถส่ง Request เช่น

ฉันต้องการเข้า Party 15

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

Party มีจริงไหม?
Player เป็นสมาชิกไหม?
Mission เริ่มหรือยัง?
Bucket ของ Party คืออะไร?

แล้ว Server จึง

SetPlayerRoutingBucket(
    source,
    party.bucket
)

ไม่ควรเปิด Event แบบ

setMyBucket(anyNumber)

โดยไม่มี Validation

㊹ Event setBucket แบบ Generic อันตรายอย่างไร

ตัวอย่างไม่ดี

RegisterNetEvent(
    'instance:setBucket',
    function(bucket)

        SetPlayerRoutingBucket(
            source,
            bucket
        )

    end
)

Clientสามารถพยายามเลือก Bucket ใดก็ได้

อาจเข้า

  • Private Mission

  • Character Instance

  • Admin Instance

  • Party อื่น

ถ้าระบบพึ่ง Bucket Isolation

นี่เป็นช่องโหว่เชิง Logic

㊺ วิธีที่ดีกว่าสำหรับ Mission

Client

TriggerServerEvent(
    'mission:join',
    missionId
)

Server

Validate missionId
↓
Validate membership
↓
หา mission.bucket จาก Server
↓
SetPlayerRoutingBucket

Client ไม่จำเป็นต้องรู้หรือควบคุม Bucket ID โดยตรง

㊻ Bucket Allocator คืออะไร

Server ขนาดใหญ่ควรมีระบบแจก Bucket IDs

เช่น

local nextBucket = 1000

เมื่อสร้าง Instance

nextBucket =
    nextBucket + 1

local bucket =
    nextBucket

แต่ระบบจริงต้องคิดถึง

  • Reuse

  • Cleanup

  • Collision

  • Restart

  • Maximum Active Instances

ไม่ควรสุ่ม Bucket ID แบบไม่มีการจัดการ

㊼ Bucket ID ต้อง Unique ตลอดไปไหม

ไม่จำเป็นต้อง Unique ข้ามเวลา ถ้า Instance เก่าถูก Cleanup สมบูรณ์แล้วสามารถ Reuse Bucket ID ได้ตามระบบของคุณ

ตัวอย่าง

Bucket 100
→ Mission A
→ Mission จบ
→ Cleanup
→ ไม่มี Player/Entity

ภายหลัง
Bucket 100
→ Mission B

ได้ถ้า State เก่าถูกล้างหมด

㊽ Cleanup Routing Bucket สำคัญไหม

สำคัญมาก

เมื่อ Mission จบควร

Players
→ Bucket 0

Mission Entities
→ Delete หรือ Move ตาม Requirement

Instance State
→ Clear

Bucket Registry
→ Release

ไม่เช่นนั้นอาจเกิด

  • Player ติด Instance

  • Entity ค้าง

  • State Leak

  • Bucket ID ไม่ถูก Reuse

  • Memory/Resource Usage เพิ่ม

㊾ Player Disconnect ขณะอยู่ Instance ทำอย่างไร

Server ควร Handle

AddEventHandler(
    'playerDropped',
    function()

        local src =
            source

        -- remove from instance
        -- cleanup instance if empty

    end
)

ถ้า Player คนสุดท้ายออก

Instance อาจถูก Destroy และ Mission Entities Cleanup

ตาม Architecture

㊿ Player Resource Restart แล้ว Bucket หายไหม

Routing Bucket State อยู่ระดับ Server Networking ไม่ใช่ Lua Variable ธรรมดาของ Resource เพียงอย่างเดียว

ถ้า Resource Restart แต่ไม่ได้ Reset Players อาจเกิด State ที่ Resource Registry กับ Actual Bucket ไม่ตรงกัน

Resource ที่ดูแล Instance ควรมี Recovery/Initialization Strategy ตามความสำคัญของระบบ

51 onPlayerBucketChange คืออะไร

FiveM มี Server Event

onPlayerBucketChange

ซึ่งถูกเรียกเมื่อ Player เปลี่ยน Routing Bucket

Parameters คือ

player
bucket
oldBucket

ตัวอย่าง

AddEventHandler(
    'onPlayerBucketChange',
    function(
        player,
        bucket,
        oldBucket
    )

        print(
            player,
            oldBucket,
            bucket
        )

    end
)

เหมาะกับ Debug, Audit หรือ Instance Tracking

52 onEntityBucketChange คืออะไร

มี Event

onEntityBucketChange

เมื่อ Entity เปลี่ยน Routing Bucket

ได้รับ

entity
bucket
oldBucket

ตัวอย่าง

AddEventHandler(
    'onEntityBucketChange',
    function(
        entity,
        bucket,
        oldBucket
    )

        print(
            entity,
            oldBucket,
            bucket
        )

    end
)

ช่วย Debug Vehicle/Ped/Object ที่ถูกย้ายผิด Bucket

53 Routing Bucket ใช้ทำ Interior ได้ไหม

Cfx.re ระบุอย่างชัดเจนว่า Interior ไม่ใช่ Use Case ที่แนะนำสำหรับ Routing Buckets

เหตุผลคือ GTA V มี Interior ที่สามารถมองออกไปเห็น Outside World ได้ และ Routing Bucket ตัด Routing Context ในลักษณะที่ไม่เหมาะกับ Use Case เหล่านี้

เอกสารแนะนำ Traditional Conceal Natives หรือแนวทาง Routing แบบ 3D-scoped ที่มีการกล่าวถึงสำหรับอนาคตแทน

ดังนั้นอย่าใช้

Interior ทุกห้อง
=
Bucket ใหม่

โดยอัตโนมัติ

54 แล้ว MLO ควรใช้ Routing Bucket ไหม

ไม่ควรตอบว่า MLO ทุกตัวต้องใช้ Bucket

ถ้าเป็น Interior ปกติที่ Player ควรยังอยู่ใน Shared World Cfx.re ไม่แนะนำ Routing Bucket เป็น Default Solution

Routing Bucket เหมาะกับ

Session / Instance

มากกว่า

แค่เดินเข้าตึกหนึ่งหลัง

ต้องดู Gameplay Requirement จริง

55 Character Selection เหมาะกว่าทำ Interior

ใช่ เพราะ Character Selection คือ Instance แยกชัดเจน

Player ยังไม่ควรอยู่ร่วมกับ Main Gameplay

จึงสามารถ

Connect
↓
Private Bucket
↓
Select Character
↓
Load Character
↓
Bucket 0

นี่เป็นหนึ่งใน Use Cases ที่ Cfx.re ยกตัวอย่างโดยตรง

56 Routing Bucket มี Cost ไหม

มี

เอกสาร Cfx.re ปัจจุบันระบุว่าทุก Routing Bucket มี Memory Cost

ดังนั้นไม่ควรสร้าง Bucket จำนวนมหาศาลโดยไม่มี Lifecycle

ระบบควร

  • Create เมื่อจำเป็น

  • Reuse เมื่อเหมาะสม

  • Cleanup หลังใช้

  • ไม่สร้าง Instance ถาวรโดยไม่จำเป็น

โดยเฉพาะ Server ขนาดใหญ่

57 Bucket ต่อ Player ตลอดเวลา ดีไหม

ขึ้นกับระบบ

Character Selection ชั่วคราวใช้ Private Bucket ต่อ Playerได้

แต่ถ้า Server มีผู้เล่นจำนวนมากและสร้าง Bucket ถาวรให้ Player ทุกคนโดยไม่จำเป็น ต้องคำนึงถึง Memory Cost และ Complexity

อย่าใช้ Bucket เพียงเพราะทำได้

ใช้เมื่อมี Requirement ด้าน Isolation จริง

58 Routing Bucket Debug อย่างไร

สร้าง Command ฝั่ง Server เช่น

RegisterCommand(
    'mybucket',
    function(source)

        if source == 0 then
            return
        end

        local bucket =
            GetPlayerRoutingBucket(
                source
            )

        print(
            ('Player %s bucket %s')
            :format(
                source,
                bucket
            )
        )

    end,
    false
)

สำหรับ Entity สามารถตรวจ

local bucket =
    GetEntityRoutingBucket(
        entity
    )

และใช้ onPlayerBucketChange / onEntityBucketChange ช่วย Log การเปลี่ยนแปลง

59 Checklist ก่อนใช้ FiveM Routing Bucket

ตรวจอย่างน้อย

① ต้องการ Instance จริงหรือไม่?
② OneSync พร้อมหรือไม่?
③ Bucket 0 ใช้เป็น Main World หรือไม่?
④ Bucket ID มาจาก Server หรือยัง?
⑤ มี Bucket Allocator หรือไม่?
⑥ Players ใน Party ถูกย้ายครบไหม?
⑦ Vehicles ถูกย้าย Bucket หรือยัง?
⑧ Mission Peds ถูกย้ายหรือยัง?
⑨ Mission Objects ถูกย้ายหรือยัง?
⑩ Population ควรเปิดหรือปิด?
⑪ Entity Lockdown Mode ควรเป็นอะไร?
⑫ Event ถูกส่งเฉพาะ Instance Players หรือไม่?
⑬ Server Event ตรวจ Player Bucket หรือไม่?
⑭ Client สามารถเลือก Bucket เองได้หรือไม่?
⑮ Instance State ถูกเก็บ Server-side หรือไม่?
⑯ Player Disconnect ถูก Cleanup หรือไม่?
⑰ Instance ว่างแล้วถูก Destroy หรือไม่?
⑱ Entities ถูก Cleanup หรือไม่?
⑲ Bucket ID ถูก Release หรือไม่?
⑳ กำลังใช้ Bucket กับ Interior ที่ไม่เหมาะหรือไม่?
㉑ จำนวน Buckets มากเกินจำเป็นหรือไม่?
㉒ Resource Restart Recovery ถูกคิดไว้หรือไม่?

⑥⓪ ตัวอย่าง Routing Bucket สำหรับ Mission แบบสมบูรณ์

server.lua

local instances = {}
local nextBucket = 1000

local function createInstance(
    owner
)
    nextBucket =
        nextBucket + 1

    local bucket =
        nextBucket

    instances[bucket] = {
        owner = owner,
        players = {
            [owner] = true
        },
        entities = {}
    }

    SetRoutingBucketEntityLockdownMode(
        bucket,
        'strict'
    )

    SetRoutingBucketPopulationEnabled(
        bucket,
        false
    )

    SetPlayerRoutingBucket(
        owner,
        bucket
    )

    return bucket
end

RegisterNetEvent(
    'mission:create',
    function()

        local src =
            source

        local currentBucket =
            GetPlayerRoutingBucket(
                src
            )

        if currentBucket ~= 0 then
            return
        end

        local bucket =
            createInstance(src)

        local ped =
            GetPlayerPed(src)

        if ped == 0 then
            return
        end

        local coords =
            GetEntityCoords(ped)

        local vehicle =
            CreateVehicleServerSetter(
                joaat('sultan'),
                'automobile',
                coords.x + 5.0,
                coords.y,
                coords.z,
                0.0
            )

        if vehicle ~= 0 then

            SetEntityRoutingBucket(
                vehicle,
                bucket
            )

            SetEntityOrphanMode(
                vehicle,
                2
            )

            instances[bucket]
                .entities[vehicle] =
                true
        end
    end
)

ออกจาก Mission

RegisterNetEvent(
    'mission:leave',
    function()

        local src =
            source

        local bucket =
            GetPlayerRoutingBucket(
                src
            )

        local instance =
            instances[bucket]

        if not instance then
            return
        end

        instance.players[src] =
            nil

        SetPlayerRoutingBucket(
            src,
            0
        )

        local hasPlayers =
            next(instance.players)
            ~= nil

        if not hasPlayers then

            for entity in pairs(
                instance.entities
            ) do

                if DoesEntityExist(
                    entity
                ) then

                    DeleteEntity(
                        entity
                    )
                end
            end

            instances[bucket] =
                nil
        end
    end
)

Concept คือ

Player
↓
Server Validate
↓
Allocate Bucket
↓
Configure Lockdown
↓
Disable Population
↓
Move Player
↓
Create Mission Entity
↓
Move Entity เข้า Bucket
↓
Mission
↓
Player Leave
↓
Bucket 0
↓
Cleanup

นี่เป็นพื้นฐานที่สามารถต่อยอดไปสู่ Party Instance ได้

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

FiveM Routing Bucket คืออะไร

คือระบบ Dimension/Instance ของ OneSync สำหรับแยก Player และ Entities ออกเป็น Routing Context ต่างกันภายใน Server เดียว

Bucket 0 คืออะไร

โดยทั่วไปใช้เป็น Main World และ Player มักกลับ Bucket 0 เมื่อออกจาก Instance

วิธีเปลี่ยน Player Bucket

ใช้

SetPlayerRoutingBucket(
    playerId,
    bucket
)

วิธีดู Player Bucket

ใช้

GetPlayerRoutingBucket(
    playerId
)

วิธีเปลี่ยน Entity Bucket

ใช้

SetEntityRoutingBucket(
    entity,
    bucket
)

วิธีดู Entity Bucket

ใช้

GetEntityRoutingBucket(
    entity
)

Player กับ Vehicle ควรอยู่ Bucket เดียวกันไหม

ถ้า Vehicle เป็นส่วนหนึ่งของ Instance เดียวกัน โดยทั่วไปควรจัดให้อยู่ Bucket เดียวกัน

Routing Bucket ใช้ทำ Mission Instance ได้ไหม

ได้ และเป็นหนึ่งใน Use Case หลัก

ใช้ทำ Party ได้ไหม

ได้

ใช้ทำ Lobby ได้ไหม

ได้

ใช้ทำ Character Selection ได้ไหม

ได้ และ Cfx.re ยกเป็น Use Case โดยตรง

ใช้ทำ Interior ได้ไหม

Cfx.re ระบุว่า Interior ไม่ใช่ Use Case ที่แนะนำสำหรับ Routing Bucket โดยทั่วไป

Routing Bucket แยก Database ไหม

ไม่

Routing Bucket แยก Lua Variables ไหม

ไม่

Routing Bucket แยก Event Broadcast ให้อัตโนมัติไหม

อย่าพึ่งสมมติแบบนั้น ควร Target Events เฉพาะ Players ใน Instance ของคุณ

Routing Bucket ต้องใช้ OneSync ไหม

ใช่ เป็น Feature ใน OneSync/State Awareness Architecture

ปิด NPC ใน Bucket ได้ไหม

ได้ด้วย

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

ป้องกัน Client Spawn Entity ใน Bucket ได้ไหม

ได้ด้วย Entity Lockdown Mode เช่น strict ตาม Requirement

strict คืออะไร

ไม่อนุญาตให้ Clients สร้าง Entities ใน Bucket นั้นตาม OneSync Lockdown Policy

Player เลือก Bucket เองควรไหม

ไม่ควรสำหรับ Instance ที่มี Security/Privacy Server ควร Validate แล้วเป็นผู้กำหนด Bucket

มี Event ตอน Player เปลี่ยน Bucket ไหม

มี onPlayerBucketChange

มี Event ตอน Entity เปลี่ยน Bucket ไหม

มี onEntityBucketChange

Routing Bucket มีผลกับ Performance ไหม

แต่ละ Bucket มี Memory Cost จึงไม่ควรสร้างจำนวนมากโดยไม่มีเหตุผลและ Lifecycle

สรุป FiveM Routing Bucket คืออะไร

FiveM Routing Bucket คือระบบ Instance หรือ Dimension ของ OneSync ที่ใช้แยก Player และ Entity ออกเป็น Routing Context คนละชุดภายใน FXServer เดียว

ตัวอย่าง

Bucket 0
→ Main World

Bucket 101
→ Party Mission A

Bucket 102
→ Party Mission B

Bucket 500
→ Character Selection

Player เปลี่ยน Bucket ด้วย

SetPlayerRoutingBucket(
    playerId,
    bucket
)

Entity เปลี่ยนด้วย

SetEntityRoutingBucket(
    entity,
    bucket
)

และสามารถตรวจด้วย

GetPlayerRoutingBucket(...)
GetEntityRoutingBucket(...)

สิ่งสำคัญคืออย่าย้ายเฉพาะ Player แต่ลืม Mission Vehicles, Peds และ Objects เพราะ Entities ที่อยู่ Bucket อื่นจะไม่ได้อยู่ Routing Context เดียวกัน

สำหรับ Bucket ที่ต้องการควบคุมเข้มงวด ยังสามารถใช้

SetRoutingBucketEntityLockdownMode(
    bucket,
    'strict'
)

และ

SetRoutingBucketPopulationEnabled(
    bucket,
    false
)

เพื่อควบคุม Client Entity Creation และ Population ตาม Requirement

แต่ Routing Bucket ไม่ใช่คำตอบสำหรับทุกสิ่ง Cfx.re ระบุชัดว่า Interior ปกติไม่ใช่ Use Case ที่แนะนำสำหรับ Routing Buckets และทุก Bucket ยังมี Memory Cost จึงควรสร้างเท่าที่จำเป็นพร้อม Cleanup Lifecycle ที่ชัดเจน

สำหรับผู้ที่เรียน FiveM Developer กับ comsiam ให้จำว่า Routing Bucket ไม่ใช่แค่ “เลขห้อง” แต่เป็นส่วนหนึ่งของ OneSync Networking Architecture ซึ่ง Player, Vehicle, Ped, Object, Scope, Population และ Entity Security ล้วนได้รับผลจากการจัด Bucket

และหลักสำคัญจาก comsiam คือ Client ควรขอเข้า Session หรือ Mission ส่วน Server เป็นผู้ตัดสินว่าจะนำ Player ไป Bucket ใด ไม่ควรเปิด Network Event ที่ให้ Client ส่ง Bucket ID แล้ว Server ย้ายตามทันที

หัวข้อถัดไปคือ วิธีใช้ Routing Bucket ทำ Instance หรือ Dimension ใน FiveM ซึ่งจะนำพื้นฐานทั้งหมดนี้ไปสร้างระบบจริง ตั้งแต่ Bucket Allocator, Party Instance, การย้าย Player/Entity, การกลับ Bucket 0 ไปจนถึง Cleanup เมื่อ Instance ไม่มีผู้เล่นเหลือ

Comments

Popular posts from this blog

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

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

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