fix(channelserver): handle bare Exec errors and filter expected ErrNoRows

138 bare db.Exec calls across 22 handler files silently dropped write
errors. Each is now wrapped with error check and zap logging.

4 QueryRow sites that legitimately return sql.ErrNoRows during normal
operation (new player mezfes, festa rankings, empty guild item box)
now filter it out to reduce log noise.
This commit is contained in:
Houmgaor
2026-02-17 23:33:44 +01:00
parent 88fc17e790
commit 47f7a1f636
22 changed files with 446 additions and 156 deletions

View File

@@ -303,7 +303,9 @@ func logoutPlayer(s *Session) {
if mhfcourse.CourseExists(30, s.courses) {
rpGained = timePlayed / 900
timePlayed = timePlayed % 900
_, _ = s.server.db.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.charID); err != nil {
s.logger.Error("Failed to update cafe time", zap.Error(err))
}
} else {
rpGained = timePlayed / 1800
timePlayed = timePlayed % 1800
@@ -329,8 +331,12 @@ func logoutPlayer(s *Session) {
}
// Update time_played and guild treasure hunt
_, _ = s.server.db.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.charID)
_, _ = s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE character_id=$1`, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.charID); err != nil {
s.logger.Error("Failed to update time played", zap.Error(err))
}
if _, err := s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE character_id=$1`, s.charID); err != nil {
s.logger.Error("Failed to clear treasure hunt", zap.Error(err))
}
}
// NOW do cleanup (after save is complete)
@@ -449,7 +455,9 @@ func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) {
for i := 0; i < 176; i++ {
val = bf.ReadUint8()
if val > 0 && mhfmon.Monsters[i].Large {
_, _ = s.server.db.Exec(`INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, $2, $3, $4)`, s.charID, i, val, TimeAdjusted())
if _, err := s.server.db.Exec(`INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, $2, $3, $4)`, s.charID, i, val, TimeAdjusted()); err != nil {
s.logger.Error("Failed to insert kill log", zap.Error(err))
}
}
}
}
@@ -977,7 +985,9 @@ func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateUnionItem)
newStacks := mhfitem.DiffItemStacks(userGetItems(s), pkt.UpdatedItems)
_, _ = s.server.db.Exec(`UPDATE users u SET item_box=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, mhfitem.SerializeWarehouseItems(newStacks), s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET item_box=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, mhfitem.SerializeWarehouseItems(newStacks), s.charID); err != nil {
s.logger.Error("Failed to update union item box", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -990,13 +1000,19 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow(fmt.Sprintf("SELECT %s_checked FROM stamps WHERE character_id=$1", pkt.StampType), s.charID).Scan(&lastCheck)
if err != nil {
lastCheck = TimeAdjusted()
_, _ = s.server.db.Exec("INSERT INTO stamps (character_id, hl_checked, ex_checked) VALUES ($1, $2, $2)", s.charID, TimeAdjusted())
if _, err := s.server.db.Exec("INSERT INTO stamps (character_id, hl_checked, ex_checked) VALUES ($1, $2, $2)", s.charID, TimeAdjusted()); err != nil {
s.logger.Error("Failed to insert stamps record", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(fmt.Sprintf(`UPDATE stamps SET %s_checked=$1 WHERE character_id=$2`, pkt.StampType), TimeAdjusted(), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf(`UPDATE stamps SET %s_checked=$1 WHERE character_id=$2`, pkt.StampType), TimeAdjusted(), s.charID); err != nil {
s.logger.Error("Failed to update stamp check time", zap.Error(err))
}
}
if lastCheck.Before(TimeWeekStart()) {
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE stamps SET %s_total=%s_total+1 WHERE character_id=$1", pkt.StampType, pkt.StampType), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE stamps SET %s_total=%s_total+1 WHERE character_id=$1", pkt.StampType, pkt.StampType), s.charID); err != nil {
s.logger.Error("Failed to increment stamp total", zap.Error(err))
}
updated = 1
}
@@ -1043,7 +1059,9 @@ func getGoocooData(s *Session, cid uint32) [][]byte {
for i := 0; i < 5; i++ {
err := s.server.db.QueryRow(fmt.Sprintf("SELECT goocoo%d FROM goocoo WHERE id=$1", i), cid).Scan(&goocoo)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO goocoo (id) VALUES ($1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO goocoo (id) VALUES ($1)", s.charID); err != nil {
s.logger.Error("Failed to insert goocoo record", zap.Error(err))
}
return goocoos
}
if err == nil && goocoo != nil {
@@ -1069,7 +1087,9 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateGuacot)
for _, goocoo := range pkt.Goocoos {
if goocoo.Data1[0] == 0 {
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID); err != nil {
s.logger.Error("Failed to clear goocoo slot", zap.Error(err))
}
} else {
bf := byteframe.NewByteFrame()
bf.WriteUint32(goocoo.Index)
@@ -1081,7 +1101,9 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
}
bf.WriteUint8(uint8(len(goocoo.Name)))
bf.WriteBytes(goocoo.Name)
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=$1 WHERE id=$2", goocoo.Index), bf.Data(), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=$1 WHERE id=$2", goocoo.Index), bf.Data(), s.charID); err != nil {
s.logger.Error("Failed to update goocoo slot", zap.Error(err))
}
dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", goocoo.Index))
}
}
@@ -1144,7 +1166,9 @@ func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {
var dailyTime time.Time
_ = s.server.db.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.charID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime)
if TimeAdjusted().After(dailyTime) {
_, _ = s.server.db.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.charID); err != nil {
s.logger.Error("Failed to reset daily quests", zap.Error(err))
}
}
var bonusQuests, dailyQuests, promoPoints uint32
@@ -1174,9 +1198,13 @@ func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow(fmt.Sprintf(`SELECT %s FROM characters WHERE id = $1`, column), s.charID).Scan(&value)
if err == nil {
if value+pkt.Delta < 0 {
_, _ = s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = 0 WHERE id = $1`, column), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = 0 WHERE id = $1`, column), s.charID); err != nil {
s.logger.Error("Failed to reset etc point", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = %s + $1 WHERE id = $2`, column, column), pkt.Delta, s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = %s + $1 WHERE id = $2`, column, column), pkt.Delta, s.charID); err != nil {
s.logger.Error("Failed to update etc point", zap.Error(err))
}
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
@@ -1517,7 +1545,9 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
bitInByte := bit % 8
data[startByte+byteInd] |= bits.Reverse8(1 << uint(bitInByte))
dumpSaveData(s, data, "skinhist")
_, _ = s.server.db.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.charID); err != nil {
s.logger.Error("Failed to update skin history", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -1600,7 +1630,9 @@ func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateUseTrendWeaponLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateUseTrendWeaponLog)
_, _ = s.server.db.Exec(`INSERT INTO trend_weapons (weapon_id, weapon_type, count) VALUES ($1, $2, 1) ON CONFLICT (weapon_id) DO
UPDATE SET count = trend_weapons.count+1`, pkt.WeaponID, pkt.WeaponType)
if _, err := s.server.db.Exec(`INSERT INTO trend_weapons (weapon_id, weapon_type, count) VALUES ($1, $2, 1) ON CONFLICT (weapon_id) DO
UPDATE SET count = trend_weapons.count+1`, pkt.WeaponID, pkt.WeaponType); err != nil {
s.logger.Error("Failed to update trend weapon log", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -5,6 +5,8 @@ import (
"erupe-ce/network/mhfpacket"
"fmt"
"io"
"go.uber.org/zap"
)
var achievementCurves = [][]int32{
@@ -90,7 +92,9 @@ func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {
var exists int
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", pkt.CharID).Scan(&exists)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID)
if _, err := s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID); err != nil {
s.logger.Error("Failed to insert achievements record", zap.Error(err))
}
}
var scores [33]int32
@@ -152,10 +156,14 @@ func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {
var exists int
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID).Scan(&exists)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", s.charID); err != nil {
s.logger.Error("Failed to insert achievements record", zap.Error(err))
}
}
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.charID); err != nil {
s.logger.Error("Failed to update achievement score", zap.Error(err))
}
}
func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -58,7 +58,9 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
bondBonus = 5 // Bond point bonus quests
bonusQuests = s.server.erupeConfig.GameplayOptions.BonusQuestAllowance
dailyQuests = s.server.erupeConfig.GameplayOptions.DailyQuestAllowance
_, _ = s.server.db.Exec("UPDATE characters SET daily_time=$1, bonus_quests = $2, daily_quests = $3 WHERE id=$4", midday, bonusQuests, dailyQuests, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET daily_time=$1, bonus_quests = $2, daily_quests = $3 WHERE id=$4", midday, bonusQuests, dailyQuests, s.charID); err != nil {
s.logger.Error("Failed to update daily cafe data", zap.Error(err))
}
bf.WriteBool(true) // Success?
} else {
bf.WriteBool(false)
@@ -77,12 +79,18 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset)
if err != nil {
cafeReset = TimeWeekNext()
_, _ = s.server.db.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID)
if _, err := s.server.db.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID); err != nil {
s.logger.Error("Failed to set cafe reset time", zap.Error(err))
}
}
if TimeAdjusted().After(cafeReset) {
cafeReset = TimeWeekNext()
_, _ = s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID)
_, _ = s.server.db.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, s.charID)
if _, err := s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID); err != nil {
s.logger.Error("Failed to reset cafe time", zap.Error(err))
}
if _, err := s.server.db.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, s.charID); err != nil {
s.logger.Error("Failed to delete accepted cafe bonuses", zap.Error(err))
}
}
var cafeTime uint32
@@ -199,7 +207,9 @@ func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket
_ = addPointNetcafe(s, int(cafeBonus.Quantity))
}
}
_, _ = s.server.db.Exec("INSERT INTO public.cafe_accepted VALUES ($1, $2)", cbID, s.charID)
if _, err := s.server.db.Exec("INSERT INTO public.cafe_accepted VALUES ($1, $2)", cbID, s.charID); err != nil {
s.logger.Error("Failed to insert accepted cafe bonus", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -215,7 +225,9 @@ func addPointNetcafe(s *Session, p int) error {
} else {
points += p
}
_, _ = s.server.db.Exec("UPDATE characters SET netcafe_points=$1 WHERE id=$2", points, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET netcafe_points=$1 WHERE id=$2", points, s.charID); err != nil {
s.logger.Error("Failed to update netcafe points", zap.Error(err))
}
return nil
}
@@ -228,7 +240,9 @@ func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
return
}
_, _ = s.server.db.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.charID); err != nil {
s.logger.Error("Failed to update boost time", zap.Error(err))
}
bf.WriteUint32(uint32(boostLimit.Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}

View File

@@ -123,12 +123,16 @@ func parseChatCommand(s *Session, command string) {
err := s.server.db.QueryRow(`SELECT id, username FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, cid).Scan(&uid, &uname)
if err == nil {
if expiry.IsZero() {
_, _ = s.server.db.Exec(`INSERT INTO bans VALUES ($1)
ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid)
if _, err := s.server.db.Exec(`INSERT INTO bans VALUES ($1)
ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid); err != nil {
s.logger.Error("Failed to ban user", zap.Error(err))
}
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.ban.success, uname))
} else {
_, _ = s.server.db.Exec(`INSERT INTO bans VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry)
if _, err := s.server.db.Exec(`INSERT INTO bans VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry); err != nil {
s.logger.Error("Failed to ban user with expiry", zap.Error(err))
}
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.ban.success, uname)+fmt.Sprintf(s.server.i18n.commands.ban.length, expiry.Format(time.DateTime)))
}
s.server.DisconnectUser(uid)
@@ -150,7 +154,9 @@ func parseChatCommand(s *Session, command string) {
if err := s.server.db.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&state); err != nil {
s.logger.Error("Failed to get timer state", zap.Error(err))
}
_, _ = s.server.db.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.charID); err != nil {
s.logger.Error("Failed to update timer setting", zap.Error(err))
}
if state {
sendServerChatMessage(s, s.server.i18n.commands.timer.disabled)
} else {
@@ -308,7 +314,9 @@ func parseChatCommand(s *Session, command string) {
}
err := s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
if err == nil {
_, _ = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.charID); err != nil {
s.logger.Error("Failed to update user rights", zap.Error(err))
}
}
updateRights(s)
} else {
@@ -406,7 +414,9 @@ func parseChatCommand(s *Session, command string) {
randToken := make([]byte, 4)
_, _ = rand.Read(randToken)
_token = fmt.Sprintf("%x-%x", randToken[:2], randToken[2:])
_, _ = s.server.db.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.charID); err != nil {
s.logger.Error("Failed to update discord token", zap.Error(err))
}
}
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.discord.success, _token))
} else {

View File

@@ -186,8 +186,10 @@ func (save *CharacterSaveData) Save(s *Session) {
s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID))
}
_, _ = s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7
`, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID)
if _, err := s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7
`, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID); err != nil {
s.logger.Error("Failed to update user binary house data", zap.Error(err))
}
}
func (save *CharacterSaveData) Compress() error {

View File

@@ -94,7 +94,9 @@ func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {
} else {
csv = stringsupport.CSVAdd(csv, int(cid))
}
_, _ = s.server.db.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.charID); err != nil {
s.logger.Error("Failed to update blocked list", zap.Error(err))
}
}
} else { // Friendlist
err := s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&csv)
@@ -104,7 +106,9 @@ func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {
} else {
csv = stringsupport.CSVAdd(csv, int(cid))
}
_, _ = s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID); err != nil {
s.logger.Error("Failed to update friends list", zap.Error(err))
}
}
}
}

View File

@@ -78,7 +78,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
s.rawConn.Close()
s.logger.Warn("Save cancelled due to corruption.")
if s.server.erupeConfig.DeleteOnSaveCorruption {
_, _ = s.server.db.Exec("UPDATE characters SET deleted=true WHERE id=$1", s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET deleted=true WHERE id=$1", s.charID); err != nil {
s.logger.Error("Failed to mark character as deleted", zap.Error(err))
}
}
return
}

View File

@@ -170,11 +170,17 @@ func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
case 17:
_ = addPointNetcafe(s, int(item.Quantity))
case 19:
_, _ = s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID); err != nil {
s.logger.Error("Failed to update gacha premium", zap.Error(err))
}
case 20:
_, _ = s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID); err != nil {
s.logger.Error("Failed to update gacha trial", zap.Error(err))
}
case 21:
_, _ = s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID); err != nil {
s.logger.Error("Failed to update frontier points", zap.Error(err))
}
case 23:
saveData, err := GetCharacterSaveData(s, s.charID)
if err == nil {

View File

@@ -12,7 +12,9 @@ import (
)
func cleanupDiva(s *Session) {
_, _ = s.server.db.Exec("DELETE FROM events WHERE event_type='diva'")
if _, err := s.server.db.Exec("DELETE FROM events WHERE event_type='diva'"); err != nil {
s.logger.Error("Failed to delete diva events", zap.Error(err))
}
}
func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
@@ -49,7 +51,9 @@ func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
cleanupDiva(s)
// Generate a new diva defense, starting midnight tomorrow
start = uint32(midnight.Add(24 * time.Hour).Unix())
_, _ = s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('diva', to_timestamp($1)::timestamp without time zone)", start)
if _, err := s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('diva', to_timestamp($1)::timestamp without time zone)", start); err != nil {
s.logger.Error("Failed to insert diva event", zap.Error(err))
}
}
timestamps[0] = start
timestamps[1] = timestamps[0] + 601200

