guild scouting improvements

This commit is contained in:
wish
2022-08-21 23:11:07 +10:00
parent 62dacd3a78
commit 1364de9a5e
5 changed files with 118 additions and 102 deletions

View File

@@ -16,11 +16,7 @@ func (m MsgBinMailNotify) Parse(bf *byteframe.ByteFrame) error {
func (m MsgBinMailNotify) Build(bf *byteframe.ByteFrame) error { func (m MsgBinMailNotify) Build(bf *byteframe.ByteFrame) error {
bf.WriteUint8(0x01) // Unk bf.WriteUint8(0x01) // Unk
byteName, _ := stringsupport.ConvertUTF8ToShiftJIS(m.SenderName) bf.WriteBytes(stringsupport.PaddedString(m.SenderName, 21, true))
bf.WriteBytes(byteName)
bf.WriteBytes(make([]byte, 21-len(byteName)))
return nil return nil
} }

View File

@@ -0,0 +1,13 @@
BEGIN;
ALTER TABLE IF EXISTS public.mail
ADD COLUMN IF NOT EXISTS is_sys_message bool DEFAULT false;
UPDATE mail SET is_sys_message=false;
ALTER TABLE IF EXISTS public.mail
DROP CONSTRAINT IF EXISTS mail_sender_id_fkey;
INSERT INTO public.characters (id, name) VALUES (0, '');
END;

View File

@@ -700,6 +700,14 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
if err != nil { if err != nil {
// All successful acks return 0x01, assuming 0x00 is failure // All successful acks return 0x01, assuming 0x00 is failure
response = 0x00 response = 0x00
} else {
mail := Mail{
RecipientID: s.charID,
Subject: "Withdrawal",
Body: fmt.Sprintf("You have withdrawn from 「%s」.", guild.Name),
IsSystemMessage: true,
}
mail.Send(s, nil)
} }
bf.WriteUint32(uint32(response)) bf.WriteUint32(uint32(response))
@@ -823,14 +831,14 @@ func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
guild, err := GetGuildInfoByCharacterId(s, pkt.CharID) guild, err := GetGuildInfoByCharacterId(s, pkt.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
actorCharacter, err := GetCharacterGuildData(s, s.charID) actorCharacter, err := GetCharacterGuildData(s, s.charID)
if err != nil || (!actorCharacter.IsSubLeader() && guild.LeaderCharID != s.charID) || (!actorCharacter.Recruiter && guild.LeaderCharID != s.charID) { if err != nil || (!actorCharacter.IsSubLeader() && guild.LeaderCharID != s.charID) || (!actorCharacter.Recruiter && guild.LeaderCharID != s.charID) {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
@@ -839,41 +847,45 @@ func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
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 = Mail{
SenderID: s.charID, 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), IsSystemMessage: true,
IsGuildInvite: false,
} }
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 = Mail{
SenderID: s.charID, 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), IsSystemMessage: true,
IsGuildInvite: false,
} }
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 = Mail{
SenderID: s.charID, 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), IsSystemMessage: true,
IsGuildInvite: false,
} }
default: default:
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
s.logger.Warn(fmt.Sprintf("unhandled operateGuildMember action '%d'", pkt.Action)) s.logger.Warn(fmt.Sprintf("unhandled operateGuildMember action '%d'", pkt.Action))
} }
if err != nil { if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
mail.Send(s, nil) mail.Send(s, nil)
for _, channel := range s.server.Channels {
for _, session := range channel.sessions {
if session.charID == pkt.CharID {
SendMailNotification(s, &mail, session)
}
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
doAckSimpleSucceed(s, pkt.AckHandle, nil)
} }
func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
@@ -947,7 +959,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBytes(guildLeaderName) bf.WriteBytes(guildLeaderName)
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk
bf.WriteBool(false) // isReturnGuild bf.WriteBool(false) // isReturnGuild
bf.WriteBytes([]byte{0x01, 0x02, 0x02}) // Unk bf.WriteBool(false) // Unk
bf.WriteBytes([]byte{0x02, 0x02}) // Unk
bf.WriteUint32(guild.EventRP) bf.WriteUint32(guild.EventRP)
if guild.PugiName1 == "" { if guild.PugiName1 == "" {
@@ -1099,12 +1112,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
//// REALLY large/complex format... stubbing it out here for simplicity. doAckBufSucceed(s, pkt.AckHandle, make([]byte, 5))
//resp := byteframe.NewByteFrame()
//resp.WriteUint32(0) // Count
//resp.WriteUint8(0) // Unk, read if count == 0.
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 8))
} }
} }
@@ -1448,12 +1456,8 @@ func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {
guild, err = GetGuildInfoByID(s, pkt.GuildID) guild, err = GetGuildInfoByID(s, pkt.GuildID)
} }
if err != nil { if err != nil || guild == nil {
s.logger.Warn("failed to find guild", zap.Error(err), zap.Uint32("guildID", pkt.GuildID)) doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x02})
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} else if guild == nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }

View File

@@ -21,7 +21,7 @@ func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
panic(err) panic(err)
} }
if actorCharGuildData == nil || !actorCharGuildData.Recruiter { if actorCharGuildData == nil || (!actorCharGuildData.Recruiter && !actorCharGuildData.IsLeader && !actorCharGuildData.IsSubLeader()) {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
@@ -59,19 +59,13 @@ func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
panic(err) panic(err)
} }
senderName, err := getCharacterName(s, s.charID)
if err != nil {
panic(err)
}
mail := &Mail{ mail := &Mail{
SenderID: s.charID, SenderID: s.charID,
RecipientID: pkt.CharID, RecipientID: pkt.CharID,
Subject: "Guild! ヽ(・∀・)ノ", Subject: "Invitation!",
Body: fmt.Sprintf( Body: fmt.Sprintf(
"%s has invited you to join the wonderful guild %s, do you accept this challenge?", "%s has invited you to join 「%s」\nDo you want to accept?",
senderName, getCharacterName(s, s.charID),
guildInfo.Name, guildInfo.Name,
), ),
IsGuildInvite: true, IsGuildInvite: true,
@@ -104,7 +98,7 @@ func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {
panic(err) panic(err)
} }
if guildCharData == nil || !guildCharData.Recruiter { if guildCharData == nil || (!guildCharData.Recruiter && !guildCharData.IsLeader && !guildCharData.IsSubLeader()) {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
@@ -128,61 +122,72 @@ func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout) pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout)
bf := byteframe.NewByteFrame()
guild, err := GetGuildInfoByCharacterId(s, pkt.LeaderID) guild, err := GetGuildInfoByCharacterId(s, pkt.LeaderID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_, err = guild.GetApplicationForCharID(s, s.charID, GuildApplicationTypeInvited) app, err := guild.GetApplicationForCharID(s, s.charID, GuildApplicationTypeInvited)
if err != nil { if app == nil || err != nil {
s.logger.Warn( s.logger.Warn(
"could not retrieve guild invitation", "Guild invite missing, deleted?",
zap.Error(err), zap.Error(err),
zap.Uint32("guildID", guild.ID), zap.Uint32("guildID", guild.ID),
zap.Uint32("charID", s.charID), zap.Uint32("charID", s.charID),
) )
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) bf.WriteUint32(7)
bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
var mail []Mail
if pkt.Answer { if pkt.Answer {
err = guild.AcceptApplication(s, s.charID) err = guild.AcceptApplication(s, s.charID)
mail = append(mail, Mail{
RecipientID: s.charID,
Subject: "Success!",
Body: fmt.Sprintf("You successfully joined 「%s」.", guild.Name),
IsSystemMessage: true,
})
mail = append(mail, Mail{
SenderID: s.charID,
RecipientID: pkt.LeaderID,
Subject: "Accepted",
Body: fmt.Sprintf("%s accepted your invitation to join 「%s」.", s.Name, guild.Name),
IsSystemMessage: true,
})
} else { } else {
err = guild.RejectApplication(s, s.charID) err = guild.RejectApplication(s, s.charID)
mail = append(mail, Mail{
RecipientID: s.charID,
Subject: "Declined",
Body: fmt.Sprintf("You declined the invitation to join 「%s」.", guild.Name),
IsSystemMessage: true,
})
mail = append(mail, Mail{
SenderID: s.charID,
RecipientID: pkt.LeaderID,
Subject: "Declined",
Body: fmt.Sprintf("%s declined your invitation to join 「%s」.", s.Name, guild.Name),
IsSystemMessage: true,
})
} }
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) bf.WriteUint32(7)
return bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else {
bf.WriteUint32(0)
bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
for _, m := range mail {
m.Send(s, nil)
}
} }
senderName, err := getCharacterName(s, pkt.LeaderID)
if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err)
}
successMail := Mail{
SenderID: pkt.LeaderID,
RecipientID: s.charID,
Subject: "Happy days!",
Body: fmt.Sprintf("You successfully joined %s and should be proud of all you have accomplished.", guild.Name),
IsGuildInvite: false,
SenderName: senderName,
}
err = successMail.Send(s, nil)
if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err)
}
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x0f, 0x42, 0x81, 0x7e})
} }
func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
@@ -191,12 +196,12 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
guildInfo, err := GetGuildInfoByCharacterId(s, s.charID) guildInfo, err := GetGuildInfoByCharacterId(s, s.charID)
if guildInfo == nil && s.prevGuildID == 0 { if guildInfo == nil && s.prevGuildID == 0 {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} else { } else {
guildInfo, err = GetGuildInfoByID(s, s.prevGuildID) guildInfo, err = GetGuildInfoByID(s, s.prevGuildID)
if guildInfo == nil || err != nil { if guildInfo == nil || err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
@@ -210,7 +215,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
if err != nil { if err != nil {
s.logger.Error("failed to retrieve scouted characters", zap.Error(err)) s.logger.Error("failed to retrieve scouted characters", zap.Error(err))
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }

View File

@@ -25,21 +25,22 @@ type Mail struct {
AttachedItemAmount uint16 `db:"attached_item_amount"` AttachedItemAmount uint16 `db:"attached_item_amount"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
IsGuildInvite bool `db:"is_guild_invite"` IsGuildInvite bool `db:"is_guild_invite"`
IsSystemMessage bool `db:"is_sys_message"`
SenderName string `db:"sender_name"` SenderName string `db:"sender_name"`
} }
func (m *Mail) Send(s *Session, transaction *sql.Tx) error { func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
query := ` query := `
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite) 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) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
` `
var err error var err error
if transaction == nil { if transaction == nil {
_, err = s.server.db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite) _, err = s.server.db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
} else { } else {
_, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite) _, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
} }
if err != nil { if err != nil {
@@ -53,6 +54,7 @@ func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
zap.Uint16("itemID", m.AttachedItemID), zap.Uint16("itemID", m.AttachedItemID),
zap.Uint16("itemAmount", m.AttachedItemAmount), zap.Uint16("itemAmount", m.AttachedItemAmount),
zap.Bool("isGuildInvite", m.IsGuildInvite), zap.Bool("isGuildInvite", m.IsGuildInvite),
zap.Bool("isSystemMessage", m.IsSystemMessage),
) )
return err return err
} }
@@ -141,6 +143,7 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
m.attached_item_amount, m.attached_item_amount,
m.created_at, m.created_at,
m.is_guild_invite, m.is_guild_invite,
m.is_sys_message,
m.deleted, m.deleted,
m.locked, m.locked,
c.name as sender_name c.name as sender_name
@@ -189,6 +192,7 @@ func GetMailByID(s *Session, ID int) (*Mail, error) {
m.attached_item_amount, m.attached_item_amount,
m.created_at, m.created_at,
m.is_guild_invite, m.is_guild_invite,
m.is_sys_message,
m.deleted, m.deleted,
m.locked, m.locked,
c.name as sender_name c.name as sender_name
@@ -215,16 +219,10 @@ func GetMailByID(s *Session, ID int) (*Mail, error) {
} }
func SendMailNotification(s *Session, m *Mail, recipient *Session) { func SendMailNotification(s *Session, m *Mail, recipient *Session) {
senderName, err := getCharacterName(s, m.SenderID)
if err != nil {
panic(err)
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
notification := &binpacket.MsgBinMailNotify{ notification := &binpacket.MsgBinMailNotify{
SenderName: senderName, SenderName: getCharacterName(s, m.SenderID),
} }
notification.Build(bf) notification.Build(bf)
@@ -241,7 +239,7 @@ func SendMailNotification(s *Session, m *Mail, recipient *Session) {
recipient.QueueSendMHF(castedBinary) recipient.QueueSendMHF(castedBinary)
} }
func getCharacterName(s *Session, charID uint32) (string, error) { func getCharacterName(s *Session, charID uint32) string {
row := s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", charID) row := s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", charID)
charName := "" charName := ""
@@ -249,10 +247,9 @@ func getCharacterName(s *Session, charID uint32) (string, error) {
err := row.Scan(&charName) err := row.Scan(&charName)
if err != nil { if err != nil {
return "", err return ""
} }
return charName
return charName, nil
} }
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
@@ -325,8 +322,9 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
flags |= 0x02 flags |= 0x02
} }
// System message, hides ID if m.IsSystemMessage {
// flags |= 0x04 flags |= 0x04
}
// Workaround until EN mail items are patched // Workaround until EN mail items are patched
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DisableMailItems { if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DisableMailItems {