Skip to content

📬 AFU.Mailbox

ข้อมูลสคริปต์

  • Resource: AFU.Mailbox (v1.0.8) — ระบบกล่องจดหมาย / ส่งของขวัญให้ผู้เล่น
  • Framework: ESX Legacy (es_extended)
  • Dependencies (จำเป็น):
  • Optional (ทางเลือก):
    • AFU.Notify — ใช้แทนระบบแจ้งเตือนภายใน (กรณีปิด Internal Notification)
    • afu_log / nc_discordlogs — เปิดใช้เฉพาะเซิร์ฟเวอร์ที่มีระบบ Log เหล่านี้ (ถ้าไม่มีสคริปต์ทำงานได้ปกติ)

ข้อควรระวังเรื่องการแก้ไขไฟล์

  • หาก Resource ของคุณมาพร้อมระบบ License ให้ใช้ Token/License ที่ได้รับจากผู้ขายเท่านั้น และติดต่อผู้ขาย (awayfromus.store) เมื่อเกิดปัญหา
  • ให้แก้ไขเฉพาะไฟล์ในโฟลเดอร์ config/ เท่านั้น

🛠️ Installation

1. Download & Placement

นำโฟลเดอร์ Resource ไปวางใน resources/ ของเซิร์ฟเวอร์

text
resources/
└── [afu]/
    └── AFU.Mailbox/
        ├── config/
        ├── modules/
        ├── nui/
        ├── source/
        └── fxmanifest.lua

ห้ามเปลี่ยนชื่อโฟลเดอร์

ต้องตั้งชื่อโฟลเดอร์ว่า AFU.Mailbox ตามตัวอย่าง ชื่อต้องมีจุด (.) ตรงตามนี้เสมอ เพราะระบบเรียกใช้งานผ่านชื่อ Resource จากสคริปต์อื่น เช่น exports['AFU.Mailbox'] หากเปลี่ยนชื่อ Command และ Export ทั้งหมดจะใช้งานไม่ได้

2. ตั้งค่า server.cfg

เพิ่มบรรทัดเหล่านี้ โดย ต้อง ensure oxmysql และ es_extended ก่อนเสมอ

cfg
ensure oxmysql
ensure es_extended
ensure AFU.Mailbox

3. Database

ไม่ต้อง Import SQL เอง — เมื่อ Start Resource ครั้งแรก ระบบจะสร้าง Table ที่จำเป็นให้อัตโนมัติ 2 ตาราง:

ตารางหน้าที่
afu_mailsเก็บเมลที่ส่งให้ผู้เล่นแต่ละคน (สถานะอ่าน/รับของ/ลบ)
afu_mail_templatesเก็บเทมเพลตเมลที่แอดมินสร้าง (หัวเรื่อง, เนื้อหา, รางวัล)

::: note เงื่อนไขการสร้าง Table อัตโนมัติ

  • User ของ MySQL ที่ประกาศไว้ใน oxmysql ต้องมีสิทธิ์ CREATE ในฐานข้อมูลของเซิร์ฟเวอร์
  • ระบบใช้ตาราง users ของ ESX ที่มีอยู่แล้วสำหรับการส่งเมลหาผู้เล่นแบบ Offline / ตามอาชีพ (ไม่ต้องสร้างเพิ่ม) :::
📋 โครงสร้าง Table (สำหรับผู้ที่ต้องการ Import เองเท่านั้น)
sql
CREATE TABLE IF NOT EXISTS `afu_mails` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `identifier` varchar(50) NOT NULL,
    `mail_template_id` char(30) NOT NULL DEFAULT '',
    `get_reward_at` timestamp NULL DEFAULT NULL,
    `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
    `readed_at` timestamp NULL DEFAULT NULL,
    `deleted_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

CREATE TABLE IF NOT EXISTS `afu_mail_templates` (
    `id` char(30) NOT NULL DEFAULT '',
    `title` varchar(255) NOT NULL DEFAULT 'UNTITLE',
    `content` longtext NOT NULL,
    `rewards` longtext NOT NULL DEFAULT '{}',
    `created_by_identifier` varchar(50) NOT NULL,
    `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
    `updated_at` timestamp NOT NULL DEFAULT current_timestamp(),
    `deleted_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

4. Restart Server

Restart เซิร์ฟเวอร์ 1 ครั้ง แล้วตรวจสอบ Console ว่าไม่มี Error จาก AFU.Mailbox


⚙️ Configuration

ไฟล์ Config ที่ User แก้ไขได้มี 2 ไฟล์ อยู่ในโฟลเดอร์ config/:

ไฟล์ใช้ทำอะไร
config/system.config.luaตั้งค่าทั่วไป — รูปไอเทม, ประเภทของขวัญพิเศษ, การแจ้งเตือน
config/server.functions.luaตั้งค่าฝั่งเซิร์ฟเวอร์ — กลุ่มแอดมิน, การมอบรางวัล, ระบบ Log

🖼️ ตั้งค่ารูปไอเทม (system.config.lua)

Config.InventoryPath

Typestring
Default'nui://inventory/web/assets/icons/'

ที่อยู่โฟลเดอร์รูปภาพไอเทมที่ใช้แสดงในหน้า UI เมล ให้เปลี่ยนตาม Inventory ที่เซิร์ฟเวอร์ใช้งาน เช่น

lua
-- ตัวอย่าง
Config.InventoryPath = 'nui://inventory/web/assets/icons/'   -- default inventory
Config.InventoryPath = 'nui://ox_inventory/web/images/'      -- ox_inventory

WARNING

Path ต้องปิดท้ายด้วย / เสมอ และชื่อไฟล์รูปต้องตรงกับ spawn name ของไอเทม

Config.DefaultExtImage

Typestring
Default'.png'

นามสกุลไฟล์รูปภาพเริ่มต้นของไอเทม เช่น .png, .webp

Config.OverrideImageExtImageItems

Typetable<string, string>
Default{ ["weapon_box"] = ".gif" }

กำหนดนามสกุลรูปเฉพาะตัวของไอเทมบางชิ้น (เช่น ไอเทมที่เป็นไฟล์ GIF)

lua
Config.OverrideImageExtImageItems = {
    ["weapon_box"] = ".gif",
    ["gift_special"] = ".webp", -- เพิ่มไอเทมอื่นได้ตามต้องการ
}

Config.OverrideTypeItems

Typetable<string, string>
Default{ ["weapon_box"] = "item" }

บังคับชนิดการแสดงผลของไอเทมบางตัวในหน้า UI เช่น ให้ weapon_box แสดงเป็นไอเทมปกติ

🎁 ของขวัญแบบ Custom (AddOnItemsExecuteServerSide)

Typetable[] (name, label, svExecFunc)
Defaultมีตัวอย่าง new_player_item_set ให้ 1 รายการ

ใช้สร้าง ของขวัญแบบกำหนดเอง ที่ไม่ใช่ไอเทม/เงินปกติ เมื่อผู้เล่นกดรับเมล ฟังก์ชัน svExecFunc จะทำงานฝั่งเซิร์ฟเวอร์ทันที และรายการนี้จะปรากฏเป็นตัวเลือกของขวัญในหน้า UI ของแอดมินด้วย

lua
Config.AddOnItemsExecuteServerSide = {
    {
        name = "new_player_item_set",          -- ชื่ออ้างอิง (ห้ามซ้ำ, ห้ามมีช่องว่าง)
        label = "ชุดไอเทมผู้เล่นใหม่",           -- ชื่อที่แสดงใน UI
        svExecFunc = function(source, identifier, xPlayer)
            xPlayer.addInventoryItem('a_f_rod', 1)
            xPlayer.addMoney(50000)
        end
    }
}
FieldTypeคำอธิบาย
namestringชื่อ Key สำหรับอ้างอิง (ใช้ในระบบรางวัล)
labelstringชื่อที่แสดงในหน้า UI ของแอดมิน
svExecFuncfunction(source, identifier, xPlayer)โค้ดที่ทำงานเมื่อผู้เล่นกดรับของ

🔔 ตั้งค่าการแจ้งเตือน (Config.Notifications)

ตัวแปรTypeDefaultคำอธิบาย
useInternalNotificationbooleantruetrue = ใช้ระบบแจ้งเตือนในตัวของเมลเมื่อมีเมลเข้า
notifyTimeoutnumber5000ระยะเวลาแสดงผลแจ้งเตือน (มิลลิวินาที)

ใช้ Notify ภายนอก (External Callback)

หากตั้ง useInternalNotification = false ระบบจะเรียก Callback 2 ตัวนี้แทน ให้แก้ไขข้างในให้เป็น Notify ของเซิร์ฟเวอร์คุณ (ค่าเริ่มต้นใช้ AFU.Notify):

Callbackได้รับค่าใช้เมื่อ
Config.Notifications.ExternalCallbackAddMail(notificationItem){ id, type, label, title }มีเมลใหม่เข้ามาของผู้เล่น
Config.Notifications.ExternalCallbackStatus(res){ status: boolean, message: string }แจ้งผลสำเร็จ/ผิดพลาดต่าง ๆ ของระบบ

TIP

ถ้าไม่มี AFU.Notify ในเซิร์ฟเวอร์ ให้แก้เนื้อใน Callback เป็น Notify ของเซิร์ฟเวอร์คุณเอง (เช่น TriggerEvent('chat:addMessage', ...)) อย่าลบ Function ทิ้ง

👑 ตั้งค่าแอดมิน (server.functions.lua)

Functions.isAdmin(source)

Returnboolean
Defaultผู้เล่นที่อยู่กลุ่ม ESX admin หรือ superadmin เท่านั้น

ฟังก์ชันนี้ใช้ตรวจสิทธิ์ทั้งหมดของระบบเมล ได้แก่ การใช้ /mba, การสร้าง/แก้ไข/ลบเทมเพลต และการส่งเมล

lua
-- ตัวอย่าง: เพิ่มกลุ่ม mod ให้เป็นแอดมินของระบบเมลได้
return group == 'admin' or group == 'superadmin' or group == 'mod'

DANGER

อย่าเปิดสิทธิ์กว้างเกินไป เพราะผู้ที่ผ่าน isAdmin สามารถ ส่งของ/เงินให้ผู้เล่นคนใดก็ได้ ผ่านหน้า UI

💰 การมอบรางวัล (Functions.OnAddItemsFromMailRewards)

เมื่อผู้เล่นกดรับของในเมล ระบบจะมอบรางวัลตามประเภทที่แอดมินตั้งไว้:

ประเภทรางวัล (type)การมอบให้ (ESX)ตัวอย่าง name ที่ใช้ได้
itemxPlayer.addInventoryItem(name, count)ไอเทมในตาราง items เช่น water, bread
accountxPlayer.addAccountMoney(name, count)money, bank, black_money
exec-server-sideเรียกใช้ฟังก์ชันจาก Config.AddOnItemsExecuteServerSideชื่อ name ที่คุณสร้างเอง

ภายในฟังก์ชันนี้มีจุดที่ปรับแต่งได้ดังนี้:

  1. Discord Log (ทางเลือก) — มีการเรียก nc_discordlogs โดยมี Placeholder ให้ใส่ Webhook:
lua
exports.nc_discordlogs:Discord({
    webhook = 'your_web_hook_key', -- 👈 เปลี่ยนเป็นชื่อ Webhook ของคุณ หรือ Comment บล็อกนี้ออกถ้าไม่ใช้
    ...
})

WARNING

หากเซิร์ฟเวอร์ไม่มี nc_discordlogs หรือ afu_log ไม่ต้องตกใจ — โค้ดส่วนนี้ถูกป้องกัน Error ไว้แล้ว แต่ควร Comment ออกเพื่อความสะอาด และ อย่าปล่อยค่า your_web_hook_key ไว้ หากเปิดใช้ระบบ Log

  1. ลบเมลถาวรเมื่อรับของแล้ว (ทางเลือก) — ปกติเมลที่ลบจะถูกซ่อนไว้ในฐานข้อมูล หากต้องการให้ หายจาก Database ทันที เมื่อผู้เล่นกดรับของ ให้เปิดบรรทัดนี้ในไฟล์ Config:
lua
Queries.UnscopeDeleteMailByIds(mailIds)

🎮 Usage

Commands

Commandสิทธิ์คำอธิบาย
/mbpผู้เล่นทุกคนเปิดกล่องจดหมายของตัวเอง (อ่านเมล / รับของขวัญ / ลบเมล)
/mbaAdmin เท่านั้นเปิดหน้าจัดการเมล (สร้างเทมเพลต / ส่งเมล)

หน้าจอผู้เล่น (Mail Reader)

  • ดูรายการเมลทั้งหมดที่ได้รับ พร้อมจุดแจ้งเตือนเมลที่ยังไม่ได้อ่าน
  • เปิดอ่าน เมล — เนื้อหารองรับการจัดรูปแบบ HTML จาก Rich Text Editor
  • รับของขวัญ ได้ทั้งทีละเมลหรือหลายเมลพร้อมกัน (เมลที่รับแล้วจะไม่รับซ้ำ)
  • ลบเมล ออกจากกล่องจดหมาย
  • เมื่อมีเมลเข้าใหม่ขณะออนไลน์ ระบบจะแจ้งเตือนทันที (พร้อมเสียงประกอบใน UI)

หน้าจอแอดมิน (Mail Sender)

  1. สร้างเทมเพลตเมล — ตั้งหัวเรื่อง, เนื้อหา (HTML), และแนบรางวัลได้หลายชิ้น (ไอเทม / เงิน / ของขวัญ Custom)
  2. บันทึกเทมเพลต ไว้ใช้ซ้ำ, แก้ไข หรือลบได้
  3. เลือกกลุ่มผู้รับ ได้หลายรูปแบบ:
โหมดคำอธิบาย
ส่งทุกคนผู้เล่นทุกคนทั้ง ออนไลน์และออฟไลน์
ส่งผู้เล่นออนไลน์ทั้งหมดเฉพาะผู้เล่นที่ออนไลน์ตอนนั้น
ส่งตามอาชีพ (Job)ระบุชื่อ Job ได้หลายอัน ครอบคลุมผู้เล่นออฟไลน์ด้วย
สุ่มผู้เล่น N คนสุ่มจากผู้เล่นที่ออนไลน์
เลือกรายคนระบุ Server ID หรือ Steam Hex ได้
พื้นที่รอบตัว (Radius)ดึงวงเลือกพื้นที่รอบตัวแอดมิน แล้วส่งให้ผู้เล่นในวง
🎯 ปุ่มควบคุมการเลือกพื้นที่ (Radius Picker)
ปุ่มการทำงาน
Eเพิ่มรัศมี
Qลดรัศมี
Shift (ค้าง)ปรับรัศมีเร็วขึ้น
Enterยืนยันพื้นที่
Backspaceยกเลิก

🔌 Exports (สำหรับ Developer)

ฝั่ง Server

exports.AFU.Mailbox:sendMailToPlayer(targetIds, mailTemplateId)

ส่งเมลให้ผู้เล่นจากสคริปต์อื่น (เช่น ระบบสมัครสมาชิก, Event, Shop)

lua
-- รับได้ทั้ง Server ID (number) และ Identifier (steam hex) ผสมกันได้ใน array เดียว
local targetIds = { 23, "steam:110000112345678" }
local mailTemplateId = "FGQLJFRQROFGEFZNMJAAXFUACUHELU"
exports.AFU.Mailbox:sendMailToPlayer(targetIds, mailTemplateId)
ParameterTypeคำอธิบาย
targetIdstableArray ของ Server ID หรือ Identifier
mailTemplateIdstringID ของเทมเพลต (ดูได้จากหน้าจัดการเมลของแอดมิน)

TIP

  • ผู้เล่นที่ ออนไลน์ จะได้รับเมลและการแจ้งเตือนทันที
  • ผู้เล่นที่ ออฟไลน์ ให้ส่งด้วย Steam Hex Identifier ระบบจะฝากเมลไว้ให้เมื่อกลับมา Online
  • mailTemplateId ต้องเป็นเทมเพลตที่ถูกสร้างไว้แล้วในระบบ (สร้างผ่าน /mba)

exports.AFU.Mailbox:isReady()

รอจนระบบเมลพร้อมทำงาน (เช่น ก่อนเรียก sendMailToPlayer ตอน Resource Start)

lua
exports['AFU.Mailbox']:isReady()

ฝั่ง Client

exports['AFU.Mailbox']:openMailUI()

เปิดหน้ากล่องจดหมายของผู้เล่น (เหมือน /mbp) — เหมาะกับการผูกกับ Object/Marker ตู้ไปรษณีย์

lua
exports['AFU.Mailbox']:openMailUI()

exports['AFU.Mailbox']:openAdminMailUI()

เปิดหน้าจัดการเมล (เหมือน /mba)

lua
exports['AFU.Mailbox']:openAdminMailUI()

exports['AFU.Mailbox']:toggleMailboxInterface(mode)

สลับเปิด/ปิดหน้า UI แบบระบุโหมด

lua
exports['AFU.Mailbox']:toggleMailboxInterface("reader") -- หน้าผู้เล่น
exports['AFU.Mailbox']:toggleMailboxInterface("sender") -- หน้าแอดมิน (ต้องมีสิทธิ์)

WARNING

การเรียก "sender" จากผู้เล่นที่ไม่มีสิทธิ์แอดมินจะถูก ปฏิเสธโดยอัตโนมัติ และฝั่งเซิร์ฟเวอร์ยังตรวจสิทธิ์ซ้ำอีกชั้น


🧰 Troubleshooting

อาการสาเหตุที่พบบ่อยวิธีแก้
พิมพ์ /mba แล้วไม่มีหน้าต่างเปิดผู้เล่นไม่ได้อยู่กลุ่ม admin / superadminเพิ่ม Group ผ่าน ESX หรือแก้ Functions.isAdmin() ตามหัวข้อ Configuration
/mbp ไม่ตอบสนองResource start ก่อน oxmysql / es_extended หรือ NUI โหลดไม่สำเร็จตรวจ Order ของ ensure ใน server.cfg และดู Error ใน F8 Console / Server Console
มี Error เกี่ยวกับ MySQL ตอน Startoxmysql ไม่ทำงาน, ฐานข้อมูลเชื่อมต่อไม่ได้ หรือ User ไม่มีสิทธิ์ CREATEตรวจ oxmysql ก่อน แล้วตรวจสิทธิ์ MySQL User
รูปไอเทมในเมลเป็นภาพเดียวกันหมด / ไม่ขึ้นConfig.InventoryPath ไม่ตรงกับ Inventoryแก้ Path และนามสกุลไฟล์ (DefaultExtImage, OverrideImageExtImageItems) ให้ถูกต้อง
กดรับของแล้วไม่ได้ไอเทมไม่มีชื่อไอเทมนั้นในตาราง items ของ ESX หรือชื่อ Account ผิดเพิ่มไอเทมใน Database ก่อน และใช้ Account มาตรฐาน (money, bank, black_money)
ส่งเมลหาผู้เล่นออฟไลน์ไม่ถึงส่งด้วย Server ID ขณะที่ผู้เล่นออฟไลน์ใช้ Steam Hex Identifier แทน (เช่น steam:1100001xxxxxxxxx)
แจ้งเตือนเมลเข้าซ้ำหรือไม่ขึ้นตั้งทั้ง Internal และ External Notification พร้อมกันเลือกอย่างใดอย่างหนึ่ง: useInternalNotification = true หรือ ใช้ External Callback
มี Error จาก nc_discordlogs / afu_logเซิร์ฟเวอร์ไม่มีระบบ Log เหล่านี้Comment บล็อก Log ใน Functions.OnAddItemsFromMailRewards ออก
ลบ/แก้ไขเทมเพลตไม่ได้เทมเพลตถูกสร้างโดยแอดมินคนอื่น หรือสิทธิ์ไม่พอระบบอนุญาตเฉพาะผู้ที่ผ่าน isAdmin เท่านั้น

การขอ Support

หากยังแก้ปัญหาไม่ได้ ให้แนบ Console Log (F8) และ Server Console ที่มี Error ของ AFU.Mailbox พร้อมเวอร์ชัน Resource แจ้งผู้ขายได้ที่ awayfromus.store