View File

@@ -8,6 +8,7 @@ import (
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)
type Event struct {
@@ -69,7 +70,9 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
weapons := token.RNG.Intn(s.server.erupeConfig.GameplayOptions.MaxFeatureWeapons-s.server.erupeConfig.GameplayOptions.MinFeatureWeapons+1) + s.server.erupeConfig.GameplayOptions.MinFeatureWeapons
temp = generateFeatureWeapons(weapons)
temp.StartTime = t
_, _ = s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures)
if _, err := s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures); err != nil {
s.logger.Error("Failed to insert feature weapon", zap.Error(err))
}
}
features = append(features, temp)
}
@@ -155,7 +158,9 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
{WeekReq: 5, Expiration: temp},
}
for _, boost := range loginBoosts {
_, _ = s.server.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, s.charID, boost.WeekReq, boost.Expiration, time.Time{})
if _, err := s.server.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, s.charID, boost.WeekReq, boost.Expiration, time.Time{}); err != nil {
s.logger.Error("Failed to insert login boost", zap.Error(err))
}
}
}
@@ -164,7 +169,9 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
if !boost.Reset.IsZero() && boost.Reset.Before(TimeAdjusted()) {
boost.Expiration = TimeWeekStart()
boost.Reset = time.Time{}
_, _ = s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, boost.Expiration, boost.Reset, s.charID, boost.WeekReq)
if _, err := s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, boost.Expiration, boost.Reset, s.charID, boost.WeekReq); err != nil {
s.logger.Error("Failed to reset login boost", zap.Error(err))
}
}
boost.WeekCount = uint8((TimeAdjusted().Unix()-boost.Expiration.Unix())/604800 + 1)
@@ -207,7 +214,9 @@ func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {
expiration = TimeAdjusted().Add(240 * time.Minute)
}
bf.WriteUint32(uint32(expiration.Unix()))
_, _ = s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, TimeWeekNext(), s.charID, pkt.BoostWeekUsed)
if _, err := s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, TimeWeekNext(), s.charID, pkt.BoostWeekUsed); err != nil {
s.logger.Error("Failed to use login boost", zap.Error(err))
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}

View File

