FiveM playerJoining คืออะไร? ต่างจาก playerConnecting อย่างไร และควรใช้ตอนไหน
FiveM playerJoining คือ Server Event ที่เกิดขึ้นเมื่อผู้เล่นผ่านช่วง Connecting มาแล้วและได้รับ NetID ที่กำหนดเสร็จสมบูรณ์ จาก Server โดย Cfx.re ระบุว่า Event นี้ส่งทั้ง source ซึ่งเป็น NetID ปัจจุบันของผู้เล่น และ oldID ซึ่งเป็น Temporary ID เดิมที่ใช้ในช่วง playerConnecting.
ดังนั้น playerConnecting และ playerJoining ไม่ใช่ Event เดียวกันและไม่ควรถูกใช้แทนกันทุกกรณี โดย playerConnecting เหมาะกับการตรวจสอบก่อนยอมรับ Connection เช่น Allowlist หรือ Ban Check ส่วน playerJoining เหมาะกับ Logic ที่ต้องทำหลังผู้เล่นได้รับ NetID จริงแล้ว.
Meta SEO
Meta Title: FiveM playerJoining คืออะไร? ต่างจาก playerConnecting อย่างไร
Meta Description: อธิบาย FiveM playerJoining แบบละเอียด source, oldID, NetID ต่างจาก playerConnecting อย่างไร ควรใช้ตอนไหน พร้อมตัวอย่าง Lua และวิธี Debug
Focus Keyword: FiveM playerJoining
Related Keywords: FiveM playerJoining event, FiveM playerConnecting, FiveM source, FiveM NetID, FiveM oldID, FiveM server events
สารบัญ
① FiveM playerJoining คืออะไร
playerJoining เป็น Server-side Event ของ FiveM ที่ Trigger เมื่อผู้เล่นได้รับ NetID ที่ถูก Assign เสร็จแล้ว.
รูปแบบข้อมูลของ Event คือ:
playerJoining(source, oldID)
โดย:
source= NetID ปัจจุบันของผู้เล่นoldID= Temporary ID จากช่วงplayerConnecting
นี่คือความแตกต่างสำคัญที่ Server Developer ควรเข้าใจ.
② playerJoining ทำงานฝั่งไหน
เป็น Server-side Event
จึงควรเขียน Handler ไว้ใน Server Script เช่น:
AddEventHandler('playerJoining', function(oldID)
local src = source
print(('Player joined with source %s'):format(src))
end)
FiveM ระบุ playerJoining อยู่ในรายการ Server Events ไม่ใช่ Client Events.
③ playerJoining ทำงานตอนไหน
ลำดับอย่างง่ายคือ:
Player กดเข้า Server
↓
playerConnecting
↓
ตรวจ Allowlist / Ban / Identifier
↓
Connection ผ่าน
↓
ผู้เล่นได้รับ NetID
↓
playerJoining
↓
เข้าสู่ระบบ Server ต่อ
Cfx.re ระบุว่า playerConnecting เกิดตอน Player กำลังพยายาม Connect ส่วน playerJoining เกิดเมื่อ Player ได้รับ NetID ที่ Assign เสร็จแล้ว.
④ playerJoining เกิดก่อนหรือหลัง playerConnecting
หลัง playerConnecting
ใน playerConnecting ตัว source ยังเป็น Temporary Player ID ที่ใช้ได้กับ Function บางส่วนเท่านั้น.
เมื่อมาถึง playerJoining FiveM จะมี NetID ที่ Assign เสร็จแล้ว และยังส่ง oldID ซึ่งอ้างถึง TempID เดิมจากช่วง Connecting มาให้ด้วย.
⑤ ทำไมต้องมีสอง Event
เพราะสองช่วงมีหน้าที่ต่างกัน
playerConnecting
เหมาะกับการตัดสินว่า Player ควรได้รับอนุญาตให้เข้า Server หรือไม่
playerJoining
เหมาะกับ Logic ที่ต้องทำเมื่อ Player ได้รับ NetID และกำลังเข้าสู่ Server จริง
การแยกสองช่วงทำให้ Connection Pipeline ชัดเจนขึ้น.
⑥ source ใน playerJoining คืออะไร
Cfx.re ระบุว่า source ใน playerJoining คือ Player NetID ที่ถูก Assign แล้ว.
ใน Lua สามารถเก็บไว้ด้วย:
local src = source
แล้วนำไปใช้กับ Server-side Player Functions ที่รองรับ Player ID ได้
⑦ source คือเลขอะไร
มักเป็นตัวเลข Server-side ที่ใช้ระบุผู้เล่นที่ Connected อยู่ เช่น:
1
7
24
53
FiveM มี GetPlayers() ซึ่งคืนรายการ Server IDs ของผู้เล่นที่ Connected อยู่ทั้งหมด.
ตัวเลขนี้ไม่ใช่ License Identifier และไม่ควรถูกใช้เป็น Persistent Database Account Key
⑧ source เปลี่ยนได้ไหมหลัง Reconnect
Server ID/Player ID ใช้ระบุตัวผู้เล่นใน Connection ปัจจุบัน จึงไม่ควรถูกมองเป็น Persistent Identity
สำหรับข้อมูล Account ที่ต้องติดตามข้าม Session ควรใช้ Identifiers เช่น License/Cfx Identifier ตาม Architecture ของ Resource.
⑨ oldID คืออะไร
oldID คือ Temporary ID เดิมของ Player ในช่วง playerConnecting
Cfx.re ระบุไว้โดยตรงใน Parameters ของ playerJoining.
จึงช่วยเชื่อมสถานะระหว่าง:
Temporary Connecting ID
↓
Final Player NetID
⑩ oldID ใช้ทำอะไร
เหมาะกับระบบที่ต้อง Track Player ตั้งแต่ช่วง Connecting แล้วต้อง Mapping State ต่อเมื่อเข้าสู่ playerJoining
ตัวอย่างแนวคิด:
playerConnecting
Temp ID = 65535
↓
เก็บ Temporary State
↓
playerJoining
oldID = 65535
source = 27
↓
ย้าย State ไป source 27
ค่าเลขเป็นเพียงตัวอย่าง แนวคิดเรื่อง oldID อ้างอิงจากนิยามของ Cfx.re.
⑪ ต้องใช้ oldID ทุก Resource ไหม
ไม่ต้อง
Resource ทั่วไปที่ไม่ได้เก็บ Temporary Connection State อาจไม่จำเป็นต้องใช้ oldID
หากต้องการเพียงรู้ว่า Player คนใหม่ได้รับ NetID และเข้าสู่ Server แล้ว ใช้ source อาจเพียงพอ
⑫ อย่าเก็บ oldID เป็น Account ID
oldID เป็น Temporary ID จากช่วง Connection ไม่ใช่ Persistent Player Identity.
Database Account ควรใช้ Identifier Strategy ที่เหมาะสม เช่น Rockstar Online Services License หรือ Cfx Identifier ตามระบบที่ออกแบบไว้.
⑬ playerConnecting กับ playerJoining ต่างกันอย่างไร
| หัวข้อ | playerConnecting | playerJoining |
|---|---|---|
| ช่วงเวลา | กำลัง Connect | ได้ NetID แล้ว |
| Player ID | Temporary | Final-assigned NetID |
| Reject Connection | ทำได้ | ไม่ใช่จุดหลักสำหรับงานนี้ |
| Deferrals | มี | ไม่มี Deferrals แบบ Connecting |
| Allowlist Check | เหมาะ | ควรทำก่อนหน้านี้ |
| Ban Check | เหมาะ | ควรทำก่อนหน้านี้ |
| Post-connect Initialization | ไม่ใช่จุดหลัก | เหมาะกว่า |
| oldID | ยังเป็น ID ปัจจุบัน | ได้รับเป็น Parameter |
ความแตกต่างนี้อ้างอิงจาก Server Event Definitions ปัจจุบันของ Cfx.re.
⑭ Allowlist ควรทำใน Event ไหน
โดยทั่วไปงานที่ต้อง ตัดสินก่อนให้ Player เข้า Server เหมาะกับ playerConnecting
Cfx.re มี Deferrals และตัวอย่างตรวจ License/Ban ใน playerConnecting โดยตรง.
ดังนั้นอย่ารอจนถึง playerJoining แล้วค่อยทำ Allowlist หลัก หากเป้าหมายคือป้องกัน Connection ตั้งแต่ต้น
⑮ Ban Check ควรทำใน playerJoining ไหม
Ban Check สำหรับป้องกันการเข้า Server ควรทำใน playerConnecting
Official Example ของ Cfx.re ใช้ License Identifier และ Deferrals ตรวจ Ban ก่อนอนุญาต Connection.
playerJoining ควรใช้กับงานหลัง Connection ผ่านแล้วมากกว่า
⑯ Database Check ใช้ Event ไหน
ขึ้นกับวัตถุประสงค์
ต้องรู้ก่อนว่าจะให้เข้าไหม
ใช้ playerConnecting
ไม่จำเป็นต้อง Block Connection และต้องการ Initialize หลังมี NetID
พิจารณา playerJoining หรือ Stage หลังจากนั้นตาม Framework Architecture
Cfx.re ออกแบบ Deferrals ใน playerConnecting สำหรับ Async Check ที่ต้อง Block Connection โดยเฉพาะ.
⑰ playerJoining เหมาะกับงานอะไร
ตัวอย่าง Use Cases:
Log ว่า Player ผ่าน Connection แล้ว
Mapping TempID → NetID
เตรียม Server-side State
ส่ง Event ต่อไปยัง Resource อื่น
Initialize ระบบที่ต้องรู้ Player NetID
จัด Session Tracking
แต่ต้องระวังไม่ทำ Initialization ซ้ำกับ Framework ที่ใช้อยู่แล้ว
⑱ ใช้ playerJoining Log Player ได้ไหม
ได้
ตัวอย่าง:
AddEventHandler('playerJoining', function(oldID)
local src = source
local name = GetPlayerName(src)
print(('%s joined with server ID %s'):format(name or 'Unknown', src))
end)
FiveM มี Server-side Player IDs สำหรับ Connected Players และ GetPlayers() ใช้ ID ประเภทเดียวกันในการวนรายชื่อผู้เล่น.
⑲ ใช้ GetPlayerName ได้ไหม
เมื่อ Player อยู่ในช่วงที่มี NetID แล้ว Server-side API ที่รองรับ Player ID สามารถนำ source ไปใช้ตามบริบทได้
อย่างไรก็ตาม Developer ควรตรวจว่า Native/Function ที่ใช้สามารถทำงานใน Stage นั้นได้จริง ไม่ควรเรียก Client-dependent API เร็วเกินไป. Cfx.re เองเตือนว่าบาง Client-side APIs ไม่พร้อมใช้งานใน Server-side Context และบาง Entity ต้องตรวจการมีอยู่ก่อนใช้.
⑳ playerJoining หมายความว่า Character พร้อมแล้วไหม
ไม่จำเป็น
playerJoining หมายความว่าผู้เล่นมี Final-assigned NetID ตามนิยาม Cfx.re ไม่ได้หมายความว่า Framework Character, Ped, Inventory, Job, Housing หรือทุก Client Resource Initialize เสร็จแล้ว.
นี่เป็นจุดที่ Developer FiveM มักสับสน
㉑ อย่า Initialize Gameplay ทุกอย่างทันที
Resource บางระบบต้องรอ:
Framework Player Loaded
Character Selection
Database Load
Ped Creation
Client Resource Ready
ดังนั้น playerJoining ไม่ควรถูกใช้เป็นสัญญาณว่า Gameplay ทุกระบบพร้อม 100%
ควรใช้ Event ของ Framework หรือ Resource ที่เหมาะสมต่อไป
㉒ Trigger Client Event ตอน playerJoining ได้ไหม
FiveM รองรับการ Trigger Network Events ระหว่าง Server และ Client แต่ควร Trigger เมื่อ Client-side Resource และ State ที่ต้องใช้พร้อมจริง.
หาก Trigger เร็วเกินไป Event อาจไม่ให้ผลตามที่ Resource คาด
จึงควรออกแบบ Initialization Sequence อย่างชัดเจน
㉓ TriggerServerEvent ต่างจาก playerJoining อย่างไร
TriggerServerEvent เป็นวิธีให้ Client Script ส่ง Network Event มายัง Server
ส่วน playerJoining เป็น Core Server Event ที่ FiveM Trigger เองเมื่อผู้เล่นได้รับ NetID.
สองอย่างจึงทำหน้าที่คนละแบบ
㉔ AddEventHandler ใช้ฟัง playerJoining อย่างไร
FiveM มี AddEventHandler() สำหรับลงทะเบียน Callback ให้ Event.
ตัวอย่าง:
AddEventHandler('playerJoining', function(oldID)
local src = source
print(('Player %s joined'):format(src))
end)
ควรเก็บ source ไว้ใน Local Variable หากมี Async Logic ตามหลัง
㉕ ทำไมควรเก็บ source เป็น local
ใน Event-driven Code โดยเฉพาะเมื่อมี Callback/Async Operations การเก็บ:
local src = source
ตั้งแต่ต้นทำให้ Code ชัดเจนว่า Player คนใดเป็นต้นทางของ Handler
และช่วยลดความสับสนเมื่อมี Events หลาย Player เกิดใกล้กัน
㉖ ใช้ GetPlayerIdentifiers ใน playerJoining ได้ไหม
เมื่อมี Player ID ที่ Server รู้จัก สามารถใช้ Player Identifier APIs ตาม Context ที่รองรับได้
GetPlayerIdentifiers(player) คืน Identifiers เช่น steam, discord, license, license2, fivem และ ip.
อย่างไรก็ตาม Official Example ระบุว่า Function นี้เหมาะมากกับ playerConnecting เมื่อจำเป็นต้องตรวจ Identity ก่อน Connection ผ่าน.
㉗ Identifier กับ source ต่างกันอย่างไร
source
Player ID ของ Connection ปัจจุบัน
Identifier
ตัวระบุจาก Provider เช่น:
license:
license2:
fivem:
steam:
discord:
Cfx.re แยก PlayerIds และ Account Identifiers เป็นคนละแนวคิดอย่างชัดเจน.
㉘ license2 ควรใช้เมื่อไหร่
Cfx.re ระบุว่า FiveM ใช้ License Identifier ที่ตรวจสอบผ่าน Rockstar Online Services และถ้ามีทั้ง license และ license2 ควร Prefer license2.
แต่หาก Database เดิมใช้ license อยู่แล้ว ควรทำ Migration Plan ก่อนเปลี่ยน Primary Key
㉙ Server ID ใช้เก็บเงินหรือ Inventory ได้ไหม
ไม่ควรใช้ Server ID เป็น Persistent Database Key
เพราะ Server ID ใช้ระบุ Connected Player ใน Session ปัจจุบัน ขณะที่ข้อมูลอย่างเงิน, Inventory หรือ Character ต้องสามารถ Mapping กลับไปยัง Account หลัง Reconnect
ควรใช้ Account/Character Identifier ตาม Framework Architecture
㉚ ใช้ oldID หา Identifier เดิมได้ไหม
ไม่ควรใช้ oldID แทน Identifier
oldID เป็น Temporary ID เดิมจาก playerConnecting เท่านั้น.
หากต้องการ Identity ให้ใช้ Identifier APIs โดยตรง
㉛ playerJoining กับ GetPlayers เกี่ยวข้องกันอย่างไร
playerJoining แจ้ง Event ของ Player ที่เพิ่งได้รับ NetID
ส่วน:
GetPlayers()
คืนรายการ Server IDs ของผู้เล่นที่ Connected อยู่ทั้งหมด.
จึงเหมาะคนละ Use Case:
playerJoining→ Event-drivenGetPlayers()→ Query Current Players
㉜ ไม่ควร Loop GetPlayers ทุก Tick
หากระบบต้องทำงาน “เมื่อ Player เข้า” ควรใช้ Event-driven Architecture เช่น playerJoining แทนการ Loop GetPlayers() ทุก Frame/Tick โดยไม่มีเหตุผล
ช่วยลดงานที่ Server ต้องทำซ้ำ
㉝ playerJoining ไม่ทำงาน แก้อย่างไร
ตรวจ:
Script เป็น
server_scriptหรือไม่Resource Start อยู่หรือไม่
Event Name สะกดถูกหรือไม่
Console มี Script Error หรือไม่
Resource Restart หลังแก้หรือไม่
Player Connect ผ่านถึง Stage Joining จริงหรือไม่
Cfx.re ระบุ playerJoining เป็น Server Event ดังนั้น Handler ต้องอยู่ใน Server-side Context.
㉞ Event Name ต้องสะกดอย่างไร
ต้องใช้:
playerJoining
ไม่ใช่:
playerJoin
playerJoined
onPlayerJoining
ชื่อ Core Event ปัจจุบันใน Cfx.re Server Events คือ playerJoining.
㉟ playerJoining ไม่ Trigger เพราะ Player ถูก Reject ก่อน
หาก Player ถูกปฏิเสธใน playerConnecting เขาจะไม่ผ่านเข้าสู่ Stage ที่ได้รับ Final NetID ตาม Flow ปกติ
ดังนั้นหาก playerJoining ไม่เกิด ให้ตรวจ Connection Resource และ Deferrals ก่อน โดยเฉพาะ Allowlist/Ban Script.
㊱ Player ค้าง Connecting แล้วไม่มี playerJoining
ตรวจ playerConnecting Resources ก่อน
หาก Resource เริ่ม Deferral แต่ยังไม่ Finalize Connection ผู้เล่นอาจยังไม่เข้าสู่ขั้นที่ playerJoining จะ Trigger
Cfx.re ระบุ deferrals.done() เป็นส่วนหนึ่งของการ Finalize Connection Decision.
㊲ playerJoining Trigger แต่ Framework หา Player ไม่เจอ
เป็นไปได้ว่า Framework Player Object ยังไม่ได้ Initialize เสร็จ
playerJoining รับประกันเรื่อง Final NetID ตาม Cfx.re แต่ไม่ได้รับประกัน Framework-specific Player Loaded State.
ควรใช้ Framework Event ที่ Framework นั้นกำหนด
㊳ Player Ped หาไม่เจอใน playerJoining
อย่าสมมติว่าทุก Entity พร้อมทันทีที่ NetID ถูก Assign
Cfx.re แนะนำในบริบทการ Migration ว่าเพื่อหลีกเลี่ยงการเรียก Function เร็วเกินไป ควรตรวจ DoesEntityExist ก่อนใช้ Entity เมื่อเหมาะสม.
ดังนั้น Ped-dependent Initialization อาจต้องรอ Stage หลังจากนี้
㊴ Trigger Client Event แล้ว Client ไม่รับ
ตรวจ:
Client Resource Start หรือยัง
Client Event Registered หรือยัง
Player Stage พร้อมหรือยัง
Event Name ตรงกันหรือไม่
Target Server ID ถูกหรือไม่
FiveM รองรับ Server-to-Client และ Client-to-Server Network Events แต่ Timing ยังคงมีผลต่อ Resource Logic.
㊵ ทุก Resource ใช้ playerJoining พร้อมกันได้ไหม
ได้ในเชิง Event System เพราะหลาย Handlers สามารถฟัง Event เดียวกันได้
แต่หากแต่ละ Resourceทำ Database Query หรือ Initialization ขนาดใหญ่พร้อมกัน อาจทำให้ Architecture ซับซ้อน
ควรกำหนดว่า Resource ใดเป็นเจ้าของ
Identity
Character
Session
Inventory
ให้ชัดเจน
㊶ อย่า Query Database ซ้ำโดยไม่จำเป็น
หาก Identifier และ Account ถูกตรวจแล้วใน playerConnecting ไม่จำเป็นต้องทำ Query ชุดเดียวกันซ้ำอีกครั้งใน playerJoining หาก Architecture สามารถส่ง/Cache State อย่างเหมาะสม
เป้าหมายคือให้แต่ละ Stage มีหน้าที่ชัดเจน
㊷ Connection Pipeline ที่เป็นระเบียบ
ตัวอย่าง:
playerConnecting
├── Identifier
├── Allowlist
├── Ban
└── Connection Decision
playerJoining
├── Session Mapping
├── NetID-dependent logic
└── Post-connect state
Framework Player Loaded
├── Character
├── Inventory
├── Job
└── Gameplay
นี่เป็น Architecture ตัวอย่างเพื่อแยกความรับผิดชอบ ไม่ใช่ Requirement ตายตัวของ Cfx.re
㊸ playerJoining ใช้ประกาศ Player เข้า Server ได้ไหม
ทำได้ในเชิง Event แต่ควรพิจารณาว่าต้องการประกาศตอน:
ได้ NetID
Character Loaded
Spawn สำเร็จ
แบบไหน
สำหรับ Roleplay Server การประกาศว่า “Player พร้อมเล่นแล้ว” อาจเหมาะกับ Stage หลัง Character Load มากกว่า playerJoining
㊹ playerJoining ใช้เพิ่ม Player ใน Session Table ได้ไหม
ได้หาก Session Table ต้องอ้าง Server ID ปัจจุบัน
ตัวอย่าง:
local sessions = {}
AddEventHandler('playerJoining', function(oldID)
local src = source
sessions[src] = {
joinedAt = os.time()
}
end)
แต่ต้อง Cleanup เมื่อ Player ออกด้วย
㊺ Cleanup Session ใช้ Event ไหน
Cfx.re มี playerDropped ซึ่ง Trigger เมื่อ Player Disconnect จาก Server และส่งข้อมูล Reason, Resource Name และ Client Drop Reason.
จึงสามารถใช้ร่วมกับ playerJoining ใน Session Tracking
ตัวอย่าง:
playerJoining → เพิ่ม Session
playerDropped → ลบ Session
㊻ playerDropped คือ Event คู่ที่ควรรู้
Cfx.re ระบุว่า playerDropped ถูกเรียกเมื่อ Player หลุดออกจาก Server และสามารถอ่าน source ของ Player ที่ Disconnect ได้.
ดังนั้น Resource ที่สร้าง State ใน playerJoining ควรมี Cleanup Strategy เมื่อ Player ออกด้วย
㊼ ระวัง Memory State ค้างหลัง Player ออก
ถ้าสร้าง:
sessions[src] = {...}
แต่ไม่ลบเมื่อ playerDropped ค่าเก่าสามารถค้างใน Memory ของ Resource ได้
ควร Cleanup:
AddEventHandler('playerDropped', function()
sessions[source] = nil
end)
playerDropped เป็น Core Server Event สำหรับ Player Disconnect.
㊽ Server ID ถูกนำกลับมาใช้ใหม่ได้ไหม
Server-side Player IDs ไม่ควรถูกออกแบบเป็น Permanent Identity
ดังนั้นเมื่อ Player ออก ต้อง Cleanup State ที่ผูกกับ source และเมื่อ Player ใหม่เข้ามาให้สร้าง State ใหม่จาก Event/Identity ที่เหมาะสม
㊾ Debug playerJoining ด้วย Console อย่างไร
เพิ่ม Log ชั่วคราว:
AddEventHandler('playerJoining', function(oldID)
local src = source
print(('playerJoining: source=%s oldID=%s'):format(src, oldID))
end)
จากนั้น:
Restart Resource
เข้า Server
เปิด txAdmin Console
ดูว่า Event Trigger หรือไม่
เปรียบเทียบ
sourceและoldIDตรวจ Error ต่อจากนั้น
เหมาะกับ Development Server มากกว่าการ Debug จากการเดา
㊿ Checklist playerJoining สำหรับ Developer
ตรวจว่า:
Handler อยู่ Server Script
ใช้ชื่อ
playerJoiningถูกต้องเข้าใจว่า
sourceคือ Final NetIDเข้าใจว่า
oldIDคือ TempIDไม่ใช้ Server ID เป็น Persistent Account Key
Allowlist/Ban ทำใน Stage ที่เหมาะสม
ไม่สมมติ Character พร้อมแล้ว
ไม่สมมติ Ped พร้อมแล้ว
ใช้ Framework Player-loaded Event เมื่อต้องการ
ไม่ Query Database ซ้ำโดยไม่จำเป็น
Cleanup Session ตอน
playerDroppedดู Console เมื่อ Event ไม่ Trigger
ทดสอบ Reconnect
ทดสอบ Resource Restart
ทดสอบผู้เล่นหลายคนพร้อมกัน
ตัวอย่าง playerJoining แบบพื้นฐาน
AddEventHandler('playerJoining', function(oldID)
local src = source
local name = GetPlayerName(src)
print(('Player %s joined: source=%s oldID=%s')
:format(name or 'Unknown', src, oldID))
end)
source และ oldID มีความหมายตาม Server Event Definition ของ Cfx.re.
ตัวอย่าง Mapping Temporary ID
local pendingPlayers = {}
AddEventHandler('playerConnecting', function(playerName)
local tempId = source
pendingPlayers[tostring(tempId)] = {
name = playerName
}
end)
AddEventHandler('playerJoining', function(oldID)
local src = source
local pending = pendingPlayers[tostring(oldID)]
if pending then
print(('%s moved from temp ID %s to source %s')
:format(pending.name, oldID, src))
pendingPlayers[tostring(oldID)] = nil
end
end)
นี่เป็นตัวอย่าง Architecture เพื่อแสดงประโยชน์ของ oldID; Cfx.re ระบุว่า oldID คือ TempID เดิมจาก playerConnecting.
ตัวอย่าง Session Cleanup
local sessions = {}
AddEventHandler('playerJoining', function()
local src = source
sessions[src] = {
connected = true,
joinedAt = os.time()
}
end)
AddEventHandler('playerDropped', function()
sessions[source] = nil
end)
playerDropped เป็น Event ที่ถูกเรียกเมื่อ Player Disconnect จาก Server.
FiveM playerJoining ไม่ทำงาน แก้อย่างไร
เริ่มจากตรวจ:
Server Script → Resource Running → Event Name → playerConnecting → Console
หาก Player ถูก Reject หรือค้างใน Deferral ก่อน Connection ผ่าน เขาจะยังไม่ถึง Stage ที่มี Final-assigned NetID สำหรับ playerJoining.
FiveM playerJoining กับ playerConnecting ใช้อันไหนดี
ถ้าต้องการ:
ตรวจว่าจะให้ Player เข้าไหม → playerConnecting
ถ้าต้องการ:
ทำงานหลัง Player มี NetID → playerJoining
นี่เป็นวิธีแยกสอง Event ที่ตรงกับนิยามของ Cfx.re มากที่สุด.
FiveM playerJoining กับ playerDropped ใช้คู่กันอย่างไร
ใช้:
playerJoining
↓
สร้าง Session State
playerDropped
↓
ล้าง Session State
playerDropped ให้ทั้ง Reason, Resource Name และ Client Drop Reason สำหรับการตรวจ Disconnect เพิ่มเติม.
FiveM source ใน playerJoining ใช้กับ Database ได้ไหม
ใช้เพื่ออ้าง Player ใน Session ปัจจุบันได้ แต่ไม่ควรใช้เป็น Primary Persistent ID
หากต้องการ Account Identity ให้ใช้ Identifier Strategy เช่น License/Cfx Identifier ตามระบบ Server.
FiveM oldID ต้องเก็บไหม
ไม่จำเป็นถ้า Resource ไม่มี Temporary State ที่ต้อง Mapping จาก playerConnecting
แต่หาก Resource เก็บข้อมูลด้วย TempID ระหว่าง Connection oldID ช่วยให้หา State เดิมและย้ายไปยัง Final source ได้.
FAQ FiveM playerJoining
FiveM playerJoining คืออะไร
เป็น Server Event ที่ Trigger เมื่อ Player ได้รับ NetID ที่ Assign เสร็จแล้ว.
playerJoining เกิดก่อนหรือหลัง playerConnecting
เกิดหลัง playerConnecting เพราะ Connecting ใช้ Temporary Player ID ส่วน Joining เกิดเมื่อมี Final NetID แล้ว.
source ใน playerJoining คืออะไร
คือ Player NetID/Server-side Player ID ที่ Assign แล้วสำหรับ Connection ปัจจุบัน.
oldID คืออะไร
คือ Temporary ID เดิมของ Player จากช่วง playerConnecting.
playerJoining ใช้ทำ Whitelist ได้ไหม
ทางเทคนิคสามารถเขียน Logic ได้หลายแบบ แต่หากต้องการปฏิเสธ Player ก่อนเข้า Server ควรทำใน playerConnecting ซึ่งมี Deferrals และ Connection Rejection Flow โดยตรง.
playerJoining หมายความว่า Character โหลดเสร็จแล้วไหม
ไม่ Cfx.re ระบุเพียงว่า Player ได้รับ Final NetID แล้ว ไม่ได้ระบุว่า Framework Character หรือ Gameplay State ทั้งหมดพร้อมแล้ว.
Player ออก Server ใช้ Event อะไร
ใช้ playerDropped ซึ่ง Trigger เมื่อ Player Disconnect และมีข้อมูล Reason รวมถึง Client Drop Reason.
ประเด็นสำคัญ
FiveM playerJoining เป็น Server Event สำหรับช่วงที่ Player ผ่าน Connection มาแล้วและได้รับ Final-assigned NetID โดย source คือ ID ปัจจุบันและ oldID คือ Temporary ID จาก playerConnecting.
ความแตกต่างที่ควรจำที่สุดคือ playerConnecting ใช้ก่อนอนุญาต Connection ส่วน playerJoining ใช้หลังมี NetID แล้ว ดังนั้น Allowlist, Ban Check และ Async Database Validation ที่ต้อง Block Connection ควรอยู่ใน playerConnecting ซึ่งมี Deferrals รองรับโดยตรง.
อย่างไรก็ตาม playerJoining ไม่ได้หมายความว่า Character, Ped, Inventory หรือ Framework Player Object พร้อมทั้งหมดแล้ว Developer จึงควรใช้ Framework-specific Loaded Events หรือ Client Ready Logic ต่อเมื่อระบบนั้นต้องการ.
หาก Resource สร้าง Session State ด้วย source เมื่อ Player Join ก็ควร Cleanup State ตอน playerDropped เพราะ Event ดังกล่าวเกิดเมื่อ Player Disconnect จาก Server.
สำหรับผู้อ่าน comsiam ให้จำสูตร “Connecting = ตรวจสิทธิ์, Joining = ได้ NetID, Dropped = ล้าง Session” และ comsiam แนะนำให้แยกแต่ละ Stage ให้มีหน้าที่ชัดเจน จะช่วยลดปัญหา Player Data โหลดซ้ำ, Query Database ซ้ำ และ Script ทำงานเร็วเกินกว่าที่ Character หรือ Client จะพร้อม
Comments
Post a Comment