mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-14 16:04:38 +01:00
make mail a service
This commit is contained in:
18
internal/constant/cast.go
Normal file
18
internal/constant/cast.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
BinaryMessageTypeState = 0
|
||||||
|
BinaryMessageTypeChat = 1
|
||||||
|
BinaryMessageTypeQuest = 2
|
||||||
|
BinaryMessageTypeData = 3
|
||||||
|
BinaryMessageTypeMailNotify = 4
|
||||||
|
BinaryMessageTypeEmote = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
// MSG_SYS_CAST[ED]_BINARY broadcast types enum
|
||||||
|
const (
|
||||||
|
BroadcastTypeTargeted = 0x01
|
||||||
|
BroadcastTypeStage = 0x03
|
||||||
|
BroadcastTypeServer = 0x06
|
||||||
|
BroadcastTypeWorld = 0x0a
|
||||||
|
)
|
||||||
236
internal/service/mail.go
Normal file
236
internal/service/mail.go
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"erupe-ce/internal/constant"
|
||||||
|
"erupe-ce/network/binpacket"
|
||||||
|
"erupe-ce/network/mhfpacket"
|
||||||
|
"erupe-ce/utils/byteframe"
|
||||||
|
"erupe-ce/utils/db"
|
||||||
|
|
||||||
|
"erupe-ce/utils/logger"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mail struct {
|
||||||
|
ID int `db:"id"`
|
||||||
|
SenderID uint32 `db:"sender_id"`
|
||||||
|
RecipientID uint32 `db:"recipient_id"`
|
||||||
|
Subject string `db:"subject"`
|
||||||
|
Body string `db:"body"`
|
||||||
|
Read bool `db:"read"`
|
||||||
|
Deleted bool `db:"deleted"`
|
||||||
|
Locked bool `db:"locked"`
|
||||||
|
AttachedItemReceived bool `db:"attached_item_received"`
|
||||||
|
AttachedItemID uint16 `db:"attached_item"`
|
||||||
|
AttachedItemAmount uint16 `db:"attached_item_amount"`
|
||||||
|
CreatedAt time.Time `db:"created_at"`
|
||||||
|
IsGuildInvite bool `db:"is_guild_invite"`
|
||||||
|
IsSystemMessage bool `db:"is_sys_message"`
|
||||||
|
SenderName string `db:"sender_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mail) Send(transaction *sql.Tx) error {
|
||||||
|
db, err := db.GetDB()
|
||||||
|
logger := logger.Get()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||||
|
}
|
||||||
|
query := `
|
||||||
|
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
`
|
||||||
|
|
||||||
|
if transaction == nil {
|
||||||
|
_, err = db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
||||||
|
} else {
|
||||||
|
_, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to send mail",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Uint32("senderID", m.SenderID),
|
||||||
|
zap.Uint32("recipientID", m.RecipientID),
|
||||||
|
zap.String("subject", m.Subject),
|
||||||
|
zap.String("body", m.Body),
|
||||||
|
zap.Uint16("itemID", m.AttachedItemID),
|
||||||
|
zap.Uint16("itemAmount", m.AttachedItemAmount),
|
||||||
|
zap.Bool("isGuildInvite", m.IsGuildInvite),
|
||||||
|
zap.Bool("isSystemMessage", m.IsSystemMessage),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mail) MarkRead() error {
|
||||||
|
db, err := db.GetDB()
|
||||||
|
logger := logger.Get()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||||
|
}
|
||||||
|
_, err = db.Exec(`
|
||||||
|
UPDATE mail SET read = true WHERE id = $1
|
||||||
|
`, m.ID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to mark mail as read",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Int("mailID", m.ID),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMailListForCharacter(charID uint32) ([]Mail, error) {
|
||||||
|
db, err := db.GetDB()
|
||||||
|
logger := logger.Get()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||||
|
}
|
||||||
|
rows, err := db.Queryx(`
|
||||||
|
SELECT
|
||||||
|
m.id,
|
||||||
|
m.sender_id,
|
||||||
|
m.recipient_id,
|
||||||
|
m.subject,
|
||||||
|
m.read,
|
||||||
|
m.attached_item_received,
|
||||||
|
m.attached_item,
|
||||||
|
m.attached_item_amount,
|
||||||
|
m.created_at,
|
||||||
|
m.is_guild_invite,
|
||||||
|
m.is_sys_message,
|
||||||
|
m.deleted,
|
||||||
|
m.locked,
|
||||||
|
c.name as sender_name
|
||||||
|
FROM mail m
|
||||||
|
JOIN characters c ON c.id = m.sender_id
|
||||||
|
WHERE recipient_id = $1 AND m.deleted = false
|
||||||
|
ORDER BY m.created_at DESC, id DESC
|
||||||
|
LIMIT 32
|
||||||
|
`, charID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to get mail for character", zap.Error(err), zap.Uint32("charID", charID))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
allMail := make([]Mail, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
mail := Mail{}
|
||||||
|
|
||||||
|
err := rows.StructScan(&mail)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allMail = append(allMail, mail)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allMail, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMailByID(ID int) (*Mail, error) {
|
||||||
|
db, err := db.GetDB()
|
||||||
|
logger := logger.Get()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||||
|
}
|
||||||
|
row := db.QueryRowx(`
|
||||||
|
SELECT
|
||||||
|
m.id,
|
||||||
|
m.sender_id,
|
||||||
|
m.recipient_id,
|
||||||
|
m.subject,
|
||||||
|
m.read,
|
||||||
|
m.body,
|
||||||
|
m.attached_item_received,
|
||||||
|
m.attached_item,
|
||||||
|
m.attached_item_amount,
|
||||||
|
m.created_at,
|
||||||
|
m.is_guild_invite,
|
||||||
|
m.is_sys_message,
|
||||||
|
m.deleted,
|
||||||
|
m.locked,
|
||||||
|
c.name as sender_name
|
||||||
|
FROM mail m
|
||||||
|
JOIN characters c ON c.id = m.sender_id
|
||||||
|
WHERE m.id = $1
|
||||||
|
LIMIT 1
|
||||||
|
`, ID)
|
||||||
|
|
||||||
|
mail := &Mail{}
|
||||||
|
|
||||||
|
err = row.StructScan(mail)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(
|
||||||
|
"failed to retrieve mail",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Int("mailID", ID),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mail, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionMail interface {
|
||||||
|
QueueSendMHF(packet mhfpacket.MHFPacket)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendMailNotification(s SessionMail, m *Mail, recipient SessionMail) {
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
|
notification := &binpacket.MsgBinMailNotify{
|
||||||
|
SenderName: getCharacterName(m.SenderID),
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.Build(bf)
|
||||||
|
|
||||||
|
castedBinary := &mhfpacket.MsgSysCastedBinary{
|
||||||
|
CharID: m.SenderID,
|
||||||
|
BroadcastType: 0x00,
|
||||||
|
MessageType: constant.BinaryMessageTypeMailNotify,
|
||||||
|
RawDataPayload: bf.Data(),
|
||||||
|
}
|
||||||
|
|
||||||
|
castedBinary.Build(bf)
|
||||||
|
|
||||||
|
recipient.QueueSendMHF(castedBinary)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCharacterName(charID uint32) string {
|
||||||
|
db, err := db.GetDB()
|
||||||
|
logger := logger.Get()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||||
|
}
|
||||||
|
row := db.QueryRow("SELECT name FROM characters WHERE id = $1", charID)
|
||||||
|
|
||||||
|
charName := ""
|
||||||
|
|
||||||
|
err = row.Scan(&charName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return charName
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"erupe-ce/config"
|
"erupe-ce/config"
|
||||||
|
"erupe-ce/internal/constant"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/utils/byteframe"
|
"erupe-ce/utils/byteframe"
|
||||||
"erupe-ce/utils/db"
|
"erupe-ce/utils/db"
|
||||||
@@ -357,7 +358,7 @@ func teleport(s *Session, args []string) error {
|
|||||||
payload.WriteInt16(int16(y))
|
payload.WriteInt16(int16(y))
|
||||||
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
|
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
|
||||||
CharID: s.CharID,
|
CharID: s.CharID,
|
||||||
MessageType: BinaryMessageTypeState,
|
MessageType: constant.BinaryMessageTypeState,
|
||||||
RawDataPayload: payload.Data(),
|
RawDataPayload: payload.Data(),
|
||||||
})
|
})
|
||||||
s.sendMessage(t("commands.teleport.success", v{"x": fmt.Sprintf("%d", x), "y": fmt.Sprintf("%d", y)}))
|
s.sendMessage(t("commands.teleport.success", v{"x": fmt.Sprintf("%d", x), "y": fmt.Sprintf("%d", y)}))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package channelserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"erupe-ce/config"
|
"erupe-ce/config"
|
||||||
|
"erupe-ce/internal/constant"
|
||||||
"erupe-ce/network/binpacket"
|
"erupe-ce/network/binpacket"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/utils/byteframe"
|
"erupe-ce/utils/byteframe"
|
||||||
@@ -18,22 +19,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MSG_SYS_CAST[ED]_BINARY types enum
|
// MSG_SYS_CAST[ED]_BINARY types enum
|
||||||
const (
|
|
||||||
BinaryMessageTypeState = 0
|
|
||||||
BinaryMessageTypeChat = 1
|
|
||||||
BinaryMessageTypeQuest = 2
|
|
||||||
BinaryMessageTypeData = 3
|
|
||||||
BinaryMessageTypeMailNotify = 4
|
|
||||||
BinaryMessageTypeEmote = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
// MSG_SYS_CAST[ED]_BINARY broadcast types enum
|
|
||||||
const (
|
|
||||||
BroadcastTypeTargeted = 0x01
|
|
||||||
BroadcastTypeStage = 0x03
|
|
||||||
BroadcastTypeServer = 0x06
|
|
||||||
BroadcastTypeWorld = 0x0a
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
commands map[string]config.Command
|
commands map[string]config.Command
|
||||||
@@ -72,7 +57,7 @@ func sendServerChatMessage(s *Session, message string) {
|
|||||||
|
|
||||||
castedBin := &mhfpacket.MsgSysCastedBinary{
|
castedBin := &mhfpacket.MsgSysCastedBinary{
|
||||||
CharID: 0,
|
CharID: 0,
|
||||||
MessageType: BinaryMessageTypeChat,
|
MessageType: constant.BinaryMessageTypeChat,
|
||||||
RawDataPayload: bf.Data(),
|
RawDataPayload: bf.Data(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +103,7 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
var msgBinTargeted *binpacket.MsgBinTargeted
|
var msgBinTargeted *binpacket.MsgBinTargeted
|
||||||
var message, author string
|
var message, author string
|
||||||
var returnToSender bool
|
var returnToSender bool
|
||||||
if pkt.MessageType == BinaryMessageTypeChat {
|
if pkt.MessageType == constant.BinaryMessageTypeChat {
|
||||||
tmp.SetLE()
|
tmp.SetLE()
|
||||||
tmp.Seek(8, 0)
|
tmp.Seek(8, 0)
|
||||||
message = string(tmp.ReadNullTerminatedBytes())
|
message = string(tmp.ReadNullTerminatedBytes())
|
||||||
@@ -127,7 +112,7 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
// Customise payload
|
// Customise payload
|
||||||
realPayload := pkt.RawDataPayload
|
realPayload := pkt.RawDataPayload
|
||||||
if pkt.BroadcastType == BroadcastTypeTargeted {
|
if pkt.BroadcastType == constant.BroadcastTypeTargeted {
|
||||||
tmp.SetBE()
|
tmp.SetBE()
|
||||||
tmp.Seek(0, 0)
|
tmp.Seek(0, 0)
|
||||||
msgBinTargeted = &binpacket.MsgBinTargeted{}
|
msgBinTargeted = &binpacket.MsgBinTargeted{}
|
||||||
@@ -137,11 +122,11 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
realPayload = msgBinTargeted.RawDataPayload
|
realPayload = msgBinTargeted.RawDataPayload
|
||||||
} else if pkt.MessageType == BinaryMessageTypeChat {
|
} else if pkt.MessageType == constant.BinaryMessageTypeChat {
|
||||||
if message == "@dice" {
|
if message == "@dice" {
|
||||||
returnToSender = true
|
returnToSender = true
|
||||||
m := binpacket.MsgBinChat{
|
m := binpacket.MsgBinChat{
|
||||||
Type: BinaryMessageTypeChat,
|
Type: constant.BinaryMessageTypeChat,
|
||||||
Flags: 4,
|
Flags: 4,
|
||||||
Message: fmt.Sprintf(`%d`, token.RNG.Intn(100)+1),
|
Message: fmt.Sprintf(`%d`, token.RNG.Intn(100)+1),
|
||||||
SenderName: author,
|
SenderName: author,
|
||||||
@@ -162,7 +147,7 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
|
if (pkt.BroadcastType == constant.BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == constant.BroadcastTypeWorld {
|
||||||
s.Server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
|
s.Server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,15 +163,15 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
// Send to the proper recipients.
|
// Send to the proper recipients.
|
||||||
switch pkt.BroadcastType {
|
switch pkt.BroadcastType {
|
||||||
case BroadcastTypeWorld:
|
case constant.BroadcastTypeWorld:
|
||||||
s.Server.WorldcastMHF(resp, s, nil)
|
s.Server.WorldcastMHF(resp, s, nil)
|
||||||
case BroadcastTypeStage:
|
case constant.BroadcastTypeStage:
|
||||||
if returnToSender {
|
if returnToSender {
|
||||||
s.stage.BroadcastMHF(resp, nil)
|
s.stage.BroadcastMHF(resp, nil)
|
||||||
} else {
|
} else {
|
||||||
s.stage.BroadcastMHF(resp, s)
|
s.stage.BroadcastMHF(resp, s)
|
||||||
}
|
}
|
||||||
case BroadcastTypeServer:
|
case constant.BroadcastTypeServer:
|
||||||
if pkt.MessageType == 1 {
|
if pkt.MessageType == 1 {
|
||||||
raviSema := s.Server.getRaviSemaphore()
|
raviSema := s.Server.getRaviSemaphore()
|
||||||
if raviSema != nil {
|
if raviSema != nil {
|
||||||
@@ -195,7 +180,7 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
} else {
|
} else {
|
||||||
s.Server.BroadcastMHF(resp, s)
|
s.Server.BroadcastMHF(resp, s)
|
||||||
}
|
}
|
||||||
case BroadcastTypeTargeted:
|
case constant.BroadcastTypeTargeted:
|
||||||
for _, targetID := range (*msgBinTargeted).TargetCharIDs {
|
for _, targetID := range (*msgBinTargeted).TargetCharIDs {
|
||||||
char := s.Server.FindSessionByCharID(targetID)
|
char := s.Server.FindSessionByCharID(targetID)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"erupe-ce/config"
|
"erupe-ce/config"
|
||||||
"erupe-ce/internal/model"
|
"erupe-ce/internal/model"
|
||||||
|
"erupe-ce/internal/service"
|
||||||
|
|
||||||
"erupe-ce/utils/db"
|
"erupe-ce/utils/db"
|
||||||
"erupe-ce/utils/gametime"
|
"erupe-ce/utils/gametime"
|
||||||
"erupe-ce/utils/mhfitem"
|
"erupe-ce/utils/mhfitem"
|
||||||
@@ -723,13 +725,13 @@ func HandleMsgMhfOperateGuild(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
response = 0
|
response = 0
|
||||||
} else {
|
} else {
|
||||||
mail := Mail{
|
mail := service.Mail{
|
||||||
RecipientID: s.CharID,
|
RecipientID: s.CharID,
|
||||||
Subject: "Withdrawal",
|
Subject: "Withdrawal",
|
||||||
Body: fmt.Sprintf("You have withdrawn from 「%s」.", guild.Name),
|
Body: fmt.Sprintf("You have withdrawn from 「%s」.", guild.Name),
|
||||||
IsSystemMessage: true,
|
IsSystemMessage: true,
|
||||||
}
|
}
|
||||||
mail.Send(s, nil)
|
mail.Send(nil)
|
||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(response))
|
bf.WriteUint32(uint32(response))
|
||||||
case mhfpacket.OperateGuildDonateRank:
|
case mhfpacket.OperateGuildDonateRank:
|
||||||
@@ -900,11 +902,11 @@ func HandleMsgMhfOperateGuildMember(s *Session, db *sqlx.DB, p mhfpacket.MHFPack
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var mail Mail
|
var mail service.Mail
|
||||||
switch pkt.Action {
|
switch pkt.Action {
|
||||||
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT:
|
||||||
err = guild.AcceptApplication(s, pkt.CharID)
|
err = guild.AcceptApplication(s, pkt.CharID)
|
||||||
mail = Mail{
|
mail = service.Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Accepted!",
|
Subject: "Accepted!",
|
||||||
Body: fmt.Sprintf("Your application to join 「%s」 was accepted.", guild.Name),
|
Body: fmt.Sprintf("Your application to join 「%s」 was accepted.", guild.Name),
|
||||||
@@ -912,7 +914,7 @@ func HandleMsgMhfOperateGuildMember(s *Session, db *sqlx.DB, p mhfpacket.MHFPack
|
|||||||
}
|
}
|
||||||
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_REJECT:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_REJECT:
|
||||||
err = guild.RejectApplication(s, pkt.CharID)
|
err = guild.RejectApplication(s, pkt.CharID)
|
||||||
mail = Mail{
|
mail = service.Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Rejected",
|
Subject: "Rejected",
|
||||||
Body: fmt.Sprintf("Your application to join 「%s」 was rejected.", guild.Name),
|
Body: fmt.Sprintf("Your application to join 「%s」 was rejected.", guild.Name),
|
||||||
@@ -920,7 +922,7 @@ func HandleMsgMhfOperateGuildMember(s *Session, db *sqlx.DB, p mhfpacket.MHFPack
|
|||||||
}
|
}
|
||||||
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_KICK:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_KICK:
|
||||||
err = guild.RemoveCharacter(s, pkt.CharID)
|
err = guild.RemoveCharacter(s, pkt.CharID)
|
||||||
mail = Mail{
|
mail = service.Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Kicked",
|
Subject: "Kicked",
|
||||||
Body: fmt.Sprintf("You were kicked from 「%s」.", guild.Name),
|
Body: fmt.Sprintf("You were kicked from 「%s」.", guild.Name),
|
||||||
@@ -934,11 +936,11 @@ func HandleMsgMhfOperateGuildMember(s *Session, db *sqlx.DB, p mhfpacket.MHFPack
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.DoAckSimpleFail(pkt.AckHandle, make([]byte, 4))
|
s.DoAckSimpleFail(pkt.AckHandle, make([]byte, 4))
|
||||||
} else {
|
} else {
|
||||||
mail.Send(s, nil)
|
mail.Send(nil)
|
||||||
for _, channel := range s.Server.Channels {
|
for _, channel := range s.Server.Channels {
|
||||||
for _, session := range channel.sessions {
|
for _, session := range channel.sessions {
|
||||||
if session.CharID == pkt.CharID {
|
if session.CharID == pkt.CharID {
|
||||||
SendMailNotification(s, &mail, session)
|
service.SendMailNotification(s, &mail, session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"erupe-ce/internal/service"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/utils/byteframe"
|
"erupe-ce/utils/byteframe"
|
||||||
"erupe-ce/utils/gametime"
|
"erupe-ce/utils/gametime"
|
||||||
@@ -60,7 +61,7 @@ func HandleMsgMhfPostGuildScout(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mail := &Mail{
|
mail := &service.Mail{
|
||||||
SenderID: s.CharID,
|
SenderID: s.CharID,
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: s.Server.i18n.guild.invite.title,
|
Subject: s.Server.i18n.guild.invite.title,
|
||||||
@@ -71,7 +72,7 @@ func HandleMsgMhfPostGuildScout(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
|||||||
IsGuildInvite: true,
|
IsGuildInvite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mail.Send(s, transaction)
|
err = mail.Send(transaction)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rollbackTransaction(s, transaction)
|
rollbackTransaction(s, transaction)
|
||||||
@@ -144,16 +145,16 @@ func HandleMsgMhfAnswerGuildScout(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var mail []Mail
|
var mail []service.Mail
|
||||||
if pkt.Answer {
|
if pkt.Answer {
|
||||||
err = guild.AcceptApplication(s, s.CharID)
|
err = guild.AcceptApplication(s, s.CharID)
|
||||||
mail = append(mail, Mail{
|
mail = append(mail, service.Mail{
|
||||||
RecipientID: s.CharID,
|
RecipientID: s.CharID,
|
||||||
Subject: s.Server.i18n.guild.invite.success.title,
|
Subject: s.Server.i18n.guild.invite.success.title,
|
||||||
Body: fmt.Sprintf(s.Server.i18n.guild.invite.success.body, guild.Name),
|
Body: fmt.Sprintf(s.Server.i18n.guild.invite.success.body, guild.Name),
|
||||||
IsSystemMessage: true,
|
IsSystemMessage: true,
|
||||||
})
|
})
|
||||||
mail = append(mail, Mail{
|
mail = append(mail, service.Mail{
|
||||||
SenderID: s.CharID,
|
SenderID: s.CharID,
|
||||||
RecipientID: pkt.LeaderID,
|
RecipientID: pkt.LeaderID,
|
||||||
Subject: s.Server.i18n.guild.invite.accepted.title,
|
Subject: s.Server.i18n.guild.invite.accepted.title,
|
||||||
@@ -162,13 +163,13 @@ func HandleMsgMhfAnswerGuildScout(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
err = guild.RejectApplication(s, s.CharID)
|
err = guild.RejectApplication(s, s.CharID)
|
||||||
mail = append(mail, Mail{
|
mail = append(mail, service.Mail{
|
||||||
RecipientID: s.CharID,
|
RecipientID: s.CharID,
|
||||||
Subject: s.Server.i18n.guild.invite.rejected.title,
|
Subject: s.Server.i18n.guild.invite.rejected.title,
|
||||||
Body: fmt.Sprintf(s.Server.i18n.guild.invite.rejected.body, guild.Name),
|
Body: fmt.Sprintf(s.Server.i18n.guild.invite.rejected.body, guild.Name),
|
||||||
IsSystemMessage: true,
|
IsSystemMessage: true,
|
||||||
})
|
})
|
||||||
mail = append(mail, Mail{
|
mail = append(mail, service.Mail{
|
||||||
SenderID: s.CharID,
|
SenderID: s.CharID,
|
||||||
RecipientID: pkt.LeaderID,
|
RecipientID: pkt.LeaderID,
|
||||||
Subject: s.Server.i18n.guild.invite.declined.title,
|
Subject: s.Server.i18n.guild.invite.declined.title,
|
||||||
@@ -185,7 +186,7 @@ func HandleMsgMhfAnswerGuildScout(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket
|
|||||||
bf.WriteUint32(guild.ID)
|
bf.WriteUint32(guild.ID)
|
||||||
s.DoAckBufSucceed(pkt.AckHandle, bf.Data())
|
s.DoAckBufSucceed(pkt.AckHandle, bf.Data())
|
||||||
for _, m := range mail {
|
for _, m := range mail {
|
||||||
m.Send(s, nil)
|
m.Send(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,228 +1,15 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"erupe-ce/internal/service"
|
||||||
"erupe-ce/utils/db"
|
|
||||||
"erupe-ce/utils/stringsupport"
|
"erupe-ce/utils/stringsupport"
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"erupe-ce/network/binpacket"
|
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/utils/byteframe"
|
"erupe-ce/utils/byteframe"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mail struct {
|
|
||||||
ID int `db:"id"`
|
|
||||||
SenderID uint32 `db:"sender_id"`
|
|
||||||
RecipientID uint32 `db:"recipient_id"`
|
|
||||||
Subject string `db:"subject"`
|
|
||||||
Body string `db:"body"`
|
|
||||||
Read bool `db:"read"`
|
|
||||||
Deleted bool `db:"deleted"`
|
|
||||||
Locked bool `db:"locked"`
|
|
||||||
AttachedItemReceived bool `db:"attached_item_received"`
|
|
||||||
AttachedItemID uint16 `db:"attached_item"`
|
|
||||||
AttachedItemAmount uint16 `db:"attached_item_amount"`
|
|
||||||
CreatedAt time.Time `db:"created_at"`
|
|
||||||
IsGuildInvite bool `db:"is_guild_invite"`
|
|
||||||
IsSystemMessage bool `db:"is_sys_message"`
|
|
||||||
SenderName string `db:"sender_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
|
|
||||||
db, err := db.GetDB()
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
||||||
}
|
|
||||||
query := `
|
|
||||||
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message)
|
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
||||||
`
|
|
||||||
|
|
||||||
if transaction == nil {
|
|
||||||
_, err = db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
|
||||||
} else {
|
|
||||||
_, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Error(
|
|
||||||
"failed to send mail",
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Uint32("senderID", m.SenderID),
|
|
||||||
zap.Uint32("recipientID", m.RecipientID),
|
|
||||||
zap.String("subject", m.Subject),
|
|
||||||
zap.String("body", m.Body),
|
|
||||||
zap.Uint16("itemID", m.AttachedItemID),
|
|
||||||
zap.Uint16("itemAmount", m.AttachedItemAmount),
|
|
||||||
zap.Bool("isGuildInvite", m.IsGuildInvite),
|
|
||||||
zap.Bool("isSystemMessage", m.IsSystemMessage),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mail) MarkRead(s *Session) error {
|
|
||||||
db, err := db.GetDB()
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
||||||
}
|
|
||||||
_, err = db.Exec(`
|
|
||||||
UPDATE mail SET read = true WHERE id = $1
|
|
||||||
`, m.ID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Error(
|
|
||||||
"failed to mark mail as read",
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Int("mailID", m.ID),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
|
|
||||||
db, err := db.GetDB()
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
||||||
}
|
|
||||||
rows, err := db.Queryx(`
|
|
||||||
SELECT
|
|
||||||
m.id,
|
|
||||||
m.sender_id,
|
|
||||||
m.recipient_id,
|
|
||||||
m.subject,
|
|
||||||
m.read,
|
|
||||||
m.attached_item_received,
|
|
||||||
m.attached_item,
|
|
||||||
m.attached_item_amount,
|
|
||||||
m.created_at,
|
|
||||||
m.is_guild_invite,
|
|
||||||
m.is_sys_message,
|
|
||||||
m.deleted,
|
|
||||||
m.locked,
|
|
||||||
c.name as sender_name
|
|
||||||
FROM mail m
|
|
||||||
JOIN characters c ON c.id = m.sender_id
|
|
||||||
WHERE recipient_id = $1 AND m.deleted = false
|
|
||||||
ORDER BY m.created_at DESC, id DESC
|
|
||||||
LIMIT 32
|
|
||||||
`, charID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Error("failed to get mail for character", zap.Error(err), zap.Uint32("charID", charID))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
allMail := make([]Mail, 0)
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
mail := Mail{}
|
|
||||||
|
|
||||||
err := rows.StructScan(&mail)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
allMail = append(allMail, mail)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allMail, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMailByID(s *Session, ID int) (*Mail, error) {
|
|
||||||
db, err := db.GetDB()
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
||||||
}
|
|
||||||
row := db.QueryRowx(`
|
|
||||||
SELECT
|
|
||||||
m.id,
|
|
||||||
m.sender_id,
|
|
||||||
m.recipient_id,
|
|
||||||
m.subject,
|
|
||||||
m.read,
|
|
||||||
m.body,
|
|
||||||
m.attached_item_received,
|
|
||||||
m.attached_item,
|
|
||||||
m.attached_item_amount,
|
|
||||||
m.created_at,
|
|
||||||
m.is_guild_invite,
|
|
||||||
m.is_sys_message,
|
|
||||||
m.deleted,
|
|
||||||
m.locked,
|
|
||||||
c.name as sender_name
|
|
||||||
FROM mail m
|
|
||||||
JOIN characters c ON c.id = m.sender_id
|
|
||||||
WHERE m.id = $1
|
|
||||||
LIMIT 1
|
|
||||||
`, ID)
|
|
||||||
|
|
||||||
mail := &Mail{}
|
|
||||||
|
|
||||||
err = row.StructScan(mail)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Error(
|
|
||||||
"failed to retrieve mail",
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Int("mailID", ID),
|
|
||||||
)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mail, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendMailNotification(s *Session, m *Mail, recipient *Session) {
|
|
||||||
bf := byteframe.NewByteFrame()
|
|
||||||
|
|
||||||
notification := &binpacket.MsgBinMailNotify{
|
|
||||||
SenderName: getCharacterName(s, m.SenderID),
|
|
||||||
}
|
|
||||||
|
|
||||||
notification.Build(bf)
|
|
||||||
|
|
||||||
castedBinary := &mhfpacket.MsgSysCastedBinary{
|
|
||||||
CharID: m.SenderID,
|
|
||||||
BroadcastType: 0x00,
|
|
||||||
MessageType: BinaryMessageTypeMailNotify,
|
|
||||||
RawDataPayload: bf.Data(),
|
|
||||||
}
|
|
||||||
|
|
||||||
castedBinary.Build(bf)
|
|
||||||
|
|
||||||
recipient.QueueSendMHF(castedBinary)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCharacterName(s *Session, charID uint32) string {
|
|
||||||
db, err := db.GetDB()
|
|
||||||
if err != nil {
|
|
||||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
||||||
}
|
|
||||||
row := db.QueryRow("SELECT name FROM characters WHERE id = $1", charID)
|
|
||||||
|
|
||||||
charName := ""
|
|
||||||
|
|
||||||
err = row.Scan(&charName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return charName
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfReadMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
func handleMsgMhfReadMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfReadMail)
|
pkt := p.(*mhfpacket.MsgMhfReadMail)
|
||||||
|
|
||||||
@@ -232,7 +19,7 @@ func handleMsgMhfReadMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mail, err := GetMailByID(s, mailId)
|
mail, err := service.GetMailByID(mailId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.DoAckBufSucceed(pkt.AckHandle, []byte{0})
|
s.DoAckBufSucceed(pkt.AckHandle, []byte{0})
|
||||||
return
|
return
|
||||||
@@ -248,7 +35,7 @@ func handleMsgMhfReadMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfListMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
func handleMsgMhfListMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfListMail)
|
pkt := p.(*mhfpacket.MsgMhfListMail)
|
||||||
|
|
||||||
mail, err := GetMailListForCharacter(s, s.CharID)
|
mail, err := service.GetMailListForCharacter(s.CharID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.DoAckBufSucceed(pkt.AckHandle, []byte{0})
|
s.DoAckBufSucceed(pkt.AckHandle, []byte{0})
|
||||||
return
|
return
|
||||||
@@ -317,7 +104,7 @@ func handleMsgMhfListMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfOprtMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
func handleMsgMhfOprtMail(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOprtMail)
|
pkt := p.(*mhfpacket.MsgMhfOprtMail)
|
||||||
|
|
||||||
mail, err := GetMailByID(s, s.mailList[pkt.AccIndex])
|
mail, err := service.GetMailByID(s.mailList[pkt.AccIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.DoAckSimpleSucceed(pkt.AckHandle, make([]byte, 4))
|
s.DoAckSimpleSucceed(pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"erupe-ce/internal/constant"
|
||||||
"erupe-ce/network/binpacket"
|
"erupe-ce/network/binpacket"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/utils/byteframe"
|
"erupe-ce/utils/byteframe"
|
||||||
@@ -45,7 +46,7 @@ func (server *ChannelServer) BroadcastChatMessage(message string) {
|
|||||||
msgBinChat.Build(bf)
|
msgBinChat.Build(bf)
|
||||||
|
|
||||||
server.BroadcastMHF(&mhfpacket.MsgSysCastedBinary{
|
server.BroadcastMHF(&mhfpacket.MsgSysCastedBinary{
|
||||||
MessageType: BinaryMessageTypeChat,
|
MessageType: constant.BinaryMessageTypeChat,
|
||||||
RawDataPayload: bf.Data(),
|
RawDataPayload: bf.Data(),
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
@@ -76,8 +77,8 @@ func (server *ChannelServer) BroadcastRaviente(ip uint32, port uint16, stage []b
|
|||||||
bf.WriteUint16(0) // Unk
|
bf.WriteUint16(0) // Unk
|
||||||
bf.WriteBytes(stage)
|
bf.WriteBytes(stage)
|
||||||
server.WorldcastMHF(&mhfpacket.MsgSysCastedBinary{
|
server.WorldcastMHF(&mhfpacket.MsgSysCastedBinary{
|
||||||
BroadcastType: BroadcastTypeServer,
|
BroadcastType: constant.BroadcastTypeServer,
|
||||||
MessageType: BinaryMessageTypeChat,
|
MessageType: constant.BinaryMessageTypeChat,
|
||||||
RawDataPayload: bf.Data(),
|
RawDataPayload: bf.Data(),
|
||||||
}, nil, server)
|
}, nil, server)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"erupe-ce/config"
|
"erupe-ce/config"
|
||||||
|
"erupe-ce/internal/constant"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"erupe-ce/network/binpacket"
|
"erupe-ce/network/binpacket"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
@@ -15,6 +16,7 @@ import (
|
|||||||
"erupe-ce/utils/stringstack"
|
"erupe-ce/utils/stringstack"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -269,7 +271,7 @@ func (s *Session) sendMessage(message string) {
|
|||||||
msgBinChat.Build(bf)
|
msgBinChat.Build(bf)
|
||||||
castedBin := &mhfpacket.MsgSysCastedBinary{
|
castedBin := &mhfpacket.MsgSysCastedBinary{
|
||||||
CharID: 0,
|
CharID: 0,
|
||||||
MessageType: BinaryMessageTypeChat,
|
MessageType: constant.BinaryMessageTypeChat,
|
||||||
RawDataPayload: bf.Data(),
|
RawDataPayload: bf.Data(),
|
||||||
}
|
}
|
||||||
s.QueueSendMHF(castedBin)
|
s.QueueSendMHF(castedBin)
|
||||||
|
|||||||
Reference in New Issue
Block a user