@@ -1,26 +1,32 @@
package channelserver
import (
"database/sql"
"errors"
"sort"
"time"
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/token"
_config "erupe-ce/config"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
"sort"
"time"
)
func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveMezfesData)
_, _ = s.server.db.Exec(`UPDATE characters SET mezfes=$1 WHERE id=$2`, pkt.RawDataPayload, s.charID)
if _, err := s.server.db.Exec(`UPDATE characters SET mezfes=$1 WHERE id=$2`, pkt.RawDataPayload, s.charID); err != nil {
s.logger.Error("Failed to save mezfes data", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadMezfesData)
var data []byte
if err := s.server.db.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.charID).Scan(&data); err != nil {
if err := s.server.db.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.charID).Scan(&data); err != nil && !errors.Is(err, sql.ErrNoRows) {
s.logger.Error("Failed to load mezfes data", zap.Error(err))
}
bf := byteframe.NewByteFrame()
@@ -96,11 +102,21 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
}
func cleanupFesta(s *Session) {
_, _ = s.server.db.Exec("DELETE FROM events WHERE event_type='festa'")
_, _ = s.server.db.Exec("DELETE FROM festa_registrations")
_, _ = s.server.db.Exec("DELETE FROM festa_submissions")
_, _ = s.server.db.Exec("DELETE FROM festa_prizes_accepted")
_, _ = s.server.db.Exec("UPDATE guild_characters SET trial_vote=NULL")
if _, err := s.server.db.Exec("DELETE FROM events WHERE event_type='festa'"); err != nil {
s.logger.Error("Failed to delete festa events", zap.Error(err))
}
if _, err := s.server.db.Exec("DELETE FROM festa_registrations"); err != nil {
s.logger.Error("Failed to delete festa registrations", zap.Error(err))
}
if _, err := s.server.db.Exec("DELETE FROM festa_submissions"); err != nil {
s.logger.Error("Failed to delete festa submissions", zap.Error(err))
}
if _, err := s.server.db.Exec("DELETE FROM festa_prizes_accepted"); err != nil {
s.logger.Error("Failed to delete festa prizes accepted", zap.Error(err))
}
if _, err := s.server.db.Exec("UPDATE guild_characters SET trial_vote=NULL"); err != nil {
s.logger.Error("Failed to reset festa trial votes", zap.Error(err))
}
}
func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
@@ -134,7 +150,9 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
cleanupFesta(s)
// Generate a new festa, starting midnight tomorrow
start = uint32(midnight.Add(24 * time.Hour).Unix())
_, _ = s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start)
if _, err := s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start); err != nil {
s.logger.Error("Failed to insert festa event", zap.Error(err))
}
}
timestamps[0] = start
timestamps[1] = timestamps[0] + 604800
@@ -324,7 +342,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
WHERE fs.trial_type = $1
GROUP BY fs.guild_id, g.name, fr.team
ORDER BY _ DESC LIMIT 1
`, i+1).Scan(&guildID, &guildName, &guildTeam, &temp); err != nil {
`, i+1).Scan(&guildID, &guildName, &guildTeam, &temp); err != nil && !errors.Is(err, sql.ErrNoRows) {
s.logger.Error("Failed to get festa trial ranking", zap.Error(err))
}
bf.WriteUint32(guildID)
@@ -346,7 +364,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
WHERE EXTRACT(EPOCH FROM fs.timestamp)::int > $1 AND EXTRACT(EPOCH FROM fs.timestamp)::int < $2
GROUP BY fs.guild_id, g.name, fr.team
ORDER BY _ DESC LIMIT 1
`, timestamps[1]+offset, timestamps[1]+offset+86400).Scan(&guildID, &guildName, &guildTeam, &temp); err != nil {
`, timestamps[1]+offset, timestamps[1]+offset+86400).Scan(&guildID, &guildName, &guildTeam, &temp); err != nil && !errors.Is(err, sql.ErrNoRows) {
s.logger.Error("Failed to get festa daily ranking", zap.Error(err))
}
bf.WriteUint32(guildID)
@@ -466,7 +484,9 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfVoteFesta)
_, _ = s.server.db.Exec(`UPDATE guild_characters SET trial_vote=$1 WHERE character_id=$2`, pkt.TrialID, s.charID)
if _, err := s.server.db.Exec(`UPDATE guild_characters SET trial_vote=$1 WHERE character_id=$2`, pkt.TrialID, s.charID); err != nil {
s.logger.Error("Failed to update festa trial vote", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -480,9 +500,13 @@ func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {
team := uint32(token.RNG.Intn(2))
switch team {
case 0:
_, _ = s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID)
if _, err := s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID); err != nil {
s.logger.Error("Failed to register guild for festa blue team", zap.Error(err))
}
case 1:
_, _ = s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'red')", guild.ID)
if _, err := s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'red')", guild.ID); err != nil {
s.logger.Error("Failed to register guild for festa red team", zap.Error(err))
}
}
bf := byteframe.NewByteFrame()
bf.WriteUint32(team)
@@ -512,19 +536,25 @@ func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFesta)
_, _ = s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID); err != nil {
s.logger.Error("Failed to accept festa prize", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFestaPersonalPrize)
_, _ = s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID)
if _, err := s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID); err != nil {
s.logger.Error("Failed to accept festa personal prize", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFestaIntermediatePrize)
_, _ = s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID)
if _, err := s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID); err != nil {
s.logger.Error("Failed to accept festa intermediate prize", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -715,9 +715,13 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
case mhfpacket.OperateGuildDonateRank:
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, 0))
case mhfpacket.OperateGuildSetApplicationDeny:
_, _ = s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID)
if _, err := s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID); err != nil {
s.logger.Error("Failed to deny guild applications", zap.Error(err))
}
case mhfpacket.OperateGuildSetApplicationAllow:
_, _ = s.server.db.Exec("UPDATE guilds SET recruiting=true WHERE id=$1", guild.ID)
if _, err := s.server.db.Exec("UPDATE guilds SET recruiting=true WHERE id=$1", guild.ID); err != nil {
s.logger.Error("Failed to allow guild applications", zap.Error(err))
}
case mhfpacket.OperateGuildSetAvoidLeadershipTrue:
handleAvoidLeadershipUpdate(s, pkt, true)
case mhfpacket.OperateGuildSetAvoidLeadershipFalse:
@@ -751,7 +755,9 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
case mhfpacket.OperateGuildChangePugi3:
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3)
case mhfpacket.OperateGuildUnlockOutfit:
_, _ = s.server.db.Exec(`UPDATE guilds SET pugi_outfits=$1 WHERE id=$2`, pkt.Data1.ReadUint32(), guild.ID)
if _, err := s.server.db.Exec(`UPDATE guilds SET pugi_outfits=$1 WHERE id=$2`, pkt.Data1.ReadUint32(), guild.ID); err != nil {
s.logger.Error("Failed to unlock guild pugi outfit", zap.Error(err))
}
case mhfpacket.OperateGuildDonateRoom:
quantity := uint16(pkt.Data1.ReadUint32())
bf.WriteBytes(handleDonateRP(s, quantity, guild, 2))
@@ -759,7 +765,9 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
quantity := uint16(pkt.Data1.ReadUint32())
bf.WriteBytes(handleDonateRP(s, quantity, guild, 1))
// 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)
if _, err := s.server.db.Exec(`UPDATE guild_characters SET rp_today=rp_today+$1 WHERE character_id=$2`, quantity, s.charID); err != nil {
s.logger.Error("Failed to update guild character daily RP", zap.Error(err))
}
case mhfpacket.OperateGuildEventExchange:
rp := uint16(pkt.Data1.ReadUint32())
var balance uint32
@@ -825,15 +833,25 @@ func handleDonateRP(s *Session, amount uint16, guild *Guild, _type int) []byte {
saveData.Save(s)
switch _type {
case 0:
_, _ = s.server.db.Exec(`UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2`, amount, guild.ID)
if _, err := s.server.db.Exec(`UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2`, amount, guild.ID); err != nil {
s.logger.Error("Failed to update guild rank RP", zap.Error(err))
}
case 1:
_, _ = s.server.db.Exec(`UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2`, amount, guild.ID)
if _, err := s.server.db.Exec(`UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2`, amount, guild.ID); err != nil {
s.logger.Error("Failed to update guild event RP", zap.Error(err))
}
case 2:
if resetRoom {
_, _ = s.server.db.Exec(`UPDATE guilds SET room_rp = 0 WHERE id = $1`, guild.ID)
_, _ = s.server.db.Exec(`UPDATE guilds SET room_expiry = $1 WHERE id = $2`, TimeAdjusted().Add(time.Hour*24*7), guild.ID)
if _, err := s.server.db.Exec(`UPDATE guilds SET room_rp = 0 WHERE id = $1`, guild.ID); err != nil {
s.logger.Error("Failed to reset guild room RP", zap.Error(err))
}
if _, err := s.server.db.Exec(`UPDATE guilds SET room_expiry = $1 WHERE id = $2`, TimeAdjusted().Add(time.Hour*24*7), guild.ID); err != nil {
s.logger.Error("Failed to update guild room expiry", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(`UPDATE guilds SET room_rp = room_rp + $1 WHERE id = $2`, amount, guild.ID)
if _, err := s.server.db.Exec(`UPDATE guilds SET room_rp = room_rp + $1 WHERE id = $2`, amount, guild.ID); err != nil {
s.logger.Error("Failed to update guild room RP", zap.Error(err))
}
}
}
_, _ = bf.Seek(0, 0)
@@ -1597,7 +1615,7 @@ func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {
func guildGetItems(s *Session, guildID uint32) []mhfitem.MHFItemStack {
var data []byte
var items []mhfitem.MHFItemStack
if err := s.server.db.QueryRow(`SELECT item_box FROM guilds WHERE id=$1`, guildID).Scan(&data); err != nil {
if err := s.server.db.QueryRow(`SELECT item_box FROM guilds WHERE id=$1`, guildID).Scan(&data); err != nil && !errors.Is(err, sql.ErrNoRows) {
s.logger.Error("Failed to get guild item box", zap.Error(err))
}
if len(data) > 0 {
@@ -1622,7 +1640,9 @@ func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateGuildItem)
newStacks := mhfitem.DiffItemStacks(guildGetItems(s, pkt.GuildID), pkt.UpdatedItems)
_, _ = s.server.db.Exec(`UPDATE guilds SET item_box=$1 WHERE id=$2`, mhfitem.SerializeWarehouseItems(newStacks), pkt.GuildID)
if _, err := s.server.db.Exec(`UPDATE guilds SET item_box=$1 WHERE id=$2`, mhfitem.SerializeWarehouseItems(newStacks), pkt.GuildID); err != nil {
s.logger.Error("Failed to update guild item box", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -1810,7 +1830,9 @@ func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
startTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.ClanMealDuration-3600) * time.Second)
if pkt.OverwriteID != 0 {
_, _ = s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, startTime, pkt.OverwriteID)
if _, err := s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, startTime, pkt.OverwriteID); err != nil {
s.logger.Error("Failed to update guild meal", zap.Error(err))
}
} else {
_ = s.server.db.QueryRow("INSERT INTO guild_meals (guild_id, meal_id, level, created_at) VALUES ($1, $2, $3, $4) RETURNING id", guild.ID, pkt.MealID, pkt.Success, startTime).Scan(&pkt.OverwriteID)
}
@@ -1843,7 +1865,9 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
switch pkt.Operation {
case 0: // Acquire
_, _ = s.server.db.Exec(`UPDATE guild_characters SET box_claimed=$1 WHERE character_id=$2`, TimeAdjusted(), s.charID)
if _, err := s.server.db.Exec(`UPDATE guild_characters SET box_claimed=$1 WHERE character_id=$2`, TimeAdjusted(), s.charID); err != nil {
s.logger.Error("Failed to update guild hunt box claimed time", zap.Error(err))
}
case 1: // Enumerate
bf.WriteUint8(0) // Entries
rows, err := s.server.db.Query(`SELECT kl.id, kl.monster FROM kill_logs kl
@@ -1913,7 +1937,9 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
_, _ = s.server.db.Exec("UPDATE characters SET guild_post_checked = now() WHERE id = $1", s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET guild_post_checked = now() WHERE id = $1", s.charID); err != nil {
s.logger.Error("Failed to update guild post checked time", zap.Error(err))
}
bf := byteframe.NewByteFrame()
var postCount uint32
for msgs.Next() {
@@ -1952,21 +1978,31 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
}
switch pkt.MessageOp {
case 0: // Create message
_, _ = 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, pkt.StampID, pkt.PostType, pkt.Title, pkt.Body)
if _, 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, pkt.StampID, pkt.PostType, pkt.Title, pkt.Body); err != nil {
s.logger.Error("Failed to insert guild post", zap.Error(err))
}
maxPosts := 100
if pkt.PostType == 1 {
maxPosts = 4
}
_, _ = s.server.db.Exec(`DELETE FROM guild_posts WHERE id IN (
if _, err := s.server.db.Exec(`DELETE FROM guild_posts WHERE id IN (
SELECT id FROM guild_posts WHERE guild_id = $1 AND post_type = $2
ORDER BY created_at DESC OFFSET $3
)`, guild.ID, pkt.PostType, maxPosts)
)`, guild.ID, pkt.PostType, maxPosts); err != nil {
s.logger.Error("Failed to purge excess guild posts", zap.Error(err))
}
case 1: // Delete message
_, _ = s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", pkt.PostID)
if _, err := s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", pkt.PostID); err != nil {
s.logger.Error("Failed to delete guild post", zap.Error(err))
}
case 2: // Update message
_, _ = s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", pkt.Title, pkt.Body, pkt.PostID)
if _, err := s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", pkt.Title, pkt.Body, pkt.PostID); err != nil {
s.logger.Error("Failed to update guild post", zap.Error(err))
}
case 3: // Update stamp
_, _ = s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", pkt.StampID, pkt.PostID)
if _, err := s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", pkt.StampID, pkt.PostID); err != nil {
s.logger.Error("Failed to update guild post stamp", zap.Error(err))
}
case 4: // Like message
var likedBy string
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", pkt.PostID).Scan(&likedBy)
@@ -1975,10 +2011,14 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
} else {
if pkt.LikeState {
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
_, _ = s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
if _, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID); err != nil {
s.logger.Error("Failed to update guild post likes", zap.Error(err))
}
} else {
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
_, _ = s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
if _, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID); err != nil {
s.logger.Error("Failed to update guild post likes", zap.Error(err))
}
}
}
case 5: // Check for new messages
@@ -2019,7 +2059,9 @@ func handleMsgMhfUpdateGuild(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfSetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetGuildManageRight)
_, _ = s.server.db.Exec("UPDATE guild_characters SET recruiter=$1 WHERE character_id=$2", pkt.Allowed, pkt.CharID)
if _, err := s.server.db.Exec("UPDATE guild_characters SET recruiter=$1 WHERE character_id=$2", pkt.Allowed, pkt.CharID); err != nil {
s.logger.Error("Failed to update guild manage right", zap.Error(err))
}
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -145,11 +145,17 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
case mhfpacket.OPERATE_JOINT_LEAVE:
if guild.LeaderCharID == s.charID {
if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to update alliance on guild leave", zap.Error(err))
}
} else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to remove sub guild 1 from alliance", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to remove sub guild 2 from alliance", zap.Error(err))
}
}
// NOTE: Alliance join requests are not yet implemented (no DB table exists),
// so there are no pending applications to clean up on leave.
@@ -165,11 +171,17 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
if alliance.ParentGuild.LeaderCharID == s.charID {
kickedGuildID := pkt.Data1.ReadUint32()
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to update alliance on guild kick", zap.Error(err))
}
} else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to remove kicked sub guild 1 from alliance", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
if _, err := s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID); err != nil {
s.logger.Error("Failed to remove kicked sub guild 2 from alliance", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {

View File

@@ -5,6 +5,8 @@ import (
"erupe-ce/common/stringsupport"
"erupe-ce/network/mhfpacket"
"time"
"go.uber.org/zap"
)
type TreasureHunt struct {
@@ -108,14 +110,18 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {
huntData.WriteBytes(bf.ReadBytes(9))
}
}
_, _ = s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6)
`, guild.ID, s.charID, destination, level, huntData.Data(), catsUsed)
if _, err := s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6)
`, guild.ID, s.charID, destination, level, huntData.Data(), catsUsed); err != nil {
s.logger.Error("Failed to register guild treasure hunt", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresure)
_, _ = s.server.db.Exec(`UPDATE guild_hunts SET acquired=true WHERE id=$1`, pkt.HuntID)
if _, err := s.server.db.Exec(`UPDATE guild_hunts SET acquired=true WHERE id=$1`, pkt.HuntID); err != nil {
s.logger.Error("Failed to acquire guild treasure hunt", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -123,12 +129,20 @@ func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport)
switch pkt.State {
case 0: // Report registration
_, _ = s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.charID)
if _, err := s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.charID); err != nil {
s.logger.Error("Failed to register treasure hunt report", zap.Error(err))
}
case 1: // Collected by hunter
_, _ = s.server.db.Exec(`UPDATE guild_hunts SET collected=true WHERE id=$1`, pkt.HuntID)
_, _ = s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID)
if _, err := s.server.db.Exec(`UPDATE guild_hunts SET collected=true WHERE id=$1`, pkt.HuntID); err != nil {
s.logger.Error("Failed to mark treasure hunt collected", zap.Error(err))
}
if _, err := s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID); err != nil {
s.logger.Error("Failed to clear treasure hunt from guild characters", zap.Error(err))
}
case 2: // Claim treasure
_, _ = s.server.db.Exec(`INSERT INTO guild_hunts_claimed VALUES ($1, $2)`, pkt.HuntID, s.charID)
if _, err := s.server.db.Exec(`INSERT INTO guild_hunts_claimed VALUES ($1, $2)`, pkt.HuntID, s.charID); err != nil {
s.logger.Error("Failed to claim treasure hunt reward", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -41,7 +41,9 @@ FROM warehouse
func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateInterior)
_, _ = s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID)
if _, err := s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID); err != nil {
s.logger.Error("Failed to update house furniture", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -142,7 +144,9 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
// 03 = open friends
// 04 = open guild
// 05 = open friends+guild
_, _ = s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID)
if _, err := s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID); err != nil {
s.logger.Error("Failed to update house state", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -248,7 +252,9 @@ func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo)
_, _ = s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Data, s.charID)
if _, err := s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Data, s.charID); err != nil {
s.logger.Error("Failed to update myhouse mission", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -317,7 +323,9 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
}
dumpSaveData(s, bf.Data(), "decomyset")
_, _ = s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", bf.Data(), s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", bf.Data(), s.charID); err != nil {
s.logger.Error("Failed to save decomyset", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -361,9 +369,13 @@ func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {
var exists int
err := s.server.db.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, title, s.charID).Scan(&exists)
if err != nil || exists == 0 {
_, _ = s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, title, s.charID)
if _, err := s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, title, s.charID); err != nil {
s.logger.Error("Failed to insert title", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, title, s.charID)
if _, err := s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, title, s.charID); err != nil {
s.logger.Error("Failed to update title", zap.Error(err))
}
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
@@ -375,7 +387,9 @@ func initializeWarehouse(s *Session) {
var t int
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID); err != nil {
s.logger.Error("Failed to initialize warehouse", zap.Error(err))
}
}
}
@@ -418,9 +432,13 @@ func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
case 2:
switch pkt.BoxType {
case 0:
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID); err != nil {
s.logger.Error("Failed to rename warehouse item box", zap.Error(err))
}
case 1:
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET equip%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET equip%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID); err != nil {
s.logger.Error("Failed to rename warehouse equip box", zap.Error(err))
}
}
case 3:
bf.WriteUint32(0) // Usage renewal time, >1 = disabled
@@ -443,7 +461,9 @@ func addWarehouseItem(s *Session, item mhfitem.MHFItemStack) {
giftBox := warehouseGetItems(s, 10)
item.WarehouseID = token.RNG.Uint32()
giftBox = append(giftBox, item)
_, _ = s.server.db.Exec("UPDATE warehouse SET item10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseItems(giftBox), s.charID)
if _, err := s.server.db.Exec("UPDATE warehouse SET item10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseItems(giftBox), s.charID); err != nil {
s.logger.Error("Failed to update warehouse gift box", zap.Error(err))
}
}
func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {

View File

@@ -216,7 +216,9 @@ func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
return
}
_, _ = s.server.db.Exec(`UPDATE mail SET read = true WHERE id = $1`, mail.ID)
if _, err := s.server.db.Exec(`UPDATE mail SET read = true WHERE id = $1`, mail.ID); err != nil {
s.logger.Error("Failed to mark mail as read", zap.Error(err))
}
bf := byteframe.NewByteFrame()
body := stringsupport.UTF8ToSJIS(mail.Body)
bf.WriteNullTerminatedBytes(body)
@@ -303,13 +305,21 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
switch pkt.Operation {
case mhfpacket.OperateMailDelete:
_, _ = s.server.db.Exec(`UPDATE mail SET deleted = true WHERE id = $1`, mail.ID)
if _, err := s.server.db.Exec(`UPDATE mail SET deleted = true WHERE id = $1`, mail.ID); err != nil {
s.logger.Error("Failed to delete mail", zap.Error(err))
}
case mhfpacket.OperateMailLock:
_, _ = s.server.db.Exec(`UPDATE mail SET locked = TRUE WHERE id = $1`, mail.ID)
if _, err := s.server.db.Exec(`UPDATE mail SET locked = TRUE WHERE id = $1`, mail.ID); err != nil {
s.logger.Error("Failed to lock mail", zap.Error(err))
}
case mhfpacket.OperateMailUnlock:
_, _ = s.server.db.Exec(`UPDATE mail SET locked = FALSE WHERE id = $1`, mail.ID)
if _, err := s.server.db.Exec(`UPDATE mail SET locked = FALSE WHERE id = $1`, mail.ID); err != nil {
s.logger.Error("Failed to unlock mail", zap.Error(err))
}
case mhfpacket.OperateMailAcquireItem:
_, _ = s.server.db.Exec(`UPDATE mail SET attached_item_received = TRUE WHERE id = $1`, mail.ID)
if _, err := s.server.db.Exec(`UPDATE mail SET attached_item_received = TRUE WHERE id = $1`, mail.ID); err != nil {
s.logger.Error("Failed to mark mail item received", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -178,7 +178,9 @@ func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
var nextID uint32
_ = s.server.db.QueryRow("SELECT nextval('rasta_id_seq')").Scan(&nextID)
_, _ = s.server.db.Exec("UPDATE characters SET rasta_id=$1 WHERE id=$2", nextID, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET rasta_id=$1 WHERE id=$2", nextID, s.charID); err != nil {
s.logger.Error("Failed to set rasta ID", zap.Error(err))
}
bf.WriteUint32(nextID)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}
@@ -188,9 +190,13 @@ func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, pkt.MercData, "mercenary")
if len(pkt.MercData) > 0 {
temp := byteframe.NewByteFrameFromBytes(pkt.MercData)
_, _ = s.server.db.Exec("UPDATE characters SET savemercenary=$1, rasta_id=$2 WHERE id=$3", pkt.MercData, temp.ReadUint32(), s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET savemercenary=$1, rasta_id=$2 WHERE id=$3", pkt.MercData, temp.ReadUint32(), s.charID); err != nil {
s.logger.Error("Failed to save mercenary data", zap.Error(err))
}
}
if _, err := s.server.db.Exec("UPDATE characters SET gcp=$1, pact_id=$2 WHERE id=$3", pkt.GCP, pkt.PactMercID, s.charID); err != nil {
s.logger.Error("Failed to update GCP and pact ID", zap.Error(err))
}
_, _ = s.server.db.Exec("UPDATE characters SET gcp=$1, pact_id=$2 WHERE id=$3", pkt.GCP, pkt.PactMercID, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
@@ -273,11 +279,17 @@ func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfContractMercenary)
switch pkt.Op {
case 0: // Form loan
_, _ = s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, pkt.CID)
if _, err := s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, pkt.CID); err != nil {
s.logger.Error("Failed to form mercenary loan", zap.Error(err))
}
case 1: // Cancel lend
_, _ = s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID); err != nil {
s.logger.Error("Failed to cancel mercenary lend", zap.Error(err))
}
case 2: // Cancel loan
_, _ = s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", pkt.CID)
if _, err := s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", pkt.CID); err != nil {
s.logger.Error("Failed to cancel mercenary loan", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -332,7 +344,9 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
s.logger.Error("Failed to compress airou", zap.Error(err))
} else {
comp = append([]byte{0x01}, comp...)
_, _ = s.server.db.Exec("UPDATE characters SET otomoairou=$1 WHERE id=$2", comp, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET otomoairou=$1 WHERE id=$2", comp, s.charID); err != nil {
s.logger.Error("Failed to save otomoairou", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -442,15 +456,15 @@ func GetAirouDetails(bf *byteframe.ByteFrame) []Airou {
catStart, _ := bf.Seek(0, io.SeekCurrent)
catDef.ID = bf.ReadUint32()
_, _ = bf.Seek(1, io.SeekCurrent) // unknown value, probably a bool
catDef.Name = bf.ReadBytes(18) // always 18 len, reads first null terminated string out of section and discards rest
_, _ = bf.Seek(1, io.SeekCurrent) // unknown value, probably a bool
catDef.Name = bf.ReadBytes(18) // always 18 len, reads first null terminated string out of section and discards rest
catDef.Task = bf.ReadUint8()
_, _ = bf.Seek(16, io.SeekCurrent) // appearance data and what is seemingly null bytes
catDef.Personality = bf.ReadUint8()
catDef.Class = bf.ReadUint8()
_, _ = bf.Seek(5, io.SeekCurrent) // affection and colour sliders
_, _ = bf.Seek(5, io.SeekCurrent) // affection and colour sliders
catDef.Experience = bf.ReadUint32() // raw cat rank points, doesn't have a rank
_, _ = bf.Seek(1, io.SeekCurrent) // bool for weapon being equipped
_, _ = bf.Seek(1, io.SeekCurrent) // bool for weapon being equipped
catDef.WeaponType = bf.ReadUint8() // weapon type, presumably always 6 for melee?
catDef.WeaponID = bf.ReadUint16() // weapon id
_, _ = bf.Seek(catStart+int64(catDefLen), io.SeekStart)

View File

@@ -206,7 +206,9 @@ func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest)
dumpSaveData(s, pkt.Data, "favquest")
_, _ = s.server.db.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.charID); err != nil {
s.logger.Error("Failed to save favorite quest", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}

View File

@@ -33,9 +33,13 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
var t int
err = s.server.db.QueryRow("SELECT character_id FROM rengoku_score WHERE character_id=$1", s.charID).Scan(&t)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.charID); err != nil {
s.logger.Error("Failed to insert rengoku score", zap.Error(err))
}
}
if _, err := s.server.db.Exec("UPDATE rengoku_score SET max_stages_mp=$1, max_points_mp=$2, max_stages_sp=$3, max_points_sp=$4 WHERE character_id=$5", maxStageMp, maxScoreMp, maxStageSp, maxScoreSp, s.charID); err != nil {
s.logger.Error("Failed to update rengoku score", zap.Error(err))
}
_, _ = s.server.db.Exec("UPDATE rengoku_score SET max_stages_mp=$1, max_points_mp=$2, max_stages_sp=$3, max_points_sp=$4 WHERE character_id=$5", maxStageMp, maxScoreMp, maxStageSp, maxScoreSp, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -6,6 +6,8 @@ import (
_config "erupe-ce/config"
"erupe-ce/network/mhfpacket"
"math/rand"
"go.uber.org/zap"
)
type ShopItem struct {
@@ -270,11 +272,13 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
continue
}
buyCount := bf.ReadUint32()
_, _ = s.server.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought)
if _, err := s.server.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought)
VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id)
DO UPDATE SET bought = bought + $3
WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2
`, s.charID, itemHash, buyCount)
`, s.charID, itemHash, buyCount); err != nil {
s.logger.Error("Failed to update shop item purchase count", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
@@ -300,10 +304,14 @@ func handleMsgMhfGetGachaPoint(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUseGachaPoint)
if pkt.TrialCoins > 0 {
_, _ = s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.TrialCoins, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.TrialCoins, s.charID); err != nil {
s.logger.Error("Failed to deduct gacha trial coins", zap.Error(err))
}
}
if pkt.PremiumCoins > 0 {
_, _ = s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.PremiumCoins, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.PremiumCoins, s.charID); err != nil {
s.logger.Error("Failed to deduct gacha premium coins", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -312,9 +320,13 @@ func spendGachaCoin(s *Session, quantity uint16) {
var gt uint16
_ = s.server.db.QueryRow(`SELECT COALESCE(gacha_trial, 0) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&gt)
if quantity <= gt {
_, _ = s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID); err != nil {
s.logger.Error("Failed to deduct gacha trial coins", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID)
if _, err := s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID); err != nil {
s.logger.Error("Failed to deduct gacha premium coins", zap.Error(err))
}
}
}
@@ -343,7 +355,9 @@ func transactGacha(s *Session, gachaID uint32, rollID uint8) (int, error) {
case 20:
spendGachaCoin(s, itemNumber)
case 21:
_, _ = s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", itemNumber, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", itemNumber, s.charID); err != nil {
s.logger.Error("Failed to deduct frontier points for gacha", zap.Error(err))
}
}
return rolls, nil
}
@@ -383,7 +397,9 @@ func addGachaItem(s *Session, items []GachaItem) {
newItem.WriteUint16(items[i].ItemID)
newItem.WriteUint16(items[i].Quantity)
}
_, _ = s.server.db.Exec(`UPDATE characters SET gacha_items = $1 WHERE id = $2`, newItem.Data(), s.charID)
if _, err := s.server.db.Exec(`UPDATE characters SET gacha_items = $1 WHERE id = $2`, newItem.Data(), s.charID); err != nil {
s.logger.Error("Failed to update gacha items", zap.Error(err))
}
}
func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) {
@@ -436,9 +452,13 @@ func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
update := byteframe.NewByteFrame()
update.WriteUint8(uint8(len(data[181:]) / 5))
update.WriteBytes(data[181:])
_, _ = s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", update.Data(), s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", update.Data(), s.charID); err != nil {
s.logger.Error("Failed to update gacha items overflow", zap.Error(err))
}
} else {
_, _ = s.server.db.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.charID)
if _, err := s.server.db.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.charID); err != nil {
s.logger.Error("Failed to clear gacha items", zap.Error(err))
}
}
}
}
@@ -507,9 +527,15 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return
}
_, _ = s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.charID)
_, _ = s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID)
_, _ = s.server.db.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.charID)
if _, err := s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.charID); err != nil {
s.logger.Error("Failed to award stepup gacha frontier points", zap.Error(err))
}
if _, err := s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID); err != nil {
s.logger.Error("Failed to delete gacha stepup state", zap.Error(err))
}
if _, err := s.server.db.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.charID); err != nil {
s.logger.Error("Failed to insert gacha stepup state", zap.Error(err))
}
rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil {
@@ -567,7 +593,9 @@ func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
var stepCheck int
_ = s.server.db.QueryRow(`SELECT COUNT(1) FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2`, pkt.GachaID, step).Scan(&stepCheck)
if stepCheck == 0 {
_, _ = s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID)
if _, err := s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID); err != nil {
s.logger.Error("Failed to reset gacha stepup state", zap.Error(err))
}
step = 0
}
bf := byteframe.NewByteFrame()
@@ -627,7 +655,9 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
continue
}
_, _ = s.server.db.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.charID)
if _, err := s.server.db.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.charID); err != nil {
s.logger.Error("Failed to insert gacha box entry", zap.Error(err))
}
for items.Next() {
err = items.StructScan(&reward)
if err == nil {
@@ -648,7 +678,9 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfResetBoxGachaInfo)
_, _ = s.server.db.Exec("DELETE FROM gacha_box WHERE gacha_id = $1 AND character_id = $2", pkt.GachaID, s.charID)
if _, err := s.server.db.Exec("DELETE FROM gacha_box WHERE gacha_id = $1 AND character_id = $2", pkt.GachaID, s.charID); err != nil {
s.logger.Error("Failed to reset gacha box", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

View File

@@ -65,7 +65,9 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), COALESCE(skills, $1) FROM tower WHERE char_id=$2
`, EmptyTowerCSV(64), s.charID).Scan(&towerInfo.TRP[0].TR, &towerInfo.TRP[0].TRP, &towerInfo.Skill[0].TSP, &towerInfo.Level[0].Floors, &towerInfo.Level[1].Floors, &tempSkills)
if err != nil {
_, _ = s.server.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.charID)
if _, err := s.server.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.charID); err != nil {
s.logger.Error("Failed to initialize tower data", zap.Error(err))
}
}
if _config.ErupeConfig.RealClientMode <= _config.G7 {
@@ -143,10 +145,14 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
case 2:
var skills string
_ = s.server.db.QueryRow(`SELECT COALESCE(skills, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(64), s.charID).Scan(&skills)
_, _ = s.server.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, stringsupport.CSVSetIndex(skills, int(pkt.Skill), stringsupport.CSVGetIndex(skills, int(pkt.Skill))+1), pkt.Cost, s.charID)
if _, err := s.server.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, stringsupport.CSVSetIndex(skills, int(pkt.Skill), stringsupport.CSVGetIndex(skills, int(pkt.Skill))+1), pkt.Cost, s.charID); err != nil {
s.logger.Error("Failed to update tower skills", zap.Error(err))
}
case 1, 7:
// This might give too much TSP? No idea what the rate is supposed to be
_, _ = s.server.db.Exec(`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`, pkt.TR, pkt.TRP, pkt.Cost, pkt.Block1, s.charID)
if _, err := s.server.db.Exec(`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`, pkt.TR, pkt.TRP, pkt.Cost, pkt.Block1, s.charID); err != nil {
s.logger.Error("Failed to update tower progress", zap.Error(err))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -382,12 +388,18 @@ func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
sd.RP -= pkt.DonatedRP
sd.Save(s)
if donated+int(pkt.DonatedRP) >= requirement {
_, _ = s.server.db.Exec(`UPDATE guilds SET tower_mission_page=tower_mission_page+1 WHERE id=$1`, pkt.GuildID)
_, _ = s.server.db.Exec(`UPDATE guild_characters SET tower_mission_1=NULL, tower_mission_2=NULL, tower_mission_3=NULL WHERE guild_id=$1`, pkt.GuildID)
if _, err := s.server.db.Exec(`UPDATE guilds SET tower_mission_page=tower_mission_page+1 WHERE id=$1`, pkt.GuildID); err != nil {
s.logger.Error("Failed to advance tower mission page", zap.Error(err))
}
if _, err := s.server.db.Exec(`UPDATE guild_characters SET tower_mission_1=NULL, tower_mission_2=NULL, tower_mission_3=NULL WHERE guild_id=$1`, pkt.GuildID); err != nil {
s.logger.Error("Failed to reset tower mission progress", zap.Error(err))
}
pkt.DonatedRP = uint16(requirement - donated)
}
bf.WriteUint32(uint32(pkt.DonatedRP))
_, _ = s.server.db.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, pkt.DonatedRP, pkt.GuildID)
if _, err := s.server.db.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, pkt.DonatedRP, pkt.GuildID); err != nil {
s.logger.Error("Failed to update guild tower RP", zap.Error(err))
}
} else {
bf.WriteUint32(0)
}
@@ -486,7 +498,9 @@ func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {
switch pkt.Op {
case 1: // Add gem
i := int((pkt.Gem >> 8 * 5) + (pkt.Gem - pkt.Gem&0xFF00 - 1%5))
_, _ = s.server.db.Exec(`UPDATE tower SET gems=$1 WHERE char_id=$2`, stringsupport.CSVSetIndex(gems, i, stringsupport.CSVGetIndex(gems, i)+int(pkt.Quantity)), s.charID)
if _, err := s.server.db.Exec(`UPDATE tower SET gems=$1 WHERE char_id=$2`, stringsupport.CSVSetIndex(gems, i, stringsupport.CSVGetIndex(gems, i)+int(pkt.Quantity)), s.charID); err != nil {
s.logger.Error("Failed to update tower gems", zap.Error(err))
}
case 2: // Transfer gem
// no way im doing this for now
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)
func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {}
@@ -19,10 +20,14 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
var exists []byte
err := s.server.db.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.charID).Scan(&exists)
if err != nil {
_, _ = s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID)
if _, err := s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID); err != nil {
s.logger.Error("Failed to insert user binary", zap.Error(err))
}
}
_, _ = s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID)
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID); err != nil {
s.logger.Error("Failed to update user binary", zap.Error(err))
}
msg := &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID,