Merge branch 'main' into feature/diva

This commit is contained in:
wish
2023-02-18 18:09:24 +11:00
93 changed files with 1594 additions and 2339 deletions

View File

@@ -736,7 +736,10 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
case mhfpacket.OPERATE_GUILD_DONATE_EVENT:
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true))
quantity := uint16(pkt.Data1.ReadUint32())
bf.WriteBytes(handleDonateRP(s, quantity, guild, true))
// TODO: Move this value onto rp_yesterday and reset to 0... daily?
s.server.db.Exec(`UPDATE guild_characters SET rp_today=rp_today+$1 WHERE character_id=$2`, quantity, s.charID)
case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE:
rp := uint16(pkt.Data1.ReadUint32())
var balance uint32
@@ -1443,8 +1446,9 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0)
}
for range guildMembers {
bf.WriteUint32(0x00) // Unk
for _, member := range guildMembers {
bf.WriteUint16(member.RPToday)
bf.WriteUint16(member.RPYesterday)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -1523,10 +1527,11 @@ func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents)
if err != nil {
s.logger.Fatal("Failed to get guild item box contents from db", zap.Error(err))
s.logger.Error("Failed to get guild item box contents from db", zap.Error(err))
bf.WriteBytes(make([]byte, 4))
} else {
if len(boxContents) == 0 {
bf.WriteUint32(0x00)
bf.WriteBytes(make([]byte, 4))
} else {
amount := len(boxContents) / 4
bf.WriteUint16(uint16(amount))
@@ -1556,7 +1561,9 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
var oldItems []Item
err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents)
if err != nil {
s.logger.Fatal("Failed to get guild item box contents from db", zap.Error(err))
s.logger.Error("Failed to get guild item box contents from db", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} else {
amount := len(boxContents) / 4
oldItems = make([]Item, amount)
@@ -1604,7 +1611,7 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
// Upload new item cache
_, err = s.server.db.Exec("UPDATE guilds SET item_box = $1 WHERE id = $2", bf.Data(), int(pkt.GuildId))
if err != nil {
s.logger.Fatal("Failed to update guild item box contents in db", zap.Error(err))
s.logger.Error("Failed to update guild item box contents in db", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -1729,7 +1736,8 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
data, err := s.server.db.Queryx("SELECT id, meal_id, level, expires FROM guild_meals WHERE guild_id = $1", guild.ID)
if err != nil {
s.logger.Fatal("Failed to get guild meals from db", zap.Error(err))
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
}
temp := byteframe.NewByteFrame()
count := 0
@@ -1737,7 +1745,7 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
mealData := &GuildMeal{}
err = data.StructScan(&mealData)
if err != nil {
s.logger.Fatal("Failed to scan meal data", zap.Error(err))
continue
}
if mealData.Expires > uint32(Time_Current_Adjusted().Add(-60*time.Minute).Unix()) {
count++
@@ -1759,12 +1767,12 @@ func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
if pkt.OverwriteID != 0 {
_, err := s.server.db.Exec("DELETE FROM guild_meals WHERE id = $1", pkt.OverwriteID)
if err != nil {
s.logger.Fatal("Failed to delete meal in db", zap.Error(err))
s.logger.Error("Failed to delete meal in db", zap.Error(err))
}
}
_, err := s.server.db.Exec("INSERT INTO guild_meals (guild_id, meal_id, level, expires) VALUES ($1, $2, $3, $4)", guild.ID, pkt.MealID, pkt.Success, Time_Current_Adjusted().Add(30*time.Minute).Unix())
if err != nil {
s.logger.Fatal("Failed to register meal in db", zap.Error(err))
s.logger.Error("Failed to register meal in db", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x00})
}
@@ -1803,58 +1811,51 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
}
type MessageBoardPost struct {
Type uint32 `db:"post_type"`
StampID uint32 `db:"stamp_id"`
Title string `db:"title"`
Body string `db:"body"`
AuthorID uint32 `db:"author_id"`
Timestamp uint64 `db:"created_at"`
LikedBy string `db:"liked_by"`
ID uint32 `db:"id"`
StampID uint32 `db:"stamp_id"`
Title string `db:"title"`
Body string `db:"body"`
AuthorID uint32 `db:"author_id"`
Timestamp time.Time `db:"created_at"`
LikedBy string `db:"liked_by"`
}
func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMessageBoard)
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
msgs, err := s.server.db.Queryx("SELECT post_type, stamp_id, title, body, author_id, (EXTRACT(epoch FROM created_at)::int) as created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
if err != nil {
s.logger.Fatal("Failed to get guild messages from db", zap.Error(err))
if pkt.BoardType == 1 {
pkt.MaxPosts = 4
}
msgs, err := s.server.db.Queryx("SELECT id, stamp_id, title, body, author_id, created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
if err != nil {
s.logger.Error("Failed to get guild messages from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID)
bf := byteframe.NewByteFrame()
noMsgs := true
postCount := 0
var postCount uint32
for msgs.Next() {
noMsgs = false
postCount++
postData := &MessageBoardPost{}
err = msgs.StructScan(&postData)
if err != nil {
s.logger.Fatal("Failed to get guild messages from db", zap.Error(err))
continue
}
bf.WriteUint32(postData.Type)
postCount++
bf.WriteUint32(postData.ID)
bf.WriteUint32(postData.AuthorID)
bf.WriteUint64(postData.Timestamp)
likedBySlice := strings.Split(postData.LikedBy, ",")
if likedBySlice[0] == "" {
bf.WriteUint32(0)
} else {
bf.WriteUint32(uint32(len(likedBySlice)))
}
bf.WriteUint32(0)
bf.WriteUint32(uint32(postData.Timestamp.Unix()))
bf.WriteUint32(uint32(stringsupport.CSVLength(postData.LikedBy)))
bf.WriteBool(stringsupport.CSVContains(postData.LikedBy, int(s.charID)))
bf.WriteUint32(postData.StampID)
ps.Uint32(bf, postData.Title, true)
ps.Uint32(bf, postData.Body, true)
}
if noMsgs {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} else {
data := byteframe.NewByteFrame()
data.WriteUint32(uint32(postCount))
data.WriteBytes(bf.Data())
doAckBufSucceed(s, pkt.AckHandle, data.Data())
}
data := byteframe.NewByteFrame()
data.WriteUint32(postCount)
data.WriteBytes(bf.Data())
doAckBufSucceed(s, pkt.AckHandle, data.Data())
}
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
@@ -1869,101 +1870,62 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
var titleConv, bodyConv string
switch pkt.MessageOp {
case 0: // Create message
postType := bf.ReadUint32() // 0 = message, 1 = news
stampId := bf.ReadUint32()
stampID := bf.ReadUint32()
titleLength := bf.ReadUint32()
bodyLength := bf.ReadUint32()
title := bf.ReadBytes(uint(titleLength))
body := bf.ReadBytes(uint(bodyLength))
titleConv = stringsupport.SJISToUTF8(title)
bodyConv = stringsupport.SJISToUTF8(body)
_, err := s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, int(stampId), int(postType), titleConv, bodyConv)
if err != nil {
s.logger.Fatal("Failed to add new guild message to db", zap.Error(err))
}
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, stampID, postType, title, body)
// TODO: if there are too many messages, purge excess
_, err = s.server.db.Exec("")
if err != nil {
s.logger.Fatal("Failed to remove excess guild messages from db", zap.Error(err))
}
case 1: // Delete message
postType := bf.ReadUint32()
timestamp := bf.ReadUint64()
_, err := s.server.db.Exec("DELETE FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID)
if err != nil {
s.logger.Fatal("Failed to delete guild message from db", zap.Error(err))
}
postID := bf.ReadUint32()
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", postID)
case 2: // Update message
postType := bf.ReadUint32()
timestamp := bf.ReadUint64()
postID := bf.ReadUint32()
bf.ReadBytes(8)
titleLength := bf.ReadUint32()
bodyLength := bf.ReadUint32()
title := bf.ReadBytes(uint(titleLength))
body := bf.ReadBytes(uint(bodyLength))
titleConv = stringsupport.SJISToUTF8(title)
bodyConv = stringsupport.SJISToUTF8(body)
_, err := s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE post_type = $3 AND (EXTRACT(epoch FROM created_at)::int) = $4 AND guild_id = $5", titleConv, bodyConv, int(postType), int(timestamp), guild.ID)
if err != nil {
s.logger.Fatal("Failed to update guild message in db", zap.Error(err))
}
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", title, body, postID)
case 3: // Update stamp
postType := bf.ReadUint32()
timestamp := bf.ReadUint64()
stampId := bf.ReadUint32()
_, err := s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", int(stampId), int(postType), int(timestamp), guild.ID)
if err != nil {
s.logger.Fatal("Failed to update guild message stamp in db", zap.Error(err))
}
postID := bf.ReadUint32()
bf.ReadBytes(8)
stampID := bf.ReadUint32()
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", stampID, postID)
case 4: // Like message
postType := bf.ReadUint32()
timestamp := bf.ReadUint64()
postID := bf.ReadUint32()
bf.ReadBytes(8)
likeState := bf.ReadBool()
var likedBy string
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID).Scan(&likedBy)
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", postID).Scan(&likedBy)
if err != nil {
s.logger.Fatal("Failed to get guild message like data from db", zap.Error(err))
s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
} else {
if likeState {
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
if err != nil {
s.logger.Fatal("Failed to like guild message in db", zap.Error(err))
}
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
} else {
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
if err != nil {
s.logger.Fatal("Failed to unlike guild message in db", zap.Error(err))
}
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
}
}
case 5: // Check for new messages
var timeChecked int
var timeChecked time.Time
var newPosts int
err := s.server.db.QueryRow("SELECT (EXTRACT(epoch FROM guild_post_checked)::int) FROM characters WHERE id = $1", s.charID).Scan(&timeChecked)
if err != nil {
s.logger.Fatal("Failed to get last guild post check timestamp from db", zap.Error(err))
} else {
_, err = s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID)
if err != nil {
s.logger.Fatal("Failed to update guild post check timestamp in db", zap.Error(err))
} else {
err = s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2 AND author_id != $3", guild.ID, timeChecked, s.charID).Scan(&newPosts)
if err != nil {
s.logger.Fatal("Failed to check for new guild posts in db", zap.Error(err))
} else {
if newPosts > 0 {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
return
}
}
err := s.server.db.QueryRow("SELECT guild_post_checked FROM characters WHERE id = $1", s.charID).Scan(&timeChecked)
if err == nil {
s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2", guild.ID, timeChecked.Unix()).Scan(&newPosts)
if newPosts > 0 {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
return
}
}
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {